Python wrapper for Rust's httparse HTTP parser

Overview

httparse

CI

Python wrapper for Rust's httparse. See this project on GitHub.

Example

from httparse import RequestParser

parser = RequestParser()

buff = b"GET /index.html HTTP/1.1\r\nHost"
parsed = parser.parse(buff)
assert parsed is None

# a partial request, so we try again once we have more data
buff = b"GET /index.html HTTP/1.1\r\nHost: example.domain\r\n\r\n"
parsed = parser.parse(buff)
assert parsed is not None
assert parsed.method == "GET"
assert parsed.path == "/index.html"
assert parsed.version == 1
assert parsed.body_start_byte_offset == len(buff)
headers = [(h.name, h.value.encode()) for h in parsed.headers]
assert headers == [(b"Host", b"example.com")]
You might also like...
Command line wrapper of the DeepL API

deeprs - A command line wrapper of DeepL API About deeprs is a command line wrapper of the DeepL translator API. To use it you need a API key which yo

Wrapper around atspi-code to provide higher-level at-spi Rust bindings

atspi Wrapper around atspi-codegen to provide higher-level at-spi Rust bindings. Contributions Take a look at our atspi-codegen crate, and try inpleme

Shared memory - A Rust wrapper around native shared memory for Linux and Windows

shared_memory A crate that allows you to share memory between processes. This crate provides lightweight wrappers around shared memory APIs in an OS a

Idiomatic inotify wrapper for the Rust programming language

inotify-rs Idiomatic inotify wrapper for the Rust programming language. extern crate inotify; use std::env; use inotify::{ EventMask, Watch

A wrapper around the code action dump from https://mcdiamondfire.com.

DiamondFire Action Dump for Rust A wrapper around the code action dump from https://mcdiamondfire.com. This currently only provides schema types for u

Rust wrapper for gphoto2 (mirror of https://git.maxicarlos.de/maxicarlos08/gphoto2-rs)

GPhoto2-rs Rust bindings to libgphoto2 What about gphoto-rs? I know about the other crate (gphoto and gphoto2-sys which was created by @dcuddeback, bu

Plain Rust wrapper of Ableton Link's C 11 extension

rusty_link rusty_link is a Rust wrapper of abl_link, which is a C 11 extension for Ableton Link, provided by Ableton. This library attempts to be most

A `nix` and `nix-shell` wrapper for shells other than `bash`

nix-your-shell A nix and nix-shell wrapper for shells other than bash. nix develop and nix-shell use bash as the default shell, so nix-your-shell prin

An unofficial rust wrapper for hyprland's IPC [maintainer=@yavko]

Hyprland-rs An unofficial rust wrapper for Hyprland's IPC Disclaimer If something doesn't work, doesn't matter what, make sure you are on the latest c

Comments
  • perf: Use string interning for HTTP methods & popular headers

    perf: Use string interning for HTTP methods & popular headers

    Hey! Thank you for working on this!

    This PR shows possible performance improvements via string interning. I guess it might be a bit slower for one-off use cases (but I assume they are pretty rare) due to the cell overhead, but shows a consistent improvement in the benchmark locally - 1.44 µs (main) vs. 1.26 µs (this branch) which is >10%.

    Let me know what you think! The PR is mostly to start a discussion about whether it is the right direction or not.

    P.S. header names are chosen based on the benchmark and are highly arbitrary, but I guess that interning should be done for the most popular ones.

    opened by Stranger6667 5
  • Macro for interning & clippy fixes

    Macro for interning & clippy fixes

    Hey!

    These are assorted changes that:

    • Make the interning process more reliable as there is no need to duplicate the string in the match statement
    • Adjust the code a bit so various Clippy lints are happy (I didn't include them though)
    • Add InvalidStatus exception

    it also reduces nesting a bit, which IMO improves readability. Let me know what you think :)

    opened by Stranger6667 2
  • Fix typos in README example

    Fix typos in README example

    Hey there,

    Pretty interesting one.

    I was playing around with this and ran into issues running the README example. Here's a PR with the changes I had to make to make it pass. :)

    Also I had a question -- how does httparse (the Rust version or this one) handle parsing the body? Is the client code supposed to basically join the rest of its buffer or whatever it's using to get data from the network, starting at body_start_offset? Edit: answered that question for myself — looks like that works!

    opened by florimondmanca 1
  • Consider adding `parse` as a free standing function

    Consider adding `parse` as a free standing function

    What do you think of adding httparse.parse function, so the user doesn't have to create a parser instance? E.g.

    #[pyfunction]
    fn parse(buff: &PyBytes, py: Python<'_>) -> PyResult<Option<ParsedRequest>> {
        ...
    }
    

    The code pyo3 generates for the class method involves a few extra steps (working with PyCell to get the RequestParser instance), which should be slower than using a free-standing function. In my local experiments, I can observe this difference.

    Method code
    unsafe extern "C" fn __pymethod_parse__(
        _slf: *mut _pyo3::ffi::PyObject,
        _args: *mut _pyo3::ffi::PyObject,
        _kwargs: *mut _pyo3::ffi::PyObject,
    ) -> *mut _pyo3::ffi::PyObject {
        let gil = _pyo3::GILPool::new();
        let _py = gil.python();
        _pyo3::callback::panic_result_into_callback_output(
            _py,
            ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
                let _cell = _py
                    .from_borrowed_ptr::<_pyo3::PyAny>(_slf)
                    .downcast::<_pyo3::PyCell<RequestParser>>()?;
                let mut _ref = _cell.try_borrow_mut()?;
                let _slf: &mut RequestParser = &mut *_ref;
                const DESCRIPTION: _pyo3::impl_::extract_argument::FunctionDescription =
                    _pyo3::impl_::extract_argument::FunctionDescription {
                        cls_name: ::std::option::Option::Some(
                            <RequestParser as _pyo3::type_object::PyTypeInfo>::NAME,
                        ),
                        func_name: "parse",
                        positional_parameter_names: &["buff"],
                        positional_only_parameters: 0usize,
                        required_positional_parameters: 1usize,
                        keyword_only_parameters: &[],
                    };
                let mut output = [::std::option::Option::None; 1usize];
                let (_args, _kwargs) = DESCRIPTION.extract_arguments_tuple_dict::<_pyo3::impl_::extract_argument::NoVarargs, _pyo3::impl_::extract_argument::NoVarkeywords>(_py, _args, _kwargs, &mut output)?;
                let mut ret = RequestParser::parse(
                    _slf,
                    _pyo3::impl_::extract_argument::extract_argument(
                        _pyo3::impl_::extract_argument::unwrap_required_argument(output[0usize]),
                        &mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
                        "buff",
                    )?,
                    _py,
                );
                if false {
                    use _pyo3::impl_::ghost::IntoPyResult;
                    ret.assert_into_py_result();
                }
                _pyo3::callback::convert(_py, ret)
            }),
        )
    }
    
    Function code
    unsafe extern "C" fn __pyfunction_parse(
        _slf: *mut _pyo3::ffi::PyObject,
        _args: *mut _pyo3::ffi::PyObject,
        _kwargs: *mut _pyo3::ffi::PyObject,
    ) -> *mut _pyo3::ffi::PyObject {
        let gil = _pyo3::GILPool::new();
        let _py = gil.python();
        _pyo3::callback::panic_result_into_callback_output(
            _py,
            ::std::panic::catch_unwind(move || -> _pyo3::PyResult<_> {
                const DESCRIPTION: _pyo3::impl_::extract_argument::FunctionDescription =
                    _pyo3::impl_::extract_argument::FunctionDescription {
                        cls_name: ::std::option::Option::None,
                        func_name: "parse",
                        positional_parameter_names: &["buff"],
                        positional_only_parameters: 0usize,
                        required_positional_parameters: 1usize,
                        keyword_only_parameters: &[],
                    };
                let mut output = [::std::option::Option::None; 1usize];
                let (_args, _kwargs) = DESCRIPTION.extract_arguments_tuple_dict::<_pyo3::impl_::extract_argument::NoVarargs, _pyo3::impl_::extract_argument::NoVarkeywords>(_py, _args, _kwargs, &mut output)?;
                let mut ret = parse(
                    _pyo3::impl_::extract_argument::extract_argument(
                        _pyo3::impl_::extract_argument::unwrap_required_argument(output[0usize]),
                        &mut { _pyo3::impl_::extract_argument::FunctionArgumentHolder::INIT },
                        "buff",
                    )?,
                    _py,
                );
                if false {
                    use _pyo3::impl_::ghost::IntoPyResult;
                    ret.assert_into_py_result();
                }
                _pyo3::callback::convert(_py, ret)
            }),
        )
    }
    

    Though, the parser instance still could be helpful for cases if you'd like to pass some configuration to the httparse::Request::parse call.

    Let me know what you think about this possible API design approach :)

    opened by Stranger6667 1
Owner
Adrian Garcia Badaracco
Adrian Garcia Badaracco
🐎 A fast implementation of the Aho-Corasick algorithm using the compact double-array data structure. (Python wrapper for daachorse)

python-daachorse daachorse is a fast implementation of the Aho-Corasick algorithm using the compact double-array data structure. This is a Python wrap

Koichi Akabe 11 Nov 30, 2022
Python wrapper around reth db. Written in Rust.

reth-db-py Bare-bones Python package allowing you to interact with the Reth DB via Python. Written with Rust and Pyo3. This python wrapper can access

gibz 44 Jul 3, 2023
⚡ Blazing fast async/await HTTP client for Python written on Rust using reqwests

Reqsnaked Reqsnaked is a blazing fast async/await HTTP client for Python written on Rust using reqwests. Works 15% faster than aiohttp on average RAII

Yan Kurbatov 8 Mar 2, 2023
Rust Imaging Library's Python binding: A performant and high-level image processing library for Python written in Rust

ril-py Rust Imaging Library for Python: Python bindings for ril, a performant and high-level image processing library written in Rust. What's this? Th

Cryptex 13 Dec 6, 2022
A low-level ncurses wrapper for Rust

ncurses-rs This is a very thin wrapper around the ncurses TUI lib. NOTE: The ncurses lib is terribly unsafe and ncurses-rs is only the lightest wrappe

Jeaye Wilkerson 628 Jan 7, 2023
ddi is a wrapper for dd. It takes all the same arguments, and all it really does is call dd in the background

ddi A safer dd Introduction If you ever used dd, the GNU coreutil that lets you copy data from one file to another, then you may have encountered a ty

Tomás Ralph 80 Sep 8, 2022
A small CLI wrapper for authenticating with SSH keys from Hashicorp Vault

vaultssh A small CLI wrapper for authenticating with SSH keys from Hashicorp Vault vaultssh is a small CLI wrapper for automatically fetching and usin

Joshua Gilman 50 Dec 10, 2022
A newtype wrapper that causes Debug impls to skip a field.

debug-ignore This library contains DebugIgnore, a newtype wrapper that causes a field to be skipped while printing out Debug output. Examples use debu

Rain 15 Sep 22, 2022
argmax is a library that allows Rust applications to avoid Argument list too long errors (E2BIG) by providing a std::process::Command wrapper with a

argmax argmax is a library that allows Rust applications to avoid Argument list too long errors (E2BIG) by providing a std::process::Command wrapper w

David Peter 22 Nov 20, 2022
🌌⭐cosmo is a wrapper for Git essentially, allowing you to compress multiple commands into one

❯ Cosmo Git tooling of the future New feature: Cosmo hooks! Click here for more info! ❯ ?? Features Config files (with defaults!) Fast Easy to use Fri

Jack 1 Oct 31, 2021