nginx / unit

NGINX Unit - universal web app server - a lightweight and versatile open source server that simplifies the application stack by natively executing application code across eight different programming language runtimes.
https://unit.nginx.org
Apache License 2.0
5.39k stars 327 forks source link

WebSocket mistaken for HTTP because of Connection header #772

Open SlingShot44 opened 2 years ago

SlingShot44 commented 2 years ago

Hello there! I am currently developing an application, that uses WebSockets. Therefor, I use Django Channels together with Unit. On the developement server (daphne) everything works fine, but on the production server Firefox won't establish the WebSocket connection.

The problem is, Channels routes the request to HTTP because Unit passes the asgi app scope[“type”] = "http”, receive = <built-in method receive of unit._asgi_http object at 0x7fb03ca1b0> and send = <built-in method send of unit._asgi_http object at 0x7fb03ca1b0> instead of scope["type”] = "websocket”, <built-in method receive of unit._asgi_websocket object at 0x7f84419930> and <built-in method send of unit._asgi_websocket object at 0x7f84419930> it sends when using Chrome.

After comparing the requests of different browsers, I could traceback the issue to the Connection header. While other browsers like Chromium send “Connection: Upgrade”, Firefox sends “Connection: keep-alive, Upgrade”. A test with postman confirmed my assumption: a request working with just “Connection: Upgrade” broke after adding the “keep-alive” because of the wrong routing.

Greetings!

tippexs commented 2 years ago

Thanks for reporting this issue to us. We will investigate the issue and come back to you. Do you have a demo application covering this issue? Looks like you already done a lot of testing and this would help us to investigate.

Also what Python and Unit Version are you using?

SlingShot44 commented 2 years ago

Hello @tippexs, thanks for your reply. Because I cannot share my production code, I tinkered a small demo app. There I could reproduce the error. You can find it under https://github.com/SlingShot44/Demo. In both environments I use Python 3.9.2 (But in demo I use fewer libraries and the new Channels 4.0.0 version). I am afraid, I don't know the Unit version of the production setup and I can't look it up anytime soon, but in Demo I use Unit 1.28.0. I assume it's the same for the production.

tippexs commented 2 years ago

Wonderful! Thanks for sharing. I will have a look and let you know.

hubert-abendroth commented 1 year ago

I think the problem is in nxt_h1p_connection() in nxt_h1proto.c. There it compares the field value to either "close","keep-alive" or "upgrade" but the code does not take into account that the value could be a comma-separated list of these strings (see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection). Could you fix that? I need to be able to use it with Firefox.

SunFulong commented 8 months ago

This bug still occurs now!

When I overwrite "Connection: keep-alive, Upgrade" (which Firefox send) with "Connection: Upgrade" at front level proxy, it works!