httparse v1.0
The HTTP/1.1 parser used in hyper, hasn’t really seen any API changes since it was designed, and in the spirit of moving “stable” things to 1.0, I bumped that magical number up.
httparse?
If you mainly use hyper (or a framework on top, like iron, nickel, rustless, etc), then this really shouldn’t affect you at all. It’s just the parsing logic for the HTTP/1.1 spec in a standalone crate.
If you work on some other project that requires parsing HTTP11, then you may want to try using httparse. Why?
It’s fast.
First, some buzz words. It’s stateless. It’s zero-copy. It performs zero allocations. It’s design piggybacks on the design of picohttpparser, which does the same.
- Stateless: Keeping state means branches. Branches slow down individual parsing attempts. Instead, state of a socket can and should be handled outside of the parser itself. As the socket receives more data, you can try to parse again
- Zero-copy
- Zero allocations
It’s safe.
To be fast, and yet safe, an Iterator
is used to prevent unnecessary bounds checks. That implementation is encapsulated in an inner private module, so the safety is easier to audit, and a safe API is exposed from the module, so the main API must use the iterator safely.2
Coming 1.1 and 1.2
There’s two lower hanging fruit that could provide noticeable speed improvements: branch predictions, and SIMD. There’s an accepted Rust RFC for adding a likely
intrinsic that gives us branch prediction, but its implementation needs an extra push to get in.
There’s the simd crate, with only 2 things preventing it from speeding up httparse: its using an unstable feature or three, and SSE4 support is needed to get _mm_cmpestri
, which would provide the biggest boost.
Or maybe both of these will be available at the same time, and they both can be added in httparse 1.1.
-
Building your own HTTP library? Get out of here! <3 ↩
-
Don’t look at the
next_8
API. It’s wonky. I wanted a safe way to get 8 bytes at a time, and also be able to safely tell theIterator
how far into those 8 bytes I actually got. It’d probably be better to make that a closure instead, likebytes.with_8(|eight| check!(eight))
. ↩