1use bytes::{Buf, Bytes, BytesMut};
8
9use crate::{Error, Result};
10
11pub const DEFAULT_MAX_FRAME: usize = 100 * 1024 * 1024;
14
15#[derive(Debug)]
17pub struct FrameDecoder {
18 buf: BytesMut,
19 max_frame: usize,
20}
21
22impl Default for FrameDecoder {
23 fn default() -> Self {
24 Self::new(DEFAULT_MAX_FRAME)
25 }
26}
27
28impl FrameDecoder {
29 #[must_use]
30 pub fn new(max_frame: usize) -> Self {
31 Self {
32 buf: BytesMut::new(),
33 max_frame,
34 }
35 }
36
37 pub fn push(&mut self, bytes: &[u8]) {
39 self.buf.extend_from_slice(bytes);
40 }
41
42 #[must_use]
44 pub fn buffered(&self) -> usize {
45 self.buf.len()
46 }
47
48 #[must_use]
59 pub fn needed(&self) -> usize {
60 if self.buf.len() < 4 {
61 return 4 - self.buf.len();
62 }
63 let len = i32::from_be_bytes([self.buf[0], self.buf[1], self.buf[2], self.buf[3]]);
64 let len = usize::try_from(len).unwrap_or(0).min(self.max_frame);
65 (4 + len).saturating_sub(self.buf.len())
66 }
67
68 pub fn next_frame(&mut self) -> Result<Option<Bytes>> {
77 if self.buf.len() < 4 {
78 return Ok(None);
79 }
80 let len = i32::from_be_bytes([self.buf[0], self.buf[1], self.buf[2], self.buf[3]]);
81 let len = usize::try_from(len).map_err(|_| Error::FrameTooLarge {
82 len: usize::MAX,
83 limit: self.max_frame,
84 })?;
85 if len > self.max_frame {
86 return Err(Error::FrameTooLarge {
87 len,
88 limit: self.max_frame,
89 });
90 }
91 if self.buf.len() < 4 + len {
92 return Ok(None);
93 }
94 self.buf.advance(4);
95 Ok(Some(self.buf.split_to(len).freeze()))
96 }
97}
98
99pub fn frame(body: &[u8]) -> Result<Bytes> {
104 let len = i32::try_from(body.len()).map_err(|_| Error::FrameTooLarge {
105 len: body.len(),
106 limit: i32::MAX as usize,
107 })?;
108 let mut out = BytesMut::with_capacity(body.len() + 4);
109 out.extend_from_slice(&len.to_be_bytes());
110 out.extend_from_slice(body);
111 Ok(out.freeze())
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn a_whole_frame_round_trips() {
120 let mut dec = FrameDecoder::default();
121 dec.push(&frame(b"hello").unwrap());
122 assert_eq!(dec.next_frame().unwrap().as_deref(), Some(&b"hello"[..]));
123 assert!(dec.next_frame().unwrap().is_none());
124 }
125
126 #[test]
129 fn a_frame_split_byte_by_byte_still_arrives() {
130 let bytes = frame(b"a longer payload").unwrap();
131 let mut dec = FrameDecoder::default();
132 for (i, b) in bytes.iter().enumerate() {
133 dec.push(&[*b]);
134 if i + 1 < bytes.len() {
135 assert!(
136 dec.next_frame().unwrap().is_none(),
137 "yielded a frame after {} of {} bytes",
138 i + 1,
139 bytes.len()
140 );
141 }
142 }
143 assert_eq!(
144 dec.next_frame().unwrap().as_deref(),
145 Some(&b"a longer payload"[..])
146 );
147 }
148
149 #[test]
152 fn many_frames_and_a_fragment_in_one_read() {
153 let mut wire = Vec::new();
154 wire.extend_from_slice(&frame(b"one").unwrap());
155 wire.extend_from_slice(&frame(b"two").unwrap());
156 let third = frame(b"three").unwrap();
157 wire.extend_from_slice(&third[..4]); let mut dec = FrameDecoder::default();
160 dec.push(&wire);
161 assert_eq!(dec.next_frame().unwrap().as_deref(), Some(&b"one"[..]));
162 assert_eq!(dec.next_frame().unwrap().as_deref(), Some(&b"two"[..]));
163 assert!(dec.next_frame().unwrap().is_none());
164
165 dec.push(&third[4..]);
166 assert_eq!(dec.next_frame().unwrap().as_deref(), Some(&b"three"[..]));
167 }
168
169 #[test]
173 fn an_empty_frame_is_a_frame() {
174 let mut dec = FrameDecoder::default();
175 dec.push(&frame(b"").unwrap());
176 assert_eq!(dec.next_frame().unwrap().as_deref(), Some(&b""[..]));
177 }
178
179 #[test]
181 fn an_absurd_length_prefix_is_rejected_before_allocating() {
182 let mut dec = FrameDecoder::new(1024);
183 dec.push(&i32::MAX.to_be_bytes());
184 assert!(matches!(
185 dec.next_frame(),
186 Err(Error::FrameTooLarge { limit: 1024, .. })
187 ));
188 assert_eq!(
189 dec.buffered(),
190 4,
191 "a rejected frame must not consume the buffer; the caller drops the connection"
192 );
193 }
194
195 #[test]
197 fn a_negative_length_prefix_is_rejected() {
198 let mut dec = FrameDecoder::default();
199 dec.push(&(-1i32).to_be_bytes());
200 assert!(matches!(dec.next_frame(), Err(Error::FrameTooLarge { .. })));
201 }
202}