Hi Eric/Adam,

Just reviving an old thread.  Here is the full thread archive if it helps. 
http://apache-http-server.18135.x6.nabble.com/Web-sockets-amp-proxypass-No-protocol-handler-was-valid-for-the-URL-td5033887.html

I am using Apache virtual host as frontend, and Node.js as backend running 
express and socket.io

I’ve come into the same issue as you Adam.  

Node.js Socket.io library uses the path /socket.io/ for both web socket and 
non-websocket requests where the difference is in the query parameter, rather 
than the path.  This means you can’t differentiate by simply using ProxyPass or 
ProxyPassMatch - both only match the path (not query).  

I’m using an adaptation of Eric’s rewrite rule from the bottom of this email 
(only difference is just http and ws, rather than https and wss).

RewriteEngine on
RewriteCond %{HTTP:Upgrade} "(?i)websocket"
RewriteRule ^/(.*)$ ws://localhost:3000/$1 [P]
ProxyPass        / http://localhost:3000/

I have confirmed that the request makes it to the localhost:3000, but with the 
upgrade header missing.

I have also confirmed that the client request from the browser does have the 
upgrade header.  

I am wondering whether the use of a rewriterule with the “P” flag is the reason 
the upgrade header hasn’t been included.  I wonder this because it is pretty 
widely reported to work fine when using ProxyPass to ws uri.

So Eric, do you think this is this a bug, or a misconfiguration on my part?

Following is the diagnostics I have performed.

Here are screenshots from Mozilla Firefox, and also Chromium showing that the 
upgrade headers were sent from these browsers.

https://www.evernote.com/l/AF1VDE7CjrNFeY5BsM1MlNCktM_RaqUBbgE
https://www.evernote.com/l/AF3TRPlHiNlBKK0SShHOqwPsKCuJNxUzUdE

The “Connection” header has “Upgrade” and the “Upgrade” header has “websocket” 
for both browsers.

Here is an excerpt from a packet capture between apache and node.js via 
localhost port 3000 as per this rewrite (I know as the transport=websocket 
query parameter matches the request from the browser).

—

GET /socket.io/?EIO=3&transport=websocket&sid=-hLhxB1f2Cdu0brhAAA_ HTTP/1.1
Host: buzzer.click
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:55.0) 
Gecko/20100101 Firefox/55.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-AU,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://buzzer.click
Sec-WebSocket-Extensions: permessage-deflate
Sec-WebSocket-Key: kRvxOrD3J3GpnliwvReJ8Q==
Cookie: io=-hLhxB1f2Cdu0brhAAA_
Pragma: no-cache
Via: 1.1 router (squid/3.4.8), 1.1 buzzer.click (Apache/2.4.27)
X-Forwarded-For: 192.168.100.9, 119.18.39.57
Cache-Control: no-cache
X-Forwarded-Host: buzzer.click
X-Forwarded-Server: buzzer.click
Connection: Keep-Alive

—

and response from node.js

—

HTTP/1.1 400 Bad Request
Content-Type: application/json
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://buzzer.click
Date: Thu, 07 Sep 2017 12:05:07 GMT
Connection: keep-alive
Transfer-Encoding: chunked

22
{"code":3,"message":"Bad request"}
0

—

Output from node.js console with debugging enabled:

—

  engine setting new request for existing client +0ms
  engine:polling setting request +1ms
  engine intercepting request for path "/socket.io/" +64ms
  engine handling "GET" http request 
"/socket.io/?EIO=3&transport=websocket&sid=Fv3505Tz0oOu7J3AAAAr" +0ms
  engine bad request: unexpected transport without upgrade +0ms

—

Eric, do you have any suggestions for things I may have done wrong, or other 
tests I could perform?

Many thanks.

Regards,
Damien.

On Wed, Dec 28, 2016 at 3:53 PM, Eric Covener <[hidden email]> wrote:

> On Tue, Dec 27, 2016 at 8:39 AM, Adam Teale <[hidden email]> wrote: 
>> Hi! 
>> 
>> I've been trying to setup a reverse proxy to a localhost websocket url. 
>> 
>> ProxyPass /chat/stream/ wss://localhost:8000/chat/stream/ 
>> ProxyPassReverse /chat/stream/ wss://localhost:8000/chat/stream/ 
>> 
>> I get an error in the apache error_log that reads: 
>> 
>> No protocol handler was valid for the URL /chat/stream/. If you are using a 
>> DSO version of mod_proxy, make sure the proxy submodules are included in the 
>> configuration using LoadModule. 
>> 
>> I have read a lot of pages via google of people using this method so I 
>> wonder if there is some issue in our setup/install of Apache that ships with 
>> Mac OS X 10.11 & Server.app 5.2? 
>> 
>> I have all the standard modules loaded in httpd_server_app.conf 
>> 
>> LoadModule proxy_module libexec/apache2/mod_proxy.so 
>> LoadModule proxy_http_module libexec/apache2/mod_proxy_http.so 
>> LoadModule proxy_wstunnel_module libexec/apache2/mod_proxy_wstunnel.so 
>> 
>> When I access the application running on localhost:8000 directly on the 
>> server everything works fine 
>> 
>> Any ideas what could be going on? 
> 
> There is a bug in this area, but you need to decide what you expect to 
> happen with non-websockets requests to /chat/stream/ which is what's 
> happening here. 
> 
> If you intend to proxy it, you might need to change the LoadModule 
> order of mod_proxy_http and mod_proxy_wstunnel to try to get a 
> different order at runtime. 
> 
> If you expect to satisfy it somehow else... you have a bit of a 
> puzzler.  I'm not sure there's a good recipe for this.  Otherwise as 
> Yann said, you should use different URLs if you can.
«  [hide part of quote]

For the record (after private discussion with Adam), it seems that a 
configuration like the below would work for http(s) and ws(s) on the 
same URL: 

  RewriteEngine on 
  RewriteCond %{HTTP:Upgrade} "(?i)websocket" 
  RewriteRule ^/(.*)$ wss://backend/$1 [P] 
  ProxyPass / https://backend/

Actually it didn't work for him because of other app issues (Upgrade 
missing), but httpd behaved correctly with this. 

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

Reply via email to