Erlang_quic 1.3.0 — production-ready QUIC + HTTP/3

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_h3 with 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

Pull as a rebar3 dependency, or activate the QUIC distribution mode on a cluster. Issues and pull requests welcome on the tracker.

5 Likes