Skip to content

blackbull.protocol.frame

blackbull.protocol.frame

HTTP/2 frame factory — parsing and creation.

FrameFactory produces frames of the requested type and decodes raw bytes from the wire. Frame-type definitions live in frame_types.

FrameFactory

Builds outbound HTTP/2 frames and parses inbound ones for one connection.

The factory owns the connection's HPACK encoder and decoder, which is why it is per-connection rather than shared: HPACK state is connection-wide, so a frame built or parsed with the wrong codec corrupts every later header block on that connection.

create builds any frame type from its registry; the named helpers below are the shorthands for the control frames a server sends most. load is the inbound direction.

__init__(*, max_header_list_size=None)

max_header_list_size is the decoded field-section total this connection will accept (RFC 9113 §6.5.2). None leaves hpack's own default in force; a caller that advertises the value to its peer passes the same number here, so advice and defence cannot disagree.

apply_peer_header_table_size(settings)

Apply peer encoder limits in order, retaining the local capacity cap.

create(type_, flags, stream_id, *, data=b'', **kwds)

Build the frame class registered for type_, ready to save().

data is the payload as it goes on the wire; flags accepts the type's flag enum or a raw int. The frame receives this connection's HPACK codecs, so a HEADERS built here shares decoder state with every other frame on the connection.

goaway(last_stream_id=0, error_code=0)

Create a GOAWAY frame.

RFC 9113 §6.8 — GOAWAY MUST be associated with the connection (stream identifier 0). The last_stream_id argument is the last-stream-id payload field, not the frame's stream identifier.

push_promise(parent_stream_id, promised_stream_id, pseudo_headers, headers)

Create a PUSH_PROMISE frame sent on parent_stream_id.

promised_stream_id must be an even server-allocated ID (RFC 7540 §5.1.1). pseudo_headers: dict mapping PseudoHeaders → bytes value. headers: list of (name, value) regular-header tuples.

rst_stream(stream_id, error_code)

Create a RST_STREAM frame with the given error code.

settings(*, ack=False, enable_connect_protocol=False, initial_window_size=None, max_concurrent_streams=None, enable_push=None, max_header_list_size=None)

Create a SETTINGS frame (INIT or ACK).

Every identifier is opt-in: None emits no entry, so a caller stays silent about a parameter rather than announcing the RFC's initial value back at the peer as if it were a position.

Parameters

ack: True → ACK frame (no payload). enable_connect_protocol: Include SETTINGS_ENABLE_CONNECT_PROTOCOL=1 (RFC 8441 §3). initial_window_size: Include SETTINGS_INITIAL_WINDOW_SIZE (identifier 0x4, RFC 7540 §6.5.2). max_concurrent_streams: Include SETTINGS_MAX_CONCURRENT_STREAMS (identifier 0x3, RFC 7540 §6.5.2). Tells the peer the maximum number of concurrent streams we will accept. enable_push: Include SETTINGS_ENABLE_PUSH (identifier 0x2, RFC 9113 §6.5.2). 0 forbids the peer to push; §6.5.2 binds it only once acknowledged. max_header_list_size: Include SETTINGS_MAX_HEADER_LIST_SIZE (identifier 0x6, RFC 9113 §6.5.2). Advisory: it is advice to the peer, and the local decoder's limit is what enforces it.

window_update(stream_id, increment)

Create a WINDOW_UPDATE frame with the given increment.