0
# Event System
1
2
Structured events representing HTTP/2 protocol actions and state changes. All H2Connection operations generate events that applications process to handle requests, responses, data transmission, and protocol state changes.
3
4
## Capabilities
5
6
### Base Event Class
7
8
All events inherit from the base Event class.
9
10
```python { .api }
11
class Event:
12
"""Base class for all h2 events."""
13
```
14
15
### Request/Response Events
16
17
Events related to HTTP request and response processing.
18
19
#### RequestReceived
20
21
Event generated when a complete request is received (headers with possible END_STREAM).
22
23
```python { .api }
24
class RequestReceived(Event):
25
"""
26
Request received from remote peer.
27
28
Attributes:
29
stream_id: Stream ID for the request
30
headers: List of header objects
31
stream_ended: Associated StreamEnded event if END_STREAM flag set
32
priority_updated: Associated PriorityUpdated event if priority info present
33
"""
34
stream_id: int
35
headers: list[Header]
36
stream_ended: StreamEnded | None
37
priority_updated: PriorityUpdated | None
38
```
39
40
#### ResponseReceived
41
42
Event generated when a complete response is received (headers with possible END_STREAM).
43
44
```python { .api }
45
class ResponseReceived(Event):
46
"""
47
Response received from remote peer.
48
49
Attributes:
50
stream_id: Stream ID for the response
51
headers: List of header objects
52
stream_ended: Associated StreamEnded event if END_STREAM flag set
53
priority_updated: Associated PriorityUpdated event if priority info present
54
"""
55
stream_id: int
56
headers: list[Header]
57
stream_ended: StreamEnded | None
58
priority_updated: PriorityUpdated | None
59
```
60
61
#### TrailersReceived
62
63
Event generated when HTTP trailers are received (always includes END_STREAM).
64
65
```python { .api }
66
class TrailersReceived(Event):
67
"""
68
Trailers received from remote peer.
69
70
Attributes:
71
stream_id: Stream ID for the trailers
72
headers: List of header objects
73
stream_ended: Associated StreamEnded event (always present for trailers)
74
priority_updated: Associated PriorityUpdated event if priority info present
75
"""
76
stream_id: int
77
headers: list[Header]
78
stream_ended: StreamEnded | None
79
priority_updated: PriorityUpdated | None
80
```
81
82
#### InformationalResponseReceived
83
84
Event generated when 1xx informational response is received.
85
86
```python { .api }
87
class InformationalResponseReceived(Event):
88
"""
89
Informational response (1xx) received from remote peer.
90
91
Attributes:
92
stream_id: Stream ID for the informational response
93
headers: List of header objects
94
priority_updated: Associated PriorityUpdated event if priority info present
95
"""
96
stream_id: int
97
headers: list[Header]
98
priority_updated: PriorityUpdated | None
99
```
100
101
### Data Events
102
103
Events related to data transmission and reception.
104
105
#### DataReceived
106
107
Event generated when data is received on a stream.
108
109
```python { .api }
110
class DataReceived(Event):
111
"""
112
Data received from remote peer.
113
114
Attributes:
115
stream_id: Stream ID the data was received on
116
data: Raw data bytes received
117
flow_controlled_length: Number of flow-controlled bytes (may differ from len(data) due to padding)
118
stream_ended: Associated StreamEnded event if END_STREAM flag set
119
"""
120
stream_id: int
121
data: bytes
122
flow_controlled_length: int
123
stream_ended: StreamEnded | None
124
```
125
126
### Flow Control Events
127
128
Events related to HTTP/2 flow control window management.
129
130
#### WindowUpdated
131
132
Event generated when a flow control window changes size.
133
134
```python { .api }
135
class WindowUpdated(Event):
136
"""
137
Flow control window updated.
138
139
Attributes:
140
stream_id: Stream ID whose window was updated (0 for connection window)
141
delta: Number of bytes the window was increased by
142
"""
143
stream_id: int
144
delta: int
145
```
146
147
### Stream Lifecycle Events
148
149
Events related to stream creation, termination, and management.
150
151
#### StreamEnded
152
153
Event generated when a stream is ended by a remote party.
154
155
```python { .api }
156
class StreamEnded(Event):
157
"""
158
Stream ended by remote peer.
159
160
Attributes:
161
stream_id: Stream ID that was ended
162
"""
163
stream_id: int
164
```
165
166
#### StreamReset
167
168
Event generated when a stream is reset by either party.
169
170
```python { .api }
171
class StreamReset(Event):
172
"""
173
Stream reset by local or remote peer.
174
175
Attributes:
176
stream_id: Stream ID that was reset
177
error_code: HTTP/2 error code for reset reason
178
remote_reset: True if reset by remote peer, False if reset locally
179
"""
180
stream_id: int
181
error_code: ErrorCodes | int
182
remote_reset: bool
183
```
184
185
#### PushedStreamReceived
186
187
Event generated when a pushed stream is received from a server (client-side only).
188
189
```python { .api }
190
class PushedStreamReceived(Event):
191
"""
192
Pushed stream received from server.
193
194
Attributes:
195
pushed_stream_id: Stream ID for the pushed response
196
parent_stream_id: Stream ID that initiated the push
197
headers: List of header objects for the pushed request
198
"""
199
pushed_stream_id: int
200
parent_stream_id: int
201
headers: list[Header]
202
```
203
204
### Connection Control Events
205
206
Events related to connection-level control operations.
207
208
#### PingReceived
209
210
Event generated when a PING frame is received.
211
212
```python { .api }
213
class PingReceived(Event):
214
"""
215
PING frame received from remote peer.
216
217
A ping acknowledgment with the same opaque data is automatically emitted
218
after receiving a ping.
219
220
Attributes:
221
ping_data: 8 bytes of opaque data from the PING frame
222
223
.. versionadded:: 3.1.0
224
"""
225
ping_data: bytes
226
```
227
228
#### PingAckReceived
229
230
Event generated when a PING acknowledgment is received.
231
232
```python { .api }
233
class PingAckReceived(Event):
234
"""
235
PING acknowledgment received from remote peer.
236
237
Contains the opaque data of the PING+ACK frame, allowing correlation
238
of PINGs and calculation of RTT.
239
240
Attributes:
241
ping_data: 8 bytes of opaque data from the PING+ACK frame
242
243
.. versionadded:: 3.1.0
244
.. versionchanged:: 4.0.0
245
Removed deprecated but equivalent PingAcknowledged
246
"""
247
ping_data: bytes
248
```
249
250
#### ConnectionTerminated
251
252
Event generated when a connection is terminated.
253
254
```python { .api }
255
class ConnectionTerminated(Event):
256
"""
257
Connection terminated by local or remote peer.
258
259
Attributes:
260
error_code: HTTP/2 error code for termination reason
261
last_stream_id: Last stream ID processed before termination
262
additional_data: Additional debug information
263
"""
264
error_code: ErrorCodes | int | None
265
last_stream_id: int | None
266
additional_data: bytes | None
267
```
268
269
### Settings Events
270
271
Events related to HTTP/2 settings negotiation and acknowledgment.
272
273
#### RemoteSettingsChanged
274
275
Event generated when remote peer changes its settings.
276
277
```python { .api }
278
class RemoteSettingsChanged(Event):
279
"""
280
Remote peer settings changed.
281
282
Attributes:
283
changed_settings: Dictionary of setting codes to ChangedSetting objects
284
"""
285
changed_settings: dict[int, ChangedSetting]
286
287
@classmethod
288
def from_settings(
289
cls,
290
old_settings: Settings | dict[int, int],
291
new_settings: dict[int, int]
292
) -> RemoteSettingsChanged:
293
"""
294
Create event from old and new settings.
295
296
Args:
297
old_settings: Previous settings state
298
new_settings: New settings state
299
300
Returns:
301
RemoteSettingsChanged event with populated changed_settings
302
"""
303
```
304
305
#### SettingsAcknowledged
306
307
Event generated when a settings acknowledgment is received.
308
309
```python { .api }
310
class SettingsAcknowledged(Event):
311
"""
312
Settings acknowledged by remote peer.
313
314
Attributes:
315
changed_settings: Dictionary of setting codes to ChangedSetting objects
316
"""
317
changed_settings: dict[SettingCodes | int, ChangedSetting]
318
```
319
320
### Priority Events
321
322
Events related to stream priority and dependency management.
323
324
#### PriorityUpdated
325
326
Event generated when stream priority information is updated.
327
328
```python { .api }
329
class PriorityUpdated(Event):
330
"""
331
Stream priority updated.
332
333
Attributes:
334
stream_id: Stream ID whose priority was updated
335
weight: New stream weight (1-256)
336
depends_on: Stream ID this stream depends on
337
exclusive: Whether dependency is exclusive
338
"""
339
stream_id: int | None
340
weight: int | None
341
depends_on: int | None
342
exclusive: bool | None
343
```
344
345
### Extension Events
346
347
Events related to HTTP/2 extensions and unknown frames.
348
349
#### AlternativeServiceAvailable
350
351
Event generated when alternative service is advertised.
352
353
```python { .api }
354
class AlternativeServiceAvailable(Event):
355
"""
356
Alternative service advertised by remote peer.
357
358
Attributes:
359
origin: Origin for which alternative service is available
360
field_value: Alt-Svc field value as defined in RFC 7838
361
"""
362
origin: bytes | None
363
field_value: bytes | None
364
```
365
366
#### UnknownFrameReceived
367
368
Event generated when an unknown or unsupported frame is received.
369
370
```python { .api }
371
class UnknownFrameReceived(Event):
372
"""
373
Unknown frame received from remote peer.
374
375
This occurs primarily when the remote peer is employing HTTP/2 extensions
376
that h2 doesn't know anything about.
377
378
Attributes:
379
frame: The unknown frame object
380
381
.. versionadded:: 2.7.0
382
"""
383
frame: Frame
384
```
385
386
## Header Type
387
388
For events that include headers, the `Header` type represents HTTP/2 headers:
389
390
```python { .api }
391
from typing import Union
392
from hpack.struct import Header
393
394
# Header is a union type that can be:
395
Header = Union[
396
tuple[bytes, bytes], # (name, value) as bytes
397
tuple[str, str], # (name, value) as strings
398
tuple[bytes, str], # Mixed types
399
tuple[str, bytes] # Mixed types
400
]
401
```
402
403
## Event Processing Patterns
404
405
### Basic Event Handling
406
407
Simple event processing loop for handling HTTP/2 events:
408
409
```python
410
from h2.connection import H2Connection
411
from h2.events import (
412
RequestReceived, ResponseReceived, DataReceived,
413
StreamEnded, ConnectionTerminated
414
)
415
416
def process_events(conn: H2Connection, data: bytes):
417
events = conn.receive_data(data)
418
419
for event in events:
420
if isinstance(event, RequestReceived):
421
print(f"Request on stream {event.stream_id}")
422
for name, value in event.headers:
423
print(f" {name}: {value}")
424
425
elif isinstance(event, DataReceived):
426
print(f"Data on stream {event.stream_id}: {len(event.data)} bytes")
427
# Acknowledge received data for flow control
428
conn.acknowledge_received_data(
429
acknowledged_size=event.flow_controlled_length,
430
stream_id=event.stream_id
431
)
432
433
elif isinstance(event, StreamEnded):
434
print(f"Stream {event.stream_id} ended")
435
436
elif isinstance(event, ConnectionTerminated):
437
print(f"Connection terminated: {event.error_code}")
438
break
439
440
# Send any response data
441
data_to_send = conn.data_to_send()
442
if data_to_send:
443
# Send data_to_send over your socket
444
pass
445
```
446
447
### Advanced Event Handling
448
449
More sophisticated event handling with error handling and stream management:
450
451
```python
452
from h2.connection import H2Connection
453
from h2.events import *
454
from h2.exceptions import ProtocolError
455
456
class HTTP2EventHandler:
457
def __init__(self, conn: H2Connection):
458
self.conn = conn
459
self.streams = {} # Track active streams
460
461
def handle_events(self, data: bytes):
462
try:
463
events = self.conn.receive_data(data)
464
465
for event in events:
466
handler = getattr(self, f"handle_{event.__class__.__name__}", None)
467
if handler:
468
handler(event)
469
else:
470
print(f"Unhandled event: {event.__class__.__name__}")
471
472
except ProtocolError as e:
473
print(f"Protocol error: {e}")
474
self.conn.close_connection()
475
476
return self.conn.data_to_send()
477
478
def handle_RequestReceived(self, event: RequestReceived):
479
self.streams[event.stream_id] = {
480
'headers': event.headers,
481
'method': next((v for n, v in event.headers if n == b':method'), None),
482
'path': next((v for n, v in event.headers if n == b':path'), None)
483
}
484
485
if event.stream_ended:
486
self.handle_complete_request(event.stream_id)
487
488
def handle_DataReceived(self, event: DataReceived):
489
if event.stream_id in self.streams:
490
stream_data = self.streams[event.stream_id].setdefault('data', b'')
491
self.streams[event.stream_id]['data'] = stream_data + event.data
492
493
# Acknowledge for flow control
494
self.conn.acknowledge_received_data(
495
acknowledged_size=event.flow_controlled_length,
496
stream_id=event.stream_id
497
)
498
499
if event.stream_ended:
500
self.handle_complete_request(event.stream_id)
501
502
def handle_PingReceived(self, event: PingReceived):
503
print(f"Ping received with data: {event.ping_data.hex()}")
504
# Ping acknowledgment is sent automatically
505
506
def handle_complete_request(self, stream_id: int):
507
if stream_id in self.streams:
508
stream = self.streams[stream_id]
509
print(f"Complete request on stream {stream_id}: {stream.get('method')} {stream.get('path')}")
510
# Process complete request...
511
del self.streams[stream_id]
512
```