1use crate::decode::{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 frame_end = offset + 5 + frame_length;
91 if self.buffer.len() < frame_end {
92 self.offset = Some(offset);
93 return Ok(None);
94 }
95 offset = frame_end;
96 if frame_type == frame_type::END {
97 self.complete = true;
98 self.offset = Some(offset);
99 return Ok(Some(ScannedMessage {
100 message: self.buffer[..frame_end].to_vec(),
101 excess: self.buffer.len() - frame_end,
102 }));
103 }
104 }
105 }
106
107 fn check_header(&self) -> Result<()> {
108 let b = &self.buffer;
109 if b[0..4] != SSP2_MAGIC[..] {
110 return Err(DecodeError::invalid("bad envelope magic (expected SSP2)"));
111 }
112 let wire_version = u16::from_le_bytes([b[4], b[5]]);
113 if wire_version != WIRE_VERSION {
114 return Err(DecodeError::invalid(format!(
115 "unsupported wireVersion {wire_version}"
116 )));
117 }
118 if b[6] != 0x01 && b[6] != 0x02 {
119 return Err(DecodeError::invalid(format!(
120 "unknown msgKind byte 0x{:02x}",
121 b[6]
122 )));
123 }
124 if b[7] != 0x00 {
125 return Err(DecodeError::invalid(format!(
126 "envelope flags must be 0x00, got 0x{:02x}",
127 b[7]
128 )));
129 }
130 Ok(())
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use crate::encode::encode_message;
138 use crate::model::{Frame, Message, MsgKind};
139
140 fn request_bytes() -> Vec<u8> {
143 let message = Message {
144 msg_kind: MsgKind::Request,
145 frames: vec![
146 Frame::ReqHeader {
147 client_id: "c1".to_owned(),
148 schema_version: 1,
149 },
150 Frame::PullHeader {
151 limit_commits: 0,
152 limit_snapshot_rows: 0,
153 max_snapshot_pages: 0,
154 accept: 0b0011,
155 },
156 ],
157 };
158 encode_message(&message)
159 }
160
161 #[test]
162 fn whole_message_in_one_chunk_completes_with_zero_excess() {
163 let request = request_bytes();
164 let mut scanner = MessageStreamScanner::new();
165 let result = scanner.push(&request).unwrap().expect("complete");
166 assert_eq!(result.excess, 0);
167 assert_eq!(result.message, request);
168 }
169
170 #[test]
171 fn every_split_point_reassembles_byte_exactly() {
172 let request = request_bytes();
173 for split in 1..request.len() {
174 let mut scanner = MessageStreamScanner::new();
175 assert!(
176 scanner.push(&request[..split]).unwrap().is_none(),
177 "split {split}: first half must be incomplete"
178 );
179 let result = scanner
180 .push(&request[split..])
181 .unwrap()
182 .unwrap_or_else(|| panic!("split {split}: second half must complete"));
183 assert_eq!(result.excess, 0, "split {split}");
184 assert_eq!(result.message, request, "split {split}");
185 }
186 }
187
188 #[test]
189 fn one_byte_at_a_time_trickle_completes() {
190 let request = request_bytes();
191 let mut scanner = MessageStreamScanner::new();
192 let mut result = None;
193 for byte in &request {
194 result = scanner.push(&[*byte]).unwrap();
195 }
196 let result = result.expect("complete after last byte");
197 assert_eq!(result.excess, 0);
198 assert_eq!(result.message, request);
199 }
200
201 #[test]
202 fn bytes_past_end_are_reported_as_excess() {
203 let request = request_bytes();
204 let mut with_excess = request.clone();
205 with_excess.extend_from_slice(&[0xaa, 0xbb, 0xcc]);
206 let mut scanner = MessageStreamScanner::new();
207 let result = scanner.push(&with_excess).unwrap().expect("complete");
208 assert_eq!(result.excess, 3);
209 assert_eq!(result.message, request);
210 }
211
212 #[test]
213 fn two_message_stream_every_split_reassembles_first_exactly() {
214 let first = request_bytes();
220 let second = request_bytes();
221 let mut stream = first.clone();
222 stream.extend_from_slice(&second);
223 for split in 1..stream.len() {
224 let mut scanner = MessageStreamScanner::new();
225 let (result, buffered_at_completion) = match scanner.push(&stream[..split]).unwrap() {
229 Some(done) => (done, split),
230 None => {
231 let done = scanner
232 .push(&stream[split..])
233 .unwrap()
234 .unwrap_or_else(|| panic!("split {split}: first message must complete"));
235 (done, stream.len())
236 }
237 };
238 assert_eq!(result.message, first, "split {split}: first message bytes");
239 assert_eq!(
240 result.excess,
241 buffered_at_completion - first.len(),
242 "split {split}: excess equals second-message bytes buffered at END"
243 );
244 }
245 }
246
247 #[test]
248 fn bad_magic_is_a_decode_error_once_header_arrived() {
249 let mut request = request_bytes();
250 request[0] = 0x58;
251 let mut scanner = MessageStreamScanner::new();
252 assert!(scanner.push(&request[..4]).unwrap().is_none());
253 assert!(scanner.push(&request[4..]).is_err());
254 }
255
256 #[test]
257 fn non_zero_flags_and_unknown_msg_kind_are_decode_errors() {
258 for (index, value) in [(6usize, 0x03u8), (7usize, 0x01u8)] {
259 let mut request = request_bytes();
260 request[index] = value;
261 let mut scanner = MessageStreamScanner::new();
262 assert!(scanner.push(&request).is_err(), "index {index}");
263 }
264 }
265
266 #[test]
267 #[should_panic(expected = "already complete")]
268 fn push_after_completion_panics() {
269 let request = request_bytes();
270 let mut scanner = MessageStreamScanner::new();
271 scanner.push(&request).unwrap();
272 let _ = scanner.push(&[0]);
273 }
274}