pub struct Fragmentizer { /* private fields */ }Expand description
Splits IMAP bytes into line and literal fragments.
The Fragmentizer prevents excessive memory allocation through a configurable maximum message size.
Correct fragmentation is ensured even for messages exceeding the allowed message size.
If the message size is exceeded,
Fragmentizer::decode_message will fail and
Fragmentizer::message_bytes will emit truncated message bytes.
However, fragmentation will seamlessly continue with the following message.
Implementations§
Source§impl Fragmentizer
impl Fragmentizer
Sourcepub fn new(max_message_size: u32) -> Self
pub fn new(max_message_size: u32) -> Self
Creates a Fragmentizer with a maximum message size.
The maximum message size is bounded by max_message_size to prevent excessive memory allocation.
Examples found in repository?
5fn main() {
6 let mut fragmentizer = Fragmentizer::new(1024);
7
8 loop {
9 match fragmentizer.progress() {
10 Some(fragment_info) => {
11 println!(
12 "[!] Fragment: {fragment_info:#?} // b\"{}\"",
13 escape_byte_string(fragmentizer.fragment_bytes(fragment_info))
14 );
15
16 if fragmentizer.is_message_complete() {
17 println!(
18 "[!] Complete message: {}",
19 escape_byte_string(fragmentizer.message_bytes())
20 );
21 }
22 }
23 None => {
24 println!("[!] Reading stdin (ctrl+d to flush)...");
25 let mut buffer = [0; 64];
26 let count = stdin().read(&mut buffer).unwrap();
27 if count == 0 {
28 println!("[!] Connection closed");
29 break;
30 }
31 let chunk = &buffer[..count];
32
33 println!(
34 "[!] Enqueueing {} byte(s) (b\"{}\")",
35 count,
36 escape_byte_string(chunk)
37 );
38 fragmentizer.enqueue_bytes(chunk);
39 }
40 }
41 }
42}More examples
27fn main() {
28 println!("{WELCOME}");
29
30 let mut fragmentizer = Fragmentizer::new(10 * 1024);
31 let mut state = State::Greeting;
32
33 loop {
34 // Progress next fragment.
35 let Some(_fragment_info) = fragmentizer.progress() else {
36 // Read more bytes ...
37 let bytes = read_more(Role::Server, fragmentizer.message_bytes().is_empty());
38
39 // ... and pass the bytes to the Fragmentizer ...
40 fragmentizer.enqueue_bytes(&bytes);
41
42 // ... and try again.
43 continue;
44 };
45
46 // Check whether the Fragmentizer detected a complete message.
47 if !fragmentizer.is_message_complete() {
48 // Read next fragment.
49 continue;
50 }
51
52 // The Fragmentizer detected a complete message.
53 match state {
54 State::Greeting => {
55 match fragmentizer.decode_message(&GreetingCodec::default()) {
56 Ok(greeting) => {
57 // Do something with the greeting ...
58 println!("{greeting:#?}");
59
60 // ... and proceed with reponses.
61 state = State::Response;
62 }
63 Err(err) => {
64 println!("Error parsing greeting: {err:?}");
65 }
66 };
67 }
68 State::Response => {
69 match fragmentizer.decode_message(&ResponseCodec::default()) {
70 Ok(response) => {
71 // Do something with the response.
72 println!("{response:#?}");
73 }
74 Err(err) => {
75 println!("Error parsing response: {err:?}");
76 }
77 };
78 }
79 };
80 }
81}37fn main() {
38 println!("{WELCOME}");
39
40 let mut fragmentizer = Fragmentizer::new(10 * 1024);
41 let mut state = State::Command;
42
43 // Send a greeting.
44 println!("S: {COLOR_SERVER}* OK ...{RESET}");
45
46 loop {
47 // Progress next fragment.
48 let Some(fragment_info) = fragmentizer.progress() else {
49 // Read more bytes ...
50 let bytes = read_more(Role::Client, fragmentizer.message_bytes().is_empty());
51
52 // ... and pass the bytes to the Fragmentizer ...
53 fragmentizer.enqueue_bytes(&bytes);
54
55 // ... and try again.
56 continue;
57 };
58
59 // The Fragmentizer detected a line that announces a sync literal.
60 if let FragmentInfo::Line {
61 announcement:
62 Some(LiteralAnnouncement {
63 mode: LiteralMode::Sync,
64 length,
65 }),
66 ..
67 } = fragment_info
68 {
69 // Check the length of the literal.
70 if length <= 1024 {
71 // Accept the literal ...
72 println!("S: {COLOR_SERVER}+ {RESET}");
73
74 // ... and continue with the remaining message.
75 continue;
76 } else if let Some(tag) = fragmentizer.decode_tag() {
77 // Reject the literal ...
78 println!("S: {COLOR_SERVER}{} BAD ...{RESET}", tag.as_ref());
79
80 // ... and skip the current message ...
81 fragmentizer.skip_message();
82
83 // ... and continue with the next message.
84 continue;
85 } else {
86 // The partially received message is malformed. It's unclear what will follow.
87 // To be on the safe side, prevent the message from being decoded ...
88 fragmentizer.poison_message();
89
90 // ... but continue parsing the message.
91 continue;
92 }
93 }
94
95 // Check whether the Fragmentizer detected a complete message.
96 if !fragmentizer.is_message_complete() {
97 // Read next fragment.
98 continue;
99 }
100
101 // The Fragmentizer detected a complete message.
102 match state {
103 State::Command => {
104 match fragmentizer.decode_message(&CommandCodec::default()) {
105 Ok(Command {
106 tag,
107 body: CommandBody::Authenticate { .. },
108 }) => {
109 // Request another SASL round ...
110 println!("S: {COLOR_SERVER}+ {RESET}");
111
112 // ... and proceed with authenticate data.
113 state = State::Authenticate(tag.into_static());
114 }
115 Ok(Command {
116 body: CommandBody::Idle,
117 ..
118 }) => {
119 // Accept the idle ...
120 println!("S: {COLOR_SERVER}+ ...{RESET}");
121
122 // ... and proceed with idle done.
123 state = State::Idle;
124 }
125 Ok(command) => {
126 // Do something with the command.
127 println!("{command:#?}");
128 }
129 Err(err) => {
130 println!("Error parsing command: {err:?}");
131 }
132 };
133 }
134 State::Authenticate(ref tag) => {
135 match fragmentizer.decode_message(&AuthenticateDataCodec::default()) {
136 Ok(_authenticate_data) => {
137 // Accept the authentication after one SASL round.
138 println!("S: {COLOR_SERVER}{} OK ...{RESET}", tag.as_ref());
139
140 // ... and proceed with commands.
141 state = State::Command;
142 }
143 Err(err) => {
144 println!("Error parsing authenticate data: {err:?}");
145 }
146 };
147 }
148 State::Idle => {
149 match fragmentizer.decode_message(&IdleDoneCodec::default()) {
150 Ok(_idle_done) => {
151 // End idle and proceed with commands.
152 state = State::Command;
153 }
154 Err(err) => {
155 println!("Error parsing idle done: {err:?}");
156 }
157 };
158 }
159 }
160 }
161}Sourcepub fn without_max_message_size() -> Self
pub fn without_max_message_size() -> Self
Creates a Fragmentizer without a maximum message size.
Sourcepub fn progress(&mut self) -> Option<FragmentInfo>
pub fn progress(&mut self) -> Option<FragmentInfo>
Continue parsing the current message until the next fragment is detected.
Returns None if more bytes need to be enqueued via Fragmentizer::enqueue_bytes.
If Fragmentizer::is_message_complete returns true after this function was called,
then the message was fully parsed. The following call of this function will then start
the next message.
Examples found in repository?
5fn main() {
6 let mut fragmentizer = Fragmentizer::new(1024);
7
8 loop {
9 match fragmentizer.progress() {
10 Some(fragment_info) => {
11 println!(
12 "[!] Fragment: {fragment_info:#?} // b\"{}\"",
13 escape_byte_string(fragmentizer.fragment_bytes(fragment_info))
14 );
15
16 if fragmentizer.is_message_complete() {
17 println!(
18 "[!] Complete message: {}",
19 escape_byte_string(fragmentizer.message_bytes())
20 );
21 }
22 }
23 None => {
24 println!("[!] Reading stdin (ctrl+d to flush)...");
25 let mut buffer = [0; 64];
26 let count = stdin().read(&mut buffer).unwrap();
27 if count == 0 {
28 println!("[!] Connection closed");
29 break;
30 }
31 let chunk = &buffer[..count];
32
33 println!(
34 "[!] Enqueueing {} byte(s) (b\"{}\")",
35 count,
36 escape_byte_string(chunk)
37 );
38 fragmentizer.enqueue_bytes(chunk);
39 }
40 }
41 }
42}More examples
27fn main() {
28 println!("{WELCOME}");
29
30 let mut fragmentizer = Fragmentizer::new(10 * 1024);
31 let mut state = State::Greeting;
32
33 loop {
34 // Progress next fragment.
35 let Some(_fragment_info) = fragmentizer.progress() else {
36 // Read more bytes ...
37 let bytes = read_more(Role::Server, fragmentizer.message_bytes().is_empty());
38
39 // ... and pass the bytes to the Fragmentizer ...
40 fragmentizer.enqueue_bytes(&bytes);
41
42 // ... and try again.
43 continue;
44 };
45
46 // Check whether the Fragmentizer detected a complete message.
47 if !fragmentizer.is_message_complete() {
48 // Read next fragment.
49 continue;
50 }
51
52 // The Fragmentizer detected a complete message.
53 match state {
54 State::Greeting => {
55 match fragmentizer.decode_message(&GreetingCodec::default()) {
56 Ok(greeting) => {
57 // Do something with the greeting ...
58 println!("{greeting:#?}");
59
60 // ... and proceed with reponses.
61 state = State::Response;
62 }
63 Err(err) => {
64 println!("Error parsing greeting: {err:?}");
65 }
66 };
67 }
68 State::Response => {
69 match fragmentizer.decode_message(&ResponseCodec::default()) {
70 Ok(response) => {
71 // Do something with the response.
72 println!("{response:#?}");
73 }
74 Err(err) => {
75 println!("Error parsing response: {err:?}");
76 }
77 };
78 }
79 };
80 }
81}37fn main() {
38 println!("{WELCOME}");
39
40 let mut fragmentizer = Fragmentizer::new(10 * 1024);
41 let mut state = State::Command;
42
43 // Send a greeting.
44 println!("S: {COLOR_SERVER}* OK ...{RESET}");
45
46 loop {
47 // Progress next fragment.
48 let Some(fragment_info) = fragmentizer.progress() else {
49 // Read more bytes ...
50 let bytes = read_more(Role::Client, fragmentizer.message_bytes().is_empty());
51
52 // ... and pass the bytes to the Fragmentizer ...
53 fragmentizer.enqueue_bytes(&bytes);
54
55 // ... and try again.
56 continue;
57 };
58
59 // The Fragmentizer detected a line that announces a sync literal.
60 if let FragmentInfo::Line {
61 announcement:
62 Some(LiteralAnnouncement {
63 mode: LiteralMode::Sync,
64 length,
65 }),
66 ..
67 } = fragment_info
68 {
69 // Check the length of the literal.
70 if length <= 1024 {
71 // Accept the literal ...
72 println!("S: {COLOR_SERVER}+ {RESET}");
73
74 // ... and continue with the remaining message.
75 continue;
76 } else if let Some(tag) = fragmentizer.decode_tag() {
77 // Reject the literal ...
78 println!("S: {COLOR_SERVER}{} BAD ...{RESET}", tag.as_ref());
79
80 // ... and skip the current message ...
81 fragmentizer.skip_message();
82
83 // ... and continue with the next message.
84 continue;
85 } else {
86 // The partially received message is malformed. It's unclear what will follow.
87 // To be on the safe side, prevent the message from being decoded ...
88 fragmentizer.poison_message();
89
90 // ... but continue parsing the message.
91 continue;
92 }
93 }
94
95 // Check whether the Fragmentizer detected a complete message.
96 if !fragmentizer.is_message_complete() {
97 // Read next fragment.
98 continue;
99 }
100
101 // The Fragmentizer detected a complete message.
102 match state {
103 State::Command => {
104 match fragmentizer.decode_message(&CommandCodec::default()) {
105 Ok(Command {
106 tag,
107 body: CommandBody::Authenticate { .. },
108 }) => {
109 // Request another SASL round ...
110 println!("S: {COLOR_SERVER}+ {RESET}");
111
112 // ... and proceed with authenticate data.
113 state = State::Authenticate(tag.into_static());
114 }
115 Ok(Command {
116 body: CommandBody::Idle,
117 ..
118 }) => {
119 // Accept the idle ...
120 println!("S: {COLOR_SERVER}+ ...{RESET}");
121
122 // ... and proceed with idle done.
123 state = State::Idle;
124 }
125 Ok(command) => {
126 // Do something with the command.
127 println!("{command:#?}");
128 }
129 Err(err) => {
130 println!("Error parsing command: {err:?}");
131 }
132 };
133 }
134 State::Authenticate(ref tag) => {
135 match fragmentizer.decode_message(&AuthenticateDataCodec::default()) {
136 Ok(_authenticate_data) => {
137 // Accept the authentication after one SASL round.
138 println!("S: {COLOR_SERVER}{} OK ...{RESET}", tag.as_ref());
139
140 // ... and proceed with commands.
141 state = State::Command;
142 }
143 Err(err) => {
144 println!("Error parsing authenticate data: {err:?}");
145 }
146 };
147 }
148 State::Idle => {
149 match fragmentizer.decode_message(&IdleDoneCodec::default()) {
150 Ok(_idle_done) => {
151 // End idle and proceed with commands.
152 state = State::Command;
153 }
154 Err(err) => {
155 println!("Error parsing idle done: {err:?}");
156 }
157 };
158 }
159 }
160 }
161}Sourcepub fn enqueue_bytes(&mut self, bytes: &[u8])
pub fn enqueue_bytes(&mut self, bytes: &[u8])
Enqueues more byte that can be parsed by Fragmentizer::progress.
Note that the message size limit is not enforced on the enqueued bytes. You can control
the size of the enqueued bytes by only calling this function if more bytes are necessary.
More bytes are necessary if Fragmentizer::progress returns None.
Examples found in repository?
5fn main() {
6 let mut fragmentizer = Fragmentizer::new(1024);
7
8 loop {
9 match fragmentizer.progress() {
10 Some(fragment_info) => {
11 println!(
12 "[!] Fragment: {fragment_info:#?} // b\"{}\"",
13 escape_byte_string(fragmentizer.fragment_bytes(fragment_info))
14 );
15
16 if fragmentizer.is_message_complete() {
17 println!(
18 "[!] Complete message: {}",
19 escape_byte_string(fragmentizer.message_bytes())
20 );
21 }
22 }
23 None => {
24 println!("[!] Reading stdin (ctrl+d to flush)...");
25 let mut buffer = [0; 64];
26 let count = stdin().read(&mut buffer).unwrap();
27 if count == 0 {
28 println!("[!] Connection closed");
29 break;
30 }
31 let chunk = &buffer[..count];
32
33 println!(
34 "[!] Enqueueing {} byte(s) (b\"{}\")",
35 count,
36 escape_byte_string(chunk)
37 );
38 fragmentizer.enqueue_bytes(chunk);
39 }
40 }
41 }
42}More examples
27fn main() {
28 println!("{WELCOME}");
29
30 let mut fragmentizer = Fragmentizer::new(10 * 1024);
31 let mut state = State::Greeting;
32
33 loop {
34 // Progress next fragment.
35 let Some(_fragment_info) = fragmentizer.progress() else {
36 // Read more bytes ...
37 let bytes = read_more(Role::Server, fragmentizer.message_bytes().is_empty());
38
39 // ... and pass the bytes to the Fragmentizer ...
40 fragmentizer.enqueue_bytes(&bytes);
41
42 // ... and try again.
43 continue;
44 };
45
46 // Check whether the Fragmentizer detected a complete message.
47 if !fragmentizer.is_message_complete() {
48 // Read next fragment.
49 continue;
50 }
51
52 // The Fragmentizer detected a complete message.
53 match state {
54 State::Greeting => {
55 match fragmentizer.decode_message(&GreetingCodec::default()) {
56 Ok(greeting) => {
57 // Do something with the greeting ...
58 println!("{greeting:#?}");
59
60 // ... and proceed with reponses.
61 state = State::Response;
62 }
63 Err(err) => {
64 println!("Error parsing greeting: {err:?}");
65 }
66 };
67 }
68 State::Response => {
69 match fragmentizer.decode_message(&ResponseCodec::default()) {
70 Ok(response) => {
71 // Do something with the response.
72 println!("{response:#?}");
73 }
74 Err(err) => {
75 println!("Error parsing response: {err:?}");
76 }
77 };
78 }
79 };
80 }
81}37fn main() {
38 println!("{WELCOME}");
39
40 let mut fragmentizer = Fragmentizer::new(10 * 1024);
41 let mut state = State::Command;
42
43 // Send a greeting.
44 println!("S: {COLOR_SERVER}* OK ...{RESET}");
45
46 loop {
47 // Progress next fragment.
48 let Some(fragment_info) = fragmentizer.progress() else {
49 // Read more bytes ...
50 let bytes = read_more(Role::Client, fragmentizer.message_bytes().is_empty());
51
52 // ... and pass the bytes to the Fragmentizer ...
53 fragmentizer.enqueue_bytes(&bytes);
54
55 // ... and try again.
56 continue;
57 };
58
59 // The Fragmentizer detected a line that announces a sync literal.
60 if let FragmentInfo::Line {
61 announcement:
62 Some(LiteralAnnouncement {
63 mode: LiteralMode::Sync,
64 length,
65 }),
66 ..
67 } = fragment_info
68 {
69 // Check the length of the literal.
70 if length <= 1024 {
71 // Accept the literal ...
72 println!("S: {COLOR_SERVER}+ {RESET}");
73
74 // ... and continue with the remaining message.
75 continue;
76 } else if let Some(tag) = fragmentizer.decode_tag() {
77 // Reject the literal ...
78 println!("S: {COLOR_SERVER}{} BAD ...{RESET}", tag.as_ref());
79
80 // ... and skip the current message ...
81 fragmentizer.skip_message();
82
83 // ... and continue with the next message.
84 continue;
85 } else {
86 // The partially received message is malformed. It's unclear what will follow.
87 // To be on the safe side, prevent the message from being decoded ...
88 fragmentizer.poison_message();
89
90 // ... but continue parsing the message.
91 continue;
92 }
93 }
94
95 // Check whether the Fragmentizer detected a complete message.
96 if !fragmentizer.is_message_complete() {
97 // Read next fragment.
98 continue;
99 }
100
101 // The Fragmentizer detected a complete message.
102 match state {
103 State::Command => {
104 match fragmentizer.decode_message(&CommandCodec::default()) {
105 Ok(Command {
106 tag,
107 body: CommandBody::Authenticate { .. },
108 }) => {
109 // Request another SASL round ...
110 println!("S: {COLOR_SERVER}+ {RESET}");
111
112 // ... and proceed with authenticate data.
113 state = State::Authenticate(tag.into_static());
114 }
115 Ok(Command {
116 body: CommandBody::Idle,
117 ..
118 }) => {
119 // Accept the idle ...
120 println!("S: {COLOR_SERVER}+ ...{RESET}");
121
122 // ... and proceed with idle done.
123 state = State::Idle;
124 }
125 Ok(command) => {
126 // Do something with the command.
127 println!("{command:#?}");
128 }
129 Err(err) => {
130 println!("Error parsing command: {err:?}");
131 }
132 };
133 }
134 State::Authenticate(ref tag) => {
135 match fragmentizer.decode_message(&AuthenticateDataCodec::default()) {
136 Ok(_authenticate_data) => {
137 // Accept the authentication after one SASL round.
138 println!("S: {COLOR_SERVER}{} OK ...{RESET}", tag.as_ref());
139
140 // ... and proceed with commands.
141 state = State::Command;
142 }
143 Err(err) => {
144 println!("Error parsing authenticate data: {err:?}");
145 }
146 };
147 }
148 State::Idle => {
149 match fragmentizer.decode_message(&IdleDoneCodec::default()) {
150 Ok(_idle_done) => {
151 // End idle and proceed with commands.
152 state = State::Command;
153 }
154 Err(err) => {
155 println!("Error parsing idle done: {err:?}");
156 }
157 };
158 }
159 }
160 }
161}Sourcepub fn fragment_bytes(&self, fragment_info: FragmentInfo) -> &[u8] ⓘ
pub fn fragment_bytes(&self, fragment_info: FragmentInfo) -> &[u8] ⓘ
Returns the bytes for a fragment of the current message.
Examples found in repository?
5fn main() {
6 let mut fragmentizer = Fragmentizer::new(1024);
7
8 loop {
9 match fragmentizer.progress() {
10 Some(fragment_info) => {
11 println!(
12 "[!] Fragment: {fragment_info:#?} // b\"{}\"",
13 escape_byte_string(fragmentizer.fragment_bytes(fragment_info))
14 );
15
16 if fragmentizer.is_message_complete() {
17 println!(
18 "[!] Complete message: {}",
19 escape_byte_string(fragmentizer.message_bytes())
20 );
21 }
22 }
23 None => {
24 println!("[!] Reading stdin (ctrl+d to flush)...");
25 let mut buffer = [0; 64];
26 let count = stdin().read(&mut buffer).unwrap();
27 if count == 0 {
28 println!("[!] Connection closed");
29 break;
30 }
31 let chunk = &buffer[..count];
32
33 println!(
34 "[!] Enqueueing {} byte(s) (b\"{}\")",
35 count,
36 escape_byte_string(chunk)
37 );
38 fragmentizer.enqueue_bytes(chunk);
39 }
40 }
41 }
42}Sourcepub fn is_message_complete(&self) -> bool
pub fn is_message_complete(&self) -> bool
Returns whether the current message was fully parsed.
If it returns true then it makes sense to call Fragmentizer::decode_message
to decode the message. Alternatively, you can access all bytes of the message via
Fragmentizer::message_bytes.
Examples found in repository?
5fn main() {
6 let mut fragmentizer = Fragmentizer::new(1024);
7
8 loop {
9 match fragmentizer.progress() {
10 Some(fragment_info) => {
11 println!(
12 "[!] Fragment: {fragment_info:#?} // b\"{}\"",
13 escape_byte_string(fragmentizer.fragment_bytes(fragment_info))
14 );
15
16 if fragmentizer.is_message_complete() {
17 println!(
18 "[!] Complete message: {}",
19 escape_byte_string(fragmentizer.message_bytes())
20 );
21 }
22 }
23 None => {
24 println!("[!] Reading stdin (ctrl+d to flush)...");
25 let mut buffer = [0; 64];
26 let count = stdin().read(&mut buffer).unwrap();
27 if count == 0 {
28 println!("[!] Connection closed");
29 break;
30 }
31 let chunk = &buffer[..count];
32
33 println!(
34 "[!] Enqueueing {} byte(s) (b\"{}\")",
35 count,
36 escape_byte_string(chunk)
37 );
38 fragmentizer.enqueue_bytes(chunk);
39 }
40 }
41 }
42}More examples
27fn main() {
28 println!("{WELCOME}");
29
30 let mut fragmentizer = Fragmentizer::new(10 * 1024);
31 let mut state = State::Greeting;
32
33 loop {
34 // Progress next fragment.
35 let Some(_fragment_info) = fragmentizer.progress() else {
36 // Read more bytes ...
37 let bytes = read_more(Role::Server, fragmentizer.message_bytes().is_empty());
38
39 // ... and pass the bytes to the Fragmentizer ...
40 fragmentizer.enqueue_bytes(&bytes);
41
42 // ... and try again.
43 continue;
44 };
45
46 // Check whether the Fragmentizer detected a complete message.
47 if !fragmentizer.is_message_complete() {
48 // Read next fragment.
49 continue;
50 }
51
52 // The Fragmentizer detected a complete message.
53 match state {
54 State::Greeting => {
55 match fragmentizer.decode_message(&GreetingCodec::default()) {
56 Ok(greeting) => {
57 // Do something with the greeting ...
58 println!("{greeting:#?}");
59
60 // ... and proceed with reponses.
61 state = State::Response;
62 }
63 Err(err) => {
64 println!("Error parsing greeting: {err:?}");
65 }
66 };
67 }
68 State::Response => {
69 match fragmentizer.decode_message(&ResponseCodec::default()) {
70 Ok(response) => {
71 // Do something with the response.
72 println!("{response:#?}");
73 }
74 Err(err) => {
75 println!("Error parsing response: {err:?}");
76 }
77 };
78 }
79 };
80 }
81}37fn main() {
38 println!("{WELCOME}");
39
40 let mut fragmentizer = Fragmentizer::new(10 * 1024);
41 let mut state = State::Command;
42
43 // Send a greeting.
44 println!("S: {COLOR_SERVER}* OK ...{RESET}");
45
46 loop {
47 // Progress next fragment.
48 let Some(fragment_info) = fragmentizer.progress() else {
49 // Read more bytes ...
50 let bytes = read_more(Role::Client, fragmentizer.message_bytes().is_empty());
51
52 // ... and pass the bytes to the Fragmentizer ...
53 fragmentizer.enqueue_bytes(&bytes);
54
55 // ... and try again.
56 continue;
57 };
58
59 // The Fragmentizer detected a line that announces a sync literal.
60 if let FragmentInfo::Line {
61 announcement:
62 Some(LiteralAnnouncement {
63 mode: LiteralMode::Sync,
64 length,
65 }),
66 ..
67 } = fragment_info
68 {
69 // Check the length of the literal.
70 if length <= 1024 {
71 // Accept the literal ...
72 println!("S: {COLOR_SERVER}+ {RESET}");
73
74 // ... and continue with the remaining message.
75 continue;
76 } else if let Some(tag) = fragmentizer.decode_tag() {
77 // Reject the literal ...
78 println!("S: {COLOR_SERVER}{} BAD ...{RESET}", tag.as_ref());
79
80 // ... and skip the current message ...
81 fragmentizer.skip_message();
82
83 // ... and continue with the next message.
84 continue;
85 } else {
86 // The partially received message is malformed. It's unclear what will follow.
87 // To be on the safe side, prevent the message from being decoded ...
88 fragmentizer.poison_message();
89
90 // ... but continue parsing the message.
91 continue;
92 }
93 }
94
95 // Check whether the Fragmentizer detected a complete message.
96 if !fragmentizer.is_message_complete() {
97 // Read next fragment.
98 continue;
99 }
100
101 // The Fragmentizer detected a complete message.
102 match state {
103 State::Command => {
104 match fragmentizer.decode_message(&CommandCodec::default()) {
105 Ok(Command {
106 tag,
107 body: CommandBody::Authenticate { .. },
108 }) => {
109 // Request another SASL round ...
110 println!("S: {COLOR_SERVER}+ {RESET}");
111
112 // ... and proceed with authenticate data.
113 state = State::Authenticate(tag.into_static());
114 }
115 Ok(Command {
116 body: CommandBody::Idle,
117 ..
118 }) => {
119 // Accept the idle ...
120 println!("S: {COLOR_SERVER}+ ...{RESET}");
121
122 // ... and proceed with idle done.
123 state = State::Idle;
124 }
125 Ok(command) => {
126 // Do something with the command.
127 println!("{command:#?}");
128 }
129 Err(err) => {
130 println!("Error parsing command: {err:?}");
131 }
132 };
133 }
134 State::Authenticate(ref tag) => {
135 match fragmentizer.decode_message(&AuthenticateDataCodec::default()) {
136 Ok(_authenticate_data) => {
137 // Accept the authentication after one SASL round.
138 println!("S: {COLOR_SERVER}{} OK ...{RESET}", tag.as_ref());
139
140 // ... and proceed with commands.
141 state = State::Command;
142 }
143 Err(err) => {
144 println!("Error parsing authenticate data: {err:?}");
145 }
146 };
147 }
148 State::Idle => {
149 match fragmentizer.decode_message(&IdleDoneCodec::default()) {
150 Ok(_idle_done) => {
151 // End idle and proceed with commands.
152 state = State::Command;
153 }
154 Err(err) => {
155 println!("Error parsing idle done: {err:?}");
156 }
157 };
158 }
159 }
160 }
161}Sourcepub fn message_bytes(&self) -> &[u8] ⓘ
pub fn message_bytes(&self) -> &[u8] ⓘ
Returns the bytes of the current message.
Note that the bytes might be incomplete:
- The message might not be fully parsed yet and
Fragmentizer::progressneed to be called. You can check whether the message is complete viaFragmentizer::is_message_complete. - The size limit might be exceeded and bytes might be dropped. You can check this
via
Fragmentizer::is_max_message_size_exceeded
Examples found in repository?
5fn main() {
6 let mut fragmentizer = Fragmentizer::new(1024);
7
8 loop {
9 match fragmentizer.progress() {
10 Some(fragment_info) => {
11 println!(
12 "[!] Fragment: {fragment_info:#?} // b\"{}\"",
13 escape_byte_string(fragmentizer.fragment_bytes(fragment_info))
14 );
15
16 if fragmentizer.is_message_complete() {
17 println!(
18 "[!] Complete message: {}",
19 escape_byte_string(fragmentizer.message_bytes())
20 );
21 }
22 }
23 None => {
24 println!("[!] Reading stdin (ctrl+d to flush)...");
25 let mut buffer = [0; 64];
26 let count = stdin().read(&mut buffer).unwrap();
27 if count == 0 {
28 println!("[!] Connection closed");
29 break;
30 }
31 let chunk = &buffer[..count];
32
33 println!(
34 "[!] Enqueueing {} byte(s) (b\"{}\")",
35 count,
36 escape_byte_string(chunk)
37 );
38 fragmentizer.enqueue_bytes(chunk);
39 }
40 }
41 }
42}More examples
27fn main() {
28 println!("{WELCOME}");
29
30 let mut fragmentizer = Fragmentizer::new(10 * 1024);
31 let mut state = State::Greeting;
32
33 loop {
34 // Progress next fragment.
35 let Some(_fragment_info) = fragmentizer.progress() else {
36 // Read more bytes ...
37 let bytes = read_more(Role::Server, fragmentizer.message_bytes().is_empty());
38
39 // ... and pass the bytes to the Fragmentizer ...
40 fragmentizer.enqueue_bytes(&bytes);
41
42 // ... and try again.
43 continue;
44 };
45
46 // Check whether the Fragmentizer detected a complete message.
47 if !fragmentizer.is_message_complete() {
48 // Read next fragment.
49 continue;
50 }
51
52 // The Fragmentizer detected a complete message.
53 match state {
54 State::Greeting => {
55 match fragmentizer.decode_message(&GreetingCodec::default()) {
56 Ok(greeting) => {
57 // Do something with the greeting ...
58 println!("{greeting:#?}");
59
60 // ... and proceed with reponses.
61 state = State::Response;
62 }
63 Err(err) => {
64 println!("Error parsing greeting: {err:?}");
65 }
66 };
67 }
68 State::Response => {
69 match fragmentizer.decode_message(&ResponseCodec::default()) {
70 Ok(response) => {
71 // Do something with the response.
72 println!("{response:#?}");
73 }
74 Err(err) => {
75 println!("Error parsing response: {err:?}");
76 }
77 };
78 }
79 };
80 }
81}37fn main() {
38 println!("{WELCOME}");
39
40 let mut fragmentizer = Fragmentizer::new(10 * 1024);
41 let mut state = State::Command;
42
43 // Send a greeting.
44 println!("S: {COLOR_SERVER}* OK ...{RESET}");
45
46 loop {
47 // Progress next fragment.
48 let Some(fragment_info) = fragmentizer.progress() else {
49 // Read more bytes ...
50 let bytes = read_more(Role::Client, fragmentizer.message_bytes().is_empty());
51
52 // ... and pass the bytes to the Fragmentizer ...
53 fragmentizer.enqueue_bytes(&bytes);
54
55 // ... and try again.
56 continue;
57 };
58
59 // The Fragmentizer detected a line that announces a sync literal.
60 if let FragmentInfo::Line {
61 announcement:
62 Some(LiteralAnnouncement {
63 mode: LiteralMode::Sync,
64 length,
65 }),
66 ..
67 } = fragment_info
68 {
69 // Check the length of the literal.
70 if length <= 1024 {
71 // Accept the literal ...
72 println!("S: {COLOR_SERVER}+ {RESET}");
73
74 // ... and continue with the remaining message.
75 continue;
76 } else if let Some(tag) = fragmentizer.decode_tag() {
77 // Reject the literal ...
78 println!("S: {COLOR_SERVER}{} BAD ...{RESET}", tag.as_ref());
79
80 // ... and skip the current message ...
81 fragmentizer.skip_message();
82
83 // ... and continue with the next message.
84 continue;
85 } else {
86 // The partially received message is malformed. It's unclear what will follow.
87 // To be on the safe side, prevent the message from being decoded ...
88 fragmentizer.poison_message();
89
90 // ... but continue parsing the message.
91 continue;
92 }
93 }
94
95 // Check whether the Fragmentizer detected a complete message.
96 if !fragmentizer.is_message_complete() {
97 // Read next fragment.
98 continue;
99 }
100
101 // The Fragmentizer detected a complete message.
102 match state {
103 State::Command => {
104 match fragmentizer.decode_message(&CommandCodec::default()) {
105 Ok(Command {
106 tag,
107 body: CommandBody::Authenticate { .. },
108 }) => {
109 // Request another SASL round ...
110 println!("S: {COLOR_SERVER}+ {RESET}");
111
112 // ... and proceed with authenticate data.
113 state = State::Authenticate(tag.into_static());
114 }
115 Ok(Command {
116 body: CommandBody::Idle,
117 ..
118 }) => {
119 // Accept the idle ...
120 println!("S: {COLOR_SERVER}+ ...{RESET}");
121
122 // ... and proceed with idle done.
123 state = State::Idle;
124 }
125 Ok(command) => {
126 // Do something with the command.
127 println!("{command:#?}");
128 }
129 Err(err) => {
130 println!("Error parsing command: {err:?}");
131 }
132 };
133 }
134 State::Authenticate(ref tag) => {
135 match fragmentizer.decode_message(&AuthenticateDataCodec::default()) {
136 Ok(_authenticate_data) => {
137 // Accept the authentication after one SASL round.
138 println!("S: {COLOR_SERVER}{} OK ...{RESET}", tag.as_ref());
139
140 // ... and proceed with commands.
141 state = State::Command;
142 }
143 Err(err) => {
144 println!("Error parsing authenticate data: {err:?}");
145 }
146 };
147 }
148 State::Idle => {
149 match fragmentizer.decode_message(&IdleDoneCodec::default()) {
150 Ok(_idle_done) => {
151 // End idle and proceed with commands.
152 state = State::Command;
153 }
154 Err(err) => {
155 println!("Error parsing idle done: {err:?}");
156 }
157 };
158 }
159 }
160 }
161}Sourcepub fn is_max_message_size_exceeded(&self) -> bool
pub fn is_max_message_size_exceeded(&self) -> bool
Returns whether the size limit is exceeded for the current message.
Sourcepub fn is_message_poisoned(&self) -> bool
pub fn is_message_poisoned(&self) -> bool
Returns whether the current message was explicitly poisoned to prevent decoding.
Sourcepub fn skip_message(&mut self)
pub fn skip_message(&mut self)
Skips the current message and starts the next message immediately.
Warning: Using this method might be dangerous. If client and server don’t
agree at which point a message is skipped, then the client or server might
treat untrusted bytes (e.g. literal bytes) as IMAP messages. Currently the
only valid use-case is a server that rejects synchronizing literals from the
client. Otherwise consider using Fragmentizer::poison_message.
Examples found in repository?
37fn main() {
38 println!("{WELCOME}");
39
40 let mut fragmentizer = Fragmentizer::new(10 * 1024);
41 let mut state = State::Command;
42
43 // Send a greeting.
44 println!("S: {COLOR_SERVER}* OK ...{RESET}");
45
46 loop {
47 // Progress next fragment.
48 let Some(fragment_info) = fragmentizer.progress() else {
49 // Read more bytes ...
50 let bytes = read_more(Role::Client, fragmentizer.message_bytes().is_empty());
51
52 // ... and pass the bytes to the Fragmentizer ...
53 fragmentizer.enqueue_bytes(&bytes);
54
55 // ... and try again.
56 continue;
57 };
58
59 // The Fragmentizer detected a line that announces a sync literal.
60 if let FragmentInfo::Line {
61 announcement:
62 Some(LiteralAnnouncement {
63 mode: LiteralMode::Sync,
64 length,
65 }),
66 ..
67 } = fragment_info
68 {
69 // Check the length of the literal.
70 if length <= 1024 {
71 // Accept the literal ...
72 println!("S: {COLOR_SERVER}+ {RESET}");
73
74 // ... and continue with the remaining message.
75 continue;
76 } else if let Some(tag) = fragmentizer.decode_tag() {
77 // Reject the literal ...
78 println!("S: {COLOR_SERVER}{} BAD ...{RESET}", tag.as_ref());
79
80 // ... and skip the current message ...
81 fragmentizer.skip_message();
82
83 // ... and continue with the next message.
84 continue;
85 } else {
86 // The partially received message is malformed. It's unclear what will follow.
87 // To be on the safe side, prevent the message from being decoded ...
88 fragmentizer.poison_message();
89
90 // ... but continue parsing the message.
91 continue;
92 }
93 }
94
95 // Check whether the Fragmentizer detected a complete message.
96 if !fragmentizer.is_message_complete() {
97 // Read next fragment.
98 continue;
99 }
100
101 // The Fragmentizer detected a complete message.
102 match state {
103 State::Command => {
104 match fragmentizer.decode_message(&CommandCodec::default()) {
105 Ok(Command {
106 tag,
107 body: CommandBody::Authenticate { .. },
108 }) => {
109 // Request another SASL round ...
110 println!("S: {COLOR_SERVER}+ {RESET}");
111
112 // ... and proceed with authenticate data.
113 state = State::Authenticate(tag.into_static());
114 }
115 Ok(Command {
116 body: CommandBody::Idle,
117 ..
118 }) => {
119 // Accept the idle ...
120 println!("S: {COLOR_SERVER}+ ...{RESET}");
121
122 // ... and proceed with idle done.
123 state = State::Idle;
124 }
125 Ok(command) => {
126 // Do something with the command.
127 println!("{command:#?}");
128 }
129 Err(err) => {
130 println!("Error parsing command: {err:?}");
131 }
132 };
133 }
134 State::Authenticate(ref tag) => {
135 match fragmentizer.decode_message(&AuthenticateDataCodec::default()) {
136 Ok(_authenticate_data) => {
137 // Accept the authentication after one SASL round.
138 println!("S: {COLOR_SERVER}{} OK ...{RESET}", tag.as_ref());
139
140 // ... and proceed with commands.
141 state = State::Command;
142 }
143 Err(err) => {
144 println!("Error parsing authenticate data: {err:?}");
145 }
146 };
147 }
148 State::Idle => {
149 match fragmentizer.decode_message(&IdleDoneCodec::default()) {
150 Ok(_idle_done) => {
151 // End idle and proceed with commands.
152 state = State::Command;
153 }
154 Err(err) => {
155 println!("Error parsing idle done: {err:?}");
156 }
157 };
158 }
159 }
160 }
161}Sourcepub fn poison_message(&mut self)
pub fn poison_message(&mut self)
Poisons the current message to prevent its decoding.
When this function is called the fragments of the current message are parsed normally, but
Fragmentizer::decode_message is guaranteed to fail and return
DecodeMessageError::MessagePoisoned. This allows to skip malformed messages (e.g.
a message with an unexpected line ending) safely without the risk of treating untrusted
bytes (e.g. literal bytes) as IMAP messages
Examples found in repository?
37fn main() {
38 println!("{WELCOME}");
39
40 let mut fragmentizer = Fragmentizer::new(10 * 1024);
41 let mut state = State::Command;
42
43 // Send a greeting.
44 println!("S: {COLOR_SERVER}* OK ...{RESET}");
45
46 loop {
47 // Progress next fragment.
48 let Some(fragment_info) = fragmentizer.progress() else {
49 // Read more bytes ...
50 let bytes = read_more(Role::Client, fragmentizer.message_bytes().is_empty());
51
52 // ... and pass the bytes to the Fragmentizer ...
53 fragmentizer.enqueue_bytes(&bytes);
54
55 // ... and try again.
56 continue;
57 };
58
59 // The Fragmentizer detected a line that announces a sync literal.
60 if let FragmentInfo::Line {
61 announcement:
62 Some(LiteralAnnouncement {
63 mode: LiteralMode::Sync,
64 length,
65 }),
66 ..
67 } = fragment_info
68 {
69 // Check the length of the literal.
70 if length <= 1024 {
71 // Accept the literal ...
72 println!("S: {COLOR_SERVER}+ {RESET}");
73
74 // ... and continue with the remaining message.
75 continue;
76 } else if let Some(tag) = fragmentizer.decode_tag() {
77 // Reject the literal ...
78 println!("S: {COLOR_SERVER}{} BAD ...{RESET}", tag.as_ref());
79
80 // ... and skip the current message ...
81 fragmentizer.skip_message();
82
83 // ... and continue with the next message.
84 continue;
85 } else {
86 // The partially received message is malformed. It's unclear what will follow.
87 // To be on the safe side, prevent the message from being decoded ...
88 fragmentizer.poison_message();
89
90 // ... but continue parsing the message.
91 continue;
92 }
93 }
94
95 // Check whether the Fragmentizer detected a complete message.
96 if !fragmentizer.is_message_complete() {
97 // Read next fragment.
98 continue;
99 }
100
101 // The Fragmentizer detected a complete message.
102 match state {
103 State::Command => {
104 match fragmentizer.decode_message(&CommandCodec::default()) {
105 Ok(Command {
106 tag,
107 body: CommandBody::Authenticate { .. },
108 }) => {
109 // Request another SASL round ...
110 println!("S: {COLOR_SERVER}+ {RESET}");
111
112 // ... and proceed with authenticate data.
113 state = State::Authenticate(tag.into_static());
114 }
115 Ok(Command {
116 body: CommandBody::Idle,
117 ..
118 }) => {
119 // Accept the idle ...
120 println!("S: {COLOR_SERVER}+ ...{RESET}");
121
122 // ... and proceed with idle done.
123 state = State::Idle;
124 }
125 Ok(command) => {
126 // Do something with the command.
127 println!("{command:#?}");
128 }
129 Err(err) => {
130 println!("Error parsing command: {err:?}");
131 }
132 };
133 }
134 State::Authenticate(ref tag) => {
135 match fragmentizer.decode_message(&AuthenticateDataCodec::default()) {
136 Ok(_authenticate_data) => {
137 // Accept the authentication after one SASL round.
138 println!("S: {COLOR_SERVER}{} OK ...{RESET}", tag.as_ref());
139
140 // ... and proceed with commands.
141 state = State::Command;
142 }
143 Err(err) => {
144 println!("Error parsing authenticate data: {err:?}");
145 }
146 };
147 }
148 State::Idle => {
149 match fragmentizer.decode_message(&IdleDoneCodec::default()) {
150 Ok(_idle_done) => {
151 // End idle and proceed with commands.
152 state = State::Command;
153 }
154 Err(err) => {
155 println!("Error parsing idle done: {err:?}");
156 }
157 };
158 }
159 }
160 }
161}Sourcepub fn decode_tag(&self) -> Option<Tag<'_>>
pub fn decode_tag(&self) -> Option<Tag<'_>>
Tries to decode the Tag for the current message.
Note that decoding the Tag is on best effort basis. Some message types don’t have
a Tag and without context you can’t know whether this function will succeed. However,
this function is useful if the message is incomplete or malformed and you want to decode
the Tag in order to send a response.
Examples found in repository?
37fn main() {
38 println!("{WELCOME}");
39
40 let mut fragmentizer = Fragmentizer::new(10 * 1024);
41 let mut state = State::Command;
42
43 // Send a greeting.
44 println!("S: {COLOR_SERVER}* OK ...{RESET}");
45
46 loop {
47 // Progress next fragment.
48 let Some(fragment_info) = fragmentizer.progress() else {
49 // Read more bytes ...
50 let bytes = read_more(Role::Client, fragmentizer.message_bytes().is_empty());
51
52 // ... and pass the bytes to the Fragmentizer ...
53 fragmentizer.enqueue_bytes(&bytes);
54
55 // ... and try again.
56 continue;
57 };
58
59 // The Fragmentizer detected a line that announces a sync literal.
60 if let FragmentInfo::Line {
61 announcement:
62 Some(LiteralAnnouncement {
63 mode: LiteralMode::Sync,
64 length,
65 }),
66 ..
67 } = fragment_info
68 {
69 // Check the length of the literal.
70 if length <= 1024 {
71 // Accept the literal ...
72 println!("S: {COLOR_SERVER}+ {RESET}");
73
74 // ... and continue with the remaining message.
75 continue;
76 } else if let Some(tag) = fragmentizer.decode_tag() {
77 // Reject the literal ...
78 println!("S: {COLOR_SERVER}{} BAD ...{RESET}", tag.as_ref());
79
80 // ... and skip the current message ...
81 fragmentizer.skip_message();
82
83 // ... and continue with the next message.
84 continue;
85 } else {
86 // The partially received message is malformed. It's unclear what will follow.
87 // To be on the safe side, prevent the message from being decoded ...
88 fragmentizer.poison_message();
89
90 // ... but continue parsing the message.
91 continue;
92 }
93 }
94
95 // Check whether the Fragmentizer detected a complete message.
96 if !fragmentizer.is_message_complete() {
97 // Read next fragment.
98 continue;
99 }
100
101 // The Fragmentizer detected a complete message.
102 match state {
103 State::Command => {
104 match fragmentizer.decode_message(&CommandCodec::default()) {
105 Ok(Command {
106 tag,
107 body: CommandBody::Authenticate { .. },
108 }) => {
109 // Request another SASL round ...
110 println!("S: {COLOR_SERVER}+ {RESET}");
111
112 // ... and proceed with authenticate data.
113 state = State::Authenticate(tag.into_static());
114 }
115 Ok(Command {
116 body: CommandBody::Idle,
117 ..
118 }) => {
119 // Accept the idle ...
120 println!("S: {COLOR_SERVER}+ ...{RESET}");
121
122 // ... and proceed with idle done.
123 state = State::Idle;
124 }
125 Ok(command) => {
126 // Do something with the command.
127 println!("{command:#?}");
128 }
129 Err(err) => {
130 println!("Error parsing command: {err:?}");
131 }
132 };
133 }
134 State::Authenticate(ref tag) => {
135 match fragmentizer.decode_message(&AuthenticateDataCodec::default()) {
136 Ok(_authenticate_data) => {
137 // Accept the authentication after one SASL round.
138 println!("S: {COLOR_SERVER}{} OK ...{RESET}", tag.as_ref());
139
140 // ... and proceed with commands.
141 state = State::Command;
142 }
143 Err(err) => {
144 println!("Error parsing authenticate data: {err:?}");
145 }
146 };
147 }
148 State::Idle => {
149 match fragmentizer.decode_message(&IdleDoneCodec::default()) {
150 Ok(_idle_done) => {
151 // End idle and proceed with commands.
152 state = State::Command;
153 }
154 Err(err) => {
155 println!("Error parsing idle done: {err:?}");
156 }
157 };
158 }
159 }
160 }
161}Sourcepub fn decode_message<'a, C: Decoder>(
&'a self,
codec: &C,
) -> Result<C::Message<'a>, DecodeMessageError<'a, C>>
pub fn decode_message<'a, C: Decoder>( &'a self, codec: &C, ) -> Result<C::Message<'a>, DecodeMessageError<'a, C>>
Tries to decode the current message with the given decoder.
You usually want to call this method once Fragmentizer::is_message_complete returns
true. Which decoder should be used depends on the state of the IMAP conversation. The
caller is responsible for tracking this state and choosing the decoder.
Examples found in repository?
27fn main() {
28 println!("{WELCOME}");
29
30 let mut fragmentizer = Fragmentizer::new(10 * 1024);
31 let mut state = State::Greeting;
32
33 loop {
34 // Progress next fragment.
35 let Some(_fragment_info) = fragmentizer.progress() else {
36 // Read more bytes ...
37 let bytes = read_more(Role::Server, fragmentizer.message_bytes().is_empty());
38
39 // ... and pass the bytes to the Fragmentizer ...
40 fragmentizer.enqueue_bytes(&bytes);
41
42 // ... and try again.
43 continue;
44 };
45
46 // Check whether the Fragmentizer detected a complete message.
47 if !fragmentizer.is_message_complete() {
48 // Read next fragment.
49 continue;
50 }
51
52 // The Fragmentizer detected a complete message.
53 match state {
54 State::Greeting => {
55 match fragmentizer.decode_message(&GreetingCodec::default()) {
56 Ok(greeting) => {
57 // Do something with the greeting ...
58 println!("{greeting:#?}");
59
60 // ... and proceed with reponses.
61 state = State::Response;
62 }
63 Err(err) => {
64 println!("Error parsing greeting: {err:?}");
65 }
66 };
67 }
68 State::Response => {
69 match fragmentizer.decode_message(&ResponseCodec::default()) {
70 Ok(response) => {
71 // Do something with the response.
72 println!("{response:#?}");
73 }
74 Err(err) => {
75 println!("Error parsing response: {err:?}");
76 }
77 };
78 }
79 };
80 }
81}More examples
37fn main() {
38 println!("{WELCOME}");
39
40 let mut fragmentizer = Fragmentizer::new(10 * 1024);
41 let mut state = State::Command;
42
43 // Send a greeting.
44 println!("S: {COLOR_SERVER}* OK ...{RESET}");
45
46 loop {
47 // Progress next fragment.
48 let Some(fragment_info) = fragmentizer.progress() else {
49 // Read more bytes ...
50 let bytes = read_more(Role::Client, fragmentizer.message_bytes().is_empty());
51
52 // ... and pass the bytes to the Fragmentizer ...
53 fragmentizer.enqueue_bytes(&bytes);
54
55 // ... and try again.
56 continue;
57 };
58
59 // The Fragmentizer detected a line that announces a sync literal.
60 if let FragmentInfo::Line {
61 announcement:
62 Some(LiteralAnnouncement {
63 mode: LiteralMode::Sync,
64 length,
65 }),
66 ..
67 } = fragment_info
68 {
69 // Check the length of the literal.
70 if length <= 1024 {
71 // Accept the literal ...
72 println!("S: {COLOR_SERVER}+ {RESET}");
73
74 // ... and continue with the remaining message.
75 continue;
76 } else if let Some(tag) = fragmentizer.decode_tag() {
77 // Reject the literal ...
78 println!("S: {COLOR_SERVER}{} BAD ...{RESET}", tag.as_ref());
79
80 // ... and skip the current message ...
81 fragmentizer.skip_message();
82
83 // ... and continue with the next message.
84 continue;
85 } else {
86 // The partially received message is malformed. It's unclear what will follow.
87 // To be on the safe side, prevent the message from being decoded ...
88 fragmentizer.poison_message();
89
90 // ... but continue parsing the message.
91 continue;
92 }
93 }
94
95 // Check whether the Fragmentizer detected a complete message.
96 if !fragmentizer.is_message_complete() {
97 // Read next fragment.
98 continue;
99 }
100
101 // The Fragmentizer detected a complete message.
102 match state {
103 State::Command => {
104 match fragmentizer.decode_message(&CommandCodec::default()) {
105 Ok(Command {
106 tag,
107 body: CommandBody::Authenticate { .. },
108 }) => {
109 // Request another SASL round ...
110 println!("S: {COLOR_SERVER}+ {RESET}");
111
112 // ... and proceed with authenticate data.
113 state = State::Authenticate(tag.into_static());
114 }
115 Ok(Command {
116 body: CommandBody::Idle,
117 ..
118 }) => {
119 // Accept the idle ...
120 println!("S: {COLOR_SERVER}+ ...{RESET}");
121
122 // ... and proceed with idle done.
123 state = State::Idle;
124 }
125 Ok(command) => {
126 // Do something with the command.
127 println!("{command:#?}");
128 }
129 Err(err) => {
130 println!("Error parsing command: {err:?}");
131 }
132 };
133 }
134 State::Authenticate(ref tag) => {
135 match fragmentizer.decode_message(&AuthenticateDataCodec::default()) {
136 Ok(_authenticate_data) => {
137 // Accept the authentication after one SASL round.
138 println!("S: {COLOR_SERVER}{} OK ...{RESET}", tag.as_ref());
139
140 // ... and proceed with commands.
141 state = State::Command;
142 }
143 Err(err) => {
144 println!("Error parsing authenticate data: {err:?}");
145 }
146 };
147 }
148 State::Idle => {
149 match fragmentizer.decode_message(&IdleDoneCodec::default()) {
150 Ok(_idle_done) => {
151 // End idle and proceed with commands.
152 state = State::Command;
153 }
154 Err(err) => {
155 println!("Error parsing idle done: {err:?}");
156 }
157 };
158 }
159 }
160 }
161}Trait Implementations§
Source§impl Clone for Fragmentizer
impl Clone for Fragmentizer
Source§fn clone(&self) -> Fragmentizer
fn clone(&self) -> Fragmentizer
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more