API reference
WebSocket frames and the upgrade handshake in Zig, with no IO and no allocator.
Callers provide all buffers. The parser handles header parsing, payload length decoding, and masking. Fragmentation sequencing and UTF-8 validation are the caller's responsibility.
Quick start
Import the server or client namespace depending on your role:
const ws = @import("websocket").server;
var parser: ws.Parser = .init(.{});
while (true) {
const result = try parser.feed(buf);
buf = buf[result.consumed..];
switch (result.event) {
.frame_header => |hdr| { ... },
.payload => |data| { ... },
.frame_end => {},
.need_more => break,
}
}
module
client
src
Client-role API for parsing unmasked inbound frames and writing masked outbound frames.
Constants
Buffer type for a base64-encoded Sec-WebSocket-Accept value.
Four-byte masking key used by client frames.
pub const ParseError = frame.ParseError
src
Protocol errors reported while parsing inbound frames.
pub const max_control_payload_len = frame.max_control_payload_len
src
Maximum payload length for WebSocket control frames (ping, pong, close).
pub const MessageWriter = @import("message_writer.zig").ClientMessageWriter
src
Fragmented message writer that masks each emitted frame.
Frame parser for unmasked frames received by a client.
pub const FrameHandler = parse.ClientFrameHandler
src
Message-oriented parser for client connections.
Functions
pub fn parseClosePayload(payload: []const u8) ClosePayloadError!?ClosePayload
src
Parse and validate a close frame payload.
pub fn generateMaskKey() MaskKey
src
Generate a cryptographically random masking key.
pub fn computeAcceptKey(key: []const u8, out: *AcceptKey) []const u8
src
Compute the expected Sec-WebSocket-Accept header value for a client handshake.
pub fn writeFrame(
writer: *Io.Writer,
payload: []u8,
options: WriteFrameOptions,
) Io.Writer.Error!void
src
Write a complete masked frame (header + payload) to writer.
Clients MUST mask all frames per RFC 6455 Section 5.3.
payload is mutable because masking is applied in-place before writing.
The buffer contents will be XOR'd with the mask key after this call returns.
Callers who need to retain the original data should copy it first.
pub fn writeClose(writer: *Io.Writer, code: CloseCode) Io.Writer.Error!void
src
Write a masked close frame with a status code (no reason text).
Write a masked ping frame with an optional payload.
Write a masked pong frame with the given payload (typically echoed from a ping).
Types
enum
CloseCode
src
pub const CloseCode = close.CloseCode
Close status codes defined by RFC 6455 Section 7.4.
Fields
normal normal = 1000
going_away going_away = 1001
protocol_error protocol_error = 1002
unsupported_data unsupported_data = 1003
no_status no_status = 1005
abnormal abnormal = 1006
invalid_payload invalid_payload = 1007
policy_violation policy_violation = 1008
too_big too_big = 1009
mandatory_extension mandatory_extension = 1010
internal_error internal_error = 1011
tls_handshake tls_handshake = 1015
_ _
Functions
RFC 6455 Section 7.4: validate whether a close code may appear on the wire. Codes 1005, 1006, and 1015 are reserved for local use and MUST NOT be sent.
Encode the status code as two big-endian bytes for a close frame payload.
struct
ClosePayload
src
pub const ClosePayload = close.ClosePayload
Parsed close frame payload containing the status code and optional reason bytes.
Fields
union
Extension
src
pub const Extension = @import("extension.zig").Extension
Supported negotiated WebSocket extensions.
Fields
permessage_deflate: DeflateConfig
Constants
pub const max_header_len = 256
src
pub const HeaderBuffer = frame.BoundedBuffer(max_header_len)
src
Functions
pub fn claimedRsv(self: Extension) RsvBits
src
pub fn allowedRsv(ext: ?Extension) RsvBits
src
pub fn writeHeader(self: Extension, buf: *HeaderBuffer) void
src
Types
struct
DeflateConfig
src
Fields
server_max_window_bits: WindowBits
client_max_window_bits: WindowBits
Constants
value
.{
.server_no_context_takeover = false,
.client_no_context_takeover = false,
.server_max_window_bits = .@"15",
.client_max_window_bits = .@"15",
}
enum
Opcode
src
pub const Opcode = frame.Opcode
WebSocket frame opcode.
Fields
continuation continuation = 0x0
text text = 0x1
binary binary = 0x2
close close = 0x8
ping ping = 0x9
pong pong = 0xA
_ _
Functions
Returns true for opcodes 0x8–0xF (control frames: close, ping, pong, and reserved).
pub fn isReserved(self: Opcode) bool
src
Returns true for opcodes not defined by RFC 6455 (i.e. not continuation, text, binary, close, ping, or pong).
struct
FrameHeader
src
pub const FrameHeader = frame.FrameHeader
Decoded frame header and its serialized buffer helper.
Fields
fin: bool = true
True if this is the final fragment in a message.
rsv: RsvBits = .empty
Reserved bits for extensions.
opcode: Opcode
The frame opcode.
payload_len: u64
Length of the payload data in bytes.
mask_key: ?MaskKey = null
The masking key, or null for unmasked frames.
Functions
pub fn encodedLen(self: FrameHeader) usize
src
Returns the total wire size of this header (2..14 bytes).
Types
struct
Buffer
src
A serialized frame header ready to write to the wire.
Fields
buf: HeaderBuffer
Functions
Serialize a FrameHeader into its wire representation.
pub fn constSlice(self: *const Buffer) []const u8
src
Returns the serialized header bytes.
Writes the serialized header to writer.
struct
Mask
src
pub const Mask = frame.Mask
Stateful XOR mask for masking and unmasking payload bytes.
Fields
Constants
A no-op mask (all-zero key). XOR with zero leaves data unchanged.
Functions
Create a mask from key with the offset starting at zero.
Apply the mask to payload in-place, advancing the internal offset.
If the key is all zeros (unmasked), the XOR is a no-op.
struct
RsvBits
src
pub const RsvBits = frame.RsvBits
RSV bitset from the frame header.
Fields
Constants
All bits unset (the default for frames without extensions).
pub const permessage_deflate: RsvBits = .{ .rsv1 = true }
src
RSV1 set, as required by permessage-deflate (RFC 7692 §6.1).
Functions
Returns true if any RSV bit is set.
pub fn hasDisallowed(self: RsvBits, allowed: RsvBits) bool
src
Returns true if any bit is set that is not in allowed.
union
Event
src
pub const Event = frame.Event
Streaming parser event.
Fields
frame_header: FrameHeader
A complete frame header has been parsed.
payload: []u8
A chunk of payload data (a slice into the caller's input buffer, already unmasked).
frame_end frame_end
The current frame is complete. The parser is ready for the next frame.
need_more need_more
More input is needed before the next event can be produced.
struct
WriteFrameOptions
src
pub const WriteFrameOptions = frame.WriteFrameOptions
Options for frame-writing helpers.
Fields
opcode: Opcode
Frame opcode. Only non-reserved opcodes are valid.
compressed: bool = false
Set when the payload has been compressed with permessage-deflate. Controls the RSV1 bit on the first frame.
struct
MessageValidator
src
pub const MessageValidator = parse.MessageValidator
Fragmentation validator shared by both roles.
Fields
state: State
Constants
Initial state, ready for the first data frame.
pub const ValidationError = …
src
value
error{
/// Continuation frame received with no message in progress.
UnexpectedContinuation,
/// Text/binary frame received while a fragmented message is in progress.
ExpectedContinuation,
}Errors returned by check for fragmentation protocol violations.
Functions
Validate a frame header against fragmentation rules. Control frames are always allowed (they can be interleaved mid-fragment).
module
server
src
Server-role API for parsing masked inbound frames, writing unmasked outbound frames, and handling upgrades.
Constants
Four-byte masking key used by client frames.
pub const ParseError = frame.ParseError
src
Protocol errors reported while parsing inbound frames.
Buffer type for a base64-encoded Sec-WebSocket-Accept value.
pub const max_control_payload_len = frame.max_control_payload_len
src
Maximum payload length for WebSocket control frames (ping, pong, close).
pub const MessageWriter = @import("message_writer.zig").ServerMessageWriter
src
Fragmented message writer that leaves each emitted frame unmasked.
Frame parser for masked frames received by a server.
pub const FrameHandler = parse.ServerFrameHandler
src
Message-oriented parser for server connections.
Functions
pub fn parseClosePayload(payload: []const u8) ClosePayloadError!?ClosePayload
src
Parse and validate a close frame payload.
pub fn computeAcceptKey(key: []const u8, out: *AcceptKey) []const u8
src
Compute the Sec-WebSocket-Accept header value for an upgrade response.
pub fn validateUpgradeRequest(request: UpgradeRequest) UpgradeError!void
src
Validate the WebSocket-specific headers from an upgrade request.
pub fn writeFrame(
writer: *Io.Writer,
payload: []const u8,
options: WriteFrameOptions,
) Io.Writer.Error!void
src
Write a complete frame (header + payload) to writer. The caller is
responsible for flushing when ready — this allows batching multiple
frames before a single flush.
pub fn writeClose(writer: *Io.Writer, code: CloseCode) Io.Writer.Error!void
src
Write a close frame with a status code (no reason text).
Write a ping frame with an optional payload.
Write a pong frame with the given payload (typically echoed from a ping).
Types
enum
CloseCode
src
pub const CloseCode = close.CloseCode
Close status codes defined by RFC 6455 Section 7.4.
Fields
normal normal = 1000
going_away going_away = 1001
protocol_error protocol_error = 1002
unsupported_data unsupported_data = 1003
no_status no_status = 1005
abnormal abnormal = 1006
invalid_payload invalid_payload = 1007
policy_violation policy_violation = 1008
too_big too_big = 1009
mandatory_extension mandatory_extension = 1010
internal_error internal_error = 1011
tls_handshake tls_handshake = 1015
_ _
Functions
RFC 6455 Section 7.4: validate whether a close code may appear on the wire. Codes 1005, 1006, and 1015 are reserved for local use and MUST NOT be sent.
Encode the status code as two big-endian bytes for a close frame payload.
struct
ClosePayload
src
pub const ClosePayload = close.ClosePayload
Parsed close frame payload containing the status code and optional reason bytes.
Fields
union
Extension
src
pub const Extension = @import("extension.zig").Extension
Supported negotiated WebSocket extensions.
Fields
permessage_deflate: DeflateConfig
Constants
pub const max_header_len = 256
src
pub const HeaderBuffer = frame.BoundedBuffer(max_header_len)
src
Functions
pub fn claimedRsv(self: Extension) RsvBits
src
pub fn allowedRsv(ext: ?Extension) RsvBits
src
pub fn writeHeader(self: Extension, buf: *HeaderBuffer) void
src
Types
struct
DeflateConfig
src
Fields
server_max_window_bits: WindowBits
client_max_window_bits: WindowBits
Constants
value
.{
.server_no_context_takeover = false,
.client_no_context_takeover = false,
.server_max_window_bits = .@"15",
.client_max_window_bits = .@"15",
}
enum
Opcode
src
pub const Opcode = frame.Opcode
WebSocket frame opcode.
Fields
continuation continuation = 0x0
text text = 0x1
binary binary = 0x2
close close = 0x8
ping ping = 0x9
pong pong = 0xA
_ _
Functions
Returns true for opcodes 0x8–0xF (control frames: close, ping, pong, and reserved).
pub fn isReserved(self: Opcode) bool
src
Returns true for opcodes not defined by RFC 6455 (i.e. not continuation, text, binary, close, ping, or pong).
struct
FrameHeader
src
pub const FrameHeader = frame.FrameHeader
Decoded frame header and its serialized buffer helper.
Fields
fin: bool = true
True if this is the final fragment in a message.
rsv: RsvBits = .empty
Reserved bits for extensions.
opcode: Opcode
The frame opcode.
payload_len: u64
Length of the payload data in bytes.
mask_key: ?MaskKey = null
The masking key, or null for unmasked frames.
Functions
pub fn encodedLen(self: FrameHeader) usize
src
Returns the total wire size of this header (2..14 bytes).
Types
struct
Buffer
src
A serialized frame header ready to write to the wire.
Fields
buf: HeaderBuffer
Functions
Serialize a FrameHeader into its wire representation.
pub fn constSlice(self: *const Buffer) []const u8
src
Returns the serialized header bytes.
Writes the serialized header to writer.
struct
Mask
src
pub const Mask = frame.Mask
Stateful XOR mask for masking and unmasking payload bytes.
Fields
Constants
A no-op mask (all-zero key). XOR with zero leaves data unchanged.
Functions
Create a mask from key with the offset starting at zero.
Apply the mask to payload in-place, advancing the internal offset.
If the key is all zeros (unmasked), the XOR is a no-op.
struct
RsvBits
src
pub const RsvBits = frame.RsvBits
RSV bitset from the frame header.
Fields
Constants
All bits unset (the default for frames without extensions).
pub const permessage_deflate: RsvBits = .{ .rsv1 = true }
src
RSV1 set, as required by permessage-deflate (RFC 7692 §6.1).
Functions
Returns true if any RSV bit is set.
pub fn hasDisallowed(self: RsvBits, allowed: RsvBits) bool
src
Returns true if any bit is set that is not in allowed.
union
Event
src
pub const Event = frame.Event
Streaming parser event.
Fields
frame_header: FrameHeader
A complete frame header has been parsed.
payload: []u8
A chunk of payload data (a slice into the caller's input buffer, already unmasked).
frame_end frame_end
The current frame is complete. The parser is ready for the next frame.
need_more need_more
More input is needed before the next event can be produced.
struct
WriteFrameOptions
src
pub const WriteFrameOptions = frame.WriteFrameOptions
Options for frame-writing helpers.
Fields
opcode: Opcode
Frame opcode. Only non-reserved opcodes are valid.
compressed: bool = false
Set when the payload has been compressed with permessage-deflate. Controls the RSV1 bit on the first frame.
struct
UpgradeRequest
src
pub const UpgradeRequest = handshake.UpgradeRequest
WebSocket-specific fields extracted from an HTTP upgrade request.
Fields
struct
UpgradeResponse
src
pub const UpgradeResponse = handshake.UpgradeResponse
Prebuilt HTTP 101 response for a successful WebSocket upgrade.
Fields
buf: Buffer
Constants
value
prefix.len + 28 + 2 + // accept + \r\n
ext_header_prefix.len + Extension.max_header_len + 2 + // extension header + \r\n
2Maximum byte length of the complete HTTP response.
Functions
Build the response from the client's Sec-WebSocket-Key header value
and an optional negotiated extension.
pub fn constSlice(self: *const UpgradeResponse) []const u8
src
Returns the complete HTTP response bytes.
Writes the complete HTTP response to writer.
Types
struct
MessageValidator
src
pub const MessageValidator = parse.MessageValidator
Fragmentation validator shared by both roles.
Fields
state: State
Constants
Initial state, ready for the first data frame.
pub const ValidationError = …
src
value
error{
/// Continuation frame received with no message in progress.
UnexpectedContinuation,
/// Text/binary frame received while a fragmented message is in progress.
ExpectedContinuation,
}Errors returned by check for fragmentation protocol violations.
Functions
Validate a frame header against fragmentation rules. Control frames are always allowed (they can be interleaved mid-fragment).