Skip to main content

saluki_io/deser/framing/
mod.rs

1use bytes::Bytes;
2use snafu::Snafu;
3use tracing::trace;
4
5use crate::buf::ReadIoBuffer;
6
7mod length_delimited;
8pub use self::length_delimited::LengthDelimitedFramer;
9
10mod newline;
11pub use self::newline::NewlineFramer;
12
13/// Framing error.
14#[derive(Debug, Snafu, Eq, PartialEq)]
15#[snafu(context(suffix(false)))]
16pub enum FramingError {
17    /// An invalid frame was received.
18    ///
19    /// This generally occurs if the frame is corrupted in some way, due to a bug in how the frame was encoded or
20    /// sent/received. For example, if a length-delimited frame indicates that the frame is larger than the buffer can
21    /// handle, it generally indicates that frame was created incorrectly by not respecting the maximum frame length
22    /// limitations, or the buffer is corrupt and spurious bytes are contributing to a decoded frame length that's
23    /// nonsensical.
24    #[snafu(display("invalid frame (frame length: {}, {})", frame_len, reason))]
25    InvalidFrame { frame_len: usize, reason: &'static str },
26
27    /// Failed to read frame due to a partial frame after reaching EOF.
28    ///
29    /// This generally only occurs if the peer closes their connection before sending the entire frame, or if a partial
30    /// write occurs on a connectionless stream, such as UDP, perhaps due to fragmentation.
31    #[snafu(display(
32        "partial frame after EOF (needed {} bytes, but only {} bytes remaining)",
33        needed,
34        remaining
35    ))]
36    PartialFrame { needed: usize, remaining: usize },
37}
38
39/// A trait for reading framed messages from a buffer.
40pub trait Framer {
41    /// Attempt to extract the next frame from the buffer.
42    ///
43    /// If enough data was present to extract a frame, `Ok(Some(frame))` is returned. If not enough data was present, and
44    /// EOF hasn't been reached, `Ok(None)` is returned.
45    ///
46    /// Behavior when EOF is reached is framer-specific and in some cases may allow for decoding a frame even when the
47    /// inherent delimiting data isn't present.
48    ///
49    /// # Errors
50    ///
51    /// If an error is detected when reading the next frame, an error is returned.
52    fn next_frame<B: ReadIoBuffer>(&mut self, buf: &mut B, is_eof: bool) -> Result<Option<Bytes>, FramingError>;
53}
54
55/// A nested framer that extracts inner frames from outer frames.
56///
57/// This framer takes two input framers -- the "outer" and "inner" framers -- and extracts outer frames, and once an
58/// outer frame has been extract, extracts as many inner frames from the outer frame as possible. Callers deal
59/// exclusively with the extracted inner frames.
60pub struct NestedFramer<Inner, Outer> {
61    inner: Inner,
62    outer: Outer,
63    current_outer_frame: Option<Bytes>,
64    completed_outer_frames: usize,
65    retain_outer_frames: bool,
66    retained_outer_frames: Vec<Bytes>,
67}
68
69impl<Inner, Outer> NestedFramer<Inner, Outer> {
70    /// Creates a new `NestedFramer` from the given inner and outer framers.
71    pub fn new(inner: Inner, outer: Outer) -> Self {
72        Self {
73            inner,
74            outer,
75            current_outer_frame: None,
76            completed_outer_frames: 0,
77            retain_outer_frames: false,
78            retained_outer_frames: Vec::new(),
79        }
80    }
81
82    /// Returns the number of outer frames that have been fully consumed since the last call.
83    pub fn take_completed_outer_frames(&mut self) -> usize {
84        let completed = self.completed_outer_frames;
85        self.completed_outer_frames = 0;
86        completed
87    }
88
89    /// Sets whether newly extracted outer frames are retained for later retrieval.
90    ///
91    /// When enabled, every outer frame extracted from the input buffer is retained, in order, until it is drained with
92    /// [`drain_outer_frames`][Self::drain_outer_frames]. Retained frames share their underlying storage with the frame
93    /// being split into inner frames, so retaining them does not copy the frame data.
94    ///
95    /// Callers that enable retention **MUST** drain retained frames after each call to `next_frame`, as they are
96    /// otherwise held indefinitely. Disabling retention discards any frames that have not yet been drained.
97    ///
98    /// Defaults to disabled.
99    pub fn set_retain_outer_frames(&mut self, retain: bool) {
100        self.retain_outer_frames = retain;
101        if !retain {
102            self.retained_outer_frames.clear();
103        }
104    }
105
106    /// Drains the outer frames retained since the last call, in the order they were extracted.
107    pub fn drain_outer_frames(&mut self) -> std::vec::Drain<'_, Bytes> {
108        self.retained_outer_frames.drain(..)
109    }
110}
111
112impl<Inner, Outer> Framer for NestedFramer<Inner, Outer>
113where
114    Inner: Framer,
115    Outer: Framer,
116{
117    fn next_frame<B: ReadIoBuffer>(&mut self, buf: &mut B, is_eof: bool) -> Result<Option<Bytes>, FramingError> {
118        loop {
119            // Take our current outer frame, or if we have none, try to get the next one.
120            let outer_frame = match self.current_outer_frame.as_mut() {
121                Some(frame) => {
122                    trace!(
123                        buf_len = buf.remaining(),
124                        frame_len = frame.len(),
125                        "Using existing outer frame."
126                    );
127
128                    frame
129                }
130                None => {
131                    trace!(buf_len = buf.remaining(), "No existing outer frame.");
132
133                    match self.outer.next_frame(buf, is_eof)? {
134                        Some(frame) => {
135                            trace!(
136                                buf_len = buf.remaining(),
137                                frame_len = frame.len(),
138                                ?frame,
139                                "Extracted outer frame."
140                            );
141
142                            if self.retain_outer_frames {
143                                self.retained_outer_frames.push(frame.clone());
144                            }
145
146                            self.current_outer_frame.get_or_insert(frame)
147                        }
148
149                        // If we can't get another outer frame, then we're done for now.
150                        None => return Ok(None),
151                    }
152                }
153            };
154
155            // Try to get the next inner frame.
156            match self.inner.next_frame(outer_frame, true)? {
157                Some(frame) => {
158                    let completed_outer_frame = outer_frame.is_empty();
159
160                    trace!(
161                        buf_len = buf.remaining(),
162                        outer_frame_len = outer_frame.len(),
163                        inner_frame_len = frame.len(),
164                        "Extracted inner frame."
165                    );
166
167                    if completed_outer_frame {
168                        self.current_outer_frame = None;
169                        self.completed_outer_frames += 1;
170                    }
171
172                    return Ok(Some(frame));
173                }
174                None => {
175                    // We can't get anything else from our inner frame. If our outer frame is empty, and our input buffer
176                    // isn't empty, clear the current outer frame so that we can try to grab the next one.
177                    trace!(
178                        buf_len = buf.remaining(),
179                        outer_frame_len = outer_frame.len(),
180                        "Couldn't extract inner frame from existing outer frame."
181                    );
182
183                    if outer_frame.is_empty() {
184                        self.current_outer_frame = None;
185                        self.completed_outer_frames += 1;
186                        if buf.remaining() != 0 {
187                            continue;
188                        }
189                    }
190
191                    return Ok(None);
192                }
193            }
194        }
195    }
196}
197
198/// An iterator of framed messages over a generic buffer.
199pub struct Framed<'a, F, B> {
200    framer: &'a mut F,
201    buffer: &'a mut B,
202    is_eof: bool,
203}
204
205impl<F, B> Iterator for Framed<'_, F, B>
206where
207    F: Framer,
208    B: ReadIoBuffer,
209{
210    type Item = Result<Bytes, FramingError>;
211
212    fn next(&mut self) -> Option<Self::Item> {
213        self.framer.next_frame(self.buffer, self.is_eof).transpose()
214    }
215}
216
217/// Extension trait for ergonomically working with framers and buffers.
218pub trait FramerExt {
219    /// Creates a new `Framed` iterator over the buffer, using the given framer.
220    ///
221    /// Returns an iterator that extracts frames from the given buffer, consuming the bytes from the buffer as frames
222    /// are yielded.
223    fn framed<'a, F>(&'a mut self, framer: &'a mut F, is_eof: bool) -> Framed<'a, F, Self>
224    where
225        Self: ReadIoBuffer + Sized,
226        F: Framer;
227}
228
229impl<B> FramerExt for B
230where
231    B: ReadIoBuffer,
232{
233    fn framed<'a, F>(&'a mut self, framer: &'a mut F, is_eof: bool) -> Framed<'a, F, Self> {
234        Framed {
235            framer,
236            buffer: self,
237            is_eof,
238        }
239    }
240}
241
242#[cfg(test)]
243mod tests {
244    use std::collections::VecDeque;
245
246    use super::{Framer as _, LengthDelimitedFramer, NestedFramer, NewlineFramer};
247
248    #[test]
249    fn nested_framer_single_outer_multiple_inner() {
250        let input_frames = &[b"frame1", b"frame2", b"frame3"];
251
252        // We create a framer that does length-delimited payloads as the outer layer, and newline-delimited payloads as
253        // the inner layer.
254        let mut framer = NestedFramer::new(NewlineFramer::default(), LengthDelimitedFramer);
255
256        // Create a buffer that has a single length-delimited frame with three newline-delimited frames inside of that.
257        let mut inner_frames = Vec::new();
258
259        for inner_frame_data in input_frames {
260            inner_frames.extend_from_slice(&inner_frame_data[..]);
261            inner_frames.push(b'\n');
262        }
263
264        let mut buf = VecDeque::new();
265        buf.extend(&(inner_frames.len() as u32).to_le_bytes());
266        buf.extend(inner_frames);
267
268        // Now we should be able to extract our original three frames from the buffer.
269        for input_frame in input_frames {
270            let frame = framer
271                .next_frame(&mut buf, false)
272                .expect("should not fail to read from payload")
273                .expect("should not fail to extract frame from payload");
274            assert_eq!(&frame[..], &input_frame[..]);
275        }
276
277        let maybe_frame = framer
278            .next_frame(&mut buf, false)
279            .expect("should not fail to read from payload");
280        assert!(maybe_frame.is_none());
281
282        // We should have consumed the entire buffer.
283        assert!(buf.is_empty());
284    }
285
286    #[test]
287    fn nested_framer_multiple_outer_single_inner() {
288        let input_frames = &[b"frame1", b"frame2", b"frame3"];
289
290        // We create a framer that does length-delimited payloads as the outer layer, and newline-delimited payloads as
291        // the inner layer.
292        let mut framer = NestedFramer::new(NewlineFramer::default(), LengthDelimitedFramer);
293
294        // Create a buffer that has a three length-delimited frames with a single newline-delimited frame inside.
295        let mut buf = VecDeque::new();
296
297        for inner_frame_data in input_frames {
298            let mut inner_frame = Vec::new();
299            inner_frame.extend_from_slice(&inner_frame_data[..]);
300            inner_frame.push(b'\n');
301
302            buf.extend(&(inner_frame.len() as u32).to_le_bytes());
303            buf.extend(inner_frame);
304        }
305
306        // Now we should be able to extract our original three frames from the buffer.
307        for input_frame in input_frames {
308            let frame = framer
309                .next_frame(&mut buf, false)
310                .expect("should not fail to read from payload")
311                .expect("should not fail to extract frame from payload");
312            assert_eq!(&frame[..], &input_frame[..]);
313        }
314
315        let maybe_frame = framer
316            .next_frame(&mut buf, false)
317            .expect("should not fail to read from payload");
318        assert!(maybe_frame.is_none());
319
320        // We should have consumed the entire buffer.
321        assert!(buf.is_empty());
322    }
323
324    #[test]
325    fn nested_framer_tracks_completed_outer_frames() {
326        let input_frames = &[b"frame1", b"frame2", b"frame3"];
327        let mut framer = NestedFramer::new(NewlineFramer::default(), LengthDelimitedFramer);
328        let mut buf = VecDeque::new();
329
330        for inner_frame_data in input_frames {
331            let mut inner_frame = Vec::new();
332            inner_frame.extend_from_slice(&inner_frame_data[..]);
333            inner_frame.push(b'\n');
334
335            buf.extend(&(inner_frame.len() as u32).to_le_bytes());
336            buf.extend(inner_frame);
337        }
338
339        for input_frame in input_frames {
340            let frame = framer
341                .next_frame(&mut buf, false)
342                .expect("should not fail to read from payload")
343                .expect("should extract frame from payload");
344            assert_eq!(&frame[..], &input_frame[..]);
345            assert_eq!(framer.take_completed_outer_frames(), 1);
346        }
347
348        assert!(buf.is_empty());
349        assert_eq!(framer.take_completed_outer_frames(), 0);
350    }
351
352    #[test]
353    fn nested_framer_retains_outer_frames_only_when_enabled() {
354        let outer_payloads: &[&[u8]] = &[b"frame1\nframe2\n", b"frame3\n"];
355        let mut buf = VecDeque::new();
356        for payload in outer_payloads {
357            buf.extend(&(payload.len() as u32).to_le_bytes());
358            buf.extend(payload.iter());
359        }
360        let mut framer = NestedFramer::new(NewlineFramer::default(), LengthDelimitedFramer);
361
362        let first = framer.next_frame(&mut buf, false).unwrap().unwrap();
363        assert_eq!(&first[..], b"frame1");
364        assert_eq!(framer.drain_outer_frames().count(), 0);
365
366        framer.set_retain_outer_frames(true);
367        let second = framer.next_frame(&mut buf, false).unwrap().unwrap();
368        assert_eq!(&second[..], b"frame2");
369        assert_eq!(framer.drain_outer_frames().count(), 0);
370
371        let third = framer.next_frame(&mut buf, false).unwrap().unwrap();
372        assert_eq!(&third[..], b"frame3");
373        let retained = framer.drain_outer_frames().collect::<Vec<_>>();
374        assert_eq!(retained.len(), 1);
375        assert_eq!(&retained[0][..], outer_payloads[1]);
376        assert_eq!(framer.drain_outer_frames().count(), 0);
377
378        buf.extend(&(outer_payloads[0].len() as u32).to_le_bytes());
379        buf.extend(outer_payloads[0].iter());
380        let _ = framer.next_frame(&mut buf, false).unwrap().unwrap();
381        framer.set_retain_outer_frames(false);
382        assert_eq!(framer.drain_outer_frames().count(), 0);
383    }
384
385    #[test]
386    fn nested_framer_waits_to_complete_outer_frame_until_last_inner_frame() {
387        let mut framer = NestedFramer::new(NewlineFramer::default(), LengthDelimitedFramer);
388        let mut inner_frames = Vec::new();
389        inner_frames.extend_from_slice(b"frame1\nframe2\n");
390
391        let mut buf = VecDeque::new();
392        buf.extend(&(inner_frames.len() as u32).to_le_bytes());
393        buf.extend(inner_frames);
394
395        let first_frame = framer
396            .next_frame(&mut buf, false)
397            .expect("should not fail to read from payload")
398            .expect("should extract first frame from payload");
399        assert_eq!(&first_frame[..], b"frame1");
400        assert_eq!(framer.take_completed_outer_frames(), 0);
401
402        let second_frame = framer
403            .next_frame(&mut buf, false)
404            .expect("should not fail to read from payload")
405            .expect("should extract second frame from payload");
406        assert_eq!(&second_frame[..], b"frame2");
407        assert_eq!(framer.take_completed_outer_frames(), 1);
408    }
409
410    #[test]
411    fn nested_framer_multiple_outer_multiple_inner() {
412        let input_frames = &[b"frame1", b"frame2", b"frame3", b"frame4", b"frame5", b"frame6"];
413
414        // We create a framer that does length-delimited payloads as the outer layer, and newline-delimited payloads as
415        // the inner layer.
416        let mut framer = NestedFramer::new(NewlineFramer::default(), LengthDelimitedFramer);
417
418        // Create a buffer that has a three length-delimited frames with two newline-delimited frames inside.
419        let mut buf = VecDeque::new();
420
421        for inner_frame_data in input_frames.chunks(2) {
422            let mut inner_frames = Vec::new();
423            inner_frames.extend_from_slice(&inner_frame_data[0][..]);
424            inner_frames.push(b'\n');
425            inner_frames.extend_from_slice(&inner_frame_data[1][..]);
426            inner_frames.push(b'\n');
427
428            buf.extend(&(inner_frames.len() as u32).to_le_bytes());
429            buf.extend(inner_frames);
430        }
431
432        // Now we should be able to extract our original six frames from the buffer.
433        for input_frame in input_frames {
434            let frame = framer
435                .next_frame(&mut buf, false)
436                .expect("should not fail to read from payload")
437                .expect("should not fail to extract frame from payload");
438            assert_eq!(&frame[..], &input_frame[..]);
439        }
440
441        let maybe_frame = framer
442            .next_frame(&mut buf, false)
443            .expect("should not fail to read from payload");
444        assert!(maybe_frame.is_none());
445
446        // We should have consumed the entire buffer.
447        assert!(buf.is_empty());
448    }
449}