Module

_h2_handler

HTTP/2 connection handler — manages multiplexed streams over a single connection.

Extracted fromworker.pyto keep protocol-specific connection handling separate from the core Worker lifecycle. The worker delegates to handle_h2_connection() when ALPN negotiation selects h2.

Each function is a standalone coroutine that receives the minimal state it needs (app, config, logger) — no Worker reference required.

Connection flow:

TLS handshake → ALPN selects "h2" → H2Connection state machine
→ per-stream ASGI tasks → multiplexed responses → GOAWAY

Functions

handle_h2_connection 11 None
Handle a full HTTP/2 connection with multiplexed streams. Runs one ASGI task p…
async
async def handle_h2_connection(app: ASGIApp, config: ServerConfig, logger: logging.Logger, reader: asyncio.StreamReader, writer: asyncio.StreamWriter, client: tuple[str, int], server: tuple[str, int], client_str: str, *, worker_id: int | None = None, lifespan_state: dict[str, Any] | None = None, is_draining: Callable[[], bool] | None = None) -> None

Handle a full HTTP/2 connection with multiplexed streams.

Runs one ASGI task per stream. The main loop reads data from the network, feeds it to H2Connection, and dispatches per-stream events to the appropriate ASGI task.

Parameters
Name Type Description
app ASGIApp

The ASGI application callable.

config ServerConfig

Immutable server configuration.

logger logging.Logger

Logger scoped to the worker.

reader asyncio.StreamReader

Asyncio stream reader for the connection.

writer asyncio.StreamWriter

Asyncio stream writer for the connection.

client tuple[str, int]

(host, port)of the remote peer.

server tuple[str, int]

(host, port)of the local endpoint.

client_str str

Formatted"host:port"string for logging.

worker_id int | None Default:None
lifespan_state dict[str, Any] | None Default:None
is_draining Callable[[], bool] | None Default:None
handle_h2_websocket_stream 12 None
Handle a WebSocket-over-HTTP/2 stream (RFC 8441). The Extended CONNECT bootstr…
async
async def handle_h2_websocket_stream(app: ASGIApp, config: ServerConfig, logger: logging.Logger, h2_conn: Any, stream_id: int, request: RequestReceived, data_queue: asyncio.Queue[dict], writer: asyncio.StreamWriter, client: tuple[str, int], server: tuple[str, int], client_str: str, *, lifespan_state: dict[str, Any] | None = None) -> None

Handle a WebSocket-over-HTTP/2 stream (RFC 8441).

The Extended CONNECT bootstraps a WebSocket session within an H2 stream. Data frames on this stream carry WebSocket frames (via wsproto), and the ASGI app sees a standardwebsocketscope.

This path mirrors the HTTP/1.1 WebSocket handler (_ws_handler): it enforceswebsocket_max_message_size(WS close 1009 + RST stream), negotiates permessage-deflate from the CONNECT headers, guardswebsocket.sendagainst send-before-accept / send-after-close, and implements thewebsocket.http.response.start / .bodyreject path. Unlike H1 the 200 acceptance headers are deferred until the app sendswebsocket.accept so the negotiated Sec-WebSocket-Extensions can be echoed (and a reject can send a non-200 status instead).

Parameters
Name Type Description
app ASGIApp

The ASGI application callable.

config ServerConfig

Immutable server configuration.

logger logging.Logger

Logger scoped to the worker.

h2_conn Any

TheH2Connectionmanaging this HTTP/2 connection.

stream_id int

The H2 stream identifier for this WebSocket session.

request RequestReceived

The parsed request event (Extended CONNECT).

data_queue asyncio.Queue[dict]

Queue fed by the H2 connection's event loop.

writer asyncio.StreamWriter

Asyncio stream writer for the connection.

client tuple[str, int]

(host, port)of the remote peer.

server tuple[str, int]

(host, port)of the local endpoint.

client_str str

Formatted"host:port"string for logging.

lifespan_state dict[str, Any] | None Default:None