0
# Protocol States
1
2
State constants and role definitions for managing HTTP/1.1 connection lifecycle and protocol compliance. h11 uses a state machine to track the current phase of HTTP message exchange for both client and server roles.
3
4
## Capabilities
5
6
### Role Constants
7
8
Define the role of each side in the HTTP connection.
9
10
```python { .api }
11
CLIENT = ...
12
"""
13
Represents the client role in an HTTP connection.
14
15
Usage:
16
conn = h11.Connection(h11.CLIENT)
17
18
The client role:
19
- Sends requests and receives responses
20
- Initiates HTTP conversations
21
- Can send Request events when in IDLE state
22
- Receives Response events when waiting for server
23
"""
24
25
SERVER = ...
26
"""
27
Represents the server role in an HTTP connection.
28
29
Usage:
30
conn = h11.Connection(h11.SERVER)
31
32
The server role:
33
- Receives requests and sends responses
34
- Responds to HTTP conversations
35
- Receives Request events when in IDLE state
36
- Can send Response events after receiving complete request
37
"""
38
```
39
40
### Connection State Constants
41
42
States that track the progression of HTTP message exchange.
43
44
```python { .api }
45
IDLE = ...
46
"""
47
Initial state - ready for new request/response cycle.
48
49
Transitions:
50
- CLIENT: Can send Request → SEND_BODY or DONE
51
- SERVER: Waits to receive Request → SEND_RESPONSE
52
"""
53
54
SEND_RESPONSE = ...
55
"""
56
Server is ready to send response after receiving complete request.
57
58
Transitions:
59
- SERVER: Can send Response/InformationalResponse → SEND_BODY or DONE
60
- Only valid for SERVER role
61
"""
62
63
SEND_BODY = ...
64
"""
65
Ready to send message body data.
66
67
Transitions:
68
- Can send Data events with body chunks
69
- Send EndOfMessage → DONE
70
- Both CLIENT and SERVER can enter this state
71
"""
72
73
DONE = ...
74
"""
75
Finished with current request/response cycle.
76
77
Transitions:
78
- Wait for peer to finish their side
79
- Both sides DONE → PAUSED (for keep-alive) or connection closes
80
"""
81
82
MUST_CLOSE = ...
83
"""
84
Connection must be closed after current message completes.
85
86
Causes:
87
- HTTP/1.0 without keep-alive
88
- Connection: close header
89
- Protocol errors requiring connection termination
90
"""
91
92
CLOSED = ...
93
"""
94
Connection is closed - no further communication possible.
95
96
Terminal state:
97
- Cannot transition to other states
98
- Connection object should be discarded
99
"""
100
101
ERROR = ...
102
"""
103
Error state due to protocol violation.
104
105
Causes:
106
- Invalid HTTP messages
107
- State machine violations
108
- Calling send_failed()
109
- Protocol specification violations
110
"""
111
112
SWITCHED_PROTOCOL = ...
113
"""
114
Successfully switched to different protocol.
115
116
Usage:
117
- After successful HTTP/1.1 protocol upgrade
118
- Connection no longer follows HTTP/1.1 state machine
119
- Application handles new protocol directly
120
"""
121
```
122
123
## State Machine Behavior
124
125
### State Transitions
126
127
The state machine enforces HTTP/1.1 protocol rules through valid state transitions:
128
129
```python
130
# CLIENT state flow
131
IDLE → SEND_BODY # After sending Request with body
132
IDLE → DONE # After sending Request without body
133
SEND_BODY → DONE # After sending EndOfMessage
134
135
# SERVER state flow
136
IDLE → SEND_RESPONSE # After receiving Request
137
SEND_RESPONSE → SEND_BODY # After sending Response with body
138
SEND_RESPONSE → DONE # After sending Response without body
139
SEND_BODY → DONE # After sending EndOfMessage
140
141
# Common flows
142
DONE → IDLE # Start new cycle (keep-alive)
143
DONE → CLOSED # Connection closes
144
* → ERROR # Protocol violation
145
* → MUST_CLOSE # Connection must close
146
```
147
148
### State Checking
149
150
Check connection states to determine valid operations:
151
152
```python { .api }
153
# Check our current state
154
if conn.our_state is h11.IDLE:
155
# Can send new request (CLIENT) or expect request (SERVER)
156
pass
157
elif conn.our_state is h11.SEND_BODY:
158
# Can send Data or EndOfMessage events
159
pass
160
elif conn.our_state is h11.DONE:
161
# Finished our side, wait for peer or start new cycle
162
pass
163
164
# Check peer state
165
if conn.their_state is h11.DONE:
166
# Peer finished, might be able to start new cycle
167
pass
168
169
# Check both states
170
if conn.states == {h11.CLIENT: h11.DONE, h11.SERVER: h11.DONE}:
171
# Both sides done, can start new cycle
172
conn.start_next_cycle()
173
```
174
175
## Usage Patterns
176
177
### Basic State Monitoring
178
179
```python
180
import h11
181
182
conn = h11.Connection(h11.CLIENT)
183
184
print(f"Initial state: {conn.our_state}") # IDLE
185
186
# Send request
187
req = h11.Request(method=b'GET', target=b'/', headers=[(b'host', b'example.com')])
188
data = conn.send(req)
189
190
print(f"After request: {conn.our_state}") # DONE (no body)
191
192
# Process response
193
while conn.our_state is not h11.DONE or conn.their_state is not h11.DONE:
194
raw_data = receive_from_socket()
195
conn.receive_data(raw_data)
196
197
event = conn.next_event()
198
if event is h11.NEED_DATA:
199
continue
200
elif isinstance(event, h11.Response):
201
print(f"Response received, their state: {conn.their_state}")
202
elif isinstance(event, h11.EndOfMessage):
203
print(f"Response complete, their state: {conn.their_state}") # DONE
204
205
# Both sides done - can start new cycle if keep-alive
206
if conn.our_state is h11.DONE and conn.their_state is h11.DONE:
207
if conn.next_event() is h11.PAUSED:
208
conn.start_next_cycle()
209
print(f"New cycle started: {conn.our_state}") # IDLE
210
```
211
212
### Error Handling
213
214
```python
215
try:
216
# Attempt invalid state transition
217
invalid_event = h11.Response(status_code=200) # SERVER event from CLIENT
218
data = conn.send(invalid_event)
219
except h11.LocalProtocolError as e:
220
print(f"Protocol error: {e}")
221
print(f"Connection state: {conn.our_state}") # ERROR
222
223
# Connection is now in ERROR state
224
assert conn.our_state is h11.ERROR
225
```
226
227
### Connection Lifecycle Management
228
229
```python
230
def handle_connection(socket):
231
conn = h11.Connection(h11.SERVER)
232
233
while True:
234
# Check if connection should close
235
if conn.our_state is h11.MUST_CLOSE or conn.our_state is h11.CLOSED:
236
socket.close()
237
break
238
239
if conn.our_state is h11.ERROR:
240
# Protocol error - log and close
241
print("Protocol error, closing connection")
242
socket.close()
243
break
244
245
# Normal processing
246
raw_data = socket.recv(4096)
247
if not raw_data:
248
break
249
250
conn.receive_data(raw_data)
251
252
while True:
253
event = conn.next_event()
254
255
if event is h11.NEED_DATA:
256
break
257
elif event is h11.PAUSED:
258
# Ready for new request/response cycle
259
conn.start_next_cycle()
260
break
261
elif isinstance(event, h11.Request):
262
# Handle request based on current state
263
handle_request(conn, event, socket)
264
```
265
266
### Keep-Alive vs Connection Close
267
268
```python
269
def check_connection_persistence(conn):
270
"""Determine if connection will be kept alive or closed."""
271
272
if conn.our_state is h11.MUST_CLOSE:
273
return "must_close"
274
elif conn.our_state is h11.CLOSED:
275
return "closed"
276
elif conn.our_state is h11.DONE and conn.their_state is h11.DONE:
277
# Both sides done - check if keep-alive
278
next_event = conn.next_event()
279
if next_event is h11.PAUSED:
280
return "keep_alive"
281
else:
282
return "closing"
283
else:
284
return "in_progress"
285
286
# Usage
287
status = check_connection_persistence(conn)
288
if status == "keep_alive":
289
conn.start_next_cycle()
290
# Can process new request/response
291
elif status in ("must_close", "closed", "closing"):
292
# Clean up and close socket
293
pass
294
```