Jun 13 2017

hyper v0.11

The async release of hyper is here, version 0.11.0. There’s an updated website, and new guides to try to help you get up to speed with all the changes.

hyper is an HTTP library built in Rust, providing fast and safe client and server implementations.

v0.11

This release marks a form of stability for async hyper. This isn’t saying hyper’s API won’t continue to evolve (and break), but that when such a break happens, it will happen in a v0.12, and the changes will be concentrated. It should be possible to start building frameworks and tools using v0.11.

Even before v0.11 was tagged, many were so excited by the prospects of async hyper, they already are using it. Some examples:

  • sccache has been using hyper’s Client to manage resources in S3.
  • npm uses hyper for their Registry change stream

Async

The biggest deal here, of course, is the switch to non-blocking (or “async”) IO. This has been the push for this release for a long time, and the landscape in the Rust community changed a lot while we were working on this. Last year, a framework for building asynchronous network protocols was released, Tokio. There a lot of great things to say about it, and hyper has embraced it fully.

This means a big change in API.

For instance, Request and Response bodies are no longer used via the std::io::{Read, Write} traits. Instead, bodies are Streams of bytes. Streams are essentially a Future that can resolve multiple times, which matches how an async connection works: bunches of bytes are received at different times.

By integrating with Tokio, hyper and the community gain a lot. Adding in Transport Layer Security is just combining hyper::server::Http with something like tokio_tls::TlsServer. That same TlsServer can be plugged into any protocol, and Http can be wrapped in any other community piece implementing the right trait. The same can be done with other concepts, like generic timeouts.

Hop over to the guides if you’d like to see how to get working examples.

Headers

Being a large breaking change release, an opportunity was taken to refine the headers system in hyper. Some standout changes:

  • A Raw type was added, and the set_raw, get_raw, etc methods now use it. It allows for a more ergonomic way of adding raw header values, and it’s also faster when a Raw in most cases.
  • The HeaderFormat trait has been merged into the Header trait. They were previously separate due to trait object safety rules, but now that trait methods can have a where Self: Sized added, there is no need to separate them.
  • The semantics of Header::fmt_header were clarified. Most of the time, headers can be written on one line. There is the rare exception (technically only Set-Cookie is specified) where each “value” must be on a separate line. Now, fmt_header receives a hyper::header::Formatter, with only a fmt_line method. Pretty much every header can just implement std::fmt::Display, and call f.fmt_line(self), but now Set-Cookie doesn’t need to use a hack to format itself.

Performance

hyper v0.10 was no slouch. It can churn through requests and pump out responses. However, as it uses blocking IO, it hits a problem when you have tons of connections to your server at the same time. Blocking IO means it needs to use multiple threads, only being able to deal with 1 connection per thread. Threads, when you have a lot, get to be expensive.1 So, switching to non-blocking IO means that we keep going fast, but each additional connection isn’t nearly as expensive.

hyper v0.11 is fast2, and handles thousands of connections like a champ.

Changelog

The changes are big. There is a changelog if you want to see all of them. The changelog tries to only contain changes from v0.10, but it’s not exhaustive.

Thanks

There are a lot of people to thank for getting this release out the door. This really is a fantastic community.

Next

hyper is now tracking the Futures and Tokio crates. Work is happening in there as well, as we find patterns and problems that aren’t unique to hyper, and should be available for any async protocol.

There has been community desire (and on the hyper team too!) to stabilize some sort of http crate. This would contain types for handle statuses, methods, versions, and headers, but without client or server or protocol version implementations. We’re trying to find a good design that supports all the possible use cases, and HTTP1 and HTTP2, without sacrificing any performance. Once such a thing exists, hyper would likely replace the types it uses with those.

In doing the above, that may mean that hyper’s current headers system won’t fit. It might make sense to break that out into its own crate, so that people who want typed headers can have them, while a bare bones server could live without them. This would also help reqwest in its road to 1.0, since it publicly exports hyper::headers, but hyper likely won’t reach v1.0 before it.

And of course, we always want to go faster. That will never stop!

v0.11.0

Again, go get it! Read the new guides. Tell us what you think!

  1. hyper uses a set number of threads, not growing as more connections are made. It’s a different trade off, but not too relevant for explaining why non-blocking IO is better. 

  2. hyper doesn’t lead the pack in benchmarks (yet), but it’s not in the back either. The last benchmark put it at 58% requests per second of the fastest. Since that benchmark was published, some significant low-hanging improvements were made. A new preview should be available soon. And we’ll keep going! 

  • #hyper
  • #rust
  • #rust-lang
  • #mozilla
  • #planet
  • #http