ws_frame (ws v0.1.1)

View Source

RFC 6455 frame codec.

Responsibilities: - Encode outbound frames (masked for clients, unmasked for servers). - Decode a stream of inbound bytes into a list of complete messages, transparently reassembling continuation fragments. - Enforce protocol invariants listed in RFC 6455: RSV bits zero when no extension is negotiated, control frames ≤ 125 bytes and not fragmented, minimal length encoding, mask bit matching the sender role, UTF-8 validity for text payloads and close reasons, valid close codes (§7.4).

The parser returns whole message frames only; partial fragments are accumulated internally. If a fragmented message exceeds max_message or a single frame exceeds max_frame, the parser errors with message_too_big (close code 1009).

The UTF-8 DFA and masking loop are adapted from hackney_ws_proto (itself derived from cowlib/cow_ws).

Summary

Types

error_reason/0

-type error_reason() :: protocol_error | invalid_utf8 | message_too_big | bad_close_code.

frame/0

-type frame() ::
          {text, iodata()} |
          {binary, iodata()} |
          {ping, iodata()} |
          {pong, iodata()} |
          {close, ws_close:code(), iodata()} |
          close.

message/0

-type message() ::
          {text, binary()} |
          {binary, binary()} |
          {ping, binary()} |
          {pong, binary()} |
          {close, ws_close:code(), binary()} |
          close.

parser/0

-type parser() ::
          #ws_parser{role :: server | client,
                     buffer :: binary(),
                     frag_op :: text | binary | undefined,
                     frag_acc :: [binary()],
                     frag_size :: non_neg_integer(),
                     utf8_state :: non_neg_integer(),
                     max_frame :: pos_integer(),
                     max_message :: pos_integer()}.

role/0

-type role() :: client | server.

Functions

encode(_, Role)

-spec encode(frame(), role()) -> iodata().

init_parser()

-spec init_parser() -> parser().

init_parser(Opts)

-spec init_parser(map()) -> parser().

mask(Data, MaskKey)

-spec mask(binary(), 0..4294967295) -> binary().

Mask or unmask Data with the 32-bit MaskKey.

parse(P, Data)

-spec parse(parser(), binary()) -> {ok, [message()], parser()} | {error, error_reason(), parser()}.