WebSocket frames and the upgrade handshake in Zig, with no IO and no allocator.
Zig's std.http.Server can answer a request and hand the connection to another
protocol, and nothing in std reads a WebSocket frame. A WebSocket library
usually arrives with a socket, a thread, and an allocator attached. This is the
frame layer only: you read the bytes, hand them over, and get frames back.
Parser.feed takes the bytes you already read and returns one event with the
count it consumed. FrameHandler sits above it and reassembles fragments into
messages. The parser holds a 14-byte header and the handler 125 bytes for a
control payload. Nothing else.
- Frames:
Parser.feedreturns.frame_header,.payload,.frame_end, or.need_more, unmasks server-side payloads in the buffer you gave it, and keeps 14 bytes of header state. - Messages:
FrameHandler.feedreassembles fragments and returns.data,.data_end,.ping,.pong, or.close. - Writing:
writeFramewrites one frame,MessageWriterstreams one message across several, andFrameHeader.Bufferserializes the header alone for a scatter-gather write. - Close:
parseClosePayloadreturns theCloseCodeand the reason bytes, and rejects the codes RFC 6455 forbids on the wire. - Extensions:
Extensionnegotiatespermessage-deflate, claims the RSV1 bit, and marks a written frame.compressed. - The upgrade:
computeAcceptKey,validateUpgradeRequest, andUpgradeResponsecover the WebSocket half of the 101, and the HTTP half is the server's. - Conformance: the Autobahn TestSuite runs against the echo server and the echo client, and the fast profile is a CI gate.
Not implemented:
- UTF-8 validation. A
textmessage reaches your handler as the bytes arrived, and Autobahn's 6.* cases pass because the echo server validates before it echoes. - HTTP parsing.
UpgradeRequestcarrieskeyandversionand nothing else; the rest of the request stays with your server. - Deflate.
permessage-deflateis negotiation and the RSV1 bit, and inflating a.compressedpayload is the caller's library. - Subprotocol negotiation.
Sec-WebSocket-Protocolis yours to read and write. - Any socket, thread, timer, or allocator.
zig fetch --save https://baskingspot.dev/websocket/v0.1.0.tar.gzAdd the module in build.zig:
const websocket = b.dependency("websocket", .{ .target = target, .optimize = optimize });
exe.root_module.addImport("websocket", websocket.module("websocket"));The package exports server and client namespaces, so a program imports the
one for its side of the connection. websocket builds with Zig 0.16.
- The guide says which piece to use at each step of a connection, with the symbols a caller needs.
- The API reference documents every symbol.
examples/holds five complete programs: a blocking echo server, its client, two HTTP upgrades, and a libxev server.
nix develop
just cinix develop provides the toolchain. just ci runs the tests, the lint, the
examples, the fast Autobahn profile, and the site build. just conformance-full
runs every Autobahn case, takes over ten minutes, and needs about 2 GB of
memory.
MIT. See LICENSE. The logo files in docs/static/ are baskingspot
marks and are not covered by it. See
docs/static/LICENSE.
Built with LLM assistance. How, in detail.