Skip to content

colibri 0.4.0: server and client modules, and a Channel that chooses h3 or TCP

Choose a tag to compare

@c4milo c4milo released this 28 Sep 19:23
· 673 commits to main since this release

colibri 0.4.0 adds the server and client modules. Each answers or sends HTTP requests behind one set of calls for h11 and h2, and the client also carries them over h3 on QUIC, choosing QUIC or TCP for each server. QUIC and h3 write qlog when the caller asks.

Breaking

  • h3: each call that reads or writes a frame takes the instant of the call, now_ns, which its qlog events carry: start, receive, shutdown, write_request, write_response and write_trailers. write_data_header is now a method of h3.Connection that takes the stream's id too (3028902).
  • quic: connection_send.pacing_deadline_ns is gone. connection_timer.next still names the pacer's instant among the connection's deadlines (d5ba436).
  • qlog, for a caller that pinned an untagged commit before abdad55, such as a5a97d2, and writes its own events: qlog.Json is gone, qlog.json is stdx's JSON module, and each event's write takes a *qlog.TextWriter. qlog.Log is unchanged, and 0.3.0 had no qlog.

To move from 0.3.0, pass h3 the instant you pass quic, call write_data_header on the connection with the stream's id, and read the pacer's instant from connection_timer.next.

Added

  • server (design §8 step 17a): Connection answers h11 and h2 requests, the version chosen by ALPN over TLS and named in cleartext. receive reports each request's head, content, trailers and cancellation; the caller answers with respond, write_body and write_trailers.
  • client (steps 17c and 17d):
    • Connection sends h11 and h2 requests over TCP, with TLS through chapulin. The caller places each request and its response's memory in an HttpExchange, and gets one finished event per exchange.
    • QuicConnection carries the same exchanges over h3 on QUIC.
    • Channel carries exchanges to one server over a QUIC and a TCP connection it chooses between. It tries QUIC first when h3 is known or allowed, and opens TCP when QUIC fails or a fallback delay passes. The caller passes DNS's answers as values, and learns h3 from a TCP response's Alt-Svc for its next channel.
    • The caller places the QUIC receive pool, sized with ReceivePool(capacity), and every window the client advertises follows its capacity.
    • An exchange can send its path and field lines never-indexed (28d3736).
  • qlog: QUIC's packets, frames, states, losses and metrics, and h3's frames and streams, as JSON-SEQ records in the caller's buffer (decision 102). A connection logs only when its caller passes a log. tools/qlog_to_qvis.py rewrites a file into the form qvis reads.

Fixed

  • h2: a server's DATA before its final response is refused (RFC 9113 §8.1), and so is END_STREAM on an interim response. Frames above a GOAWAY colibri sent are ignored (RFC 9113 §6.8). A field block that finds no room leaves nothing behind (3f6e609).
  • QUIC: a second handshake probe repeats the first one's CRYPTO octets, and a closing connection arms no acknowledgment or path deadline, which came due at every instant.

Checked against

CI ran tools/ci.sh on fd00073, on Ubuntu 24.04, and every section passed:

  • h2spec 2.6.0: 144 passed in cleartext and over TLS, and 2 skipped by name, which test an RFC 7540 rule RFC 9113 dropped. h3spec 0.1.13: 49 examples, 0 failures.
  • The client and the server over h11 and h2 against Go 1.27.1, nghttpd 1.52.0, h2o 2.2.5, curl 7.88.1 and nghttp, in cleartext and over TLS.
  • The client's Channel fetched over h3 from aioquic 1.3.0 and quic-go 9d085cc, and over h2 from Go's server with no UDP.
  • aioquic in both directions over hq-interop and h3, QPACK against ls-qpack, the TLA+ models with the h2, h3 and client traces, the Lean proofs, and 2,184 tests in Debug and in ReleaseSafe.

The QUIC Interop Runner ran on 2026-09-28 at a5a97d2, whose endpoint this release leaves as it was. colibri passed every case against quic-go, ngtcp2, neqo and quinn in both directions. Against itself it failed rebind-port alone.

docs/design.md §8 records each check: what ran, on what machine, and what it printed.

Install

zig fetch --save git+https://github.com/c4milo/colibri#v0.4.0