jpayne@68
|
1 Metadata-Version: 2.1
|
jpayne@68
|
2 Name: h11
|
jpayne@68
|
3 Version: 0.14.0
|
jpayne@68
|
4 Summary: A pure-Python, bring-your-own-I/O implementation of HTTP/1.1
|
jpayne@68
|
5 Home-page: https://github.com/python-hyper/h11
|
jpayne@68
|
6 Author: Nathaniel J. Smith
|
jpayne@68
|
7 Author-email: njs@pobox.com
|
jpayne@68
|
8 License: MIT
|
jpayne@68
|
9 Classifier: Development Status :: 3 - Alpha
|
jpayne@68
|
10 Classifier: Intended Audience :: Developers
|
jpayne@68
|
11 Classifier: License :: OSI Approved :: MIT License
|
jpayne@68
|
12 Classifier: Programming Language :: Python :: Implementation :: CPython
|
jpayne@68
|
13 Classifier: Programming Language :: Python :: Implementation :: PyPy
|
jpayne@68
|
14 Classifier: Programming Language :: Python :: 3
|
jpayne@68
|
15 Classifier: Programming Language :: Python :: 3 :: Only
|
jpayne@68
|
16 Classifier: Programming Language :: Python :: 3.7
|
jpayne@68
|
17 Classifier: Programming Language :: Python :: 3.8
|
jpayne@68
|
18 Classifier: Programming Language :: Python :: 3.9
|
jpayne@68
|
19 Classifier: Programming Language :: Python :: 3.10
|
jpayne@68
|
20 Classifier: Topic :: Internet :: WWW/HTTP
|
jpayne@68
|
21 Classifier: Topic :: System :: Networking
|
jpayne@68
|
22 Requires-Python: >=3.7
|
jpayne@68
|
23 License-File: LICENSE.txt
|
jpayne@68
|
24 Requires-Dist: typing-extensions ; python_version < "3.8"
|
jpayne@68
|
25
|
jpayne@68
|
26 h11
|
jpayne@68
|
27 ===
|
jpayne@68
|
28
|
jpayne@68
|
29 .. image:: https://travis-ci.org/python-hyper/h11.svg?branch=master
|
jpayne@68
|
30 :target: https://travis-ci.org/python-hyper/h11
|
jpayne@68
|
31 :alt: Automated test status
|
jpayne@68
|
32
|
jpayne@68
|
33 .. image:: https://codecov.io/gh/python-hyper/h11/branch/master/graph/badge.svg
|
jpayne@68
|
34 :target: https://codecov.io/gh/python-hyper/h11
|
jpayne@68
|
35 :alt: Test coverage
|
jpayne@68
|
36
|
jpayne@68
|
37 .. image:: https://readthedocs.org/projects/h11/badge/?version=latest
|
jpayne@68
|
38 :target: http://h11.readthedocs.io/en/latest/?badge=latest
|
jpayne@68
|
39 :alt: Documentation Status
|
jpayne@68
|
40
|
jpayne@68
|
41 This is a little HTTP/1.1 library written from scratch in Python,
|
jpayne@68
|
42 heavily inspired by `hyper-h2 <https://hyper-h2.readthedocs.io/>`_.
|
jpayne@68
|
43
|
jpayne@68
|
44 It's a "bring-your-own-I/O" library; h11 contains no IO code
|
jpayne@68
|
45 whatsoever. This means you can hook h11 up to your favorite network
|
jpayne@68
|
46 API, and that could be anything you want: synchronous, threaded,
|
jpayne@68
|
47 asynchronous, or your own implementation of `RFC 6214
|
jpayne@68
|
48 <https://tools.ietf.org/html/rfc6214>`_ -- h11 won't judge you.
|
jpayne@68
|
49 (Compare this to the current state of the art, where every time a `new
|
jpayne@68
|
50 network API <https://trio.readthedocs.io/>`_ comes along then someone
|
jpayne@68
|
51 gets to start over reimplementing the entire HTTP protocol from
|
jpayne@68
|
52 scratch.) Cory Benfield made an `excellent blog post describing the
|
jpayne@68
|
53 benefits of this approach
|
jpayne@68
|
54 <https://lukasa.co.uk/2015/10/The_New_Hyper/>`_, or if you like video
|
jpayne@68
|
55 then here's his `PyCon 2016 talk on the same theme
|
jpayne@68
|
56 <https://www.youtube.com/watch?v=7cC3_jGwl_U>`_.
|
jpayne@68
|
57
|
jpayne@68
|
58 This also means that h11 is not immediately useful out of the box:
|
jpayne@68
|
59 it's a toolkit for building programs that speak HTTP, not something
|
jpayne@68
|
60 that could directly replace ``requests`` or ``twisted.web`` or
|
jpayne@68
|
61 whatever. But h11 makes it much easier to implement something like
|
jpayne@68
|
62 ``requests`` or ``twisted.web``.
|
jpayne@68
|
63
|
jpayne@68
|
64 At a high level, working with h11 goes like this:
|
jpayne@68
|
65
|
jpayne@68
|
66 1) First, create an ``h11.Connection`` object to track the state of a
|
jpayne@68
|
67 single HTTP/1.1 connection.
|
jpayne@68
|
68
|
jpayne@68
|
69 2) When you read data off the network, pass it to
|
jpayne@68
|
70 ``conn.receive_data(...)``; you'll get back a list of objects
|
jpayne@68
|
71 representing high-level HTTP "events".
|
jpayne@68
|
72
|
jpayne@68
|
73 3) When you want to send a high-level HTTP event, create the
|
jpayne@68
|
74 corresponding "event" object and pass it to ``conn.send(...)``;
|
jpayne@68
|
75 this will give you back some bytes that you can then push out
|
jpayne@68
|
76 through the network.
|
jpayne@68
|
77
|
jpayne@68
|
78 For example, a client might instantiate and then send a
|
jpayne@68
|
79 ``h11.Request`` object, then zero or more ``h11.Data`` objects for the
|
jpayne@68
|
80 request body (e.g., if this is a POST), and then a
|
jpayne@68
|
81 ``h11.EndOfMessage`` to indicate the end of the message. Then the
|
jpayne@68
|
82 server would then send back a ``h11.Response``, some ``h11.Data``, and
|
jpayne@68
|
83 its own ``h11.EndOfMessage``. If either side violates the protocol,
|
jpayne@68
|
84 you'll get a ``h11.ProtocolError`` exception.
|
jpayne@68
|
85
|
jpayne@68
|
86 h11 is suitable for implementing both servers and clients, and has a
|
jpayne@68
|
87 pleasantly symmetric API: the events you send as a client are exactly
|
jpayne@68
|
88 the ones that you receive as a server and vice-versa.
|
jpayne@68
|
89
|
jpayne@68
|
90 `Here's an example of a tiny HTTP client
|
jpayne@68
|
91 <https://github.com/python-hyper/h11/blob/master/examples/basic-client.py>`_
|
jpayne@68
|
92
|
jpayne@68
|
93 It also has `a fine manual <https://h11.readthedocs.io/>`_.
|
jpayne@68
|
94
|
jpayne@68
|
95 FAQ
|
jpayne@68
|
96 ---
|
jpayne@68
|
97
|
jpayne@68
|
98 *Whyyyyy?*
|
jpayne@68
|
99
|
jpayne@68
|
100 I wanted to play with HTTP in `Curio
|
jpayne@68
|
101 <https://curio.readthedocs.io/en/latest/tutorial.html>`__ and `Trio
|
jpayne@68
|
102 <https://trio.readthedocs.io>`__, which at the time didn't have any
|
jpayne@68
|
103 HTTP libraries. So I thought, no big deal, Python has, like, a dozen
|
jpayne@68
|
104 different implementations of HTTP, surely I can find one that's
|
jpayne@68
|
105 reusable. I didn't find one, but I did find Cory's call-to-arms
|
jpayne@68
|
106 blog-post. So I figured, well, fine, if I have to implement HTTP from
|
jpayne@68
|
107 scratch, at least I can make sure no-one *else* has to ever again.
|
jpayne@68
|
108
|
jpayne@68
|
109 *Should I use it?*
|
jpayne@68
|
110
|
jpayne@68
|
111 Maybe. You should be aware that it's a very young project. But, it's
|
jpayne@68
|
112 feature complete and has an exhaustive test-suite and complete docs,
|
jpayne@68
|
113 so the next step is for people to try using it and see how it goes
|
jpayne@68
|
114 :-). If you do then please let us know -- if nothing else we'll want
|
jpayne@68
|
115 to talk to you before making any incompatible changes!
|
jpayne@68
|
116
|
jpayne@68
|
117 *What are the features/limitations?*
|
jpayne@68
|
118
|
jpayne@68
|
119 Roughly speaking, it's trying to be a robust, complete, and non-hacky
|
jpayne@68
|
120 implementation of the first "chapter" of the HTTP/1.1 spec: `RFC 7230:
|
jpayne@68
|
121 HTTP/1.1 Message Syntax and Routing
|
jpayne@68
|
122 <https://tools.ietf.org/html/rfc7230>`_. That is, it mostly focuses on
|
jpayne@68
|
123 implementing HTTP at the level of taking bytes on and off the wire,
|
jpayne@68
|
124 and the headers related to that, and tries to be anal about spec
|
jpayne@68
|
125 conformance. It doesn't know about higher-level concerns like URL
|
jpayne@68
|
126 routing, conditional GETs, cross-origin cookie policies, or content
|
jpayne@68
|
127 negotiation. But it does know how to take care of framing,
|
jpayne@68
|
128 cross-version differences in keep-alive handling, and the "obsolete
|
jpayne@68
|
129 line folding" rule, so you can focus your energies on the hard /
|
jpayne@68
|
130 interesting parts for your application, and it tries to support the
|
jpayne@68
|
131 full specification in the sense that any useful HTTP/1.1 conformant
|
jpayne@68
|
132 application should be able to use h11.
|
jpayne@68
|
133
|
jpayne@68
|
134 It's pure Python, and has no dependencies outside of the standard
|
jpayne@68
|
135 library.
|
jpayne@68
|
136
|
jpayne@68
|
137 It has a test suite with 100.0% coverage for both statements and
|
jpayne@68
|
138 branches.
|
jpayne@68
|
139
|
jpayne@68
|
140 Currently it supports Python 3 (testing on 3.7-3.10) and PyPy 3.
|
jpayne@68
|
141 The last Python 2-compatible version was h11 0.11.x.
|
jpayne@68
|
142 (Originally it had a Cython wrapper for `http-parser
|
jpayne@68
|
143 <https://github.com/nodejs/http-parser>`_ and a beautiful nested state
|
jpayne@68
|
144 machine implemented with ``yield from`` to postprocess the output. But
|
jpayne@68
|
145 I had to take these out -- the new *parser* needs fewer lines-of-code
|
jpayne@68
|
146 than the old *parser wrapper*, is written in pure Python, uses no
|
jpayne@68
|
147 exotic language syntax, and has more features. It's sad, really; that
|
jpayne@68
|
148 old state machine was really slick. I just need a few sentences here
|
jpayne@68
|
149 to mourn that.)
|
jpayne@68
|
150
|
jpayne@68
|
151 I don't know how fast it is. I haven't benchmarked or profiled it yet,
|
jpayne@68
|
152 so it's probably got a few pointless hot spots, and I've been trying
|
jpayne@68
|
153 to err on the side of simplicity and robustness instead of
|
jpayne@68
|
154 micro-optimization. But at the architectural level I tried hard to
|
jpayne@68
|
155 avoid fundamentally bad decisions, e.g., I believe that all the
|
jpayne@68
|
156 parsing algorithms remain linear-time even in the face of pathological
|
jpayne@68
|
157 input like slowloris, and there are no byte-by-byte loops. (I also
|
jpayne@68
|
158 believe that it maintains bounded memory usage in the face of
|
jpayne@68
|
159 arbitrary/pathological input.)
|
jpayne@68
|
160
|
jpayne@68
|
161 The whole library is ~800 lines-of-code. You can read and understand
|
jpayne@68
|
162 the whole thing in less than an hour. Most of the energy invested in
|
jpayne@68
|
163 this so far has been spent on trying to keep things simple by
|
jpayne@68
|
164 minimizing special-cases and ad hoc state manipulation; even though it
|
jpayne@68
|
165 is now quite small and simple, I'm still annoyed that I haven't
|
jpayne@68
|
166 figured out how to make it even smaller and simpler. (Unfortunately,
|
jpayne@68
|
167 HTTP does not lend itself to simplicity.)
|
jpayne@68
|
168
|
jpayne@68
|
169 The API is ~feature complete and I don't expect the general outlines
|
jpayne@68
|
170 to change much, but you can't judge an API's ergonomics until you
|
jpayne@68
|
171 actually document and use it, so I'd expect some changes in the
|
jpayne@68
|
172 details.
|
jpayne@68
|
173
|
jpayne@68
|
174 *How do I try it?*
|
jpayne@68
|
175
|
jpayne@68
|
176 .. code-block:: sh
|
jpayne@68
|
177
|
jpayne@68
|
178 $ pip install h11
|
jpayne@68
|
179 $ git clone git@github.com:python-hyper/h11
|
jpayne@68
|
180 $ cd h11/examples
|
jpayne@68
|
181 $ python basic-client.py
|
jpayne@68
|
182
|
jpayne@68
|
183 and go from there.
|
jpayne@68
|
184
|
jpayne@68
|
185 *License?*
|
jpayne@68
|
186
|
jpayne@68
|
187 MIT
|
jpayne@68
|
188
|
jpayne@68
|
189 *Code of conduct?*
|
jpayne@68
|
190
|
jpayne@68
|
191 Contributors are requested to follow our `code of conduct
|
jpayne@68
|
192 <https://github.com/python-hyper/h11/blob/master/CODE_OF_CONDUCT.md>`_ in
|
jpayne@68
|
193 all project spaces.
|