Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP/2 support #2125

Open
TheLonelyGhost opened this issue Feb 8, 2016 · 24 comments
Open

HTTP/2 support #2125

TheLonelyGhost opened this issue Feb 8, 2016 · 24 comments

Comments

@TheLonelyGhost
Copy link
Contributor

This is a feature request, tag it as you will. Since the specs have been clearly defined and do not appear to waver, I feel HTTP/2 should be supported in addition to HTTP/1.x.

Resources:

  • HTTP2 Working Group - includes specs and running list of implementations in other languages
  • Ruby HTTP2 gem - Maintained by Ilya Grigorik for both client and server
@asterite
Copy link
Member

asterite commented Feb 9, 2016

Thanks for adding this, we'll eventually need to support HTTP/2.

I'm not sure how it works, though. Will it integrate automagically with the current server? Because in Ilya Grigorik's implementation it doesn't look like it integrates with Rack. There's also this long thread which supports my guessing. And this Go talk which says that if you are using HTTPS and Go 1.6 you are using HTTP/2, so I guess it should be transparent.

Maybe @igrigorik could chime in and at least let us know if the current client/server implementation is easily upgradable to HTTP/2? 😁

@igrigorik
Copy link

@asterite you can definitely abstract h2 behind the same API. That said, I do think you want to think carefully about the API to enable developers take advantage of h2: persistent connections, multiplexing, server push, etc. "Rack API", at least as it was defined for http/1.1, doesn't do a good job of this.

FWIW, check out the demo client/server examples in the ruby gem:
https://github.com/igrigorik/http-2/tree/master/example

@asterite
Copy link
Member

asterite commented Feb 9, 2016

@igrigorik Thank you for replying, I'll take a look at the examples and see if I can port something to Crystal.

@ysbaddaden
Copy link
Contributor

@asterite recently changed HTTP::Server from a Rack-like interface (get a request, return a response) to instead pass a Context object with the Request and Response objects that middlewares will change, each context being evaluated in its own coroutine.

I have a feeling that HTTP::Server could handle the HTTP/2 protocol, creating a Context object for each incoming Streams, using an intermediate IO to write to the Stream instead of the Socket —like deflate middleware currently does. The Context object could have additional methods for server push (among other HTTP/2 features), and either raise or silently skip when HTTP/2 isn't supported by the client.

Hopefully this wouldn't affect the current middleware API but enhance it.

@ysbaddaden
Copy link
Contributor

ysbaddaden commented Apr 17, 2016

An initial implementation is available: https://github.com/ysbaddaden/http2

If someone could point me to great HTTP2 compliance test suites, that would be very much appreciated.

The client part is untested. It should be capable to use HTTP2::Connection, but it may require some tweaks. It's integration into HTTP::Client may be tricky, especially since we can have many requests in parallel (yay, fibers!) and the API needs a callback to handle server-push promises (accept/refuse then receive data). We can prevent server-push by default, too. We also need to configure local HTTP2 settings (frame size, max concurrent streams, etc).

The server part is almost complete, except for flow control (required) and applying priorities to send frames (nice to have). It's capable to talk with nghttp (with or without TLS) and browsers (ie. Firefox and Chrome, TLS only) and it supports server-push.

Now we should start planning to integrate this into HTTP::Server. For example:

  • Add HTTP::Server.default_ssl_context that would return an OpenSSL::SSL::Context that is compliant to HTTP2 requirements and always provides state-of-the-art OpenSSL configuration; HTTP::Client could provide the same; It's now OpenSSL::SSL::Context::Server;
  • Introduce an abstraction for HTTP1 responses, to leverage the protocol differences between HTTP1 and HTTP2 so HTTP::Server::Response::Output doesn't have to deal with protocol details (ie. encoding HTTP headers, writing body to the socket or as a stream data frame);
  • Transparently support HTTP2 in HTTP::Server:
    • configure local HTTP2 settings (max frame size, concurrent streams, etc);
    • handle the ALPN protocol for SSL connections;
    • react to the Upgrade: h2c header for non-SSL connections (and discard Upgrade: h2);
    • handlers will deal with HTTP2::Stream objects instead of a Socket, which is similar to how we wrap the socket in HTTP::Server::DeflateHandler (which will wrap HTTP2::Stream now);
  • Add method(s) to HTTP::Server::Context to enable server-push, with a solution to actually send the response, or not, if the Client accepted or refused them —and either raise or silently discard if the connection ain't HTTP2.

@igrigorik
Copy link

@ysbaddaden take a look at https://github.com/summerwind/h2spec

@ysbaddaden
Copy link
Contributor

Thank you @igrigorik! I was able to reduce a bunch of corner cases in the protocol, down to 4 failures, most related to the unimplemented flow-control.

@sdogruyol
Copy link
Member

Hey @ysbaddaden i remember you implementing HTTP/2 for Crystal. What's the status on that 😄

@samueleaton
Copy link
Contributor

samueleaton commented Dec 15, 2016

I too am very interested in the speed improvements that HTTP2 offers. I didn't know it had such wide support.

@ysbaddaden should the work you're doing for http2 be moved into a crystal branch? I wouldn't mind writing a bunch of specs for it.

@MrSorcus
Copy link
Contributor

Up.
Any progress?

@spalladino
Copy link
Contributor

@DebugReport not that we are aware of. @samueleaton, if you are interested in contributing, I'd advise to do so in @ysbaddaden's repo, and as it's finished and tested, we can then include it into the stdlib.

@jeromegn
Copy link
Contributor

As far as I can tell @ysbaddaden's http2 shard is feature-complete and passes all h2spec tests. Awesome work.

It doesn't look like there are any plans for integrating it back into Crystal though. I was planning on using it in my own project, a shard is fine, but I think it'd be nice to have in the std lib. I don't think http2 is going away.

@luislavena
Copy link
Contributor

Hello @asterite, @bcardiff, @ysbaddaden, @waj and other core-team members,

Would like to bring to your attention this issue, hoping if possible to introduce the changes required to support HTTP/2 into the stdlib.

Not necessarily suggesting introduce HTTP/2 itself to the stdlib, but perhaps tweak HTTP::Server and friends to avoid the differences currently required to support it, in that way, someone can load the http2 shard and use when required.

Given that we are still in pre-1.0, perhaps is a good time to do some final breaking changes to the related API in preparation for that.

HTTP/2 support will also open the door to gRPC, which can increase interoperability of Crystal for certain teams and projects. Also worth to mention HTTP/3 is around the corner 😉

Thank you for your hard and continuous work both Crystal core and other contributors, every new release gets better and better and you can feel how much sweat and hard work has been pour into it. Thank you! ❤️ ❤️ ❤️

Cheers.

@RX14
Copy link
Contributor

RX14 commented Oct 5, 2019

I think that HTTP needs a ground-up clean API redesign (without looking at the current API, the implementation is fine). It has collected a lot of issues which need to be collated into a requirements list for a HTTP module which is ready to be marked 1.0.

@bcardiff
Copy link
Member

bcardiff commented Oct 6, 2019

Regarding HTTP (Client/Server) we wanted a way to decouple the protocol implementation from the socket tls wrapper. That will allow simple http over unix socket and other use cases where a simple http api is needed. (And would actually remove the need for the without_openssl flag).

@pyrsmk
Copy link
Contributor

pyrsmk commented Dec 10, 2020

As a side note about WebSockets working with HTTP/2, I'm dropping these articles here, for those who are interested :

https://hpbn.co/websocket/#websocket-multiplexing-and-head-of-line-blocking
https://medium.com/@pgjones/http-2-websockets-81ae3aab36dd

And the related RFC :

https://tools.ietf.org/html/rfc8441

@eliasjpr
Copy link

eliasjpr commented May 6, 2021

Another take at Crystal HTTP2 implementation https://github.com/azutoolkit/duo

@straight-shoota
Copy link
Member

I suppose at this point HTTP/2 support isn't that useful compared to HTTP/3 (which is basically the same, just based on QUIC instead of TCP).
Recently released OpenSSL 3.2 has QUIC client support (server is expected to follow in the following release(s)), so this could serve for an easy integration into HTTP::Client.
That would be more approachable than an additional QUIC library (which https://github.com/iv-org/lsquic.cr is using).

@luislavena
Copy link
Contributor

Recently Ilya Grigorik released a pure-Ruby implementation of HTTP/2: https://github.com/igrigorik/http-2 that decouples the transport from the HTTP/2 processing.

@dentarg
Copy link

dentarg commented Jun 29, 2024

@luislavena that gem has been around since 2013 with the last release in 2021 before this recent flurry of activity that seems to be led by AWS (https://github.com/mullermp)

EDIT: Looks like http-2 1.0.0 is this fork https://gitlab.com/os85/http-2-next by https://github.com/HoneyryderChuck

There is also https://github.com/socketry/protocol-http2 by Samuel Williams

@HCLarsen
Copy link
Contributor

HCLarsen commented Jul 6, 2024

I suppose at this point HTTP/2 support isn't that useful compared to HTTP/3 (which is basically the same, just based on QUIC instead of TCP).

I would say that it is just as useful, as it's possible that some clients/servers could support HTTP/2, but not HTTP/3. We should be going for all options that developers may be using.

In any case, is anyone working on a PR yet? If not, I may tackle this myself over the summer.

@straight-shoota
Copy link
Member

You're right. I didn't realize at the time I wrote this, that there are still good reasons for HTTP/2.

I'm not aware of anyone working on this. Your help would be appreciated 👍

@ryanprior
Copy link

I had a conversation the other day about how I wish I had the background knowledge & time to take this on. A lot of tooling in the K8s/cluster orchestration space is based on HTTP2, and support for that stack in the core library would make crystal a much easier sell in the cloud ops space.

If somebody else wants to take point, I'd be happy to try and pitch in! I definitely don't have the right background to lead the effort, nor do I currently have the time to skill-up and read the relevant RFCs & existing implementations.

@HCLarsen
Copy link
Contributor

Another thought about this. When making requests with HTTP::Client, it's entirely possible that someone may want to specify which HTTP protocol they want to use. Unless I'm missing it, there's currently no mechanism for that.

My first thought for a solution includes an enum for versions, and a constant that points to the newest version (Yes, I'm thinking forward compatibility).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests