sark-h2 0.29.5

Fiber-free HTTP/2 protocol primitives and manifold server for sark
use common::{
    hpack::Fields,
    protocol::{
        Session,
        rules::{Settings, Wire},
        session::Frame,
    },
};
use sark_h2::conn::event::Event;
pub mod common;
use sark_core::manifold::stream::Boundary;
use sark_h2::{
    ClientRole,
    conn::machine::Connection,
    frame::{Block, numbers::ErrorCode},
};
use sark_http::field::metadata::map::record::Entry;

#[test]
fn accepts_status() {
    let mut conn = Connection::<ClientRole>::try_new().expect("client fixture");
    Session::new(&mut conn)
        .try_prime()
        .expect("protocol fixture");
    let id = Session::new(&mut conn)
        .try_open()
        .expect("protocol fixture");
    let block = Fields::new(&[Entry::new(b":status", b"200")])
        .try_encode()
        .expect("protocol fixture");
    let frame = Frame::new(id.into_u32(), &block)
        .try_headers(Boundary::End, Block::End)
        .expect("protocol wire fixture");
    conn.ingress()
        .ingest(&frame)
        .expect("response HEADERS frame fits ingress");
    let ev = conn.ingress().poll_event().expect("Headers event");
    assert!(matches!(ev, Event::Headers { .. }));
    assert!(
        Wire::new(conn.output().first())
            .try_reset()
            .expect("protocol wire fixture")
            .is_none()
    );
}

#[test]
fn rejects_header_limit() {
    let mut conn = Settings::limited(41)
        .try_connect::<ClientRole>()
        .expect("header limit fixture");
    Session::new(&mut conn)
        .try_prime()
        .expect("protocol fixture");
    let id = Session::new(&mut conn)
        .try_open()
        .expect("protocol fixture");
    let block = Fields::new(&[Entry::new(b":status", b"200")])
        .try_encode()
        .expect("protocol fixture");
    let frame = Frame::new(id.into_u32(), &block)
        .try_headers(Boundary::End, Block::End)
        .expect("protocol wire fixture");
    conn.ingress()
        .ingest(&frame)
        .expect("response HEADERS frame fits ingress");
    assert!(matches!(
        conn.ingress().poll_event(),
        Some(Event::StreamReset {
            stream_id, error: ErrorCode::ProtocolError, ..
        }) if stream_id == id
    ));
    let rst = Wire::new(conn.output().first())
        .try_reset()
        .expect("protocol wire fixture")
        .expect("RST_STREAM emitted");
    assert!((rst) == (id, ErrorCode::ProtocolError));
    assert!(!conn.status().has_stream(id));
}

#[test]
fn rejects_missing_status() {
    let mut conn = Connection::<ClientRole>::try_new().expect("client fixture");
    Session::new(&mut conn)
        .try_prime()
        .expect("protocol fixture");
    let id = Session::new(&mut conn)
        .try_open()
        .expect("protocol fixture");
    let block = Fields::new(&[Entry::new(b"content-type", b"text/plain")])
        .try_encode()
        .expect("protocol fixture");
    let frame = Frame::new(id.into_u32(), &block)
        .try_headers(Boundary::End, Block::End)
        .expect("protocol wire fixture");
    conn.ingress()
        .ingest(&frame)
        .expect("response HEADERS frame fits ingress");
    assert!(matches!(
        conn.ingress().poll_event(),
        Some(Event::StreamReset {
            stream_id, error: ErrorCode::ProtocolError, ..
        }) if stream_id == id
    ));
    let rst = Wire::new(conn.output().first())
        .try_reset()
        .expect("protocol wire fixture")
        .expect("RST_STREAM emitted");
    assert!((rst) == (id, ErrorCode::ProtocolError));
}

#[test]
fn rejects_uppercase() {
    let mut conn = Connection::<ClientRole>::try_new().expect("client fixture");
    Session::new(&mut conn)
        .try_prime()
        .expect("protocol fixture");
    let id = Session::new(&mut conn)
        .try_open()
        .expect("protocol fixture");
    let block = Fields::new(&[
        Entry::new(b":status", b"200"),
        Entry::new(b"Content-Type", b"text/plain"),
    ])
    .try_encode()
    .expect("protocol fixture");
    let frame = Frame::new(id.into_u32(), &block)
        .try_headers(Boundary::End, Block::End)
        .expect("protocol wire fixture");
    conn.ingress()
        .ingest(&frame)
        .expect("response HEADERS frame fits ingress");
    assert!(matches!(
        conn.ingress().poll_event(),
        Some(Event::StreamReset {
            stream_id, error: ErrorCode::ProtocolError, ..
        }) if stream_id == id
    ));
    let rst = Wire::new(conn.output().first())
        .try_reset()
        .expect("protocol wire fixture")
        .expect("RST_STREAM emitted");
    assert!((rst) == (id, ErrorCode::ProtocolError));
}

#[test]
fn rejects_request_pseudo() {
    let mut conn = Connection::<ClientRole>::try_new().expect("client fixture");
    Session::new(&mut conn)
        .try_prime()
        .expect("protocol fixture");
    let id = Session::new(&mut conn)
        .try_open()
        .expect("protocol fixture");
    let block = Fields::new(&[
        Entry::new(b":status", b"200"),
        Entry::new(b":method", b"GET"),
    ])
    .try_encode()
    .expect("protocol fixture");
    let frame = Frame::new(id.into_u32(), &block)
        .try_headers(Boundary::End, Block::End)
        .expect("protocol wire fixture");
    conn.ingress()
        .ingest(&frame)
        .expect("response HEADERS frame fits ingress");
    assert!(matches!(
        conn.ingress().poll_event(),
        Some(Event::StreamReset {
            stream_id, error: ErrorCode::ProtocolError, ..
        }) if stream_id == id
    ));
    let rst = Wire::new(conn.output().first())
        .try_reset()
        .expect("protocol wire fixture")
        .expect("RST_STREAM emitted");
    assert!((rst) == (id, ErrorCode::ProtocolError));
}

#[test]
fn rejects_unknown_pseudo() {
    let mut conn = Connection::<ClientRole>::try_new().expect("client fixture");
    Session::new(&mut conn)
        .try_prime()
        .expect("protocol fixture");
    let id = Session::new(&mut conn)
        .try_open()
        .expect("protocol fixture");
    let block = Fields::new(&[Entry::new(b":status", b"200"), Entry::new(b":foo", b"bar")])
        .try_encode()
        .expect("protocol fixture");
    let frame = Frame::new(id.into_u32(), &block)
        .try_headers(Boundary::End, Block::End)
        .expect("protocol wire fixture");
    conn.ingress()
        .ingest(&frame)
        .expect("response HEADERS frame fits ingress");
    assert!(matches!(
        conn.ingress().poll_event(),
        Some(Event::StreamReset {
            stream_id, error: ErrorCode::ProtocolError, ..
        }) if stream_id == id
    ));
    let rst = Wire::new(conn.output().first())
        .try_reset()
        .expect("protocol wire fixture")
        .expect("RST_STREAM emitted");
    assert!((rst) == (id, ErrorCode::ProtocolError));
}