livery_ws (livery v0.7.0)
View SourceWebSocket integration on top of the ws library.
A handler that wants to upgrade a request to WebSocket calls
upgrade/3 inside its body. The function performs the
protocol-specific handshake by dispatching to the adapter's
accept_ws/4 helper. The return value is a sentinel response
(status = 101, body = taken_over) that tells livery:emit/3
no further bytes need to be written: the stream/socket now belongs
to the ws session.
my_ws_route(Req) ->
livery_ws:upgrade(Req, my_chat_handler, #{}).my_chat_handler is a module implementing the ws_handler
behaviour (defined by erlang_ws).
WebSocket runs over H1 (plain Upgrade), H2 (RFC 8441 extended
CONNECT, via livery_ws_h2), and H3 (RFC 9220 extended CONNECT,
via livery_ws_h3).
Summary
Functions
Negotiate permessage-deflate for an upgrade when Opts carries
compress => true and the client offered it.
Split upgrade Opts into the two handshake option maps the adapters
need: {ValidateOpts, AcceptOpts}. ValidateOpts drives
ws_hN_upgrade:validate_request/2 (subprotocol negotiation) and
AcceptOpts drives ws:accept/6 (idle timeout). Both are #{} when the
respective key is absent, which makes the calls equivalent to the /1 and
/5 forms. Called by the H1/H2/H3 adapters.
Upgrade the current request to a WebSocket session.
Types
Functions
Negotiate permessage-deflate for an upgrade when Opts carries
compress => true and the client offered it.
Info is the validated-request info from ws_h1_upgrade /
ws_h2_upgrade / ws_h3_upgrade (its extensions key holds the
client's raw offers). Returns extra response headers (the
sec-websocket-extensions acceptance, or none) and the accept opts
with deflate merged in. Called by the H1/H2/H3 adapters.
-spec handshake_opts(handler_opts()) -> {map(), map()}.
Split upgrade Opts into the two handshake option maps the adapters
need: {ValidateOpts, AcceptOpts}. ValidateOpts drives
ws_hN_upgrade:validate_request/2 (subprotocol negotiation) and
AcceptOpts drives ws:accept/6 (idle timeout). Both are #{} when the
respective key is absent, which makes the calls equivalent to the /1 and
/5 forms. Called by the H1/H2/H3 adapters.
-spec upgrade(livery_req:req(), handler_module(), handler_opts()) -> livery_resp:resp().
Upgrade the current request to a WebSocket session.
HandlerMod must implement the ws_handler behaviour. Opts
is a map forwarded as HMod:init(Req, Opts)'s second argument by
the ws library. Some keys are also interpreted by the handshake
(and left in Opts, so the handler still sees them):
subprotocols => [binary()]drives subprotocol negotiation: the first of these the client also offers is echoed in the responseSec-WebSocket-Protocol, and a client offering none of them is rejected. Omit to skip negotiation.idle_timeout => timeout()overrides the session idle timeout (infinitynever idle-closes). Omit for thewsdefault.max_frame_size => pos_integer()andmax_message_size => pos_integer()bound a single frame and a reassembled fragmented message; a peer exceeding them is closed with1009. Omit for thewsdefaults (16 MiB / 64 MiB).compress => truenegotiates permessage-deflate (RFC 7692) when the client offers it; the session then runs compressed in both directions. Clients not offering it are served uncompressed.
When the session ends because the peer sent a close frame, the
handler's terminate/2 receives {remote, Code, Reason} (or
remote for a bare close without a status code).
The handler's Req carries peer => {IpAddress, Port}, the client
address from the socket (H1), the h2 connection (H2), or the QUIC
connection (H3).
Returns a #livery_resp{} value:
status = 101, body = taken_overon a successful handshake. The adapter owns nothing further on this stream after this point.status = 400with a textual body when the inbound headers do not satisfy RFC 6455.status = 501when the adapter does not support WebSocket upgrades (H1, H2, and H3 all do).