About half an hour ago I pushed the latest release of
hyper
, v0.1.0. This marks the
first release of hyper since early March! This delay is not because I’ve been
resting on my laurels. In fact, a quick check of the git
repository shows
that there were almost as many commits between v0.0.4 and v0.1.0 as there were
in total up to v0.0.4.
Why the delay? What have I been working on? Why wasn’t I releasing
incrementally? This post acts as a long form explanation to bring you up to
speed with what’s going on in hyper
. If you’re just interested in the
highlights, feel free to consult
the changelog directly.
Regressions
First, the bad stuff. This release of hyper
abandons support for Python 3.3,
instead supporting only Python 3.4. Why did I do this?
Simple: Python 3.3’s ssl
module is not good enough to support HTTP/2. I need
features that it does not have: specifically, I need to limit TLS negotiation
to TLS v1.2 only. When Python 3.4 came out with that support we immediately
moved to add it, expecting that PyOpenSSL
would be able to fill the gap for
Python 3.3.
Unfortunately, PyOpenSSL
was missing NPN support. At the end of March I
opened a
pull request on PyOpenSSL
that
added NPN support. I also opened two others needed for hyper
, one adding
support for ALPN and one adding support for the socket recv_into
method. I
then blocked my next release of hyper
on PyOpenSSL
merging my NPN pull
request and shipping a new release.
As of now this has not happened. PyOpenSSL
has fallen into a form of
development hell where there does not appear to be sufficient resources to fix
a major underlying problem that
blocks PyOpenSSL
’s next release. Until this gets resolved there are unlikely
to be future releases of PyOpenSSL
.
A second problem stemming from this is that I no longer get to be excited about
one of hyper
’s planned marquee features for this release. The truly excellent
Alek Storm added support for both CPython 2.7
and PyPy to hyper
in March. This support remains in the library, but without
PyOpenSSL
is unusable.
hyper
continues to have its test suite run on PyPy, CPython 2.7, and CPython
3.3, so when PyOpenSSL
is eventually updated it should be a trivial job to
re-add support for those Python distributions. I’ll make a big deal of it when
it finally happens.
If you want more details, check out issue #37.
Major New Features
Onto the good stuff! Each feature has a link to its tracking issue (where applicable) directly after the header if you want more details or to see the code that added it.
HTTP/2-14 and HPACK-9
The development version of hyper
has been keeping pace with the HPACK and
HTTP/2 draft versions as they appeared. Version 0.1.0 contains support for
HTTP/2-14 and HPACK-9. These versions are the current interop drafts, and also
represent the Working Group Last Call documents. This means they’ll be kept
unchanged for a while so that distributions can get interop experience.
This feature alone makes it a perfect time to download hyper
and give it a
try!
Server Push
Back when I wrote my
original blog post announcing
hyper
I had the following to say about Server Push:
I don’t believe it’s possible to write a pleasant API that correctly handles Server Push without using either an event loop or having hyper spawn its own background threads. Until asyncio becomes a standard, I don’t think hyper should force you to do the first, and it’s obnoxious for a library to spawn its own threads. This means that, for the moment, hyper does not support Server Push.
I’m delighted to say that this is no longer true! Once again, Alek Storm did
the heavy lifting here and deserves huge congratulations. The upshot is that
hyper
now supports Server Push and has it turned on by default. Check out
the docs
for usage examples.
Buffered Socket To Avoid Overhead
One of the bits of feedback I got in response to my investigation of hyper’s performance was that I could avoid the overhead of making many syscalls by buffering socket data in userspace.
I’ve now gone ahead and done that: hyper
maintains a 64kB buffer in memory
for each connection to ameliorate some of the performance costs. It also avoids
copying data for much longer, saving some overheads involved in unnecessarily
copying memory around. Both of these changes should cause performance
improvements.
For those interested in borrowing the implementation, the buffered socket can
be found
here.
You are welcome to use it in your own projects under the same license as
hyper
.
Nghttp2: If You Can’t Beat ‘Em, Join ‘Em
hyper
by default uses its built-in pure-Python HPACK encoder and decoder,
which is reasonably quick and fairly efficient. However, the awesome
nghttp2 project contains a C implementation of HPACK
that achieves astonishing compression faster than hyper
does, while using
less memory.
If you’re concerned about performance, you can now use nghttp2’s encoder and
decoder with hyper
! Simple install nghttp2 with the Python bindings, and
hyper
will prefer nghttp2’s encoder and decoder to its own.
This allows the best of both worlds: zero dependency installation, with optional performance improvements for those who want them.
In future, I’ll probably approach nghttp2’s maintainers to suggest that they replace the Python bindings with a CFFI-based Python module to allow PyPy users to also use nghttp2.
Trailers
Discussed in part in Issue #71.
I’ve also taken my first step into adding features that are not supported in
vanilla httplib
, by adding support for HTTP trailers. These are headers sent
after a chunk-encoded body, containing metadata that was not known before the
request was sent. This is often things like Content-Length
.
httplib
does not support trailers transparently, but hyper
does. See
this section of the docs
for the relevant methods.
I’m aware that many people will not be able to use this method for fear of
needing to switch back to vanilla httplib
, which does not have it. I plan
to start work on the abstraction layer soon, which should help ameliorate these
concerns.
Bugfixes and Minor Features
We also added a number of smaller features. These are listed below, click on their issue links to see more information.
HTTP20Response
objects are context managers. Issue #24- Pluggable window managers are now correctly informed about the document size. Issue #26
- Header blocks don’t get corrupted if read in a different order to the one in which they were sent. Issue #39
- Default window manager is now smarter about sending WINDOWUPDATE frames. Issue #41 and Issue #52
- Fixed inverted window sizes. Issue #27
- Correctly reply to PING frames. Issue #48
- Added a universal wheel. Issue #46
- HPACK encoder correctly encodes header lists with duplicate headers. Issue #50
Progress Is Being Made
This is still an exciting time to be working on hyper
. We’ve got lots of open
issues and plans for the future. This means there’s really no better time for
you to download it and try it out. Give it a go!