nhttp_ws (nhttp_lib v1.0.0)
View SourceWebSocket message-level codec, handshake, and session API (RFC 6455).
Sits on top of nhttp_ws_frame (per-frame codec) and adds:
- The handshake half: server validation and client/server response
builders,
Sec-WebSocket-Acceptderivation. - A framing-aware buffer (
ws_decoder/0) that reassembles continuation frames into messages and surfaces interleaved control frames inline. - A process-coupled session API used by the H1 / H2 / H3 connection processes after upgrade.
The pure per-frame primitives (encode/1,2, decode/1, decode_unmasked/1,
encode_masked/1) are exported here as thin shims over nhttp_ws_frame
for backwards compatibility.
Summary
Functions
Generate the Sec-WebSocket-Accept header value.
Send a message to every WebSocket session multiplexed on the connection
that owns Session (or directly to the connection pid). Equivalent to
Pid ! Msg. Handlers receive it via handle_ws_info/3 with broadcast
semantics.
Initiate the §5.5.1 close handshake with status 1000 and no reason.
Initiate the §5.5.1 close handshake with explicit code and reason.
Initiate the §5.5.1 close handshake. Pending sends flush before the
reciprocal CLOSE is written unless force => true is set in Opts.
Decode a masked WebSocket frame (client-to-server).
Returns {ok, Message, Rest} on success, {more, MinBytes} if more data needed.
Decode an unmasked WebSocket frame (server-to-client). RFC 6455 Section 5.1: a server MUST NOT mask frames sent to clients.
Decode a frame with fragmentation support. Continuation frames are accumulated until FIN=1, then the complete message is delivered. Control frames (ping, pong, close) may appear between fragments and are delivered immediately.
Create a new stateful decoder for the given role.
Create a new stateful decoder honouring max_message_size from the runtime
opts. The cap applies to the cumulative payload of fragmented messages and
to single non-control frames; exceeding it returns {error, message_too_large}.
Encode a WebSocket message as an unmasked frame (server-to-client).
Encode a WebSocket message with options. The only option is
mask => boolean(); defaults to false.
Encode a binary message (server, unmasked).
Encode a close frame with no status code (server, unmasked).
Encode a close frame with status code and reason (server, unmasked).
Encode a masked WebSocket message (client, RFC 6455 Section 5.1).
Encode a masked binary message (client).
Encode a masked close frame with no status code (client).
Encode a masked close frame with status code and reason (client).
Encode a masked ping frame with empty payload (client).
Encode a masked ping frame with payload (client).
Encode a masked pong frame (client).
Encode a masked text message (client).
Encode a ping frame with empty payload (server, unmasked).
Encode a ping frame with payload (server, unmasked).
Encode a pong frame, must echo ping payload (server, unmasked).
Encode a text message (server, unmasked).
Generate a random Sec-WebSocket-Key (RFC 6455 Section 4.1).
Generate the complete handshake response.
Deliver an arbitrary Erlang term to a specific session's handle_ws_info/3
callback. Use this instead of a bare Pid ! Msg when the connection
multiplexes more than one session and you want to address one in particular.
Liveness check for the connection process owning the session.
Build a fresh session handle owned by the calling process. Used by the
nhttp connection processes (H1/H2/H3) at upgrade time. The constructor is
the only sanctioned way to mint a session. The record itself is opaque
to callers outside nhttp_lib.
Same as new_session/3 but lets the caller supply an existing reference
(useful when the conn process needs to keep the same ref across two
different per-stream records, e.g. during in-place migrations).
Return the connection process pid for the session.
Send an empty WebSocket PING (§5.5.2) on the session.
Send a WebSocket PING with the given payload (≤ 125 bytes per §5.5).
Synchronously send a WebSocket message on the session. Returns once the
frame has cleared the per-stream flow control (or the TCP send buffer for
HTTP/1.1) or after Opts#timeout ms.
Returns {error, gone} if the session has been closed, {error, timeout}
if the deadline elapses before the write completes, or any error reported
by the transport.
Asynchronously enqueue a WebSocket message. Returns {error, would_block}
immediately if the session's outbox has crossed its high-water mark, leaving
the caller free to drop, retry, or close. Never blocks waiting for the
transport, only for the connection process to ack the enqueue (or reject
it).
Send a binary message.
Send a UTF-8 text message (caller is responsible for valid UTF-8).
Return the unique reference stamped on the session at creation. The conn process compares it against the ref it remembers per active stream and rejects sends whose ref no longer matches (stale handle after the stream ended but before the conn pid died).
Return the transport-level stream id, or undefined for HTTP/1.1.
Return the transport carrying the session.
Validate the server's Sec-WebSocket-Accept value against the client key.
Validate WebSocket upgrade request headers.
Returns {ok, Key} if valid, {error, Reason} otherwise.
Types
-type close_code() :: nhttp_ws_frame:close_code().
-type decode_result() :: nhttp_ws_frame:decode_result().
-opaque session()
-type stateful_decode_result() :: {ok, ws_message(), Rest :: binary(), ws_decoder()} | {more, MinBytes :: pos_integer(), ws_decoder()} | {error, term()}.
-opaque ws_decoder()
-type ws_message() :: nhttp_ws_frame:ws_message().
-type ws_opcode() :: nhttp_ws_frame:ws_opcode().
-type ws_runtime_opts() :: #{deliver_ping => boolean(), deliver_pong => boolean(), max_message_size => pos_integer() | infinity, outbound_high_water => pos_integer(), outbound_low_water => pos_integer(), idle_timeout => timeout()}.
-type ws_send_opts() :: #{timeout => timeout(), priority => low | normal}.
Functions
Generate the Sec-WebSocket-Accept header value.
Send a message to every WebSocket session multiplexed on the connection
that owns Session (or directly to the connection pid). Equivalent to
Pid ! Msg. Handlers receive it via handle_ws_info/3 with broadcast
semantics.
-spec close(session()) -> ok.
Initiate the §5.5.1 close handshake with status 1000 and no reason.
-spec close(session(), close_code(), binary()) -> ok.
Initiate the §5.5.1 close handshake with explicit code and reason.
-spec close(session(), close_code(), binary(), ws_close_opts()) -> ok.
Initiate the §5.5.1 close handshake. Pending sends flush before the
reciprocal CLOSE is written unless force => true is set in Opts.
-spec decode(binary()) -> decode_result().
Decode a masked WebSocket frame (client-to-server).
Returns {ok, Message, Rest} on success, {more, MinBytes} if more data needed.
-spec decode_unmasked(binary()) -> decode_result().
Decode an unmasked WebSocket frame (server-to-client). RFC 6455 Section 5.1: a server MUST NOT mask frames sent to clients.
-spec decode_with_state(binary(), ws_decoder()) -> stateful_decode_result().
Decode a frame with fragmentation support. Continuation frames are accumulated until FIN=1, then the complete message is delivered. Control frames (ping, pong, close) may appear between fragments and are delivered immediately.
-spec decoder_new(client | server) -> ws_decoder().
Create a new stateful decoder for the given role.
-spec decoder_new(client | server, ws_runtime_opts()) -> ws_decoder().
Create a new stateful decoder honouring max_message_size from the runtime
opts. The cap applies to the cumulative payload of fragmented messages and
to single non-control frames; exceeding it returns {error, message_too_large}.
-spec encode(ws_message()) -> iodata().
Encode a WebSocket message as an unmasked frame (server-to-client).
-spec encode(ws_message(), nhttp_ws_frame:encode_opts()) -> iodata().
Encode a WebSocket message with options. The only option is
mask => boolean(); defaults to false.
Encode a binary message (server, unmasked).
-spec encode_close() -> iodata().
Encode a close frame with no status code (server, unmasked).
-spec encode_close(Code :: close_code(), Reason :: binary()) -> iodata().
Encode a close frame with status code and reason (server, unmasked).
-spec encode_masked(ws_message()) -> iodata().
Encode a masked WebSocket message (client, RFC 6455 Section 5.1).
Encode a masked binary message (client).
-spec encode_masked_close() -> iodata().
Encode a masked close frame with no status code (client).
-spec encode_masked_close(Code :: close_code(), Reason :: binary()) -> iodata().
Encode a masked close frame with status code and reason (client).
-spec encode_masked_ping() -> iodata().
Encode a masked ping frame with empty payload (client).
Encode a masked ping frame with payload (client).
Encode a masked pong frame (client).
Encode a masked text message (client).
-spec encode_ping() -> iodata().
Encode a ping frame with empty payload (server, unmasked).
Encode a ping frame with payload (server, unmasked).
Encode a pong frame, must echo ping payload (server, unmasked).
Encode a text message (server, unmasked).
-spec generate_key() -> binary().
Generate a random Sec-WebSocket-Key (RFC 6455 Section 4.1).
Generate the complete handshake response.
-spec handshake_response(Key :: binary(), SessionOpts :: ws_session_opts()) -> iodata().
Deliver an arbitrary Erlang term to a specific session's handle_ws_info/3
callback. Use this instead of a bare Pid ! Msg when the connection
multiplexes more than one session and you want to address one in particular.
Liveness check for the connection process owning the session.
-spec new_session(h1 | h2 | h3, pid(), undefined | nhttp_lib:stream_id()) -> session().
Build a fresh session handle owned by the calling process. Used by the
nhttp connection processes (H1/H2/H3) at upgrade time. The constructor is
the only sanctioned way to mint a session. The record itself is opaque
to callers outside nhttp_lib.
-spec new_session(h1 | h2 | h3, pid(), undefined | nhttp_lib:stream_id(), reference()) -> session().
Same as new_session/3 but lets the caller supply an existing reference
(useful when the conn process needs to keep the same ref across two
different per-stream records, e.g. during in-place migrations).
Return the connection process pid for the session.
Send an empty WebSocket PING (§5.5.2) on the session.
Send a WebSocket PING with the given payload (≤ 125 bytes per §5.5).
-spec send(session(), ws_message()) -> ok | {error, term()}.
Synchronously send a WebSocket message on the session. Returns once the
frame has cleared the per-stream flow control (or the TCP send buffer for
HTTP/1.1) or after Opts#timeout ms.
Returns {error, gone} if the session has been closed, {error, timeout}
if the deadline elapses before the write completes, or any error reported
by the transport.
-spec send(session(), ws_message(), ws_send_opts()) -> ok | {error, term()}.
-spec send_async(session(), ws_message()) -> ok | {error, would_block | gone | term()}.
Asynchronously enqueue a WebSocket message. Returns {error, would_block}
immediately if the session's outbox has crossed its high-water mark, leaving
the caller free to drop, retry, or close. Never blocks waiting for the
transport, only for the connection process to ack the enqueue (or reject
it).
Send a binary message.
Send a UTF-8 text message (caller is responsible for valid UTF-8).
Return the unique reference stamped on the session at creation. The conn process compares it against the ref it remembers per active stream and rejects sends whose ref no longer matches (stale handle after the stream ended but before the conn pid died).
-spec stream_id(session()) -> undefined | nhttp_lib:stream_id().
Return the transport-level stream id, or undefined for HTTP/1.1.
-spec transport(session()) -> h1 | h2 | h3.
Return the transport carrying the session.
-spec validate_accept(ClientKey :: binary(), ServerAccept :: binary()) -> ok | {error, invalid_accept}.
Validate the server's Sec-WebSocket-Accept value against the client key.
-spec validate_upgrade(nhttp_h1:req()) -> {ok, binary()} | {error, term()}.
Validate WebSocket upgrade request headers.
Returns {ok, Key} if valid, {error, Reason} otherwise.