h2: Pure-Python HTTP/2 Protocol Implementation
h2 is a pure-Python, self-contained implementation of the HTTP/2 protocol stack. It handles the low-level framing and state machine, allowing users to build HTTP/2 clients and servers without dealing with raw I/O. The library aims for 100% compatibility with RFC 7540 and is designed to be embeddable in various concurrency models. The current version is 4.3.0, and it has a regular release cadence with notable updates and breaking changes between major versions.
Warnings
- breaking As of v4.3.0, many event classes (e.g., `RequestReceived`, `DataReceived`) have been converted to Python dataclasses. This means they now have required arguments for instantiation. Directly instantiating these events without arguments, a common previous API pattern, will no longer work.
- breaking The `client_side` and `header_encoding` arguments and properties of `H2Connection` were deprecated and subsequently removed. Headers are now returned as byte strings by default, and `dict` objects are no longer allowed for user-supplied headers; a sequence of 2-tuples must be used.
- breaking Header field names and values with leading/trailing whitespace are now rejected. Also, specific headers (e.g., `TE` not equal to `trailers`, connection-specific headers) are strictly enforced according to RFC 7540 and will cause rejections or normalization.
- gotcha `h2` is a purely in-memory protocol stack. It does not handle network I/O, concurrency, or parsing beyond the HTTP/2 frame layer. Users must implement their own networking (e.g., sockets), buffering, and event loops.
- gotcha Automatic flow control window management was introduced in v2.5.0 via `acknowledge_received_data`. Before this, users had to manually call `increment_flow_control_window` for both stream and connection level windows, which is a common source of deadlock or stalls if not handled correctly.
- breaking Support for Python 3.9 and PyPy 3.9 has been removed.
Install
-
pip install h2
Imports
- H2Connection
from h2.connection import H2Connection
- H2Configuration
from h2.config import H2Configuration
- ConnectionClosed
from h2.errors import ConnectionClosed
- RequestReceived
from h2.events import RequestReceived
Quickstart
import h2.connection
import h2.config
import os
# Example: Initialize H2Connection for a client or server
config = h2.config.H2Configuration(client_side=True) # or False for server_side
conn = h2.connection.H2Connection(config=config)
# Example of sending a request (client-side)
stream_id = conn.get_next_available_stream_id()
headers = [
(':method', 'GET'),
(':authority', os.environ.get('H2_EXAMPLE_AUTHORITY', 'example.com')),
(':scheme', 'https'),
(':path', '/')
]
conn.send_headers(stream_id=stream_id, headers=headers)
conn.end_stream(stream_id)
# Data to send over the wire (conceptual)
data_to_send = conn.data_to_send()
if data_to_send:
# In a real application, you would send this data over a socket.
# print(f"Sending {len(data_to_send)} bytes: {data_to_send!r}")
pass
# Simulate receiving data and processing events
# events = conn.receive_data(received_bytes)
# for event in events:
# if isinstance(event, h2.events.RequestReceived):
# print(f"Request received on stream {event.stream_id}")
print("h2 connection initialized and example headers sent.")