webtransport (webtransport v0.3.0)

View Source

WebTransport Public API

This module provides the public API for WebTransport over HTTP/2 and HTTP/3.

Server Usage

  %% Start a WebTransport listener
  {ok, Listener} = webtransport:start_listener(my_listener, #{
      transport => h3,
      port => 8443,
      certfile => "cert.pem",
      keyfile => "key.pem",
      handler => my_wt_handler
  }).
 
  %% Stop the listener
  ok = webtransport:stop_listener(my_listener).

Client Usage

  %% Connect to a WebTransport server
  {ok, Session} = webtransport:connect("example.com", 443, "/wt", #{
      transport => h3
  }).
 
  %% Open a bidirectional stream
  {ok, Stream} = webtransport:open_stream(Session, bidi).
 
  %% Send data
  ok = webtransport:send(Session, Stream, <<"Hello">>).
 
  %% Send with FIN flag
  ok = webtransport:send(Session, Stream, <<"World">>, fin).
 
  %% Send unreliable datagram
  ok = webtransport:send_datagram(Session, <<"ping">>).
 
  %% Close stream
  ok = webtransport:close_stream(Session, Stream).
 
  %% Close session
  ok = webtransport:close_session(Session).

Handler Behaviour

See webtransport_handler for the callback behaviour.

Summary

Functions

Accept a WebTransport session on an incoming CONNECT request.

Close the session gracefully.

Close the session with an error code.

Close the session with an error code and reason. draft-14 §4.6 / draft-15 §5: Reason must be at most 1024 UTF-8 bytes.

Close a stream gracefully (send FIN).

Connect to a WebTransport server.

Connect to a WebTransport server with a custom handler.

Signal that no new streams will be created.

Report whether the session's connection negotiated 0-RTT early data.

Return HTTP/2 settings to merge into an h2 server configuration.

Return HTTP/3 settings to merge into a quic_h3 server configuration.

Get information about a listener.

Get the bound {Ip, Port} of a listener.

List all active listeners.

Open a new stream on the session.

Abruptly terminate a stream with an error code.

Send data on a stream.

Send data on a stream with optional FIN flag.

Send an unreliable datagram.

Get session information.

Start a WebTransport listener.

Stop a WebTransport listener.

Request that the peer stop sending on a stream.

Types

connect_opts/0

-type connect_opts() ::
          #{transport => h2 | h3,
            certfile => file:filename(),
            keyfile => file:filename(),
            cacertfile => file:filename(),
            verify => verify_none | verify_peer,
            headers => [{binary(), binary()}],
            timeout => timeout(),
            family => inet | inet6 | any,
            happy_eyeballs => boolean(),
            connection_attempt_delay => non_neg_integer(),
            session_ticket => term(),
            compat_mode => latest | legacy_browser_compat}.

listener_name/0

-type listener_name() :: atom().

listener_opts/0

-type listener_opts() ::
          #{transport := h2 | h3,
            port := inet:port_number(),
            certfile := file:filename(),
            keyfile := file:filename(),
            handler := module(),
            handler_opts => term(),
            max_data => non_neg_integer(),
            max_streams_bidi => non_neg_integer(),
            max_streams_uni => non_neg_integer(),
            ip => inet:ip_address(),
            family => inet | inet6,
            socket_opts => list(),
            compat_mode => latest | legacy_browser_compat | auto}.

request/0

-type request() :: #{path := binary(), authority := binary(), headers => [{binary(), binary()}]}.

session/0

-type session() :: pid().

stream/0

-type stream() :: non_neg_integer().

Functions

accept(Conn, StreamId, Headers, Opts)

-spec accept(pid(), non_neg_integer(), [{binary(), binary()}], map()) ->
                {ok, session()} | {error, term()}.

Accept a WebTransport session on an incoming CONNECT request.

Call this from your HTTP request handler when you want a particular CONNECT request to become a WebTransport session. The function validates headers, starts the session gen_statem, registers it as the stream handler (like quic_h3:set_stream_handler/3), sends 200, and returns {ok, Session}.

  my_handler(Conn, StreamId, <<"CONNECT">>, <<"/wt">>, Headers) ->
      webtransport:accept(Conn, StreamId, Headers, #{
          transport => h3,
          handler => my_wt_handler,
          handler_opts => #{owner => self()}
      });
  my_handler(Conn, StreamId, <<"GET">>, _Path, _Headers) ->
      quic_h3:send_response(Conn, StreamId, 200, []),
      quic_h3:send_data(Conn, StreamId, <<"hello">>, true).

close_session(Session)

-spec close_session(session()) -> ok.

Close the session gracefully.

close_session(Session, ErrorCode)

-spec close_session(session(), non_neg_integer()) -> ok.

Close the session with an error code.

close_session(Session, ErrorCode, Reason)

-spec close_session(session(), non_neg_integer(), binary()) -> ok | {error, reason_too_long}.

Close the session with an error code and reason. draft-14 §4.6 / draft-15 §5: Reason must be at most 1024 UTF-8 bytes.

close_stream(Session, Stream)

-spec close_stream(session(), stream()) -> ok | {error, term()}.

Close a stream gracefully (send FIN).

connect(Host, Port, Path, Opts)

-spec connect(Host, Port, Path, Opts) -> {ok, session()} | {error, term()}
                 when
                     Host :: string() | binary() | inet:ip_address(),
                     Port :: inet:port_number(),
                     Path :: binary(),
                     Opts :: connect_opts().

Connect to a WebTransport server.

Options: - transport - Optional. Either h2 or h3 (default: h3) - cacertfile - Optional. CA certificate file for verification - verify - Optional. verify_none or verify_peer (default: verify_peer) - headers - Optional. Extra headers to send in CONNECT request - timeout - Optional. Connection timeout in ms (default: 30000)

connect(Host, Port, Path, Opts, Handler)

-spec connect(Host, Port, Path, Opts, Handler) -> {ok, session()} | {error, term()}
                 when
                     Host :: string() | binary() | inet:ip_address(),
                     Port :: inet:port_number(),
                     Path :: binary(),
                     Opts :: connect_opts(),
                     Handler :: module() | undefined.

Connect to a WebTransport server with a custom handler.

drain_session(Session)

-spec drain_session(session()) -> ok.

Signal that no new streams will be created.

early_data_accepted(Session)

-spec early_data_accepted(session()) -> boolean() | unknown | not_supported.

Report whether the session's connection negotiated 0-RTT early data.

Returns true, false, or unknown for h3 sessions (RFC 9001 §4.6), and not_supported for h2. This is connection-level: it reflects whether the QUIC connection used 0-RTT, regardless of whether the WebTransport CONNECT itself rode as early data.

h2_settings()

-spec h2_settings() -> map().

Return HTTP/2 settings to merge into an h2 server configuration.

  Opts = maps:merge(webtransport:h2_settings(), #{
      cert => "cert.pem", key => "key.pem",
      handler => fun my_handler/5,
      enable_connect_protocol => true
  }),
  h2:start_server(443, Opts).

h2_settings(Opts)

-spec h2_settings(map()) -> map().

h3_settings()

-spec h3_settings() -> map().

Return HTTP/3 settings to merge into a quic_h3 server configuration.

Use this when embedding WebTransport into an existing HTTP/3 server instead of using start_listener/2. The returned map contains:

- settings -- H3 SETTINGS to advertise (wt_enabled, flow control, etc.) - stream_type_handler -- claims WT extension streams (0x41 bidi, 0x54 uni) - h3_datagram_enabled -- enables QUIC datagrams - quic_opts -- QUIC transport params (max_datagram_frame_size, reset_stream_at) - connection_handler -- per-connection setup (creates the WT stream router)

Merge the result into your quic_h3 server opts:

  Opts = maps:merge(webtransport:h3_settings(), #{
      cert => CertDer, key => PrivateKey,
      handler => fun my_handler/5
  }),
  quic_h3:start_server(my_server, 443, Opts).

h3_settings(Opts)

-spec h3_settings(map()) -> map().

listener_info(Name)

-spec listener_info(listener_name()) -> {ok, map()} | {error, not_found}.

Get information about a listener.

The sockname field is the bound {Ip, Port}. For h3 it is resolved live from the QUIC socket (correct even when bound with port 0 or inet6). For h2 it is best-effort (requested address + bound port), since the h2 library does not expose the bound IP.

listener_loop(Name)

listener_sockname(Name)

-spec listener_sockname(listener_name()) ->
                           {ok, {inet:ip_address(), inet:port_number()}} | {error, term()}.

Get the bound {Ip, Port} of a listener.

For h3, resolved live from the QUIC listener socket. For h2 this is best-effort: the requested bind address (defaulting to the family wildcard) paired with the actual bound port, because the h2 library exposes only the port, not the bound IP.

listeners()

-spec listeners() -> [listener_name()].

List all active listeners.

open_stream(Session, Type)

-spec open_stream(session(), bidi | uni) -> {ok, stream()} | {error, term()}.

Open a new stream on the session.

reset_stream(Session, Stream, ErrorCode)

-spec reset_stream(session(), stream(), non_neg_integer()) -> ok | {error, term()}.

Abruptly terminate a stream with an error code.

send(Session, Stream, Data)

-spec send(session(), stream(), iodata()) -> ok | {error, term()}.

Send data on a stream.

send(Session, Stream, Data, _)

-spec send(session(), stream(), iodata(), fin | nofin) -> ok | {error, term()}.

Send data on a stream with optional FIN flag.

send_datagram(Session, Data)

-spec send_datagram(session(), iodata()) -> ok | {error, term()}.

Send an unreliable datagram.

session_info(Session)

-spec session_info(session()) -> {ok, map()} | {error, term()}.

Get session information.

start_listener(Name, Opts)

-spec start_listener(listener_name(), listener_opts()) -> {ok, pid()} | {error, term()}.

Start a WebTransport listener.

Options: - transport - Required. Either h2 (HTTP/2) or h3 (HTTP/3) - port - Required. Port to listen on - certfile - Required. Path to TLS certificate - keyfile - Required. Path to TLS private key - handler - Required. Module implementing webtransport_handler behaviour - handler_opts - Optional. Initial options passed to handler:init/2 - max_data - Optional. Initial max session data (default 1MB) - max_streams_bidi - Optional. Initial max bidi streams (default 100) - max_streams_uni - Optional. Initial max uni streams (default 100)

stop_listener(Name)

-spec stop_listener(listener_name()) -> ok | {error, term()}.

Stop a WebTransport listener.

stop_sending(Session, Stream, ErrorCode)

-spec stop_sending(session(), stream(), non_neg_integer()) -> ok | {error, term()}.

Request that the peer stop sending on a stream.