Quiver.HTTP3 (quiver v0.3.0)

Copy Markdown View Source

HTTP/3 datagram channel API (RFC 9297).

Opens an HTTP/3 request stream that is kept open without auto-ending and drives a user handler with response, datagram, stream-data, trailer, and close events. The handler may call send_datagram/2 and max_datagram_size/1 against an opaque %Quiver.HTTP3.Channel{} to push datagrams back.

Sample usage

{:ok, final_acc} =
  Quiver.HTTP3.open_datagram_channel(
    "https://h3.example/wt/session",
    [method: :connect, protocol: "webtransport"],
    fn
      {:response, 200, _hs}, channel, acc ->
        Quiver.HTTP3.send_datagram(channel, "hello")
        {:cont, acc}

      {:datagram, _payload}, _ch, acc ->
        {:cont, acc}

      {:closed, _reason}, _ch, acc ->
        {:halt, acc}
    end,
    []
  )

See guides/http3.md for the full cookbook including extended CONNECT and the WebTransport-style :protocol header.

Summary

Functions

Returns true if both peers negotiated SETTINGS_H3_DATAGRAM=1 and the underlying QUIC connection has max_datagram_frame_size > 0.

Returns the maximum usable datagram payload size on channel.

Opens an HTTP/3 datagram channel and drives handler until it halts or the channel closes.

Sends a datagram on channel. Bypasses the pool worker by calling :quic_h3.send_datagram/3 directly for hot-path speed.

Types

close_reason()

@type close_reason() ::
  :peer
  | {:reset, non_neg_integer()}
  | {:goaway, non_neg_integer()}
  | {:transport, Quiver.Error.QUICTransportError.t()}

event()

@type event() ::
  {:response, status(), headers()}
  | {:datagram, payload()}
  | {:stream_data, binary()}
  | {:trailers, headers()}
  | {:closed, close_reason()}

handler()

@type handler() :: (event(), Quiver.HTTP3.Channel.t(), term() ->
                {:cont, term()} | {:halt, term()})

headers()

@type headers() :: [{binary(), binary()}]

payload()

@type payload() :: binary()

status()

@type status() :: 100..599

Functions

h3_datagrams_enabled?(channel)

@spec h3_datagrams_enabled?(Quiver.HTTP3.Channel.t()) :: boolean()

Returns true if both peers negotiated SETTINGS_H3_DATAGRAM=1 and the underlying QUIC connection has max_datagram_frame_size > 0.

max_datagram_size(channel)

@spec max_datagram_size(Quiver.HTTP3.Channel.t()) :: non_neg_integer()

Returns the maximum usable datagram payload size on channel.

Returns 0 when the extension is not negotiated. Otherwise the value is the per-datagram payload limit after subtracting the QSID varint prefix :quic_h3 prepends internally.

open_datagram_channel(url, opts, handler, acc)

@spec open_datagram_channel(String.t(), keyword(), handler(), term()) ::
  {:ok, term()} | {:error, term()}

Opens an HTTP/3 datagram channel and drives handler until it halts or the channel closes.

Synchronous from the caller's perspective: the calling process owns the event mailbox and runs the reduce loop.

See module docs for options and event semantics.

Returns {:ok, acc} on normal close or halt, {:error, reason} on open failure / timeout / disabled datagrams.

send_datagram(ch, data)

@spec send_datagram(Quiver.HTTP3.Channel.t(), iodata()) ::
  :ok | {:error, Exception.t()}

Sends a datagram on channel. Bypasses the pool worker by calling :quic_h3.send_datagram/3 directly for hot-path speed.

Returns :ok on success or {:error, exception} where the exception is either Quiver.Error.H3DatagramsDisabled (peer didn't negotiate) or Quiver.Error.H3DatagramError (transport / sizing / lifecycle).