Skip to main content

pyllhttp

Python wrapper for llhttp

A fork of llhttp compatible with subinterpreters

======

A simple Python wrapper around llhttp, the HTTP parser for Node.js.

Install

pyllhttp via PyPI, or pip install pyllhttp

Usage

import llhttp
from pprint import pprint

pprint({"version": llhttp.version})

class request_parser(llhttp.Request):
    headers = {}

    url = b''
    current_header_field = None
    current_header_value = None

    def on_message_begin(self):
        print(f"MESSAGE BEGIN")

    def on_url(self, url):
        self.url += url
        self.pause()

    def on_url_complete(self):
        print(f"URL {self.url}")

    def on_header_field(self, field):
        assert self.current_header_value is None
        if self.current_header_field is None:
            self.current_header_field = bytearray(field)
        else:
            self.current_header_field += field

    def on_header_field_complete(self):
        self.current_header_field = self.current_header_field.decode('iso-8859-1').lower()
        assert self.current_header_field not in self.headers

    def on_header_value(self, value):
        assert self.current_header_field is not None
        if self.current_header_value is None:
            self.current_header_value = bytearray(value)
        else:
            self.current_header_value += value

    def on_header_value_complete(self):
        assert self.current_header_field is not None
        self.current_header_value = bytes(self.current_header_value)
        print(f"HEADER {self.current_header_field}: {self.current_header_value}")
        self.headers[self.current_header_field] = self.current_header_value
        self.current_header_field = None
        self.current_header_value = None

    def on_headers_complete(self):
        assert self.current_header_field is None
        assert self.current_header_value is None

    def on_message_complete(self):
        print("MESSAGE COMPLETE")

parser = request_parser()

assert parser.lenient_headers is not True
parser.lenient_headers = True
parser.reset()
assert parser.lenient_headers is True

buffer = b"GET /test HTTP/1.1\r\nlOl:wut\r\nOH: hai\r\n\r\n"
while buffer:
    consumed = parser.execute(buffer[:2])
    buffer = buffer[consumed:]
    if parser.is_paused:
        print("UNPAUSING")
        parser.unpause()

parser.finish()
pprint({
    "method": parser.method,
    "url": parser.url,
    "version": f"{parser.major}.{parser.minor}",
    "headers": parser.headers,
})
{'version': '3.0.0'}
MESSAGE BEGIN
UNPAUSING
UNPAUSING
UNPAUSING
URL b'/test'
HEADER lol: b'wut'
HEADER oh: b'hai'
MESSAGE COMPLETE
{'headers': {'lol': b'wut', 'oh': b'hai'},
 'method': 'GET',
 'url': b'/test',
 'version': '1.1'}

Extra

This project is a toy, started to reacquaint myself with Python c-api modules. If you find it useful, please let me know.

The version number tracks the version of the incorporated llhttp.

License: MIT

Metadata

Release files for pyllhttp 6.8.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyllhttp 6.8.0
File Size Uploaded Provenance
pyllhttp-6.8.0.tar.gz 41.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pyllhttp 6.8.0
File Interpreter ABI Platform
pyllhttp-6.8.0-cp313-cp313-macosx_15_0_arm64.whl CPython 3.13 CPython 3.13 macOS 15.0+ ARM64 Details

Total release size: 82.9 kB

Release files / pyllhttp-6.8.0.tar.gz

Download URL pyllhttp-6.8.0.tar.gz
Size 41.0 kB
Tags Source
SHA-256 checksum
How to use checksums
bcd7e0d265503d5b69c56f7eae944a81a445d2d1a01c0ab90a26050579e564e1
BLAKE2b-256 checksum
How to use checksums
26a771623ee0073184b13fb497b9e146fd7da1082bfa4c6bc685fb1afd281004
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.0

Release files / pyllhttp-6.8.0-cp313-cp313-macosx_15_0_arm64.whl

Download URL pyllhttp-6.8.0-cp313-cp313-macosx_15_0_arm64.whl
Size 41.9 kB
Tags CPython 3.13 macOS 15.0+ ARM64
SHA-256 checksum
How to use checksums
a95dfdd488062576a32816d19eef5d5df8eb2e29b172770c3989ac8f656c2c4d
BLAKE2b-256 checksum
How to use checksums
d67c9914ffc6c61c7921adc0a639a0c8d10a5d2b1f555e4ad3dfc8c6137a9153
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.0

Security for pyllhttp 6.8.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page