Skip to content

blackbull.protocol.stream

blackbull.protocol.stream

HTTP/2 stream state and the priority tree (RFC 7540 §5).

Each Stream node owns the dispatch target (native Connection, or ASGI scope on the compat lanes) for one in-flight request as well as its position in the dependency tree (parent + weight) used by the priority machinery. StreamState enumerates the lifecycle states defined in RFC 7540 §5.1; on_headers_received / on_data_received perform the corresponding transitions.

Stream identifier 0 is reserved for connection-level frames and is the root of every priority tree.

Stream

One node in the HTTP/2 stream-priority tree (RFC 7540 §5.1, §5.3).

A Stream carries the request's dispatch target (Connection or ASGI scope), plus its position in the priority tree (parent + weight).

identifier == 0 is the connection-level pseudo-stream (RFC 7540 §5.1.1) and acts as the root of the tree; SETTINGS, PING, GOAWAY, and connection-level WINDOW_UPDATE frames target it. Client-initiated request streams use odd identifiers, server-pushed streams use even identifiers (RFC 7540 §5.1.1).

window_size defaults to the connection's initial flow-control window when omitted (the value lives on the sender, not the stream).

find_child(stream_id)

Locate a node by stream_id.

BlackBull only nests streams under their priority parent in the rare case where PRIORITY arrives for a stream whose dependent_stream is another peer stream rather than root. h2 in the wild — and h2load in particular — never exercises this; every peer-initiated stream ends up as a direct child of root. Walking the entire subtree on a miss therefore wasted O(N) per lookup once we stopped pruning closed streams for §5.1 state validation. Keep the fast path flat; recurse only when the priority tree actually has depth.

on_data_received(end_stream)

Transition state on DATA frame (RFC 9113 §5.1).

The peer's END_STREAM closes only their half: the stream becomes half-closed (remote), from which WINDOW_UPDATE / PRIORITY / RST_STREAM remain legal. Full CLOSED is reached when the server side finishes too (stream-task done-callback prunes the node) or via RST_STREAM.

on_headers_received(end_stream)

Transition state on HEADERS frame (RFC 7540 §5.1).

on_rst_received()

Transition on incoming RST_STREAM (RFC 9113 §5.1).

Marks the stream CLOSED and remembers that it was closed via RST_STREAM (vs END_STREAM). The state is retained so later frames arriving on the same identifier can be detected and the right error type returned.

StreamState

Bases: Enum

HTTP/2 stream states per RFC 7540 §5.1.