Skip to content
baskingspotPublic

About

WebSocket frames and the upgrade handshake in Zig, with no IO and no allocator.

Topics

Resources

Stars

8 stars

Watchers

0 watching

Forks

Repository files navigation

websocket

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.

What is in it

  • Frames: Parser.feed returns .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.feed reassembles fragments and returns .data, .data_end, .ping, .pong, or .close.
  • Writing: writeFrame writes one frame, MessageWriter streams one message across several, and FrameHeader.Buffer serializes the header alone for a scatter-gather write.
  • Close: parseClosePayload returns the CloseCode and the reason bytes, and rejects the codes RFC 6455 forbids on the wire.
  • Extensions: Extension negotiates permessage-deflate, claims the RSV1 bit, and marks a written frame .compressed.
  • The upgrade: computeAcceptKey, validateUpgradeRequest, and UpgradeResponse cover 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 text message reaches your handler as the bytes arrived, and Autobahn's 6.* cases pass because the echo server validates before it echoes.
  • HTTP parsing. UpgradeRequest carries key and version and nothing else; the rest of the request stays with your server.
  • Deflate. permessage-deflate is negotiation and the RSV1 bit, and inflating a .compressed payload is the caller's library.
  • Subprotocol negotiation. Sec-WebSocket-Protocol is yours to read and write.
  • Any socket, thread, timer, or allocator.

Install

zig fetch --save https://baskingspot.dev/websocket/v0.1.0.tar.gz

Add 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.

Documentation

  • 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.

Work on it

nix develop
just ci

nix 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.

License

MIT. See LICENSE. The logo files in docs/static/ are baskingspot marks and are not covered by it. See docs/static/LICENSE.

How it's made

Built with LLM assistance. How, in detail.

baskingspot

About

WebSocket frames and the upgrade handshake in Zig, with no IO and no allocator.

Topics

Resources

Stars

8 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages