Skip to content

Protocol API ​

Low-level protocol framing, parsing, and header compression. This module provides HTTP/1.1 parsing, HTTP/2 framing with HPACK, and HTTP/3 framing with QPACK over QUIC transport primitives.

Custom Implementation

Zig's standard library does not provide HTTP/2, HTTP/3, or QUIC support. httpx.zig implements these protocols from scratch, including HPACK, QPACK, HTTP/2 framing, HTTP/3 framing, and QUIC transport frame coding as specified in the relevant RFCs.

Protocol Support Matrix ​

ProtocolVersionStatusRFCNotes
HTTP/1.01.0✅ FullRFC 1945High-level runtime support
HTTP/1.11.1✅ FullRFC 9112High-level runtime support
HTTP/2h2✅ FullRFC 7540, RFC 7541Framing/stream state/flow control/HPACK plus high-level client/server runtimes
HTTP/3h3✅ FullRFC 9114, RFC 9204Framing/QPACK/QUIC helpers plus high-level client/server runtimes
QUICv1✅ PrimitivesRFC 9000Transport/frame coding primitives in the protocol module

HTTP/1.1 Parser (httpx.http1.parser) ​

Function-style parser over byte buffers:

zig
// Request line + headers.
const head = try httpx.http1.parser.parseRequestHead(buf);
// head.method, head.path, head.minorVersion, head.majorVersion, head.headEnd
var fields: [128]httpx.http1.parser.Field = undefined;
const blk = try httpx.http1.parser.parseHeaderBlock(buf, head.headEnd, &fields);

// Framing decision (none / contentLength / chunked / tunnel).
const framing = try httpx.http1.parser.decideFraming(fields[0..blk.count], false, 0, 0);

// Incremental chunked decoding.
var dec = httpx.http1.parser.ChunkedDecoder.init();
while (!dec.isDone()) {
    _ = try dec.decode(chunk);
}

Limits live in httpx.http1.parser.Options (allowLfLineEndings); size caps in DEFAULT_MAX_HEADER_BYTES, DEFAULT_MAX_BODY_BYTES, DEFAULT_MAX_HEADERS.

HTTP/2 Support (httpx.http2) ​

  • HPACK header compression (RFC 7541)
  • Stream state machine and multiplexing
  • Flow control with WINDOW_UPDATE handling
  • Frame encoding/decoding

Frame Types ​

TypeValueDescription
DATA0x0Request/response body data
HEADERS0x1Header block fragment
PRIORITY0x2Stream priority
RST_STREAM0x3Stream termination
SETTINGS0x4Configuration parameters
PUSH_PROMISE0x5Server push
PING0x6Connection liveness
GOAWAY0x7Graceful shutdown
WINDOW_UPDATE0x8Flow control
CONTINUATION0x9Header continuation

Frames (httpx.http2.frame) ​

zig
var hdrBuf: [httpx.http2.frame.FRAME_HEADER_SIZE]u8 = undefined;
const hdr = httpx.http2.FrameHeader.parse(&hdrBuf);
var out: [9]u8 = undefined;
hdr.serialize(&out);

// Writers: writeHeader, writeData, writeRstStream, writeSettings,
// writeSettingsAck, writePing, writeWindowUpdate, writeGoaway,
// writePriority. Union decode via Frame.parse(hdr, payload, allocator).

HPACK (httpx.http2.hpack) ​

zig
var enc = httpx.http2.hpack.Encoder.init(allocator);
defer enc.deinit();
var out = std.ArrayList(u8).empty;
defer out.deinit(allocator);
try enc.encode(&out, ":method", "GET", .incremental, false);
try enc.encode(&out, ":path", "/", .incremental, false);

var dec = httpx.http2.hpack.Decoder.init(allocator);
defer dec.deinit();
const res = try dec.decode(out.items);
// res.fields: []HeaderField{name, value}

Session (httpx.http2.Session) ​

zig
var sess = try httpx.http2.Session.init(allocator, .client, .{});
defer sess.deinit();
try sess.startHandshake();
const sid = try sess.nextClientStreamId();
try sess.sendHeaders(sid, &fields, false);
_ = try sess.sendData(sid, body, true);

HTTP/3 Support (httpx.http3) ​

  • QPACK header compression (RFC 9204)
  • QUIC transport framing (RFC 9000)
  • Variable-length integer encoding
  • Stream and frame types

Frames (httpx.http3.frame) ​

zig
var off: usize = 0;
const hdr = try httpx.http3.frame.parseFrameHeader(data, &off); // FrameHeader
const parsed = try httpx.http3.frame.parseFrame(data, &off);    // ParsedFrame
var buf: [16]u8 = undefined;
const n = try httpx.http3.frame.encodeFrameHeader(&buf, 0x01, payload.len);
// Settings payloads: parseSettingsPayload / buildSettingsPayload.

Connection (httpx.http3.Connection) ​

zig
var conn = httpx.http3.Connection.init(allocator, .client);
defer conn.deinit();
const ctrl = try conn.buildControlStream();
defer allocator.free(ctrl);
const streamId = conn.nextBidiStreamId();
var req = conn.createRequestStream(streamId);
const head = try req.buildRequestHeaders(allocator, &headers, false);
const data = try req.buildData(body);

QPACK (httpx.http3.qpack) ​

Static/dynamic table header compression with encoder/decoder stream instructions; see src/protocols/http3/qpack.zig.

QUIC (httpx.quic) ​

Transport coding primitives (RFC 9000): varint.encode / varint.decode, packet, frames (STREAM, CRYPTO, ACK, RESET_STREAM, STOP_SENDING, ...), connection, params (transport parameters), stream, crypto, connectionId, path, transport.

zig
var buf: [8]u8 = undefined;
const n = try httpx.quic.varint.encode(&buf, 15293);
var off: usize = 0;
const v = try httpx.quic.varint.decode(&buf, &off);

Complete HTTP/2 Example ​

See examples/http2Client.zig (h2c client + server) and examples/http2Multiplex.zig (HPACK + multiplexed streams). For HTTP/3, see examples/http3Client.zig and examples/http3Quic.zig.

Released under the MIT License.