1use crate::decode::{MINIMUM_WIRE_VERSION, SSP2_MAGIC, WIRE_VERSION};
18use crate::error::{DecodeError, Result};
19use crate::model::frame_type;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct ScannedMessage {
25 pub message: Vec<u8>,
27 pub excess: usize,
31}
32
33#[derive(Default)]
40pub struct MessageStreamScanner {
41 buffer: Vec<u8>,
42 offset: Option<usize>,
45 complete: bool,
46}
47
48impl MessageStreamScanner {
49 pub fn new() -> Self {
50 Self::default()
51 }
52
53 pub fn started(&self) -> bool {
55 !self.buffer.is_empty()
56 }
57
58 pub fn push(&mut self, chunk: &[u8]) -> Result<Option<ScannedMessage>> {
64 assert!(
65 !self.complete,
66 "MessageStreamScanner: message already complete"
67 );
68 self.buffer.extend_from_slice(chunk);
69 if self.offset.is_none() {
70 if self.buffer.len() < 8 {
71 return Ok(None);
72 }
73 self.check_header()?;
74 self.offset = Some(8);
75 }
76 let mut offset = self.offset.expect("offset set once header parsed");
77 loop {
78 if self.buffer.len() - offset < 5 {
80 self.offset = Some(offset);
81 return Ok(None);
82 }
83 let frame_type = self.buffer[offset];
84 let frame_length = u32::from_le_bytes([
85 self.buffer[offset + 1],
86 self.buffer[offset + 2],
87 self.buffer[offset + 3],
88 self.buffer[offset + 4],
89 ]) as usize;
90 let Some(frame_end) = offset
91 .checked_add(5)
92 .and_then(|v| v.checked_add(frame_length))
93 else {
94 return Err(DecodeError::invalid("frame length overflow"));
95 };
96 if self.buffer.len() < frame_end {
97 self.offset = Some(offset);
98 return Ok(None);
99 }
100 offset = frame_end;
101 if frame_type == frame_type::END {
102 self.complete = true;
103 self.offset = Some(offset);
104 return Ok(Some(ScannedMessage {
105 message: self.buffer[..frame_end].to_vec(),
106 excess: self.buffer.len() - frame_end,
107 }));
108 }
109 }
110 }
111
112 fn check_header(&self) -> Result<()> {
113 let b = &self.buffer;
114 if b[0..4] != SSP2_MAGIC[..] {
115 return Err(DecodeError::invalid("bad envelope magic (expected SSP2)"));
116 }
117 let wire_version = u16::from_le_bytes([b[4], b[5]]);
118 if !(MINIMUM_WIRE_VERSION..=WIRE_VERSION).contains(&wire_version) {
119 return Err(DecodeError::invalid(format!(
120 "unsupported wireVersion {wire_version}"
121 )));
122 }
123 if b[6] != 0x01 && b[6] != 0x02 {
124 return Err(DecodeError::invalid(format!(
125 "unknown msgKind byte 0x{:02x}",
126 b[6]
127 )));
128 }
129 if b[7] != 0x00 {
130 return Err(DecodeError::invalid(format!(
131 "envelope flags must be 0x00, got 0x{:02x}",
132 b[7]
133 )));
134 }
135 Ok(())
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142 use crate::encode::encode_message;
143 use crate::model::{Frame, Message, MsgKind};
144
145 fn request_bytes() -> Vec<u8> {
148 let message = Message {
149 wire_version: WIRE_VERSION,
150 msg_kind: MsgKind::Request,
151 frames: vec![
152 Frame::ReqHeader {
153 client_id: "c1".to_owned(),
154 schema_version: 1,
155 log_epoch: None,
156 },
157 Frame::PullHeader {
158 limit_commits: 0,
159 limit_snapshot_rows: 0,
160 max_snapshot_pages: 0,
161 accept: 0b0011,
162 },
163 ],
164 };
165 encode_message(&message)
166 }
167
168 #[test]
169 fn whole_message_in_one_chunk_completes_with_zero_excess() {
170 let request = request_bytes();
171 let mut scanner = MessageStreamScanner::new();
172 let result = scanner.push(&request).unwrap().expect("complete");
173 assert_eq!(result.excess, 0);
174 assert_eq!(result.message, request);
175 }
176
177 #[test]
178 fn every_split_point_reassembles_byte_exactly() {
179 let request = request_bytes();
180 for split in 1..request.len() {
181 let mut scanner = MessageStreamScanner::new();
182 assert!(
183 scanner.push(&request[..split]).unwrap().is_none(),
184 "split {split}: first half must be incomplete"
185 );
186 let result = scanner
187 .push(&request[split..])
188 .unwrap()
189 .unwrap_or_else(|| panic!("split {split}: second half must complete"));
190 assert_eq!(result.excess, 0, "split {split}");
191 assert_eq!(result.message, request, "split {split}");
192 }
193 }
194
195 #[test]
196 fn one_byte_at_a_time_trickle_completes() {
197 let request = request_bytes();
198 let mut scanner = MessageStreamScanner::new();
199 let mut result = None;
200 for byte in &request {
201 result = scanner.push(&[*byte]).unwrap();
202 }
203 let result = result.expect("complete after last byte");
204 assert_eq!(result.excess, 0);
205 assert_eq!(result.message, request);
206 }
207
208 #[test]
209 fn bytes_past_end_are_reported_as_excess() {
210 let request = request_bytes();
211 let mut with_excess = request.clone();
212 with_excess.extend_from_slice(&[0xaa, 0xbb, 0xcc]);
213 let mut scanner = MessageStreamScanner::new();
214 let result = scanner.push(&with_excess).unwrap().expect("complete");
215 assert_eq!(result.excess, 3);
216 assert_eq!(result.message, request);
217 }
218
219 #[test]
220 fn two_message_stream_every_split_reassembles_first_exactly() {
221 let first = request_bytes();
227 let second = request_bytes();
228 let mut stream = first.clone();
229 stream.extend_from_slice(&second);
230 for split in 1..stream.len() {
231 let mut scanner = MessageStreamScanner::new();
232 let (result, buffered_at_completion) = match scanner.push(&stream[..split]).unwrap() {
236 Some(done) => (done, split),
237 None => {
238 let done = scanner
239 .push(&stream[split..])
240 .unwrap()
241 .unwrap_or_else(|| panic!("split {split}: first message must complete"));
242 (done, stream.len())
243 }
244 };
245 assert_eq!(result.message, first, "split {split}: first message bytes");
246 assert_eq!(
247 result.excess,
248 buffered_at_completion - first.len(),
249 "split {split}: excess equals second-message bytes buffered at END"
250 );
251 }
252 }
253
254 #[test]
255 fn bad_magic_is_a_decode_error_once_header_arrived() {
256 let mut request = request_bytes();
257 request[0] = 0x58;
258 let mut scanner = MessageStreamScanner::new();
259 assert!(scanner.push(&request[..4]).unwrap().is_none());
260 assert!(scanner.push(&request[4..]).is_err());
261 }
262
263 #[test]
264 fn non_zero_flags_and_unknown_msg_kind_are_decode_errors() {
265 for (index, value) in [(6usize, 0x03u8), (7usize, 0x01u8)] {
266 let mut request = request_bytes();
267 request[index] = value;
268 let mut scanner = MessageStreamScanner::new();
269 assert!(scanner.push(&request).is_err(), "index {index}");
270 }
271 }
272
273 #[test]
274 #[should_panic(expected = "already complete")]
275 fn push_after_completion_panics() {
276 let request = request_bytes();
277 let mut scanner = MessageStreamScanner::new();
278 scanner.push(&request).unwrap();
279 let _ = scanner.push(&[0]);
280 }
281}