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 :func: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.
WSFrameHeader
¶
Bases: NamedTuple
Decoded fields from the two-byte WebSocket frame header (RFC 6455 §5.2).
Note on masking (RFC 6455 §5.1):
- Client → server frames MUST be masked;
WebSocketRecipient raises ValueError on an unmasked client frame.
- Server → client frames MUST NOT be masked; WebSocketSender never sets
the mask bit.
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 just the unmasked 2-to-10-byte WebSocket frame header (server → client, RFC 6455 §5.1/§5.2).
Server frames MUST NOT be masked, so this never sets the mask bit and
takes no masking key. Callers that already hold the payload separately
(e.g. WebSocketSender) write (header, payload) as a vectored
writelines — avoiding the header+payload concatenation copy that
encode_frame would otherwise allocate on every send.
rsv1 (RFC 7692 §7) marks the FIRST frame of a permessage-deflate
compressed message.
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 :class: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.