Pure-Python HTTP/2 framing

raw JSON →
6.1.0 verified Tue May 12 auth: no python install: verified quickstart: verified

hyperframe is a pure-Python library providing the HTTP/2 framing code used in the hyper project. It allows for creating, serializing, and parsing HTTP/2 frames from a binary stream. The current version is 6.1.0, and it is actively maintained as part of the python-hyper organization.

pip install hyperframe
error ModuleNotFoundError: No module named 'hyperframe'
cause The 'hyperframe' library is not installed in your Python environment or the environment where your code is being executed.
fix
Install the 'hyperframe' package using pip: pip install hyperframe
error hyperframe.exceptions.UnknownFrameError
cause This error occurs when the 'hyperframe' library receives or attempts to parse an HTTP/2 frame with a type byte that it does not recognize, which can happen with custom frames or malformed data.
fix
Ensure the input data stream contains valid HTTP/2 frames. If you are intentionally working with extension frames, handle them using hyperframe.frame.ExtensionFrame or by passing strict=False to parsing functions if applicable, and then inspect the frame.type attribute.
error hyperframe.exceptions.InvalidPaddingError
cause This exception is raised when parsing a padded HTTP/2 frame (like DATA, HEADERS, or PUSH_PROMISE) where the padding length specified in the frame header is invalid or exceeds the frame's body length.
fix
Verify that the incoming HTTP/2 frame data is correctly formed according to the HTTP/2 specification, especially regarding padding length. If you are creating frames, ensure the pad_length (or deprecated total_padding) parameter is valid for the frame's body size.
error hyperframe.exceptions.InvalidDataError
cause This error, introduced in hyperframe 6.0.0, indicates that a frame's data content or specific fields violate HTTP/2 specification rules, such as an invalid stream ID for a frame type (e.g., DATA frame with stream ID 0) or malformed SETTINGS/ALTSVC frames.
fix
Inspect the specific frame and its attributes that triggered the InvalidDataError. Correct the stream ID, flag combinations, or data fields to conform to the HTTP/2 specification for that frame type. For example, DATA frames cannot have a stream ID of 0.
breaking In version 6.0.0, the base class for `InvalidPaddingError` and `InvalidFrameError` exceptions changed from `ValueError` to `HyperframeError`. `HyperframeError` was introduced as the new base class for all exceptions in the module.
fix Catch `HyperframeError` or more specific `hyperframe.exceptions` instead of `ValueError` for frame-related errors.
gotcha Starting with version 5.0.0, `hyperframe` no longer raises an exception for unknown frame types. Instead, it wraps them in an `ExtensionFrame` object. This means code expecting exceptions for unknown frames will need to handle `ExtensionFrame` instead.
fix Inspect the type of the parsed frame; if it's an `ExtensionFrame`, process its `frame_type` and `data` attributes or ignore it as appropriate.
gotcha The `parse_body` and `parse_frame_header` methods expect `memoryview` objects for performance reasons. Passing raw `bytes` or `bytearray` directly might work in some contexts but is not the intended or most efficient usage.
fix Always convert binary data to `memoryview` before passing it to parsing methods, e.g., `memoryview(my_bytes_object)`.
python os / libc status wheel install import disk
3.10 alpine (musl) - - 0.01s 17.9M
3.10 slim (glibc) - - 0.01s 18M
3.11 alpine (musl) - - 0.03s 19.7M
3.11 slim (glibc) - - 0.02s 20M
3.12 alpine (musl) - - 0.03s 11.6M
3.12 slim (glibc) - - 0.03s 12M
3.13 alpine (musl) - - 0.01s 11.2M
3.13 slim (glibc) - - 0.01s 12M
3.9 alpine (musl) - - 0.01s 17.4M
3.9 slim (glibc) - - 0.01s 18M

This example demonstrates creating a `DataFrame`, adding data and flags, serializing it, and then parsing the header and body of a frame from raw bytes. It showcases the basic workflow for working with HTTP/2 frames. Note the use of `memoryview` for efficient binary data handling during parsing.

from hyperframe.frame import DataFrame, Frame

# Create a DATA frame
f = DataFrame(stream_id=5)
f.data = b'some binary data'
f.flags.add('END_STREAM')
f.flags.add('PADDED')
f.padding_length = 30

# Serialize the frame
data = f.serialize()
print(f"Serialized frame: {data.hex()}")

# Parse a frame header from binary data
header_bytes = data[:9] # HTTP/2 frame headers are 9 bytes
parsed_frame_header, length = Frame.parse_frame_header(memoryview(header_bytes))
print(f"Parsed frame type: {type(parsed_frame_header).__name__}, Stream ID: {parsed_frame_header.stream_id}, Length to read: {length}")

# Parse the frame body
body_bytes = data[9:9 + length]
parsed_frame_header.parse_body(memoryview(body_bytes))
print(f"Parsed frame flags: {parsed_frame_header.flags}, Data: {parsed_frame_header.data}")