WebSocket via HTTP proxy

As you might know, WebSocket can be used for bi-directional "real-time" communication with multiple clients. What does that mean in proxy environments and how this even works? WebSocket uses HTTP upgrade mechanism specified in HTTP 1.1 and by design requires open (TCP) connection.

HTTP CONNECT is there for exactly these usecases. It is usually used for tunneling HTTPS via proxy, but it can be used for WebSocket as well.

I will describe complete "proxified" handshake using captured connection of Tyrus Client connecting to public echo service - echo.websocket.org. Please note that we are directly using Tyrus API - not WebSocket specification (JSR-356), because we need to set a proxy.

final ClientManager client = ClientManager.createClient();

client.getProperties().put(
  GrizzlyClientSocket.PROXY_URI, "http://my.proxy:8080"
);
final Session session = client.connectToServer(new Endpoint() {

  @Override
  public void onOpen(Session session, EndpointConfig config) {
    session.addMessageHandler(new MessageHandler.Whole<String>() {
      @Override
      public void onMessage(String message) {
        System.out.println("# Message received: " + message);
      }
    });
  }
}, ClientEndpointConfig.Builder.create().build(),
   URI.create("ws://echo.websocket.org"));

session.getBasicRemote().sendText("test message");

BTW, Tyrus Client proxy support can be improved, currently it does not support proxy authentication, JDK's ProxySelector and so on. Please vote/comment on TYRUS-204 if you lack some of the mentioned options or anything else related to proxy support.

Current modern browsers do support this out of the box, so all you need is to set your HTTP proxy and described handshake will be done automatically. There might be limitation for parallel open connection in browser tab/instance, but I don't have any exact data about this.

Also, you might ask whether there is some need to server-side support - simple answer is "no". HTTP containers will see regular connection (from proxy), there is no additional work or overhead on that side.

Lets see our dumped communication:

client > proxy
CONNECT echo.websocket.org:80 HTTP/1.1
Host: echo.websocket.org
Proxy-Connection: keep-alive
Connection: keep-alive

Firstly, client need to send a request to proxy for new "permanent" connection. As already mentioned, CONNECT method handles this. First argument is a hostname (echo.websocket.org) and standard HTTP version.

proxy > client
HTTP/1.0 200 Connection established

If you are lucky, your proxy does support CONNECT and allows you to create connection (HTTP 200 is returned).

client > proxy
GET / HTTP/1.1
Connection: Upgrade
Host: echo.websocket.org
Origin: echo.websocket.org
Sec-WebSocket-Key : sDD3Wk7PMRCPE9+C0VyOcQ==
Sec-WebSocket-Version: 13
Upgrade: websocket

This is standard WebSocket handshake request, which will be passed to target HTTP container.

proxy > client
HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Accept: 8TNIHr7bJHqQadjXYvqLql6RFEA=
Date: Tue, 16 Jul 2013 15:30:53 GMT
...

And there is a valid response to our handshake request, connection is established and communication can be started; there is nothing else different than in proxy-less environment. Please note that proxies do have limited resources and your request may be turned down because proxy "CONNECT" pool is empty.

Conclusion here is that WebSocket can work via proxies without any limitation, it just introduces different kind of traffic than pure HTTP and might cause some additional requirements related to proxy performance in case you are going to use WebSocket for long-running client connections.

Comments:

Hi Pavel,

Thanks for the explanation, that really did help me to understand the handshake. I have a scenario, wherein the connection initiation is successful and the proxy returns a HTTP/1.0 200 Connection established, but the SSL handshake fails.

HTTP/1.0 500 handshakefailed
Via: 1.0 10.X.X.X (McAfee Web Gateway 7.2.0.1.0.13253)
Content-Type: text/html
Cache-Control: no-cache
Content-Length: 2063
Proxy-Connection: Close

Any suggestions why is it failing?

Posted by Srini on September 04, 2013 at 08:05 AM CEST #

Hi Srini,

you should add -Djavax.net.debug=all (see http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/ReadDebug.html for more details). It usually is certificate issue, in your case it might be because the other side does not have properly signed certificate and you don't have truststore and/or keystore properly set on client side.

Feel free to send more details to users@tyrus.java.net.

Posted by guest on September 09, 2013 at 10:11 AM CEST #

Finally some extra info on websokets and proxies...not much on the web. I read this article on WS & proxies that every other article seemed to link to http://www.infoq.com/articles/Web-Sockets-Proxy-Servers
Problem is its dated 2010 yet the protocol was standaridzed end of 2011 and there is a part on '_Proxy Usage_:' that explains that the client can send info to a proxy asking it to connect to the given server. To me this sounds like there shouldnt be any problems as put out in the 2010 article but wasnt sure because i know about proxies but not their nitty gritties. Your article supports what I thought but i'd like to know for sure, are there any limitatons to HTTP proxy traversal when using Websockets?

Posted by tom on December 06, 2013 at 11:15 PM CET #

Hi Tom,

there are limitations, but it is very unlikely you will hit them - it is the same as for creating HTTPS connections. From what I know, the theoretical limit would be something around 60k parallel connections for one proxy. Also depends on the proxy software itself, the number of "CONNECT"s is usually capped there to be able to process other standard http requests.

Posted by Pavel on December 06, 2013 at 11:34 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Pavel Bucek

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today