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

WebSockets over HTTP/2 #4

Open
nhooyr opened this issue Sep 6, 2018 · 21 comments
Open

WebSockets over HTTP/2 #4

nhooyr opened this issue Sep 6, 2018 · 21 comments

Comments

@nhooyr
Copy link
Owner

nhooyr commented Sep 6, 2018

Blocked on the drafts and Go support.

@nhooyr
Copy link
Owner Author

nhooyr commented Sep 6, 2018

Definitely worth reading https://tools.ietf.org/html/rfc8441

@nhooyr
Copy link
Owner Author

nhooyr commented Mar 29, 2019

This does mean we cannot expose net.Conn directly as part of the API interface like gorilla/ws because there may not be a net.Conn to expose.

@nhooyr
Copy link
Owner Author

nhooyr commented Apr 5, 2019

So unfortunately, there is no clean way for a client to detect whether a HTTP server supports WebSockets over HTTP/2 without actually performing a handshake. I've emailed the working group regarding this.

@nhooyr
Copy link
Owner Author

nhooyr commented Apr 5, 2019

@nhooyr
Copy link
Owner Author

nhooyr commented Apr 7, 2019

@nhooyr nhooyr modified the milestones: v1.0.0, v1.1.0 Apr 12, 2019
@nhooyr nhooyr changed the title HTTP/2 Support WebSockets over HTTP/2 Apr 20, 2019
@nhooyr nhooyr removed this from the v1.1.0 milestone Apr 26, 2019
@nhooyr nhooyr removed the important label Apr 28, 2019
@nhooyr
Copy link
Owner Author

nhooyr commented May 30, 2019

So it looks like my suggestion won't be implemented. The only way to implement this then is to take a HTTP2 flag on the dial options or keep a global cache.

For the server, I'm sure we can do this transparently but will require some collaboration with net/http.

@nhooyr nhooyr added complex and removed blocked labels May 30, 2019
@nhooyr nhooyr modified the milestone: v1.2.0 Jun 2, 2019
@nhooyr
Copy link
Owner Author

nhooyr commented Jul 15, 2019

Could probably implement this reasonably quickly if we forked x/net/http2.

  1. Need to be able to advertise support for HTTP/2 WebSockets
  2. Use http.Hijacker on HTTP/2 Connect requests with a mocked out net.Conn for the stream.
  3. Have *http.Client return a rw body for successful HTTP/2 Connect requests
  4. Be able to set the :protocol pseduo header.

@niaow
Copy link

niaow commented Jul 16, 2019

Hi, I have been building a similar websocket package, and would be willing to help if I can. Some things I can share:

  1. I also looked into the problem of identifying whether an endpoint supports HTTP/2 WebSockets. The best I came up with was similar to that suggested elsewhere - use an HTTP/2 connection first, then downgrade to HTTP/1 if necessary. However, SETTINGS_ENABLE_CONNECT_PROTOCOL, and similar host-wide mechanisms are not actually sufficient to identify whether an endpoint supports RFC8441 or not - I think it can be theoretically confused by a non-RFC8441 service behind an RFC8441-compliant reverse proxy. In reality, once this gets pushed out into the world a lot of services are likely to have partial support during an upgrade period - with some endpoints using the upgraded websocket packages and others not yet supporting it. The most foolproof way I came up with is to send a request and check for a 405 Method Not Allowed status code. Any RFC6455-compliant server will return a 405 Method Not Allowed if it recieves an unrecognized method, such as CONNECT as used here. When I checked, all implementations I found did this correctly.
  2. The rw body for successful HTTP/2 Connect requests has already been implemented. I have tested it out, and it works.
  3. I did open an issue which you linked about being able to set the :protocol header. I have been looking into that, and so far I have not come up with any reasonable way to expose this behavior beyond adding an override hack like the one currently used to force HTTP/1 for websockets.

I see you on some of the related threads, so some of this is just to provide context to anyone else reading this issue thread.

@nhooyr
Copy link
Owner Author

nhooyr commented Jul 16, 2019

The rw body for successful HTTP/2 Connect requests has already been implemented. I have tested it out, and it works.

Nice.

However, SETTINGS_ENABLE_CONNECT_PROTOCOL, and similar host-wide mechanisms are not actually sufficient to identify whether an endpoint supports RFC8441 or not - I think it can be theoretically confused by a non-RFC8441 service behind an RFC8441-compliant reverse proxy.

I think it should be fine. A RFC 8441-complaint reverse proxy would translate HTTP/2 over web sockets into HTTP/1.1 for the origin server. e.g. Nginx translates all HTTP/2 requests into HTTP/1.1 for origin servers. Otherwise it wouldn't be RFC 8441-complaint if it just proxied the request directly.

I did open an issue which you linked about being able to set the :protocol header. I have been looking into that, and so far I have not come up with any reasonable way to expose this behavior beyond adding an override hack like the one currently used to force HTTP/1 for websockets.

Yea that is unfortunate. Maybe a new field on *http.Request to set custom pseudo headers forcing HTTP/2? Or translating the HTTP/1.1 Protocol header to :protocol for HTTP/2? I think that would be reasonable.

Hi, I have been building a similar websocket package, and would be willing to help if I can.

Awesome, would love your help :)

So then the remaining items here are:

  • HTTP/2 CONNECT support for http.Handler
  • Setting custom HTTP/2 pseudo headers

@nhooyr
Copy link
Owner Author

nhooyr commented Nov 5, 2019

See my proposal at golang/go#32763 (comment) to make net/http transparently handle http/2 upgrades server side and client side.

Would be much nicer than implementing it here as all Go WebSocket server's would work over HTTP/2 and we would get client side support for free as we use net/http's Client directly.

@nhooyr nhooyr added the blocked label Nov 5, 2019
@hons82
Copy link

hons82 commented May 13, 2021

Hi... is there a workaround that can be used until go supports something in that direction?

@nhooyr
Copy link
Owner Author

nhooyr commented Aug 6, 2021

@hons82 Unfortunately apart from forking the go net/http library nope. I don't think it'd be very difficult to implement but there just hasn't been a response from the Go team on the linked issue.

@prologic
Copy link

prologic commented Apr 6, 2022

@nhooyr Any further updates or progress on this?

@nhooyr
Copy link
Owner Author

nhooyr commented Aug 16, 2023

I'm full time on websocket the next few months. There hasn't been any movement on the Go issue but I think I'll just fork net/http and implement my proposal linked above there. Then people can use my fork if they want WebSockets over http/2 with my library.

As well I'll open a CL on the standard library with my proposal so hopefully my fork won't be necessary. These things don't tend to get moving on issue trackers unless someone shows the initiative by implementing and demonstrating the demand.

@tv42
Copy link

tv42 commented Aug 16, 2023

I believe the link was meant to be #402

@nhooyr nhooyr added this to the v1.10.0 milestone Sep 28, 2023
@mitar
Copy link

mitar commented Oct 21, 2023

Have you seen golang/go#49918?

@mitar
Copy link

mitar commented Oct 21, 2023

Also golang/go#53209 and golang/go#53208.

@nhooyr
Copy link
Owner Author

nhooyr commented Oct 22, 2023

Nope, I missed those thanks for the links!

@hons82
Copy link

hons82 commented Oct 23, 2023

That would be awesome

@fbaube

This comment was marked as off-topic.

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

7 participants