blackbull.server.permessage_deflate¶
blackbull.server.permessage_deflate
¶
permessage-deflate (RFC 7692) negotiation and per-message codec.
This module is small on purpose. It does two things:
-
Handshake: parse a peer's
Sec-WebSocket-Extensionsoffer, decide whether to acceptpermessage-deflate, and produce the response-sideSec-WebSocket-Extensionsheader value. -
Per-connection state: hold the streaming inflate/deflate state plus the
*_no_context_takeoverflags so :class:WebSocketRecipientcan decompress inbound messages and :class:WebSocketSendercan compress outbound ones.
The actual wire-level use of RSV1 happens in :mod:ws_codec and
:mod:recipient; this module just owns the policy + state.
DeflateParams
dataclass
¶
Per-connection permessage-deflate parameters as negotiated.
InboundDecompressor
¶
Streaming decompressor for inbound permessage-deflate messages.
The peer (client) is doing the compression here, so the no_context_takeover
flag we care about is client_no_context_takeover. When set, the inflater
is recreated for every message; otherwise the same inflater is reused so
the sliding-window context carries forward across messages.
decompress(payload, *, max_length=None)
¶
Inflate one whole compressed message. Raises zlib.error on bad data.
With max_length set, the inflated output is bounded by zlib
itself rather than measured after the fact: a bomb is refused
without ever being built. Asking for max_length + 1 is what
makes "exactly at the bound" and "one byte over" distinguishable
in a single call — zlib stops at the byte it was given, so a
return of exactly max_length bytes is ambiguous on its own.
Raises :class:MessageTooLarge when the peer's message inflates
past the bound. unconsumed_tail is the other half of that
check: zlib stops early when it hits the limit, so leftover input
means there was more to come even if the output landed on the
boundary.
OutboundCompressor
¶
Streaming compressor for outbound permessage-deflate messages.
Symmetric to :class:InboundDecompressor: the no_context_takeover flag
that matters here is server_no_context_takeover (we are the server),
deciding whether to reset the deflater between messages.
compress(payload)
¶
Compress one whole message; strip the trailing 0x00 0x00 0xff 0xff per RFC 7692 §7.2.1.
negotiate(offer_header)
¶
Decide whether to accept permessage-deflate based on the client's offer.
Returns (params, response_value) where:
paramsis the :class:DeflateParamsto install on the connection (orNoneto decline).response_valueis the bytes to put afterSec-WebSocket-Extensions:in the 101 response (orNonewhen declining).
Policy: accept context-takeover by default on both sides (better
compression). Honour server_no_context_takeover and
client_no_context_takeover when the client asks for them. Ignore
unknown parameter names — that's what RFC 7692 §5.1 calls for.
offer_header is the raw bytes of the client's
Sec-WebSocket-Extensions header (or None when absent). The
client may send multiple comma-separated offers; we pick the first one
that names permessage-deflate and that we can satisfy.