http-pack
Binary framing for HTTP requests/responses so they can be relayed as a stream-decodable payload.
The format is designed to carry HTTP/1.1, H2, or H3 messages after TLS termination, then rebuild HTTP/1.1 requests or responses on the receiving side.
Format (v1)
- Magic:
HPK1 - Format version:
u8 - Kind:
u8(1= request,2= response) - HTTP version:
u8(1= HTTP/1.1,2= H2,3= H3) - Request fields (length-delimited with varint):
- method
- scheme (empty = none)
- authority (empty = none)
- path
- Response fields:
- status (
u16, network order)
- status (
- Headers:
- header count (varint)
- name length + bytes
- value length + bytes
- Body:
- body length (varint)
- body bytes
Lengths are unsigned LEB128 varints so the payload can be decoded from a stream.
Usage
use Bytes;
use Request;
use ;
let req = builder
.method
.uri
.body
.unwrap;
let payload = encode_request.unwrap;
let decoded = decode.unwrap;
if let Request = decoded
The HTTP/1.1 reconstruction helpers drop transfer-encoding and add a content-length when
missing so the resulting request/response is valid in HTTP/1.1 form.
Streaming frames
For streaming relays, use the stream frame format (HPKS). Each frame is a small binary payload
that can be signed and packetized independently:
- Headers frame: carries the request/response line + headers.
- Body frame: carries a chunk of body bytes.
- End frame: marks the end of the body.
On the receiving side, Http1StreamRebuilder converts these frames into HTTP/1.1 bytes using
transfer-encoding: chunked so the body can be forwarded without buffering.
use ;
let headers = Request;
let mut rebuilder = new;
let header_bytes = rebuilder.push_frame?;
let body_bytes = rebuilder.push_frame?;
let end_bytes = rebuilder.push_frame?;
Streaming encode helpers
- HTTP/1.1 raw:
h1::H1StreamDecoderemitsStreamFramevalues as bytes arrive. - HTTP/2 (or any
http_body::Body):stream::body::encode_request/encode_responseemits frames via a callback. - HTTP/3:
stream::h3::encode_server_request/encode_client_responseemits frames fromh3::RequestStream.
These helpers let you stream the body without buffering it in memory.
HTTP/1.1 raw decoder
Enable h1 to parse raw HTTP/1.1 bytes into PackedRequest/PackedResponse values. This parser
expects either content-length or transfer-encoding: chunked when a body is present.
= { = "../http-pack", = ["h1"] }
use ;
let bytes = b"GET /hello HTTP/1.1\r\nHost: example.com\r\n\r\n";
let = decode_request.unwrap.unwrap;
let mut decoder = new;
decoder.push;
let msg = decoder.try_decode.unwrap;
Body collection for HTTP/1.1 and HTTP/2
Enable body to collect http_body::Body payloads (hyper requests/responses, h2 responses, etc.)
into PackedRequest/PackedResponse values.
= { = "../http-pack", = ["body"] }
use pack_request;
let packed = pack_request.await?;
HTTP/3 stream adapter
Enable h3 to collect data frames from h3::server::RequestStream or h3::client::RequestStream
and build packed messages.
= { = "../http-pack", = ["h3"] }
use ;
let packed_req = pack_server_request.await?;
let packed_resp = pack_client_response.await?;
message-packetizer integration
http-pack always ships a HttpPackMessage wrapper that implements
message_packetizer::SignableMessage. You encode an HTTP request/response into a packed payload,
wrap it in HttpPackMessage, then sign and stream packets using message-packetizer.
use HttpPackMessage;
use MessageSigner;
let msg = from_request.unwrap;
let mut signer = new?;
let signed = signer.sign?;
for packet in signed.to_packets
For streaming relays, use HttpPackStreamMessage and send each frame independently:
use HttpPackStreamMessage;
use StreamFrame;
use MessageSigner;
let msg = from_frame;
let mut signer = new?;
let signed = signer.sign?;
for packet in signed.to_packets
Or use the convenience adapters to emit HttpPackStreamMessage directly (requires body feature):
use stream;
encode_request.await?;
Testing
The test suite includes:
- Core HPK1 encode/decode roundtrips
- Real HTTP/2 connections via
h2 - Real HTTP/3 connections via
quinn+h3 - Byte-for-byte body fidelity across all protocols (all 256 byte values, null bytes, CRLF sequences, 1MB bodies)
License
MIT