1use thiserror::Error;
4
5pub const MAX_FRAME_LEN: usize = 16 * 1024 * 1024;
8
9#[derive(Debug, Error, PartialEq, Eq)]
10pub enum FrameError {
11 #[error("frame length {0} bytes exceeds MAX_FRAME_LEN ({MAX_FRAME_LEN})")]
12 TooLarge(usize),
13 #[error("frame decoder poisoned by a prior protocol violation")]
18 Poisoned,
19}
20
21pub fn encode_frame(payload: &[u8]) -> Result<Vec<u8>, FrameError> {
23 if payload.len() > MAX_FRAME_LEN {
24 return Err(FrameError::TooLarge(payload.len()));
25 }
26 let mut out = Vec::with_capacity(4 + payload.len());
27 out.extend_from_slice(&(payload.len() as u32).to_be_bytes());
28 out.extend_from_slice(payload);
29 Ok(out)
30}
31
32#[derive(Default)]
35pub struct FrameDecoder {
36 buf: Vec<u8>,
37 pos: usize,
39 poisoned: bool,
43}
44
45impl FrameDecoder {
46 pub fn new() -> Self {
47 Self::default()
48 }
49
50 pub fn push(&mut self, data: &[u8]) {
52 self.buf.extend_from_slice(data);
53 }
54
55 pub fn next_frame(&mut self) -> Result<Option<Vec<u8>>, FrameError> {
59 if self.poisoned {
60 return Err(FrameError::Poisoned);
61 }
62 let avail = self.buf.len() - self.pos;
63 if avail < 4 {
64 self.maybe_compact();
65 return Ok(None);
66 }
67 let p = self.pos;
68 let len = u32::from_be_bytes([
69 self.buf[p],
70 self.buf[p + 1],
71 self.buf[p + 2],
72 self.buf[p + 3],
73 ]) as usize;
74 if len > MAX_FRAME_LEN {
75 self.poisoned = true;
76 return Err(FrameError::TooLarge(len));
77 }
78 if avail < 4 + len {
79 self.maybe_compact();
80 return Ok(None);
81 }
82 let body = self.buf[p + 4..p + 4 + len].to_vec();
83 self.pos += 4 + len;
84 self.maybe_compact();
85 Ok(Some(body))
86 }
87
88 fn maybe_compact(&mut self) {
91 if self.pos > 0 && self.pos >= self.buf.len() / 2 {
92 self.buf.drain(..self.pos);
93 self.pos = 0;
94 }
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn round_trip_single_frame() {
104 let payload = br#"{"jsonrpc":"2.0"}"#;
105 let encoded = encode_frame(payload).unwrap();
106 assert_eq!(&encoded[..4], &(payload.len() as u32).to_be_bytes());
107
108 let mut dec = FrameDecoder::new();
109 dec.push(&encoded);
110 assert_eq!(dec.next_frame().unwrap(), Some(payload.to_vec()));
111 assert_eq!(dec.next_frame().unwrap(), None);
112 }
113
114 #[test]
115 fn reassembles_across_partial_pushes() {
116 let payload = b"hello";
117 let encoded = encode_frame(payload).unwrap();
118 let mut dec = FrameDecoder::new();
119 dec.push(&encoded[..2]);
121 assert_eq!(dec.next_frame().unwrap(), None);
122 dec.push(&encoded[2..6]);
123 assert_eq!(dec.next_frame().unwrap(), None);
124 dec.push(&encoded[6..]);
125 assert_eq!(dec.next_frame().unwrap(), Some(payload.to_vec()));
126 }
127
128 #[test]
129 fn decodes_two_frames_from_one_push() {
130 let mut buf = encode_frame(b"aa").unwrap();
131 buf.extend(encode_frame(b"bbb").unwrap());
132 let mut dec = FrameDecoder::new();
133 dec.push(&buf);
134 assert_eq!(dec.next_frame().unwrap(), Some(b"aa".to_vec()));
135 assert_eq!(dec.next_frame().unwrap(), Some(b"bbb".to_vec()));
136 assert_eq!(dec.next_frame().unwrap(), None);
137 }
138
139 #[test]
140 fn rejects_oversize_declared_length_without_allocating() {
141 let mut dec = FrameDecoder::new();
143 dec.push(&u32::MAX.to_be_bytes());
144 assert_eq!(
145 dec.next_frame(),
146 Err(FrameError::TooLarge(u32::MAX as usize))
147 );
148 }
149
150 #[test]
151 fn stays_poisoned_after_oversize_no_error_loop() {
152 let mut dec = FrameDecoder::new();
156 dec.push(&u32::MAX.to_be_bytes());
157 assert_eq!(
158 dec.next_frame(),
159 Err(FrameError::TooLarge(u32::MAX as usize))
160 );
161 assert_eq!(dec.next_frame(), Err(FrameError::Poisoned));
162 dec.push(&encode_frame(b"ok").unwrap());
163 assert_eq!(dec.next_frame(), Err(FrameError::Poisoned));
164 }
165
166 #[test]
167 fn encode_rejects_oversize_payload() {
168 let too_big = vec![0u8; MAX_FRAME_LEN + 1];
169 assert_eq!(
170 encode_frame(&too_big),
171 Err(FrameError::TooLarge(MAX_FRAME_LEN + 1))
172 );
173 }
174
175 #[test]
176 fn many_frames_in_one_push_all_decode_in_order() {
177 let mut buf = Vec::new();
178 for i in 0..1000u32 {
179 buf.extend(encode_frame(format!("f{i}").as_bytes()).unwrap());
180 }
181 let mut dec = FrameDecoder::new();
182 dec.push(&buf);
183 for i in 0..1000u32 {
184 assert_eq!(
185 dec.next_frame().unwrap(),
186 Some(format!("f{i}").into_bytes())
187 );
188 }
189 assert_eq!(dec.next_frame().unwrap(), None);
190 }
191}