Crate stream_framer

Source
Expand description

§Stream Framer

Framing system for streaming protocols.

§Purpose

Stream Framer is a Rust crate that provides two traits for adding header prefixes to datagrams:

  • FrameWriter prepends a header composed of 8 arbitrary bytes followed by 4 bytes representing (in big endian) the length of the following frame.
  • FrameParser provides the method parse_frame_header()to parse incoming packets, indicating the frame’s starting point and its length.

§Disclaimers

  • It is a very simplistic crate that currently have no mechanism to handle data coming in a corrupted order.

  • It can handle truncated frames (e.g. a frame that is distributed between two packets).

    I use it in the context of the QUIC protocol (with a HTTP/3 framework based on Quiche crate), which garantees data order accuracy.

§Example

Add the header (magic number: 8 bytes + frame len big endian u32: 4 bytes).

use stream_framer::{FrameParser, ParsedStreamData};
use stream_framer::FrameWriter;

// Vec<u8> implements FrameParser and FrameWriter.
let datagram: Vec<u8> = vec![1; 512];

let prefixed_datagram = datagram.prepend_frame();

Then you can parse and handle truncations:

use stream_framer::{FrameParser, ParsedStreamData};
use stream_framer::FrameWriter;
// states that keep track of truncated datas (for header and the frame)

let mut incompleted_stream_data_buffer: Option<(usize, Vec<u8>)> = None; // (frame_size, partial data already received);
let mut truncated_header_buffer: Option<Vec<u8>> = None; // The partial header truncated in the previous packet parsing.

let datagram: Vec<u8> = vec![1; 512];

let prefixed_datagram = datagram.prepend_frame().expect("failed to prepend frame");

let mut output: Vec<Vec<u8>> = vec![];

           // Start parsing, it can output multiple frames if any.
           match prefixed_datagram.parse_frame_header(
               incompleted_stream_data_buffer.take(),
               truncated_header_buffer.take(),
           ) {
               Ok(parsing_res) => {
                   for parsed in parsing_res {
                       match parsed {
                              ParsedStreamData::Completed(data) => {

                                  output.push(data);


                              }
                              ParsedStreamData::Incompleted(size, data) => {

                                  incompleted_stream_data_buffer = Some((size, data));

                              }
                              ParsedStreamData::TruncatedHeader(truncated_hdr) => {

                                  truncated_header_buffer = Some(truncated_hdr);

                              }
                     }
                   }
               }
               Err(e) => {
                   println!("[{:?}]", e);
               }
           }

Modules§

prelude

Enums§

ParsedStreamData

Traits§

FrameParser
FrameWriter