jpayne@68: Metadata-Version: 2.1 jpayne@68: Name: h11 jpayne@68: Version: 0.14.0 jpayne@68: Summary: A pure-Python, bring-your-own-I/O implementation of HTTP/1.1 jpayne@68: Home-page: https://github.com/python-hyper/h11 jpayne@68: Author: Nathaniel J. Smith jpayne@68: Author-email: njs@pobox.com jpayne@68: License: MIT jpayne@68: Classifier: Development Status :: 3 - Alpha jpayne@68: Classifier: Intended Audience :: Developers jpayne@68: Classifier: License :: OSI Approved :: MIT License jpayne@68: Classifier: Programming Language :: Python :: Implementation :: CPython jpayne@68: Classifier: Programming Language :: Python :: Implementation :: PyPy jpayne@68: Classifier: Programming Language :: Python :: 3 jpayne@68: Classifier: Programming Language :: Python :: 3 :: Only jpayne@68: Classifier: Programming Language :: Python :: 3.7 jpayne@68: Classifier: Programming Language :: Python :: 3.8 jpayne@68: Classifier: Programming Language :: Python :: 3.9 jpayne@68: Classifier: Programming Language :: Python :: 3.10 jpayne@68: Classifier: Topic :: Internet :: WWW/HTTP jpayne@68: Classifier: Topic :: System :: Networking jpayne@68: Requires-Python: >=3.7 jpayne@68: License-File: LICENSE.txt jpayne@68: Requires-Dist: typing-extensions ; python_version < "3.8" jpayne@68: jpayne@68: h11 jpayne@68: === jpayne@68: jpayne@68: .. image:: https://travis-ci.org/python-hyper/h11.svg?branch=master jpayne@68: :target: https://travis-ci.org/python-hyper/h11 jpayne@68: :alt: Automated test status jpayne@68: jpayne@68: .. image:: https://codecov.io/gh/python-hyper/h11/branch/master/graph/badge.svg jpayne@68: :target: https://codecov.io/gh/python-hyper/h11 jpayne@68: :alt: Test coverage jpayne@68: jpayne@68: .. image:: https://readthedocs.org/projects/h11/badge/?version=latest jpayne@68: :target: http://h11.readthedocs.io/en/latest/?badge=latest jpayne@68: :alt: Documentation Status jpayne@68: jpayne@68: This is a little HTTP/1.1 library written from scratch in Python, jpayne@68: heavily inspired by `hyper-h2 `_. jpayne@68: jpayne@68: It's a "bring-your-own-I/O" library; h11 contains no IO code jpayne@68: whatsoever. This means you can hook h11 up to your favorite network jpayne@68: API, and that could be anything you want: synchronous, threaded, jpayne@68: asynchronous, or your own implementation of `RFC 6214 jpayne@68: `_ -- h11 won't judge you. jpayne@68: (Compare this to the current state of the art, where every time a `new jpayne@68: network API `_ comes along then someone jpayne@68: gets to start over reimplementing the entire HTTP protocol from jpayne@68: scratch.) Cory Benfield made an `excellent blog post describing the jpayne@68: benefits of this approach jpayne@68: `_, or if you like video jpayne@68: then here's his `PyCon 2016 talk on the same theme jpayne@68: `_. jpayne@68: jpayne@68: This also means that h11 is not immediately useful out of the box: jpayne@68: it's a toolkit for building programs that speak HTTP, not something jpayne@68: that could directly replace ``requests`` or ``twisted.web`` or jpayne@68: whatever. But h11 makes it much easier to implement something like jpayne@68: ``requests`` or ``twisted.web``. jpayne@68: jpayne@68: At a high level, working with h11 goes like this: jpayne@68: jpayne@68: 1) First, create an ``h11.Connection`` object to track the state of a jpayne@68: single HTTP/1.1 connection. jpayne@68: jpayne@68: 2) When you read data off the network, pass it to jpayne@68: ``conn.receive_data(...)``; you'll get back a list of objects jpayne@68: representing high-level HTTP "events". jpayne@68: jpayne@68: 3) When you want to send a high-level HTTP event, create the jpayne@68: corresponding "event" object and pass it to ``conn.send(...)``; jpayne@68: this will give you back some bytes that you can then push out jpayne@68: through the network. jpayne@68: jpayne@68: For example, a client might instantiate and then send a jpayne@68: ``h11.Request`` object, then zero or more ``h11.Data`` objects for the jpayne@68: request body (e.g., if this is a POST), and then a jpayne@68: ``h11.EndOfMessage`` to indicate the end of the message. Then the jpayne@68: server would then send back a ``h11.Response``, some ``h11.Data``, and jpayne@68: its own ``h11.EndOfMessage``. If either side violates the protocol, jpayne@68: you'll get a ``h11.ProtocolError`` exception. jpayne@68: jpayne@68: h11 is suitable for implementing both servers and clients, and has a jpayne@68: pleasantly symmetric API: the events you send as a client are exactly jpayne@68: the ones that you receive as a server and vice-versa. jpayne@68: jpayne@68: `Here's an example of a tiny HTTP client jpayne@68: `_ jpayne@68: jpayne@68: It also has `a fine manual `_. jpayne@68: jpayne@68: FAQ jpayne@68: --- jpayne@68: jpayne@68: *Whyyyyy?* jpayne@68: jpayne@68: I wanted to play with HTTP in `Curio jpayne@68: `__ and `Trio jpayne@68: `__, which at the time didn't have any jpayne@68: HTTP libraries. So I thought, no big deal, Python has, like, a dozen jpayne@68: different implementations of HTTP, surely I can find one that's jpayne@68: reusable. I didn't find one, but I did find Cory's call-to-arms jpayne@68: blog-post. So I figured, well, fine, if I have to implement HTTP from jpayne@68: scratch, at least I can make sure no-one *else* has to ever again. jpayne@68: jpayne@68: *Should I use it?* jpayne@68: jpayne@68: Maybe. You should be aware that it's a very young project. But, it's jpayne@68: feature complete and has an exhaustive test-suite and complete docs, jpayne@68: so the next step is for people to try using it and see how it goes jpayne@68: :-). If you do then please let us know -- if nothing else we'll want jpayne@68: to talk to you before making any incompatible changes! jpayne@68: jpayne@68: *What are the features/limitations?* jpayne@68: jpayne@68: Roughly speaking, it's trying to be a robust, complete, and non-hacky jpayne@68: implementation of the first "chapter" of the HTTP/1.1 spec: `RFC 7230: jpayne@68: HTTP/1.1 Message Syntax and Routing jpayne@68: `_. That is, it mostly focuses on jpayne@68: implementing HTTP at the level of taking bytes on and off the wire, jpayne@68: and the headers related to that, and tries to be anal about spec jpayne@68: conformance. It doesn't know about higher-level concerns like URL jpayne@68: routing, conditional GETs, cross-origin cookie policies, or content jpayne@68: negotiation. But it does know how to take care of framing, jpayne@68: cross-version differences in keep-alive handling, and the "obsolete jpayne@68: line folding" rule, so you can focus your energies on the hard / jpayne@68: interesting parts for your application, and it tries to support the jpayne@68: full specification in the sense that any useful HTTP/1.1 conformant jpayne@68: application should be able to use h11. jpayne@68: jpayne@68: It's pure Python, and has no dependencies outside of the standard jpayne@68: library. jpayne@68: jpayne@68: It has a test suite with 100.0% coverage for both statements and jpayne@68: branches. jpayne@68: jpayne@68: Currently it supports Python 3 (testing on 3.7-3.10) and PyPy 3. jpayne@68: The last Python 2-compatible version was h11 0.11.x. jpayne@68: (Originally it had a Cython wrapper for `http-parser jpayne@68: `_ and a beautiful nested state jpayne@68: machine implemented with ``yield from`` to postprocess the output. But jpayne@68: I had to take these out -- the new *parser* needs fewer lines-of-code jpayne@68: than the old *parser wrapper*, is written in pure Python, uses no jpayne@68: exotic language syntax, and has more features. It's sad, really; that jpayne@68: old state machine was really slick. I just need a few sentences here jpayne@68: to mourn that.) jpayne@68: jpayne@68: I don't know how fast it is. I haven't benchmarked or profiled it yet, jpayne@68: so it's probably got a few pointless hot spots, and I've been trying jpayne@68: to err on the side of simplicity and robustness instead of jpayne@68: micro-optimization. But at the architectural level I tried hard to jpayne@68: avoid fundamentally bad decisions, e.g., I believe that all the jpayne@68: parsing algorithms remain linear-time even in the face of pathological jpayne@68: input like slowloris, and there are no byte-by-byte loops. (I also jpayne@68: believe that it maintains bounded memory usage in the face of jpayne@68: arbitrary/pathological input.) jpayne@68: jpayne@68: The whole library is ~800 lines-of-code. You can read and understand jpayne@68: the whole thing in less than an hour. Most of the energy invested in jpayne@68: this so far has been spent on trying to keep things simple by jpayne@68: minimizing special-cases and ad hoc state manipulation; even though it jpayne@68: is now quite small and simple, I'm still annoyed that I haven't jpayne@68: figured out how to make it even smaller and simpler. (Unfortunately, jpayne@68: HTTP does not lend itself to simplicity.) jpayne@68: jpayne@68: The API is ~feature complete and I don't expect the general outlines jpayne@68: to change much, but you can't judge an API's ergonomics until you jpayne@68: actually document and use it, so I'd expect some changes in the jpayne@68: details. jpayne@68: jpayne@68: *How do I try it?* jpayne@68: jpayne@68: .. code-block:: sh jpayne@68: jpayne@68: $ pip install h11 jpayne@68: $ git clone git@github.com:python-hyper/h11 jpayne@68: $ cd h11/examples jpayne@68: $ python basic-client.py jpayne@68: jpayne@68: and go from there. jpayne@68: jpayne@68: *License?* jpayne@68: jpayne@68: MIT jpayne@68: jpayne@68: *Code of conduct?* jpayne@68: jpayne@68: Contributors are requested to follow our `code of conduct jpayne@68: `_ in jpayne@68: all project spaces.