blackbull.protocol.frame_types¶
blackbull.protocol.frame_types
¶
HTTP/2 frame type definitions (RFC 9113 §6; supersedes RFC 7540 §6).
Frame-type classes, enums, and the FrameBase registry. HPACK
compression/decompression is delegated to the hpack library.
FrameFactory lives in frame.py; this module is kept free of
factory / parsing logic so the type hierarchy can be imported without
pulling in the codec.
FrameBase
¶
docstring for FrameBase
FrameFlags
¶
Bases: IntEnum
Common base for all HTTP/2 frame flag enums.
Inheriting from this empty base allows type annotations to reference
FrameFlags instead of listing every concrete flag enum. Because
FrameFlags itself has no members, Python's restriction on subclassing
a non-empty IntEnum does not apply.
FrameFormatError
¶
Bases: ValueError
A frame the RFC calls malformed, carrying the code its own section names.
A parser that raises a bare Exception leaves the caller to guess the
error code from the message, and the guess is the thing the peer acts on.
ValueError because that is what the padding checks already raised.
GoAway
¶
Bases: FrameBase
RFC 9113 §6.8 — GOAWAY frame.
The frame's stream identifier (set by FrameBase) MUST be 0; this is a
connection-level frame. The first 4 bytes of the payload are the
last_stream_id (a separate field) and the next 4 bytes are the error
code. Earlier revisions of this class assigned the payload's
last_stream_id back into self.stream_id, which made every outgoing
GOAWAY ship with the wrong frame header — h2spec saw a malformed GOAWAY
and reported "Error: connection error: PROTOCOL_ERROR" instead of
accepting the GOAWAY for the connection-error tests.
Headers
¶
PriorityUpdate
¶
Bases: FrameBase
RFC 9218 §7.1 — PRIORITY_UPDATE frame (type 0x10).
Payload: 4-byte Prioritized Stream ID + ASCII Priority field value
(e.g. u=3 or u=0, i). The server receives and logs the hint
but does not reorder stream processing.
PseudoHeaders
¶
Bases: StrEnum
RFC 7540 §8.1.2 pseudo-header field names.
PushPromise
¶
Bases: FrameBase
RFC 7540 §6.6 — PUSH_PROMISE frame (type 0x05).
Sent on the initiating (parent) stream; carries the promised stream ID and the HPACK-encoded synthetic request headers for the pushed resource.
parse_payload()
¶
Decode the promised block and discard it: the side effect on the connection-wide HPACK table is the point, and RFC 9113 §4.3 requires it even though the client acts on no push.
Splitting works as in :meth:Headers.parse_payload.
field_name_is_valid(name)
¶
RFC 9113 §8.2.1 — is name a legal HTTP/2 field name?
A field name MUST NOT contain characters in 0x00-0x20 (controls and SP), 0x41-0x5A (uppercase), or 0x7F-0xFF. It MUST NOT include a colon (0x3A) other than the single leading octet that marks a pseudo-header field. Rejecting these closes a header-injection / request-smuggling vector.
field_value_is_valid(value)
¶
RFC 9113 §8.2.1 — a field value MUST NOT contain NUL, LF, or CR.
no_hpack_context(frame, codec)
¶
The refusal for a header frame that cannot name its connection's codec.
HPACK state is connection-wide and the peer keeps exactly one table for it (RFC 7541 §2.3, RFC 9113 §4.3), so a substitute codec is never a weaker version of the right one — it is a different table. Both directions fail the same way and silently: a private encoder writes indices the peer resolves against entries someone else inserted, and a block that never reaches the connection's decoder leaves it behind its peer for good. Valid-looking bytes, wrong fields, no exception on either side.
The message has to send the reader to the connection rather than to the signature, because "missing argument" is answered by passing any codec.
parse_priority_field(s)
¶
Parse an RFC 9218 Priority field value (a Structured Fields Dictionary).
"u=5, i" → {'urgency': 5, 'incremental': True}
Defaults per RFC 9218 §4.1: urgency=3, incremental=False. A value that fails strict RFC 9651 parsing is ignored entirely (RFC 9218 §5), and out-of-range or mistyped members are ignored individually (RFC 9218 §4) — either way the defaults apply.