Current section
Files
Jump to
Current section
Files
src/webtransport_handler.erl
%% Copyright (c) 2026, Benoit Chesneau.
%% Licensed under the Apache License, Version 2.0.
%%
%% @doc WebTransport handler behaviour.
%%
%% Applications implement this behaviour to handle WebTransport sessions.
%% The callbacks are invoked by the session process when events occur.
%%
%% == Example Handler ==
%% Prefer `init/3' — it receives the `handler_opts' map from the connection
%% / listener options, which is the only way to plumb things like an owner
%% pid, a request-id, or application configuration into the handler. The
%% 2-arity `init/2' is kept only as a back-compat shim and is called when
%% the handler does not export `init/3'.
%% ```
%% -module(my_wt_handler).
%% -behaviour(webtransport_handler).
%%
%% -export([init/3, handle_stream/4, handle_datagram/2,
%% handle_stream_closed/3, terminate/2]).
%%
%% init(Session, _Req, Opts) ->
%% Owner = maps:get(owner, Opts, undefined),
%% {ok, #{session => Session, owner => Owner}}.
%%
%% handle_stream(Stream, Type, Data, State) ->
%% {ok, State, [{send, Stream, <<"echo: ", Data/binary>>}]}.
%%
%% handle_datagram(Data, State) ->
%% {ok, State}.
%%
%% handle_stream_closed(_Stream, _Reason, State) ->
%% {ok, State}.
%%
%% terminate(_Reason, _State) ->
%% ok.
%% '''
-module(webtransport_handler).
%% Callback declarations
-callback init(Session, Req) -> {ok, State} | {ok, State, Actions} | {error, Reason} when
Session :: webtransport:session(),
Req :: webtransport:request(),
State :: term(),
Actions :: [action()],
Reason :: term().
-callback init(Session, Req, Opts) -> {ok, State} | {ok, State, Actions} | {error, Reason} when
Session :: webtransport:session(),
Req :: webtransport:request(),
Opts :: map(),
State :: term(),
Actions :: [action()],
Reason :: term().
-callback handle_stream(Stream, Type, Data, State) -> Result when
Stream :: webtransport:stream(),
Type :: bidi | uni,
Data :: binary(),
State :: term(),
Result :: {ok, NewState} | {ok, NewState, Actions} | {stop, Reason, NewState},
NewState :: term(),
Actions :: [action()],
Reason :: term().
-callback handle_stream_fin(Stream, Type, Data, State) -> Result when
Stream :: webtransport:stream(),
Type :: bidi | uni,
Data :: binary(),
State :: term(),
Result :: {ok, NewState} | {ok, NewState, Actions} | {stop, Reason, NewState},
NewState :: term(),
Actions :: [action()],
Reason :: term().
-callback handle_datagram(Data, State) -> Result when
Data :: binary(),
State :: term(),
Result :: {ok, NewState} | {ok, NewState, Actions} | {stop, Reason, NewState},
NewState :: term(),
Actions :: [action()],
Reason :: term().
-callback handle_stream_closed(Stream, Reason, State) -> Result when
Stream :: webtransport:stream(),
Reason :: normal | {reset, non_neg_integer()} | {error, term()},
State :: term(),
Result :: {ok, NewState} | {stop, Reason, NewState},
NewState :: term().
-callback handle_info(Info, State) -> Result when
Info :: term(),
State :: term(),
Result :: {ok, NewState} | {ok, NewState, Actions} | {stop, Reason, NewState},
NewState :: term(),
Actions :: [action()],
Reason :: term().
%% Invoked when a handler-returned action fails at dispatch time
%% (e.g. `{send, UnknownStream, _}' returns `{error, unknown_stream}').
%% The default behaviour — when this callback is not exported — is to
%% log the failure via `logger:warning/2' and continue. Implement this
%% callback to observe failures, emit metrics, or stop the session.
-callback handle_action_failed(Action, Reason, State) -> Result when
Action :: action(),
Reason :: term(),
State :: term(),
Result :: {ok, NewState} | {stop, StopReason, NewState},
NewState :: term(),
StopReason :: term().
-callback terminate(Reason, State) -> term() when
Reason :: normal | {error, term()} | term(),
State :: term().
%% Optional pre-session origin / request filter. Invoked before
%% `init/3' is called on the accepted CONNECT request; returning
%% `{reject, Status, Reason}' causes the server to respond with the
%% given HTTP status (403, 404, or similar) instead of accepting the
%% session. Defaults to accept when not exported.
-callback origin_check(Headers, Opts) -> Result when
Headers :: [{binary(), binary()}],
Opts :: map(),
Result :: accept | {reject, Status :: 400..599, Reason :: binary()}.
%% Optional callbacks. `init/3' is preferred; `init/2' is a back-compat
%% shim that only gets called when the handler module does not export
%% `init/3'.
-optional_callbacks([init/2, init/3, handle_stream_fin/4, handle_info/2,
handle_action_failed/3, origin_check/2]).
%% Types
-type action() ::
{send, webtransport:stream(), iodata()} |
{send, webtransport:stream(), iodata(), fin} |
{send_datagram, iodata()} |
{open_stream, bidi | uni} |
{close_stream, webtransport:stream()} |
{reset_stream, webtransport:stream(), non_neg_integer()} |
{stop_sending, webtransport:stream(), non_neg_integer()} |
drain_session |
{close_session, non_neg_integer(), binary()}.
-export_type([action/0]).