# bridge

URL: /pounce/api/asgi/bridge/
Section: asgi
Description: ASGI bridge — translates between protocol events and the ASGI interface.

Builds ASGI scope dicts from protocol events, and creates the async
receive/send callables that ASGI apps interact with.

Streaming-first: send() writes response chunks immediately to the
transport. No buffering — each http.response.body message is compressed
(if applicable) and flushed to the wire before the next one.

Phase 4 hot-path optimizations:
- Pre-encoded ASGI spec constants (avoid per-request dict allocation)
- Bodyless fast-path receive (skip asyncio.Queue for GET/HEAD)
- Single write call for head+body when small
- Reduced isinstance checks

---

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

Open LLM text
(/pounce/api/asgi/bridge/index.txt)

Share with AI

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

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

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

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

Module

#
`asgi.bridge`

ASGI bridge — translates between protocol events and the ASGI interface.

Builds ASGI scope dicts from protocol events, and creates the async
receive/send callables that ASGI apps interact with.

Streaming-first: send() writes response chunks immediately to the
transport. No buffering — each http.response.body message is compressed
(if applicable) and flushed to the wire before the next one.

Phase 4 hot-path optimizations:

- Pre-encoded ASGI spec constants (avoid per-request dict allocation)

- Bodyless fast-path receive (skip asyncio.Queue for GET/HEAD)

- Single write call for head+body when small

- Reduced isinstance checks

1Class8Functions

## Classes

`SendState`

6

▼

Mutable holder for response metrics populated by the send callable.

The worker reads these after t…

Mutable holder for response metrics populated by the send callable.

The worker reads these after the ASGI app completes to get the actual
HTTP status code and byte count for access logging.

#### Attributes

Name
Type
Description

`status`

`int`

—

`bytes_sent`

`int`

—

`response_started`

`bool`

—

`response_complete`

`bool`

—

`streaming`

`bool`

—

`client_disconnected`

`bool`

—

## Functions

`is_streaming_response`

1

`bool`

▼

Return True when a response is long-lived streaming (SSE or chunked).

SSE (``t…

`def is_streaming_response(headers: list[tuple[bytes, bytes]]) -> bool`

Return True when a response is long-lived streaming (SSE or chunked).

SSE (`text/event-stream`) and responses without `Content-Length`are
expected to be long-lived; exclude them from duration-only slow heuristics.

##### Parameters

Name
Type
Description

`headers`
`list[tuple[bytes, bytes]]`

##### Returns

`bool`

`_sanitize_headers`

1

`list[tuple[bytes, bytes]]`

▼

Strip CR/LF characters from response header names and values.

Prevents CRLF in…

`def _sanitize_headers(headers: list[tuple[bytes, bytes]]) -> list[tuple[bytes, bytes]]`

Strip CR/LF characters from response header names and values.

Prevents CRLF injection attacks where a malicious ASGI app could inject
extra headers or split the HTTP response. This is defense-in-depth — h11
also validates header content, but we guard before serialization.

##### Parameters

Name
Type
Description

`headers`
`list[tuple[bytes, bytes]]`

##### Returns

`list[tuple[bytes, bytes]]`

`build_scope`

5

`dict[str, Any]`

▼

Build an ASGI HTTP scope dict from a parsed request.

`def build_scope(request: RequestReceived, config: ServerConfig, client: tuple[str, int], server: tuple[str, int], *, state: dict[str, Any] | None = None) -> dict[str, Any]`

##### Parameters

Name
Type
Description

`request`
`RequestReceived (/pounce/api/protocols/_base/#RequestReceived)`

The parsed HTTP request head.

`config`
`ServerConfig (/pounce/api/config/#ServerConfig)`

Server configuration.

`client`
`tuple[str, int]`

Client (host, port) tuple.

`server`
`tuple[str, int]`

Server (host, port) tuple.

`state`
`dict[str, Any] | None`

Lifespan state dict to inject into scope["state"].

Default:`None`

##### Returns

`dict[str, Any]`

`create_receive`

1

`Receive`

▼

Create an ASGI receive callable from a body event queue.

The worker pushes Bod…

`def create_receive(body_events: asyncio.Queue[BodyReceived]) -> Receive`

Create an ASGI receive callable from a body event queue.

The worker pushes BodyReceived events into the queue as they arrive.
The ASGI app calls receive() to consume them as http.request messages.

##### Parameters

Name
Type
Description

`body_events`
`asyncio.Queue[BodyReceived (/pounce/api/protocols/_base/#BodyReceived)]`

Queue of body events from the protocol layer.

##### Returns

`Receive`

`create_empty_receive`

0

`Receive`

▼

Create a fast-path receive for bodyless requests (GET, HEAD, etc.).

Returns a …

`def create_empty_receive() -> Receive`

Create a fast-path receive for bodyless requests (GET, HEAD, etc.).

Returns a static empty-body message without asyncio.Queue overhead.
Called at most once per request — second call would hang, but ASGI
apps should not call receive() twice for bodyless requests.

##### Returns

`Receive`

`create_disconnect_receive`

1

`Receive`

▼

Create a receive callable that delivers ``http.disconnect``.

For bodyless requ…

`def create_disconnect_receive(disconnect: asyncio.Event) -> Receive`

Create a receive callable that delivers`http.disconnect`.

For bodyless requests (GET, HEAD, etc.): returns the empty body message
on first call, then waits for the disconnect event before returning
`http.disconnect`. This allows ASGI apps (e.g. Chirp's SSE handler)
to detect client disconnects and stop producing events.

##### Parameters

Name
Type
Description

`disconnect`
`asyncio.Event`

Event set by the connection monitor when the client closes the socket.

##### Returns

`Receive`

`create_receive_with_disconnect`

2

`Receive`

▼

Create a receive callable that delivers body events then ``http.disconnect``.

…

`def create_receive_with_disconnect(body_events: asyncio.Queue[BodyReceived], disconnect: asyncio.Event) -> Receive`

Create a receive callable that delivers body events then`http.disconnect`.

Used when the request has a body (POST, PUT, etc.). Delivers body chunks
from the queue until the body is complete, then waits for the disconnect
event and returns`http.disconnect`.

##### Parameters

Name
Type
Description

`body_events`
`asyncio.Queue[BodyReceived (/pounce/api/protocols/_base/#BodyReceived)]`

Queue of body events from the protocol layer.

`disconnect`
`asyncio.Event`

Event set by the connection monitor when the client closes the socket.

##### Returns

`Receive`

`create_send`

15

`Send`

▼

Create an ASGI send callable that streams to the transport.

Streaming-first: e…

`def create_send(protocol: ProtocolHandler, writer: asyncio.StreamWriter, state: SendState, *, timing: ServerTiming | None = None, compressor: Compressor | None = None, request_method: bytes = b'GET', request_path: bytes = b'/', request_id: str | None = None, config: ServerConfig | None = None, server: tuple[str, int] | None = None, dictionary_hash: str | None = None, extra_headers: list[tuple[bytes, bytes]] | None = None, sendfile_fn: SendfileCallable | None = None, compression_min_size: int = 0, on_stream_start: Callable[[], None] | None = None) -> Send`

Create an ASGI send callable that streams to the transport.

Streaming-first: each response.body chunk is written immediately.
No buffering — the client sees data as soon as the app produces it.

Write coalescing: the response head is held back and combined with
the first body chunk in a single`writer.write()`call when the
total fits within`_COALESCE_THRESHOLD`. This halves the number
of syscalls for small responses (the common case).

##### Parameters

Name
Type
Description

`protocol`
`ProtocolHandler (/pounce/api/protocols/_base/#ProtocolHandler)`

Protocol handler for serialization.

`writer`
`asyncio.StreamWriter`

Asyncio stream writer for the connection.

`state`
`SendState (/pounce/api/asgi/bridge/#SendState)`

Mutable holder populated with response status and byte count.

`timing`
`ServerTiming (/pounce/api/_timing/#ServerTiming) | None`

Optional Server-Timing header builder.

Default:`None`

`compressor`
`Compressor (/pounce/api/_compression/#Compressor) | None`

Optional content compressor for the response.

Default:`None`

`request_method`
`bytes`

Default:`b'GET'`

`request_path`
`bytes`

Default:`b'/'`

`request_id`
`str | None`

Default:`None`

`config`
`ServerConfig (/pounce/api/config/#ServerConfig) | None`

Default:`None`

`server`
`tuple[str, int] | None`

Default:`None`

`dictionary_hash`
`str | None`

Default:`None`

`extra_headers`
`list[tuple[bytes, bytes]] | None`

Default:`None`

`sendfile_fn`
`SendfileCallable | None`

Default:`None`

`compression_min_size`
`int`

Default:`0`

`on_stream_start`
`Callable[[], None] | None`

Default:`None`

##### Returns

`Send`
