Registry / http-networking / h2

h2

JSON →
library5.0.11pypypi✓ verified 52d ago

h2 is a Python library that provides a state-machine based implementation of the HTTP/2 protocol, allowing for low-level interaction with HTTP/2 connections. It is currently at version 5.0.11 and maintains a regular release cadence, often driven by performance improvements and updates to underlying Rust dependencies via `pyo3`.

http-networking
pip install h2
Install & Compatibility
Where this runs
tested against v4.3.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.925 runs
installs and imports cleanly · install 0.0s · import 0.529s · 19MB
glibc
py 3.103.925 runs
installs and imports cleanly · install 1.7s · import 0.624s · 20MB
17MB installed
● package 17MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

H2Connection
from h2.connection import H2Connection
events
from h2 import events

Initializes an HTTP/2 client connection, sends the connection preamble, and then sends a GET request with headers. It then explains the event-driven nature of `h2` for receiving and processing data, which requires explicit integration with a network I/O layer.

import h2.connection import h2.events # 1. Initialize the H2Connection object for a client-side connection. conn = h2.connection.H2Connection(client_side=True) print("Connection initialized.") # 2. Initiate the HTTP/2 connection by sending the preamble (SETTINGS frame). conn.initiate_connection() preamble_bytes = conn.data_to_send() print(f"Preamble bytes to send: {preamble_bytes!r}") # In a real application, you would send 'preamble_bytes' over the network (e.g., after TLS handshake). # 3. Start a new stream and send headers for a GET request. stream_id = conn.get_next_available_stream_id() headers = [ (':method', 'GET'), (':authority', 'example.com'), (':scheme', 'https'), (':path', '/'), ('user-agent', 'h2-example/1.0'), ] conn.send_headers(stream_id, headers, end_stream=True) request_bytes = conn.data_to_send() print(f"Request headers bytes for stream {stream_id} to send: {request_bytes!r}") # In a real application, you would send 'request_bytes' over the network. print("\n--- Event Processing Explanation ---") print("After sending data, your application would continuously:") print("1. Read bytes from the network (e.g., from a socket or asynchronous transport).") print("2. Call `conn.receive_data(received_bytes)` to process them.") print("3. Iterate through the `events` (e.g., `h2.events.ResponseReceived`, `h2.events.DataReceived`) returned by `receive_data`.") print("4. Handle each event type to manage connection and stream state.") print("5. For `DataReceived`, call `conn.acknowledge_received_data(...)` for flow control.") print("6. Call `conn.data_to_send()` regularly to get bytes to write back to the network (e.g., `WINDOW_UPDATE`, `ACK` frames).") print("This example demonstrates the core API calls for a client-side connection and sending an initial request.")
Debug
Known issues
breakingA significant API rewrite occurred in v3.0 (released March 2017). Users migrating from `h2 < 3.0` will encounter breaking changes, including `dict` objects no longer being accepted for headers (requiring sequences of 2-tuples) and various method renamings or alterations.
fix
Refer to the `h2` documentation and changelog for v3.0 migration. Update header arguments to a list of `(name, value)` byte-string tuples. Review API calls for changed method signatures.
affects: <3.0 to >=3.0
gotcha`h2` is a pure HTTP/2 state machine and does NOT handle any network I/O (sockets, TLS, buffering). Users must integrate `h2.connection.H2Connection` with their chosen I/O layer (e.g., `socket`, `asyncio`, `trio`) to send and receive raw bytes.
fix
Implement explicit I/O loops that read data from the network, pass it to `H2Connection.receive_data()`, get output bytes from `H2Connection.data_to_send()`, and write them back to the network.
affects: All versions
gotchaThe library is event-driven. Your application MUST diligently process ALL events returned by `H2Connection.receive_data()`. Crucially, you must call `H2Connection.acknowledge_received_data()` for received data frames and then `H2Connection.data_to_send()` to send `WINDOW_UPDATE` frames, otherwise, flow control will stall the connection.
fix
Implement a comprehensive event handling loop that iterates through all `h2.events.Event` objects. Ensure `acknowledge_received_data` is called for every `DataReceived` event and `data_to_send` is regularly invoked to push out flow control updates.
affects: All versions
gotchaHeaders provided to methods like `H2Connection.send_headers()` must be a list of 2-tuple byte-strings `[(b':method', b'GET'), (b'host', b'example.com')]`. Dictionaries are not allowed, as HTTP/2 requires pseudo-headers to appear first and maintains header field order.
fix
Always construct headers as `list[tuple[bytes, bytes]]` (or automatically encoded tuples if `header_encoding` is set) to maintain order and adhere to HTTP/2 specifications.
affects: >=3.0
Errors
Common errors & fixes
h2.exceptions.ProtocolError: An action was attempted in violation of the HTTP/2 protocol.
This general error often indicates a violation of HTTP/2 protocol rules, such as sending more data than allowed by flow control windows, or sending malformed HTTP/2 header blocks (e.g., missing mandatory pseudo-headers like ':method', ':scheme', ':path' for requests, or sending connection-specific headers).
fix
For flow control issues, ensure you check the available window using `conn.local_flow_control_window(stream_id)` before sending data and segment large data into smaller frames. For header issues, verify that your header lists adhere to RFC 7540 specifications, including correct pseudo-headers and avoiding forbidden connection-specific headers (like 'connection', 'keep-alive', 'transfer-encoding'). Example for checking flow control:

```python
import h2.connection

conn = h2.connection.H2Connection()
stream_id = conn.get_next_available_stream_id()

# ... (send headers, etc.)

data_to_send = b'some data'
max_send = conn.local_flow_control_window(stream_id)
if len(data_to_send) > max_send:
    # Split data or wait for a WINDOW_UPDATE event
    print(f'Cannot send all data. Available window: {max_send}')
else:
    conn.send_data(stream_id, data_to_send)
```
h2.exceptions.StreamClosedError: A stream-specific action referenced a stream that does not exist.
This error occurs when you attempt an operation (like sending data, headers, or a reset) on an HTTP/2 stream that the `h2` state machine considers already closed. This often happens due to timing mismatches with the remote peer's state or if `h2` has already cleaned up the stream's state, for instance, after receiving an `END_STREAM` flag or a `RST_STREAM` frame.
fix
Implement robust state management for your HTTP/2 streams. After receiving `StreamEnded` or `StreamReset` events, avoid further operations on that specific `stream_id`. If interacting with a remote peer that sends frames (like `RST_STREAM` or `WINDOW_UPDATE`) on a stream that your `h2` connection has already marked as closed, consider gracefully ignoring these events in your event loop after the stream has transitioned to a terminal state.
AttributeError: module 'h2.settings' has no attribute 'ENABLE_PUSH'
This `AttributeError` typically arises when using code written for an older version of the `h2` library (or a library that depends on an older `h2` API) with a newer `h2` installation (e.g., `h2` version 3.0.0 or higher). In newer versions, the HTTP/2 setting constants, such as `ENABLE_PUSH`, were moved from direct attributes of the `h2.settings` module into the `h2.settings.SettingCodes` enumeration.
fix
Update your code to reference the setting constants through `h2.settings.SettingCodes`. For example, change `h2.settings.ENABLE_PUSH` to `h2.settings.SettingCodes.ENABLE_PUSH`. If you are using an external library that has this issue, you might need to upgrade that library to a version compatible with your `h2` installation, or temporarily pin your `h2` version to an older release (e.g., `pip install 'h2<3.0.0'`) if compatible updates are not available.
h2.exceptions.TooManyStreamsError
This error is raised when an attempt is made to open a new HTTP/2 stream, but doing so would exceed the maximum number of concurrent streams allowed by the remote peer (as defined by its `SETTINGS_MAX_CONCURRENT_STREAMS` setting) or by your local configuration.
fix
Ensure that your application respects the `SETTINGS_MAX_CONCURRENT_STREAMS` advertised by the remote peer. If you are acting as a client, you should not initiate more streams than the remote server allows. If you are acting as a server, you can configure your own `SETTINGS_MAX_CONCURRENT_STREAMS` and ensure client requests don't exceed it. When a stream is closed, its slot for concurrent streams becomes available again. Wait for streams to close before opening new ones if you are near the limit.

```python
import h2.connection

conn = h2.connection.H2Connection()
# ... process settings from remote peer ...

# Example: if remote_max_concurrent_streams is known from SETTINGS_MAX_CONCURRENT_STREAMS
# if conn.open_outbound_streams < remote_max_concurrent_streams:
#     stream_id = conn.get_next_available_stream_id()
#     conn.send_headers(stream_id, headers, end_stream=False)
# else:
#     print('Too many concurrent streams, wait for one to close.')
```
Upgrade
Version history
4.3.0latest on PyPI
Audit
Dependencies

No dependency data recorded yet.

Agent activity
11 hits · last 30 days
seranking-bot
4
node
2
ahrefsbot
2
Amazon
1
Resources