I am pleased to announce erlang_quic 1.3.0, the first production-ready release of the library. The transport layer that 0.11.0 introduced is now paired with a complete HTTP/3 stack.
What is in 1.3.0 that was not in 0.11.0
A complete HTTP/3 stack
quic_h3 ships server and client APIs for RFC 9114 with the full pseudo-header rule set, GOAWAY, server push, and the entire HTTP/3 error-code surface. QPACK (RFC 9204) is implemented with the static and dynamic tables, blocked-stream tracking, and the encoder and decoder instruction streams. The eight-bucket priority scheduler is fed by both the priority request header and PRIORITY_UPDATE frames (RFC 9218).
{ok, _} = quic_h3:start_server(my_h3, 4433, #{
cert => Cert,
key => Key,
handler =>
fun(Conn, StreamId, <<"GET">>, Path, _Headers) ->
quic_h3:send_response(Conn, StreamId, 200, [{<<"content-type">>, <<"text/plain">>}]),
quic_h3:send_data(Conn, StreamId, <<"hello ", Path/binary>>, true)
end
}).
HTTP/3 datagrams and extended CONNECT
RFC 9297 datagrams are wired in with the quarter-stream-id multiplexing of quic_h3:send_datagram/3. Extended CONNECT (RFC 9220) is the primitive on which the companion library erlang-webtransport builds its WebTransport-over-HTTP/3 implementation.
Companion libraries already on the new stack
- hackney 4.0.0 routes HTTP/3 through
quic_h3with the unchanged `hackney:request/5`` API. - erlang-webtransport uses extended CONNECT, the bidirectional and unidirectional stream claim hook, and the H3 datagram dispatch.
User streams (“circuits”) on the dist connection
The -proto_dist quic mode introduced in 0.11.0 has gained a public quic_dist:open_user_stream/2 API. Two nodes that already talk dist can open extra QUIC streams over the same connection for bulk transfer, low-latency RPC, or streaming subscriptions, with their own flow control and error code, multiplexed alongside the standard gen_server:call traffic without head-of-line blocking between them.
%% On node1@host1 — open a user stream to node2@host2.
{ok, StreamRef} = quic_dist:open_user_stream(node2@host2, self()),
ok = quic_dist:send(StreamRef, <<"chunk-1">>),
ok = quic_dist:send(StreamRef, <<"chunk-2">>, _Fin = true),
%% Owner receives:
%% {quic_dist_stream, StreamRef, {data, Data, Fin}}
%% {quic_dist_stream, StreamRef, closed}
Versioning note
The bump from 0.x to 1.3.0 reflects the production-ready commitment on the public API surface (quic, quic_h3, quic_dist, quic_qpack, quic_lb). Internals under src/ may continue to move; the exposed APIs follow semver from this release on.
Links
- Repository: GitHub - benoitc/erlang_quic: Pure Erlang QUIC implementation (RFC 9000) · GitHub
- Release notes: Release v1.3.0 · benoitc/erlang_quic · GitHub
- Compliance matrix: erlang_quic/docs/h3_compliance.md at main · benoitc/erlang_quic · GitHub
- Getting started: erlang_quic/docs/GETTING_STARTED.md at main · benoitc/erlang_quic · GitHub
- Distribution guide: erlang_quic/docs/QUIC_DIST.md at main · benoitc/erlang_quic · GitHub
- HTTP/3 guide: erlang_quic/docs/HTTP3.md at main · benoitc/erlang_quic · GitHub
Pull as a rebar3 dependency, or activate the QUIC distribution mode on a cluster. Issues and pull requests welcome on the tracker.
