net-wire 0.1.0

Allocation-free no_std wire views and codecs for network protocols.
Documentation
use net_wire::http2::{
    HTTP2_CLIENT_PREFACE, Http2BuildError, Http2ClientPreface, Http2Frame, Http2FrameBuilder,
    Http2FrameMut, Http2FrameType, Http2ParseError, Http2StreamId,
};

#[test]
fn client_preface_is_exact_and_bounded() {
    let wire = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\nnext";
    let preface = Http2ClientPreface::parse(wire).unwrap();
    assert_eq!(preface.as_bytes(), HTTP2_CLIENT_PREFACE);
    assert_eq!(preface.as_bytes(), &wire[..24]);

    assert_eq!(
        Http2ClientPreface::parse(&HTTP2_CLIENT_PREFACE[..23]),
        Err(Http2ParseError::Incomplete {
            required: 24,
            available: 23,
        })
    );
    assert_eq!(
        Http2ClientPreface::parse(b"PRI * HTTP/2.0\r\n\r\nSN\r\n\r\n"),
        Err(Http2ParseError::ClientPrefaceMismatch {
            offset: 19,
            expected: b'M',
            actual: b'N',
        })
    );
}

#[test]
fn raw_frame_distinguishes_incomplete_header_and_payload() {
    assert_eq!(
        Http2Frame::parse(&[0, 0, 0, 0, 0, 0, 0, 0], 10),
        Err(Http2ParseError::Incomplete {
            required: 9,
            available: 8,
        })
    );
    assert_eq!(
        Http2Frame::parse(&[0, 0, 3, 0, 0, 0, 0, 0, 0, 1, 2], 3),
        Err(Http2ParseError::Incomplete {
            required: 12,
            available: 11,
        })
    );
}

#[test]
fn raw_frame_preserves_unknown_values_reserved_bit_and_suffix() {
    let wire = [
        0, 0, 2, 0xfe, 0xa5, 0x80, 0x00, 0x00, 0x07, 0xde, 0xad, 0xfa,
    ];
    let frame = Http2Frame::parse(&wire, 2).unwrap();
    assert_eq!(frame.as_bytes(), &wire[..11]);
    assert_eq!(frame.payload_length(), 2);
    assert_eq!(frame.frame_type(), Http2FrameType::new(0xfe));
    assert_eq!(frame.flags(), 0xa5);
    assert_eq!(frame.stream_id().raw(), 0x8000_0007);
    assert_eq!(frame.stream_id().value(), 7);
    assert!(frame.stream_id().has_reserved_bit());
    assert_eq!(frame.payload(), [0xde, 0xad]);
}

#[test]
fn raw_frame_uses_the_callers_payload_maximum() {
    let wire = [0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 2];
    assert_eq!(
        Http2Frame::parse(&wire, 1),
        Err(Http2ParseError::PayloadTooLarge {
            maximum: 1,
            actual: 2,
        })
    );
    assert!(Http2Frame::parse(&wire, 2).is_ok());
}

#[test]
fn mutable_frame_has_the_same_bound_and_mutable_payload() {
    let mut wire = [
        0, 0, 2, 0xfe, 0xa5, 0x80, 0x00, 0x00, 0x07, 0xde, 0xad, 0xfa,
    ];
    assert_eq!(
        Http2FrameMut::parse(&mut wire, 1),
        Err(Http2ParseError::PayloadTooLarge {
            maximum: 1,
            actual: 2,
        })
    );
    let mut frame = Http2FrameMut::parse(&mut wire, 2).unwrap();
    assert_eq!(
        frame.as_bytes(),
        &[0, 0, 2, 0xfe, 0xa5, 0x80, 0x00, 0x00, 0x07, 0xde, 0xad]
    );
    frame.payload_mut()[1] = 0xbe;
    assert_eq!(frame.payload(), [0xde, 0xbe]);
    assert_eq!(
        frame.as_bytes(),
        &[0, 0, 2, 0xfe, 0xa5, 0x80, 0x00, 0x00, 0x07, 0xde, 0xbe]
    );
}

#[test]
fn raw_builder_writes_exact_bytes_and_preserves_suffix() {
    let mut destination = [0xaa; 16];
    let frame = Http2FrameBuilder::new(
        &mut destination,
        Http2FrameType::new(0xfe),
        0xa5,
        Http2StreamId::from_value(7).unwrap(),
        &[0xde, 0xad],
    )
    .build()
    .unwrap();
    assert_eq!(
        frame.as_bytes(),
        &[0, 0, 2, 0xfe, 0xa5, 0, 0, 0, 7, 0xde, 0xad]
    );
    assert!(destination[11..].iter().all(|byte| *byte == 0xaa));
}

#[test]
fn raw_builder_failures_leave_the_whole_destination_unchanged() {
    let mut reserved = [0xaa; 16];
    let before = reserved;
    assert_eq!(
        Http2FrameBuilder::new(
            &mut reserved,
            Http2FrameType::DATA,
            0,
            Http2StreamId::new(0x8000_0001),
            &[],
        )
        .build(),
        Err(Http2BuildError::ReservedStreamId)
    );
    assert_eq!(reserved, before);

    let mut oversized = [0xaa; 16];
    let before = oversized;
    assert_eq!(
        Http2FrameBuilder::new(
            &mut oversized,
            Http2FrameType::DATA,
            0,
            Http2StreamId::from_value(1).unwrap(),
            &[1, 2],
        )
        .build_with_maximum(1),
        Err(Http2BuildError::PayloadTooLarge {
            maximum: 1,
            actual: 2,
        })
    );
    assert_eq!(oversized, before);

    let mut short = [0xaa; 10];
    let before = short;
    assert_eq!(
        Http2FrameBuilder::new(
            &mut short,
            Http2FrameType::DATA,
            0,
            Http2StreamId::from_value(1).unwrap(),
            &[1, 2],
        )
        .build(),
        Err(Http2BuildError::BufferTooShort {
            required: 11,
            available: 10,
        })
    );
    assert_eq!(short, before);
}