blackbull.server.ws_codec¶
blackbull.server.ws_codec
¶
WebSocket frame codec (RFC 6455).
Shared by the server-side sender/recipient and the client. Protocol-specific callers (WebSocketSender, WebSocketRecipient, WebSocketSession) import the module-level functions directly.
FramePayloadTooLarge
¶
Bases: Exception
Raised by read_payload when max_length is set and the
declared payload length exceeds it. The caller is responsible for
translating this into a WebSocket-level CLOSE (RFC 6455 §7.4.1
code 1009 MESSAGE_TOO_BIG) — the codec stays protocol-agnostic.
InvalidFrameLength
¶
Bases: Exception
Raised by read_payload when the length field breaks RFC 6455 §5.2.
Two rules, both about the encoding rather than the size: the 16-bit and
64-bit forms carry only values that do not fit the shorter form, and the
most significant bit of the 64-bit form is zero. The caller translates
this into a protocol-error CLOSE (RFC 6455 §7.4.1 code 1002); like
FramePayloadTooLarge, the codec stays protocol-agnostic.
MessageTooLarge
¶
Bases: Exception
Raised when a message outgrows its bound.
Sibling of FramePayloadTooLarge, one layer up: that one is
about a frame on the wire, this one about what the application would
be handed once fragments are joined and permessage-deflate has
inflated. A frame small enough to pass the frame cap can still
produce a message that does not — which is the whole reason both
exist. Same division of labour: the caller translates this into
CLOSE 1009 (RFC 6455 §7.4.1); the codec stays protocol-agnostic.
produced is what the message had reached when the bound tripped, not what it would eventually have been — nothing here ever computes the size of a payload it refused to build.
WSFrameBits
¶
Bases: IntEnum
Bit masks for the two-byte WebSocket frame header (RFC 6455 §5.2).
RSV1 marks a message compressed with permessage-deflate, and is set on the first frame of it only (RFC 7692 §7). RSV2 and RSV3 have no negotiated meaning, so a peer setting either is a protocol error.
WSFrameHeader
¶
Bases: NamedTuple
Decoded fields from the two-byte WebSocket frame header (RFC 6455 §5.2).
The raw codec accepts either mask bit; WebSocketRecipient enforces
endpoint roles (RFC 6455 §5.1).
WSOpcode
¶
Bases: IntEnum
WebSocket frame opcodes (RFC 6455 §5.2).
CONTINUATION, TEXT and BINARY are data frames and may be
fragmented across several frames. CLOSE, PING and PONG are
control frames: §5.5 caps their payload at 125 bytes and forbids
fragmenting them, and one may arrive between the fragments of a message.
encode_frame(payload, opcode=WSOpcode.TEXT, *, mask=False, rsv1=False)
¶
Encode payload as a WebSocket data frame (RFC 6455 §5).
opcode defaults to WSOpcode.TEXT; pass WSOpcode.BINARY for
binary frames, WSOpcode.CLOSE for close frames, etc.
Masking (RFC 6455 §5.1):
- Server → client frames MUST NOT be masked: keep mask=False (default).
- Client → server frames MUST be masked: pass mask=True, which prepends
a random 4-byte masking key and XORs the payload with it.
RSV1 (RFC 7692 §7): pass rsv1=True on the FIRST frame of a message
whose payload has been compressed with permessage-deflate. Continuation
frames in the same message keep rsv1=False.
encode_frame_header(length, opcode=WSOpcode.TEXT, *, rsv1=False)
¶
Encode an unmasked, final server-to-client frame header (RFC 6455 §5.2).
RSV1 belongs only on the first frame of a compressed message. Pass header and payload parts to the sender; its shared size gate chooses the write.
read_frame(reader)
async
¶
Read one WebSocket frame from reader.
Returns (opcode, payload) where payload is already unmasked.
Raises asyncio.IncompleteReadError on EOF.
read_frame_header(reader)
async
¶
Read the two-byte WebSocket frame header (RFC 6455 §5.2).
Returns a WSFrameHeader with all decoded flag and length fields.
RSV1 signals per-message deflate (RFC 7692 §7); RSV2 and RSV3 are
reserved for future extensions.
Raises asyncio.IncompleteReadError on EOF.
read_payload(reader, masked, length, *, max_length=None)
async
¶
Read the payload of a WebSocket frame from reader.
If masked is True, also read the 4-byte mask and unmask the payload.
Raises asyncio.IncompleteReadError on EOF.
When max_length is set and the declared payload size — resolved
from the 16-bit or 64-bit extended-length field per RFC 6455
§5.2 — exceeds it, raises FramePayloadTooLarge before
reading any body bytes off the wire. Defends against
post-handshake OOM where the peer advertises a 2**63 - 1 payload
and the server tries to buffer it.
A length field that breaks §5.2 raises InvalidFrameLength
instead, judged the same way: before the size cap and before any
body byte, so an unreadable encoding cannot be made legal by
staying under a cap.