So, there are over 9000 HTTP libraries just for Ruby under the Sun, why the need for another one?
In my effort to write an HTTP server implementation that could handle both HTTP/2 and HTTP/1.1 seamlessly, I’ve had to select HTTP client libraries for the testing layer.
In Ruby, as of mid-2017, there are many (too many?) HTTP clients for HTTP/1, one for HTTP/2, but none handling both protocols through the same API and semantics. The HTTP/1 implementations all differ in the way they do network, parse (cURL bindings, http-parser
, Ruby Regex Scanners…), their public API, and the HTTP/1 features they cover (some don’t support Keep-Alive, most don’t support pipelining, etc…). There is an http library in ruby’s standard library (net-http
), but it has been vilified for the last decade for its unintuitive API, which created a niche of many (too many?) wrapper libraries around it.
Alas, I decided to go minimal and write my own wrapper around net-http
and a custom client based on http-2
. It was some of the ugliest code I ever wrote in ruby, but it did its job. However, I still had to battle every time there was some feature I had to decorate around for both cases. I thought about adding the missing features to existing libraries, but their internals were so tied to the HTTP/1 connection model, and the scope of changes would be so huge, that would make it harder to accept.
So I decided to write my own. I already understood the low-level part, so I started adding what I thought were good ideas from other libraries (mostly to reduce cognitive load), and to keep other not-so-good ideas out.
Besides providing the same features of other libraries, I added a feature which most libraries aren’t built to support: HTTP/2 and concurrent requests.
HTTTP/2 is already the present. Most CDNs and IaaS/PaaS services (AWS/GCE/Azure) support it by default. The future is already under development (QUIC), and in due time I’d like to get support added.
Concurrent requests is where HTTP/2 shines, so it was a no-brainer to implement. And I also thought it’d be nice to demonstrate that one could do scoped, concurrent and non-thread-based I/O in ruby without lots of magic and libraries full of C extensions and their own I/O model.
A bold goal for this library is to go wherever HTTP is going. At some point in time, I’d like to have QUIC support. In the day there’s a way to send HTTP over pigeons, I’d like this library to support it.
This library does HTTP only, and will not do other protocols. There is only one cURL :) .