Skip to content

blackbull.server.parser

blackbull.server.parser

HTTP2DATAParser

Bases: HTTP2ParserBase

Parses an HTTP/2 DATA frame. Currently returns a fresh empty ASGI scope; body bytes are delivered via HTTP2Recipient rather than this parser.

HTTP2HEADParser

Bases: HTTP2ParserBase

Parses an HTTP/2 HEADERS frame into an ASGI http scope dict.

Pulls :method / :path / :scheme from the frame's pseudo-headers, encodes the regular headers as bytes pairs into a Headers object, and resolves root_path from the X-Forwarded-Prefix header.

HTTP2ParserBase

Abstract base for HTTP/2 frame parsers that build an ASGI scope.

Subclasses set FRAME_TYPE to the FrameTypes value they handle and implement parse(). __init_subclass__ auto-registers each concrete subclass in _registry so ParserFactory.Get can dispatch by frame type. Setting FRAME_TYPE = None keeps a class abstract (skipped at registration).

ParserFactory

Dispatches an incoming HTTP/2 frame to the parser registered for its type.

Each HTTP2ParserBase subclass registers itself in HTTP2ParserBase._registry keyed on its FRAME_TYPE; Get(frame, stream) looks up that registry and instantiates the matching parser bound to the given stream.

parse_headers(frame)

Build an ASGI http (or websocket) scope from a HEADERS frame.

Hot path on every request — kept as a module-level function so that callers avoid the dict-lookup + parser allocation that ParserFactory requires.

Also performs request-level pseudo-header presence checks (RFC 9113 §8.3.1). Field-level checks already happened in parse_payload; if that flagged frame.malformed we still build a scope to keep the contract simple but the actor will discard it before dispatch. If parse_headers itself finds a missing or empty required pseudo, it sets frame.malformed so the same actor check rejects the request.