Bug 259282 - [Gtk] WebSocket connections via HTTP proxy with scheme ws:// do not use CONNECT method
Summary: [Gtk] WebSocket connections via HTTP proxy with scheme ws:// do not use CONNE...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: WebKit Local Build
Hardware: PC Linux
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-07-17 11:15 PDT by James Baldassari
Modified: 2023-07-18 16:03 PDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description James Baldassari 2023-07-17 11:15:29 PDT
RFC-6455 Section 4.1 (https://datatracker.ietf.org/doc/html/rfc6455#section-4.1) specifies that when the client is configured to use a proxy, the CONNECT method should be used to establish the WebSocket connection.  This section does not differentiate between ws and wss schemes, so the implication is that CONNECT should be used for _all_ WebSocket connections when the client is configured to use a proxy.  WebKit uses CONNECT for wss:// URLs, but for ws:// URLs it issues a normal GET request to the proxy using the absolute URI of the server in the request line.  By contrast, Firefox and Chrome use CONNECT regardless of whether the WebSocket URL scheme is ws or wss.  I've tested this with a local build with version WebKitGTK 2.41.6 (265776@main).  The problem with using GET rather than CONNECT is that some proxies that strictly conform to RFC-6455 will reject these GET requests.  One such example is mitmproxy (https://github.com/mitmproxy/mitmproxy), which returns an error code and complains about an invalid request scheme.

For reference, below is an example request/response log showing what happens when WebKit is configured to connect to a ws:// URL via mitmproxy:

> GET ws://192.168.122.1:8888/ HTTP/1.1
> Host: 192.168.122.1:8888
> User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Safari/605.1.15
> Origin: http://192.168.122.1:8888
> Pragma: no-cache
> Cache-Control: no-cache
> Upgrade: websocket
> Connection: Upgrade
> Sec-WebSocket-Key: Jed6Wvk9oJQvBqlfYCKTiw==
> Sec-WebSocket-Version: 13
> Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
> Accept-Encoding: gzip, deflate
> Accept-Language: en-US
> 
> HTTP/1.1 502 Bad Gateway
> content-length: 26
> 
> Invalid request scheme: ws

For comparison, here is the same request/response using Firefox (note that it uses CONNECT and then a subsequent GET request with a relative URI):

> CONNECT 192.168.122.1:8888 HTTP/1.1
> User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0
> Proxy-Connection: keep-alive
> Connection: keep-alive
> Host: 192.168.122.1:8888
> 
> HTTP/1.1 200 Connection established
> 
> GET / HTTP/1.1
> Host: 192.168.122.1:8888
> User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0
> Accept: */*
> Accept-Language: en-US,en;q=0.5
> Accept-Encoding: gzip, deflate
> Sec-WebSocket-Version: 13
> Origin: http://192.168.122.1:8888
> Sec-WebSocket-Extensions: permessage-deflate
> Sec-WebSocket-Key: /Uzba02mhelEhLMsoObx9Q==
> Connection: keep-alive, Upgrade
> Pragma: no-cache
> Cache-Control: no-cache
> Upgrade: websocket
> 
> HTTP/1.1 101 Switching Protocols
> Upgrade: websocket
> Connection: Upgrade
> Sec-WebSocket-Accept: Cr3XgX2NzWNx/mvS1CDZeuknHhU=

It should be easy to reproduce this issue by installing mitmproxy and starting it up locally.  The way I prefer to do this is:
> mitmdump -k -p 8080
Next, start WebKit and configure it to connect via mitmproxy:
> Tools/Scripts/run-minibrowser --gtk --proxy='http://localhost:8080'
The last piece that is needed is a server that accepts WebSocket connections over HTTP.  I've created a very simple node-based HTTP/WebSocket server for testing scenarios like this.  It includes a basic UI that can be used to initiate the WebSocket connection.  You can access that code here: https://github.com/jbaldassari/websocket-echo
> npm ci
> npm run build
> HTTP_PORT=8888 node build/index.js