# _h2_handler

URL: /pounce/api/_h2_handler/
Section: api
Description: HTTP/2 connection handler — manages multiplexed streams over a single connection.

Extracted from ``worker.py`` to 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

---

> For a complete page index, fetch /pounce/llms.txt.

Open LLM text
(/pounce/api/_h2_handler/index.txt)

Share with AI

Ask Claude
(https://claude.ai/new?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fpounce%2Fapi%2F_h2_handler%2Findex.txt)

Ask ChatGPT
(https://chatgpt.com/?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fpounce%2Fapi%2F_h2_handler%2Findex.txt)

Ask Gemini
(https://gemini.google.com/app?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fpounce%2Fapi%2F_h2_handler%2Findex.txt)

Ask Copilot
(https://copilot.microsoft.com/?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fpounce%2Fapi%2F_h2_handler%2Findex.txt)

Module

#
`_h2_handler`

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

Extracted from`worker.py`to 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
```

2Functions

## 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` (/pounce/api/protocols/h2/#H2Connection), and dispatches per-stream
events to the appropriate ASGI task.

##### Parameters

Name
Type
Description

`app`
`ASGIApp`

The ASGI application callable.

`config`
`ServerConfig (/pounce/api/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 standard`websocket`scope.

This path mirrors the HTTP/1.1 WebSocket handler (`_ws_handler` (/pounce/api/_ws_handler/)):
it enforces`websocket_max_message_size`(WS close 1009 + RST
stream), negotiates permessage-deflate from the CONNECT headers,
guards`websocket.send`against send-before-accept / send-after-close,
and implements the`websocket.http.response.start` / `.body`reject
path. Unlike H1 the 200 acceptance headers are deferred until the app
sends`websocket.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 (/pounce/api/config/#ServerConfig)`

Immutable server configuration.

`logger`
`logging.Logger`

Logger scoped to the worker.

`h2_conn`
`Any`

The`H2Connection`managing this HTTP/2 connection.

`stream_id`
`int`

The H2 stream identifier for this WebSocket session.

`request`
`RequestReceived (/pounce/api/protocols/_base/#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`
