micro-h2 0.1.0

A minimal no_std, allocation-free HTTP/2 client: framing, HPACK, and a bounded number of streams
Documentation

micro-h2

CI crates.io docs.rs

A small, client-only HTTP/2 implementation for systems without std or an allocator.

It is sans-I/O: the caller moves bytes to and from a socket while Connection owns the HTTP/2 and HPACK state. It requires Rust 1.88 and forbids unsafe Rust. The runtime dependency is heapless; HTTP/2 and HPACK reference implementations are used only in tests.

[dependencies]
micro-h2 = "0.0.1"
let mut connection = micro_h2::Connection::new();
let mut out = [0u8; 256];
let written = connection.start(&mut out).unwrap();
// Send out[..written] through the transport you provide.

This is experimental protocol software; the supported HTTP/2 surface is deliberately limited as described below.

What it handles

  • the client preface and SETTINGS exchange
  • bounded request streams with HEADERS and optional DATA
  • response HEADERS, CONTINUATION, and DATA frames
  • connection and stream flow control
  • PING, RST_STREAM, GOAWAY, padding, and unknown frame types
  • HPACK static and dynamic tables, including Huffman decoding

The usual flow is:

  1. Create a Connection and send the bytes from Connection::start.
  2. Open a stream with Connection::request.
  3. Feed each complete frame to Connection::recv.
  4. Send any acknowledgement or WINDOW_UPDATE bytes it writes, and act on the returned Event.

Deliberate limits

This is not a general browser HTTP/2 stack. It has four concurrent streams, a 2 KiB header-block buffer, no server mode, no push, no priority tree, no trailers, and no outgoing CONTINUATION frames. Unsupported features are refused instead of partially implemented.

Request bodies must fit one DATA frame and both available send windows. Error::FlowControl leaves the connection unchanged; process peer window updates or SETTINGS before retrying. New requests also respect MAX_CONCURRENT_STREAMS and stop after GOAWAY. Discard the connection after a receive-side protocol or HPACK error.

TLS, TCP, retries, and request scheduling belong to the caller. This crate only turns HTTP/2 bytes into bounded state and events.

Verification

Unit tests cover framing, HPACK state, Huffman decoding, and flow control. Differential tests in tests/ exchange traffic with the Rust h2 implementation, including a 4 MiB response that exercises flow-control updates, and compare HPACK in both directions with fluke-hpack. Protocol regressions fill all four stream slots on eight independent connections: a barrier ensures 32 simultaneous streams, with 64 round trips across two waves. Each response exceeds the receive window; tests verify exact headers and echoed bytes, credit-buffer retries, negotiated limits, and valid and malformed continuation sequences. The tests use in-memory transports and require no external service.

cargo fmt --all --check
cargo clippy --locked --all-targets --all-features -- -D warnings
cargo test --locked --all-features
cargo check --locked --lib --no-default-features --target riscv32imac-unknown-none-elf
cargo check --locked --lib --no-default-features --target wasm32-unknown-unknown

Install the cross-compilation targets with rustup target add before checking them locally. CI checks both with the Rust 1.88 minimum supported version.

Contributing and releases

See AGENTS.md for validation and Conventional Commit PR titles, and repository setup for Runnerless release-please and crates.io publishing. The library and its interoperability tests were extracted from Tailfeather; provenance records the source snapshot.

License

MIT OR Apache-2.0, at your option.