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.
Continuation
¶
Bases: FrameBase
A CONTINUATION frame — the rest of a field block (RFC 9113 §6.10).
Its payload is a fragment, never a block of its own: append it to the
HEADERS or PUSH_PROMISE frame that opened the block and decode there, so
the connection-wide HPACK table sees every insertion in order. No frame
for another stream may arrive in between, and end_headers marks the
last fragment.
Data
¶
Bases: FrameBase
A DATA frame — one chunk of a message body (RFC 9113 §6.1).
payload is the body octets with any padding already removed, so its
length is the application's and length is the wire's. Padding that
would not fit the frame raises FrameFormatError carrying
PROTOCOL_ERROR.
DataFrameFlags
¶
ErrorCodes
¶
Bases: IntEnum
HTTP/2 error codes (RFC 9113 §7), carried by RST_STREAM and GOAWAY.
The set is open: §7 requires an unknown code to be accepted without special
behaviour, so a code read off the wire is not guaranteed to be a member
here — RstStream keeps a
plain int when the peer sent one this enum does not name.
FrameBase
¶
Common frame header and the subclass registry (RFC 9113 §4.1).
Holds the four fields every frame header carries — length, type_,
flags, stream_id — and turns them back into nine octets in
save(), which a subclass extends with its own payload. Setting
FRAME_TYPE on a subclass registers it for that type; a second class
claiming the same type is a ValueError at import.
FrameFlags
¶
Bases: IntEnum
Common annotation base for frame flag enums.
FrameFormatError
¶
Bases: ValueError
Malformed frame with its RFC-defined error code.
FrameTypes
¶
Bases: bytes, Enum
Registered HTTP/2 frame types (RFC 9113 §11.2).
Each member's value is the single type octet exactly as it appears in the
frame header, so a member compares equal to the byte read off the wire and
not to the integer it encodes. PRIORITY_UPDATE is RFC 9218 §7.1.
GoAway
¶
Bases: FrameBase
RFC 9113 §6.8 — GOAWAY frame.
GOAWAY is connection-level, so the frame header's stream identifier is
always 0. last_stream_id is a separate field carried in the first 4
bytes of the payload, followed by the 4-byte error code; a GOAWAY
announcing stream 3 still rides on stream 0. Held by
tests/unit/test_frame.py::test_goaway_save_includes_last_stream_id_and_error_code.
HeaderFrameFlags
¶
Bases: FrameFlags
Flags a HEADERS frame may carry (RFC 9113 §6.2).
PRIORITY announces the exclusive/dependency/weight fields ahead of the
field block; the scheme they describe is deprecated by §5.3, but the five
octets still have to be skipped to reach the block.
Headers
¶
Bases: FrameBase
A HEADERS frame and the field block it opens (RFC 9113 §6.2).
Construct it with the connection's shared HPACK decoder / encoder: the
dynamic table spans the whole connection, so a per-frame codec decodes
against the wrong table. When END_HEADERS is set the block is decoded
immediately; otherwise append each CONTINUATION payload to raw_block
and call parse_payload once the block is complete.
Decoding splits the result two ways. pseudo_headers maps
PseudoHeaders to the received octets, which the request and response
layers grade and turn into text only where they need it; headers is
the ordinary field list as (name, value) byte pairs.
A block that breaks §8.1.2 / §8.2 does not raise — it sets malformed
with a malformed_reason, so the caller can reset the stream while the
connection-wide table stays in step with the peer's.
parse_payload()
¶
Decode the field block, which may span several frames.
Padding and priority belong to the frame that carried the flags, and
self.length is that frame's payload; everything past it was
appended by CONTINUATION and is fragment throughout.
IncompleteFrameError
¶
Bases: FrameFormatError
Fewer octets than a frame header, or than the payload its header declares (RFC 9113 §4.1).
Ping
¶
Bases: FrameBase
A PING frame — connection liveness and round-trip measurement (RFC 9113 §6.7).
The payload is exactly eight octets; any other length raises
FrameFormatError carrying FRAME_SIZE_ERROR. A reply repeats the
payload unchanged with PingFrameFlags.ACK set.
PingFrameFlags
¶
Bases: FrameFlags
The one flag a PING frame may carry (RFC 9113 §6.7): ACK marks the
frame as the reply, whose payload must echo the ping's own.
Priority
¶
Bases: FrameBase
A PRIORITY frame — a stream dependency and weight (RFC 9113 §6.3).
RFC 9113 §5.3 deprecates the scheme these fields express, but a peer may
still send them, so they are parsed rather than refused. weight is the
true weight in 1–256, one more than the octet on the wire; exclusion
holds the top bit of the dependency field and dependent_stream the
remaining 31.
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 Headers.parse_payload.
RstStream
¶
Bases: FrameBase
A RST_STREAM frame — abrupt termination of one stream (RFC 9113 §6.4).
The payload is exactly four octets; any other length raises
FrameFormatError carrying FRAME_SIZE_ERROR. error_code is an
ErrorCodes member when the
peer sent a registered code and a plain int when it did not, so read it
as an integer rather than assuming the enum.
SettingFrame
¶
Bases: FrameBase
A SETTINGS frame — connection-wide parameters (RFC 9113 §6.5).
Each identifier the peer sends becomes an attribute named for it
(header_table_size, max_concurrent_streams, max_frame_size, …).
An omitted setting leaves no attribute at all, so read one with getattr
and supply the default the RFC names — initial_window_size is the
exception, present as None until the peer sets it. An unknown
identifier is ignored, as §6.5.2 requires.
SettingFrameFlags
¶
Bases: FrameFlags
Flags a SETTINGS frame may carry (RFC 9113 §6.5).
INIT is the absence of ACK rather than a flag the RFC defines: it
names the frame that carries settings, as opposed to the empty frame that
acknowledges them.
WindowUpdate
¶
Bases: FrameBase
A WINDOW_UPDATE frame — a flow-control credit (RFC 9113 §6.9).
window_size is the increment to add, not the resulting window, and it
applies to the connection when stream_id is 0 and to that stream
otherwise.
field_name_is_valid(name)
¶
RFC 9113 §8.2.1 — is name a legal HTTP/2 field name?
The RFC 9110 §5.6.2 token alphabet, lowercased (§8.2), with the single leading colon that marks a pseudo-header field allowed. The alphabet is shared with HTTP/1.1: a separator is not a name octet on either transport, and a name that matched here but not there was a smuggling surface §8.2.1 names explicitly.
field_value_has_boundary_whitespace(value)
¶
RFC 9113 §8.2.1 — SP or HTAB at either end of a field value.
Inside the value both octets stay legal, which is why this is a second
question and not folded into field_value_is_valid: it is about the
position, not the octet.
field_value_is_valid(value)
¶
RFC 9110 §5.5 field-content — no control octet but HTAB, and no DEL.
§8.2.1 states the minimal form of this rule as a MUST and asks for the full HTTP definition as a SHOULD; HTTP/1.1 already refuses these octets, and a value is the same value on either transport.
no_hpack_context(frame, codec)
¶
Refuse header framing without the connection-owned shared HPACK context.
Never substitute a private encoder or decoder (RFC 7541 §2.3, RFC 9113 §4.3).
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.
serialize_field_block(payload, frame_type, flags, stream_id, max_frame_size)
¶
Serialize one complete field block for an uninterrupted writer handoff.