An Update On Hyper

An Update On Hyper

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

Issue #40

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

Issue #56

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

Issue #60

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!