WebSocket¶
palfrey.protocols.websocket
¶
WebSocket protocol implementation with dual backend support (wsproto/websockets).
This module handles WebSocket upgrade negotiation from HTTP, frame parsing/encoding, and full-duplex message exchange. The module supports two backends: wsproto (pure Python, ASGI-native) and websockets (C extension fallback for speed).
Backend selection is automatic: the module tries to import the Rust-accelerated websockets library first, falls back to wsproto if unavailable. Each backend provides frame masking/unmasking, frame opcode handling (text, binary, close, ping, pong), and payload reassembly from fragmented frames. Backpressure is managed via write buffers and read timeout logic to prevent unbounded accumulation.
Key Design Decisions: - WebSocket upgrade detection leverages existing HTTP request headers (Upgrade, Connection, Sec-WebSocket-Key) parsed by the HTTP module. - Frame payload unmasking uses accelerated palfrey_rust.unmask_websocket_payload when available (Rust extension) or falls back to pure Python bitwise operations. - The module enforces RFC 6455 semantics: client frames must be masked, server frames must not; close frames carry status codes and optional reasons. - Backpressure is signaled via asyncio.Event when write buffer exceeds thresholds, preventing unlimited memory growth under slow client conditions.
Key Classes
- WebSocketFrame: Decoded frame structure (fin, opcode, payload).
Key Functions
- handle_websocket: Main coroutine managing upgrade, frame I/O, and app delegation.
- _read_frame, _write_frame: Low-level frame encoding/decoding.
- _header_value, _header_map: Helper functions for HTTP header lookup.
WebSocketFrame
dataclass
¶
Decoded WebSocket frame structure containing control flags and payload data.
| ATTRIBUTE | DESCRIPTION |
|---|---|
fin |
Indicates if this is the final fragment in a message.
TYPE:
|
opcode |
Defines the interpretation of the payload data (e.g., 0x1 for text, 0x8 for close).
TYPE:
|
payload |
The raw data content of the frame.
TYPE:
|
Source code in palfrey/protocols/websocket.py
build_websocket_scope(*, target, headers, client, server, root_path, is_tls, protocol_header=None)
¶
Construct an ASGI scope dictionary for a WebSocket connection.
This scope includes connection metadata such as path, headers, and negotiated subprotocols required by the ASGI 3.0 specification.
| PARAMETER | DESCRIPTION |
|---|---|
target
|
The raw request target string.
TYPE:
|
headers
|
Initial HTTP upgrade headers.
TYPE:
|
client
|
IP and port of the connecting client.
TYPE:
|
server
|
IP and port of the server.
TYPE:
|
root_path
|
The ASGI root path.
TYPE:
|
is_tls
|
True if the connection is encrypted.
TYPE:
|
protocol_header
|
Optional pre-extracted protocol header.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Scope
|
A dictionary representing the connection scope.
TYPE:
|
Source code in palfrey/protocols/websocket.py
build_handshake_response(headers, *, subprotocol, extra_headers=None)
¶
Extract the client key and build a full Switching Protocols handshake response.
| PARAMETER | DESCRIPTION |
|---|---|
headers
|
Incoming HTTP request headers.
TYPE:
|
subprotocol
|
The negotiated subprotocol to include in headers.
TYPE:
|
extra_headers
|
Additional server headers.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bytes
|
Serialized HTTP 101 response bytes.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If the 'Sec-WebSocket-Key' header is missing from the request. |
Source code in palfrey/protocols/websocket.py
handle_websocket(app, config, *, reader, writer, headers, target, client, server, is_tls)
async
¶
Handle the ASGI WebSocket flow for a connection, dispatching to the configured backend.
Backend dispatching follows Uvicorn semantics: - 'wsproto' -> Use the wsproto engine. - 'websockets-sansio' -> Use the websockets sans-io implementation. - 'websockets' -> Use the full websockets library backend. - 'none' -> Use the core manual framing backend.
Source code in palfrey/protocols/websocket.py
2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 | |