httpd-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jon Harper <jon.harpe...@gmail.com>
Subject [users@httpd] Re: mod_proxy_wstunnel hijacks subsequent http requests in same tcp connection after websocket handshake error
Date Wed, 25 Nov 2020 14:10:54 GMT
A simpler repro is:

# in one terminal
# a cheap backend server
$ while ((1)); do (echo -ne "HTTP/1.1 401
Unauthorized\r\nContent-Length: 0\r\n\r\n" ; cat ) | nc -l 9000; done

# in another terminal, launch official httpd docker image
$ docker run -p 8080:8080 httpd:2.4 bash -c 'echo -ne "Listen
8080\nLogLevel trace8\nLoadModule proxy_module
modules/mod_proxy.so\nLoadModule proxy_wstunnel_module
modules/mod_proxy_wstunnel.so\n<VirtualHost *:8080>\n ProxyPass
/ws/gateway/ ws://172.17.0.1:9000/\n\n</VirtualHost>\n" >>
/usr/local/apache2/conf/httpd.conf; httpd-foreground'

# works
$ curl 'http://localhost:8080/'

# BUG? prints both http requests to the nc server, instead of serving
files for the first request
$ curl -v  -H 'Connection: Upgrade' -H 'Upgrade: websocket'
'http://localhost:8080/ws/gateway/notification/notify'   --next
'http://localhost:8080/' ; echo


Jon

On Wed, Nov 25, 2020 at 2:21 PM Jon Harper <jon.harper87@gmail.com> wrote:
>
> Hi list,
>
> I'm seeking help for the following problem. I have an httpd doing two things:
> - serving files
> - reverse proxying websockets to a backend server.
> In the general case, things work fine.
>
> However, when the websocket server refuses the websocket handshake
> with httpd by replying 401 Unauthorized, if the client sends another
> request for files (**not websocket**) in the same TCP connection (http
> keepalive), then the second request is incorrectly reverse proxied to
> the websocket server.
>
> Is there a solution to this?
>
> The problem is visible with this very simple following configuration:
>
> Listen 8080
> LoadModule proxy_module modules/mod_proxy.so
> LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
> <VirtualHost *:8080>
>     # an explicit worker
>     ProxyPass /ws/gateway/ ws://BACKEND:9000/
> </VirtualHost>
>
> If you run this and check with curl:
> # first getting a file works
> $ curl 'http://localhost:8080/'
> <html><body><h1>It works!</h1></body></html>
>
> # but here, connecting a websocket that is refused by the server and
> then getting the file
> # in the same tcp connection is incorrectly routed to the websocket
> server, which answers
> # with a 404
> $ curl -v  -H 'Connection: Upgrade' -H 'Upgrade: websocket'
> 'http://localhost:8080/ws/gateway/notification/notify'   --next
> 'http://localhost:8080/' ; echo
> {"timestamp":"2020-11-25T11:43:28.097+0000","path":"/","status":404,"error":"Not
> Found","message":null,"requestId":"dacfa51f-33"}
>
>
> Note that using the following configuration also show the problem:
> LoadModule proxy_module modules/mod_proxy.so
> LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
> LoadModule rewrite_module modules/mod_rewrite.so
> <VirtualHost *:8080>
>     # same problem with reverse proxying with the default worker
>     RewriteEngine On
>     RewriteRule /ws/gateway/(.*) ws://BACKEND:9000/$1 [P]
> </VirtualHost>
>
>
> If you want to reproduce locally, please feel free to use the
> following docker images:
> # my backend, a spring-boot gateway.
> # use this or any other websocket server that refuses the websocket handshake
> # but keeps the tcp connection open.
> $ docker run -p 9000:9000 gridsuite/gateway
>
> # using the official httpd image with the configuration above with trace8 logs
> # 172.17.0.1 is the default ip of your computer on the docker network
> $ docker run -p 8080:8080 httpd:2.4 bash -c 'echo -ne "Listen
> 8080\nLogLevel trace8\nLoadModule proxy_module
> modules/mod_proxy.so\nLoadModule proxy_wstunnel_module
> modules/mod_proxy_wstunnel.so\n<VirtualHost *:8080>\n ProxyPass
> /ws/gateway/ ws://172.17.0.1:9000/\n\n</VirtualHost>\n" >>
> /usr/local/apache2/conf/httpd.conf; httpd-foreground'
>
> # run the curl commands to show the problem
> $ curl 'http://localhost:8080/'
> $ curl -v -H 'Connection: Upgrade' -H 'Upgrade: websocket'
> 'http://localhost:8080/ws/gateway/notification/notify'   --next
> 'http://localhost:8080/' ; echo
>
>
> I have tried many things, setting a ttl, turning keepalive Off
> globaly, adding disablereuse=On but nothing worked. Thanks in advance,
> Jon

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@httpd.apache.org
For additional commands, e-mail: users-help@httpd.apache.org


Mime
View raw message