0
# wsproto
1
2
A pure-Python implementation of a WebSocket protocol stack. wsproto is written from the ground up to be embeddable in any program, ensuring WebSocket communication as defined in RFC 6455 and RFC 7692 (compression extensions) regardless of programming paradigm. The library provides a purely in-memory solution defined in terms of data actions and WebSocket frames, without providing parsing, network, or concurrency layers.
3
4
## Package Information
5
6
- **Package Name**: wsproto
7
- **Package Type**: pypi
8
- **Language**: Python
9
- **Installation**: `pip install wsproto`
10
- **Supported Python**: 3.7.0 or higher
11
12
## Core Imports
13
14
```python
15
from wsproto import WSConnection, ConnectionType
16
```
17
18
Common event imports:
19
20
```python
21
from wsproto.events import (
22
Request, AcceptConnection, RejectConnection, RejectData,
23
TextMessage, BytesMessage, CloseConnection,
24
Ping, Pong
25
)
26
```
27
28
Low-level protocol imports:
29
30
```python
31
from wsproto.connection import Connection, ConnectionState, CLIENT, SERVER
32
from wsproto.frame_protocol import (
33
FrameProtocol, FrameDecoder, MessageDecoder,
34
Opcode, CloseReason, Frame, Header, RsvBits, ParseFailed
35
)
36
from wsproto.extensions import Extension, PerMessageDeflate, SUPPORTED_EXTENSIONS
37
from wsproto.handshake import H11Handshake
38
from wsproto.utilities import (
39
ProtocolError, LocalProtocolError, RemoteProtocolError,
40
generate_nonce, generate_accept_token,
41
normed_header_dict, split_comma_header
42
)
43
from wsproto.typing import Headers
44
```
45
46
## Basic Usage
47
48
### Client Connection
49
50
```python
51
from wsproto import WSConnection, ConnectionType
52
from wsproto.events import Request, AcceptConnection, TextMessage
53
54
# Create a client connection
55
ws = WSConnection(ConnectionType.CLIENT)
56
57
# Generate handshake request
58
data_to_send = ws.send(Request(host='echo.websocket.org', target='/'))
59
60
# Send data_to_send over your network connection
61
# ... network sending code ...
62
63
# Process received network data
64
ws.receive_data(received_bytes)
65
66
# Handle events
67
for event in ws.events():
68
if isinstance(event, AcceptConnection):
69
print("Connection established!")
70
elif isinstance(event, TextMessage):
71
print(f"Received text: {event.data}")
72
```
73
74
### Server Connection
75
76
```python
77
from wsproto import WSConnection, ConnectionType
78
from wsproto.events import Request, AcceptConnection
79
80
# Create a server connection
81
ws = WSConnection(ConnectionType.SERVER)
82
83
# Process incoming handshake data
84
ws.receive_data(received_handshake_bytes)
85
86
# Handle events
87
for event in ws.events():
88
if isinstance(event, Request):
89
# Accept the connection
90
data_to_send = ws.send(AcceptConnection())
91
# Send data_to_send over network
92
```
93
94
## Architecture
95
96
wsproto uses a state-machine based architecture with clear separation of concerns:
97
98
- **WSConnection**: High-level interface managing handshake and connection state
99
- **Connection**: Low-level WebSocket connection handling frames and messages
100
- **H11Handshake**: HTTP/1.1 handshake protocol implementation
101
- **FrameProtocol**: WebSocket frame parsing and generation
102
- **Event System**: Type-safe event-driven API for all WebSocket operations
103
- **Extensions**: Pluggable extension system (permessage-deflate support included)
104
105
This design enables maximum reusability across different network implementations, event loops, and concurrency models while maintaining complete RFC compliance.
106
107
## Capabilities
108
109
### Connection Management
110
111
Core connection establishment, state management, and lifecycle control for both client and server WebSocket connections.
112
113
```python { .api }
114
class WSConnection:
115
def __init__(self, connection_type: ConnectionType) -> None: ...
116
def send(self, event: Event) -> bytes: ...
117
def receive_data(self, data: Optional[bytes]) -> None: ...
118
def events(self) -> Generator[Event, None, None]: ...
119
120
class ConnectionType(Enum):
121
CLIENT = 1
122
SERVER = 2
123
124
class ConnectionState(Enum):
125
CONNECTING = 0
126
OPEN = 1
127
REMOTE_CLOSING = 2
128
LOCAL_CLOSING = 3
129
CLOSED = 4
130
REJECTING = 5
131
```
132
133
[Connection Management](./connection-management.md)
134
135
### Event System
136
137
Comprehensive event-driven API covering all WebSocket operations including handshake, messages, control frames, and connection lifecycle.
138
139
```python { .api }
140
class Event(ABC): ...
141
142
class Request(Event):
143
host: str
144
target: str
145
extensions: Union[Sequence[Extension], Sequence[str]] = field(default_factory=list)
146
extra_headers: Headers = field(default_factory=list)
147
subprotocols: List[str] = field(default_factory=list)
148
149
class AcceptConnection(Event):
150
subprotocol: Optional[str] = None
151
extensions: List[Extension] = field(default_factory=list)
152
extra_headers: Headers = field(default_factory=list)
153
154
class TextMessage(Event):
155
data: str
156
frame_finished: bool = True
157
message_finished: bool = True
158
159
class BytesMessage(Event):
160
data: bytes
161
frame_finished: bool = True
162
message_finished: bool = True
163
```
164
165
[Event System](./event-system.md)
166
167
### Extensions
168
169
WebSocket extensions support including RFC 7692 permessage-deflate compression with configurable parameters and negotiation.
170
171
```python { .api }
172
class Extension:
173
name: str
174
def enabled(self) -> bool: ...
175
def offer(self) -> Union[bool, str]: ...
176
def accept(self, offer: str) -> Optional[Union[bool, str]]: ...
177
178
class PerMessageDeflate(Extension):
179
name = "permessage-deflate"
180
def __init__(
181
self,
182
client_no_context_takeover: bool = False,
183
client_max_window_bits: Optional[int] = None,
184
server_no_context_takeover: bool = False,
185
server_max_window_bits: Optional[int] = None,
186
) -> None: ...
187
```
188
189
[Extensions](./extensions.md)
190
191
### Low-Level Protocol
192
193
Direct frame protocol access for advanced use cases requiring fine-grained control over WebSocket frame generation and parsing.
194
195
```python { .api }
196
class FrameProtocol:
197
def __init__(self, client: bool, extensions: List[Extension]) -> None: ...
198
def send_data(self, payload: Union[bytes, bytearray, str] = b"", fin: bool = True) -> bytes: ...
199
def ping(self, payload: bytes = b"") -> bytes: ...
200
def pong(self, payload: bytes = b"") -> bytes: ...
201
def close(self, code: Optional[int] = None, reason: Optional[str] = None) -> bytes: ...
202
203
class Opcode(IntEnum):
204
CONTINUATION = 0x0
205
TEXT = 0x1
206
BINARY = 0x2
207
CLOSE = 0x8
208
PING = 0x9
209
PONG = 0xA
210
211
class CloseReason(IntEnum):
212
NORMAL_CLOSURE = 1000
213
GOING_AWAY = 1001
214
PROTOCOL_ERROR = 1002
215
# ... other close codes
216
```
217
218
[Low-Level Protocol](./low-level-protocol.md)
219
220
### Utilities
221
222
Helper functions for WebSocket handshake token generation and header processing.
223
224
```python { .api }
225
def generate_nonce() -> bytes:
226
"""
227
Generate a WebSocket handshake nonce.
228
229
Creates a random 16-byte value encoded in base64, used for the
230
Sec-WebSocket-Key header in client handshake requests.
231
232
Returns:
233
Base64-encoded random nonce bytes
234
"""
235
236
def generate_accept_token(token: bytes) -> bytes:
237
"""
238
Generate WebSocket accept token for handshake response.
239
240
Takes the client's Sec-WebSocket-Key value and generates the
241
corresponding Sec-WebSocket-Accept value using SHA-1 and
242
the WebSocket GUID as specified in RFC 6455.
243
244
Args:
245
token: The Sec-WebSocket-Key value from client
246
247
Returns:
248
Base64-encoded accept token for server response
249
"""
250
251
def normed_header_dict(headers: Union[Headers, H11Headers]) -> Dict[bytes, bytes]:
252
"""
253
Normalize HTTP headers to a dictionary.
254
255
Converts header list to dictionary, joining multiple values
256
with commas where appropriate.
257
258
Args:
259
headers: Headers as list of tuples or h11 headers
260
261
Returns:
262
Dictionary mapping header names to values
263
"""
264
265
def split_comma_header(value: bytes) -> List[str]:
266
"""
267
Split comma-separated header value.
268
269
Parses header values that contain comma-separated lists,
270
such as extension and subprotocol headers.
271
272
Args:
273
value: Header value as bytes
274
275
Returns:
276
List of individual header values
277
"""
278
```
279
280
## Types
281
282
```python { .api }
283
from typing import List, Tuple, Generator, Optional, Union, Sequence, Dict
284
from dataclasses import dataclass, field
285
from enum import Enum, IntEnum
286
from h11._headers import Headers as H11Headers
287
288
Headers = List[Tuple[bytes, bytes]]
289
290
class ProtocolError(Exception): ...
291
class LocalProtocolError(ProtocolError): ...
292
class RemoteProtocolError(ProtocolError):
293
def __init__(self, message: str, event_hint: Optional[Event] = None) -> None: ...
294
event_hint: Optional[Event]
295
```