Skip to content

Fix two crashes in Socket.Web on frames the RFC allows - #6

Merged
dominicletz merged 2 commits into
witchtails:masterfrom
neutrino38:fix/websocket-frame-crashes
Nov 2, 2026
Merged

dominicletz merged 2 commits into
witchtails:masterfrom
neutrino38:fix/websocket-frame-crashes

Conversation

@neutrino38

Copy link
Copy Markdown

Two small fixes in lib/socket/web.ex, each with a test that fails without it.
Both are crashes on input a well-behaved peer, or a caller reading the docs, can
produce.

  • forge/2 now treats false as "do not mask". send/3 and close/3
    document a mask: option, and mask: false is how a caller says the frame
    goes out unmasked — which RFC 6455 §5.3 requires of a server. forge/2 only
    had a clause for nil and one for an integer key, so false fell into the
    key clause and reached Bitwise.bxor/2:
    Socket.Web.send!(socket, {:text, "x"}, mask: false) raised
    ArithmeticError.

  • close_code/1 now accepts any integer code. RFC 6455 §7.4.2 leaves
    3000-4999 to applications and libraries. The function is used on both sides of
    the wire: Socket.Web.close(socket, {4000, "bye"}) raised
    FunctionClauseError, and so did reading a peer's clean close carrying such a
    code — which kills the reader on a healthy connection.

Added test/web_test.exs, the first test file for Socket.Web: a harness that
binds the listener before starting the server task, and five tests covering a
binary round trip, an unmasked send, a fragmented message, an application close
code and a registered one.

Verified on Elixir 1.18.3 / OTP 26: mix format --check-formatted passes,
mix test is 16 tests / 0 failures. mix compile --warnings-as-errors still
fails on this branch, with exactly the warnings master already has — the same
nine, at the same sites, shifted by the four lines added here. Nothing new.

send/3 and close/3 both take a `mask:` option, and `mask: false` is how a
caller says "send this frame unmasked" — a server must not mask, per RFC
6455 §5.3. forge/2 only knew `nil` and an integer key, so `false` fell
into the key clause and reached Bitwise.bxor/2: a legal call raised
ArithmeticError.

The new test file also carries the harness. The listener is bound in the
test process before the server task starts, so a client can never dial a
port nobody is listening on yet.
RFC 6455 §7.4.2 leaves the range 3000-4999 to applications and
libraries. close_code/1 only knew the registered set, and it is used on
both sides of the wire: closing with 4000 raised FunctionClauseError,
and so did reading a peer's clean close carrying such a code — a crash
of the reader on a well-behaved connection.
@dominicletz
dominicletz merged commit 3a812bc into witchtails:master Nov 2, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants