async-websocket icon indicating copy to clipboard operation
async-websocket copied to clipboard

Hangs when connecting to nginx proxied websocket server using HTTP2

Open u3shit opened this issue 1 year ago • 2 comments

I did what I shouldn't do and updated everything at one time again, and now I can no longer connect to a websocket server behind an nginx reverse proxy.

A simple program like this

require 'async/http/endpoint'
require 'async/websocket/client'

Console.logger.level = :debug

ep = Async::HTTP::Endpoint.parse 'wss://some-host/'
Async do
  Async::WebSocket::Client.connect ep do |conn|
    puts conn
  end
end

Now fails (removed IP addresses):

/home/u3/.gem/ruby/3.2.0/gems/io-event-1.3.3/lib/io/event/support.rb:24: warning: IO::Buffer is experimental and both the Ruby and C interface may change in the future!
  0.0s    debug: Async::Pool::Controller [oid=0x26c] [ec=0x280] [pid=21735] [2023-12-17 21:11:42 +0100]
               | No available resources, allocating new one...
  0.0s    debug: Async::HTTP::Client [oid=0x2a8] [ec=0x280] [pid=21735] [2023-12-17 21:11:42 +0100]
               | Making connection to #<Async::HTTP::Endpoint wss://xxxx {}>
  0.0s    debug: Async::IO::Socket [ec=0x280] [pid=21735] [2023-12-17 21:11:42 +0100]
               | Connecting to #<Addrinfo: xxx.xxx.xxx.xxx:443 TCP (xxxx)>
 0.07s    debug: Async::HTTP::Protocol::HTTPS: connected to #<Addrinfo: xxx.xxx.xxx.xxx:443 TCP (xxxx)> [fd=6] [ec=0x280] [pid=21735] [2023-12-17 21:11:43 +0100]
               | Negotiating protocol "h2"...
  0.1s    debug: Async::Pool::Controller: connected to #<Addrinfo: xxx.xxx.xxx.xxx:443 TCP (xxxx)> [fd=6] [oid=0x26c] [ec=0x280] [pid=21735] [2023-12-17 21:11:43 +0100]
               | Wait for resource -> #<Async::HTTP::Protocol::HTTP2::Client 0 active streams>

And it just hangs there until I Ctrl-C it. Nginx sends back a HTTP 400 error page (verified with wireshark), but this lib doesn't seem to handle it. Additionally nginx logs a client sent unknown pseudo-header ":protocol" while reading client request headers error, so I think it doesn't support websocket over HTTP2. (The older version I upgraded from used HTTP/1.1 so it worked fine there).

The alpn_protocols: Async::HTTP::Protocol::HTTP11.names workaround fixes the problem, but I think it should at least error out on the 400 response, instead of hanging the coroutine.

u3shit avatar Dec 17 '23 20:12 u3shit

Sorry, I haven't noticed you added a CoC in the meantime.

u3shit avatar Dec 18 '23 22:12 u3shit

Probably the correct way to handle this is to check whether the HTTP/2 connection advertises support for the connect protocol, and if not, fall back to HTTP/1 for WebSockets.

ioquatix avatar Dec 20 '23 07:12 ioquatix