Packages

WebSocket protocol library for Erlang (RFC 6455 / RFC 8441 / RFC 9220)

Current section

Files

Jump to
erlang_ws CHANGELOG.md
Raw

CHANGELOG.md

# Changelog
All notable changes to this project are documented here. Format loosely
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions
follow [Semantic Versioning](https://semver.org/).
## [0.3.0] - 2026-05-29
### Changed
- Ported to Erlang/OTP 29. Old-style `catch Expr` cleanup calls in the
test suites and examples are rewritten as `try ... catch _:_ -> ok end`
to satisfy OTP 29's `warn_deprecated_catch`. The library sources were
already free of old-style catch.
- CI now tests OTP 28 and 29 (dropped 26 and 27) and uses rebar3 3.27.
[0.3.0]: https://github.com/benoitc/erlang_ws/releases/tag/0.3.0
## [0.2.0] - 2026-05-21
### Security
- `ws_frame` UTF-8 validation no longer crashes on a non-continuation
byte in the middle of a multi-byte sequence (e.g. `0xC2 0x41`). Such
input is now reported as `invalid_utf8` so the session closes with
code 1007 instead of the process crashing with `badarg`.
- `ws_session` now enforces an `idle_timeout` (default 60000 ms) on open
connections and a `close_timeout` (default 5000 ms) while awaiting the
peer's close echo. A stalled peer can no longer hold a session and
socket open indefinitely. Both accept `infinity` to disable and are
configurable via `ws:accept/6`, `ws:connect/2`, and
`ws_h1_tcp_server:start_link/1`. Note: long-lived idle connections now
require app-level pings or `idle_timeout => infinity`.
### Fixes
- `ws_client:connect/2` returns `{error, {invalid_port, _}}` for a
non-numeric URL port instead of crashing, and accepts IPv6 literal
hosts such as `ws://[::1]:8080/`.
- `ws_frame:encode/2` caps an over-long close reason (> 123 bytes) on a
UTF-8 codepoint boundary instead of crashing.
[0.2.0]: https://github.com/benoitc/erlang_ws/releases/tag/0.2.0
## [0.1.1] — 2026-04-19
### Security
- `ws_h1_upgrade:validate_request/1,2` no longer crashes on a
malformed `Sec-WebSocket-Key` header; invalid base64 now surfaces
as `{error, bad_sec_websocket_key}`.
- `ws_deflate:inflate/3,4` caps inflated output (default 64 MiB,
configurable) and returns `{error, {inflate_too_big, _}}` past
the bound — defuses the classic permessage-deflate bomb.
- `ws_client:connect/2` caps pre-upgrade byte accumulation via a new
`max_handshake_size` option (default 64 KiB). Exceeding it
returns `{error, handshake_response_too_big}`.
- `ws_h1_tcp_server:start_link/1` gains the same
`max_handshake_size` option (default 64 KiB). Over-limit returns
`{error, handshake_too_big}` and the socket is closed.
### Tests
- New `ws_security_SUITE` with 11 targeted cases covering each of
the above plus state-machine invariants (send during closing,
handler init stop, ordered multi-frame send).
### Documentation
- `docs/embedding.md` — new "Hardening" section summarising the
embedder-side defences: handshake caps, timeouts, concurrent
connections, origin enforcement, deflate bombs, TLS defaults,
close-code handling.
- `docs/errors.md` — new "Size-limit errors" table.
### Housekeeping
- Apache-2.0 copyright header added to every `.erl` file.
[0.1.1]: https://github.com/benoitc/erlang_ws/releases/tag/0.1.1
## [0.1.0] — 2026-04-19
Initial release.
### Frame codec
- RFC 6455 encode / decode for all opcodes (text, binary, ping, pong,
close, continuation).
- Masking / unmasking (32-bit XOR), symmetric and streamable.
- Fragmentation reassembly across continuation frames, with an open
fragment state machine.
- UTF-8 validation for text payloads and close reasons via an
inlined Hoehrmann DFA, streaming-safe across fragment boundaries.
- Close-code validation per RFC 6455 §7.4 (`ws_close`). Reserved
codes 1004 / 1005 / 1006 / 1015 rejected on the wire; 3000–4999
accepted for registration / application use.
- Size guards: `max_frame` and `max_message` options on the parser,
enforced during single-frame decode and fragment accumulation.
### Handshake helpers
- `ws_h1_upgrade` — server-side validation of `Upgrade`,
`Connection`, `Sec-WebSocket-Key`, `Sec-WebSocket-Version`;
`Sec-WebSocket-Accept` generation; subprotocol negotiation;
client-side key generation, request build, 101 response validation.
- `ws_h2_upgrade` — RFC 8441 extended CONNECT pseudo-header
validation (`:method=CONNECT`, `:protocol=websocket`, `:scheme`,
`:authority`, `:path`); server response builder; client request
builder that refuses to issue a CONNECT when the peer has not
advertised `SETTINGS_ENABLE_CONNECT_PROTOCOL = 1`.
- `ws_h3_upgrade` — RFC 9220 mirror of the H2 helpers.
### Session
- `ws_session``gen_statem` driving the session. States
`ready_wait -> open -> closing`. Auto-responds to peer pings with
matching pongs; surfaces ping / pong to the handler for custom
behaviour.
- Orderly close handshake: on receiving a close frame, echoes a
close back (only once) before exiting normally. Peer-initiated
protocol violations trigger a close frame with the matching code
(1002 protocol error / 1007 invalid UTF-8 / 1009 message too big)
followed by socket shutdown.
- `ws_handler` behaviour: `init/2`, `handle_in/2`, `handle_info/2`,
`terminate/2`. All callbacks can `reply` with outbound frames.
### Transport layer
- `ws_transport` behaviour — `send/2`, `activate/1`, `close/1`,
`controlling_process/2`, `classify/2`, `recv/2` (optional, used by
the client during the HTTP/1.1 handshake), `peername/1` (optional).
- `ws_transport_gen_tcp` — reference `gen_tcp` transport used by
tests.
- `ws_transport_ssl` — OTP `ssl` transport used by `wss://` client
connections.
### Reference server
- `ws_h1_tcp_server` — a minimal `gen_tcp` acceptor + HTTP/1.1
upgrade driver built on top of the library helpers. Supports plain
TCP and TLS via the `tls` option. Doubles as a runnable example
and the server-side driver of `ws_examples_SUITE`.
### Client
- `ws_client:connect/2` for `ws://` / `wss://` URLs. Builds the
RFC 6455 upgrade request, validates the 101 response (including
`Sec-WebSocket-Accept` cross-check), starts a `ws_session` in
client mode with the user handler.
- Automatic subprotocol, extension, origin, and extra-header
handling on the request side.
### Extensions
- `ws_deflate` — RFC 7692 permessage-deflate.
- Server-side negotiation of client offers with configurable
takeover / window-bits policy; ignore-on-disagreement semantics.
- Client-side offer builder and server-response parser.
- Inflate / deflate primitives with takeover management.
### Examples
- `examples/echo_server.erl` — RFC 6455 echo server backed by
`ws_h1_tcp_server`.
- `examples/echo_client.erl` — synchronous send-and-wait client,
uses `ws:connect/2`.
- `examples/chat_server.erl` — broadcast chat server using `pg` for
fan-out between sessions.
### Tests
- 142 EUnit tests across codec, close codes, handshake helpers,
deflate.
- 4 PropEr properties: mask involution, round-trip in both
directions, chunked-delivery preserves messages.
- 25 Common Test cases total:
- 10 in `ws_session_SUITE` — text / binary / large-payload echo,
ping/pong, fragmentation, orderly-close, server-initiated close,
bad-UTF-8 rejection, oversize-frame rejection, handler info
fan-out.
- 3 in `ws_client_SUITE` — client↔server round-trip.
- 12 in `ws_examples_SUITE` — end-to-end coverage of the
`examples/` modules plus subprotocol negotiation, 20 concurrent
clients, TLS `wss://` round-trip, 512 KiB payload, fragmented
text delivered raw.
- Autobahn compliance suite (`WS_RUN_AUTOBAHN=1`) — 300 cases across
sections 1–9. All OK / NON-STRICT / INFORMATIONAL; zero failures.
### Documentation
- `README.md` — quickstart with server and client examples, module
map, embedder integration notes.
- `docs/guide.md` — tutorial (mental model, handler, server, client,
sending frames, closing, subprotocols, TLS, limits). Every code
snippet is mechanically verified by `ws_docs_snippets_SUITE`.
- `docs/embedding.md` — HTTP/1.1, RFC 8441 (HTTP/2), and RFC 9220
(HTTP/3) integration patterns plus instructions for writing a
custom `ws_transport`.
- `docs/errors.md` — every failure mode the library surfaces, with
close codes and remediation.
- `docs/features.md` — RFC coverage, hardening list, scope
boundaries, full module map.
- `LICENSE` — Apache-2.0.
[0.1.0]: https://github.com/benoitc/erlang_ws/releases/tag/0.1.0