Re: [hybi] WebSocket -76 is incompatible with HTTP reverse proxies

Willy Tarreau <> Wed, 07 July 2010 04:55 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id C6CD93A6407 for <>; Tue, 6 Jul 2010 21:55:26 -0700 (PDT)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -1.054
X-Spam-Status: No, score=-1.054 tagged_above=-999 required=5 tests=[AWL=-1.611, BAYES_50=0.001, HELO_IS_SMALL6=0.556]
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id xguzRjEYxv8S for <>; Tue, 6 Jul 2010 21:55:25 -0700 (PDT)
Received: from ( []) by (Postfix) with ESMTP id 7D83A3A6869 for <>; Tue, 6 Jul 2010 21:55:24 -0700 (PDT)
Date: Wed, 07 Jul 2010 06:55:26 +0200
From: Willy Tarreau <>
To: Greg Wilkins <>
Message-ID: <>
References: <> <>
MIME-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: inline
In-Reply-To: <>
User-Agent: Mutt/1.5.20 (2009-06-14)
Subject: Re: [hybi] WebSocket -76 is incompatible with HTTP reverse proxies
X-Mailman-Version: 2.1.9
Precedence: list
List-Id: Server-Initiated HTTP <>
List-Unsubscribe: <>, <>
List-Archive: <>
List-Post: <>
List-Help: <>
List-Subscribe: <>, <>
X-List-Received-Date: Wed, 07 Jul 2010 04:55:26 -0000

On Wed, Jul 07, 2010 at 09:14:27AM +1000, Greg Wilkins wrote:
> Willy
> thanks for giving a real world example to the problems of non HTTP
> compatibility that were predicted to occur if -76 was adopted.

In fact, I'd say that it's often hard to predict the risk of breakage
before observing it, the only thing we know is that if we respect
what others understand, the risk is low and that if we patently
ignore standards, the risk is high.

> My understanding is that the nonce is sent as a non-HTTP non-Websocket
> data packet precisely to detect if there is an intermediary that
> cannot handle websocket - and thus fail fast.

That's what I understood too and it is inefficient.

> Your example show that
> this mechanism is neither a good test for websocket capability, nor
> does it actually fail fast. I believe HAproxy is a load balancer that
> will handle the first HTTP Request/Response on a connection as HTTP,
> before turning into a byte forwarding pipe.

yes, it now properly handles the 101, which means that it becomes a
pipe once it sees the 101 in the response (once the handshake completes).
So there is no way it will send unadvertised data before the server is
OK with receiving them.

> Such a proxy will work
> fine with websocket if the handshake is compliant HTTP, but fails on
> -76 because it is not compliant.


> The proposal that I have made several times on this list is that the
> handshake should include the nonce as a header.  The 16 byte check
> code can be sent as non-HTTP data after the 101, as there is no longer
> a requirement to be HTTP then - however I think that if we wish to
> test websocket capability, it would be far better to send that in a
> websocket frame:

Yes, that's what I think would be the cleaner (and the last proposal
in my mail too).

> Send:
>     GET /index.html HTTP/1.1
>     Host:
>     Connection: Upgrade
>     Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5
>     Sec-WebSocket-Key2: 12998 5 Y3 1  .P00
>     Sec-WebSocket-Nonce: 4ABC2FEE237CD165
>     Sec-WebSocket-Protocol: sample
>     Upgrade: WebSocket
>     Origin:
> Receive:
>         HTTP/1.1 101 WebSocket Protocol Handshake
>         Upgrade: WebSocket
>         Connection: Upgrade
>         Sec-WebSocket-Origin:
>         Sec-WebSocket-Location: ws://
>         Sec-WebSocket-Protocol: sample
>         0x81 0x10  <16 bytes>
> Only after the 16 byte binary websocket frame is received and
> validated should the client trigger the onOpen handling. This
> handshake is compliant HTTP and includes a check of websocket
> capability server to client without an extra round trip.

And it's also how TLS is supposed to work over HTTP/1.1 since May 2000 !

> The only
> think it lacks is a check of client to server websocket capability,
> but:
>    a) we can see the current -76 check doesn't work anyway
>    b) all the intermediaries say the upgrade request and 101 response,
> so they had the opportunity to refuse the upgrade
>    c) it would be easy to add a client to server websocket keep-alive
> send after the handshake that would check that path.  If server could
> timeout the connection if a no message is received within a reasonable
> timeout.  To check connectivity there is no way to avoid having such a
> timeout since you can't test for something not being received any
> other way... at least this way, the message could actually be a real
> application message and thus a useful message and not another round
> trip.

In my opinion, it is not a problem because if an intermediate does not
understand the 101, the response data will not be sent to the client
(and we may have to ensure a bit more that those data can't be sent, eg
with content-length 0 in the response, and connection: close). If those
data flow to the client, then it must mean that the pipe is established.

I'm now thinking we could even further strengthen the handshake via non
compliant intermediates by adding connection: close in both directions.
This will make incompatible reverse proxies fail the earliest possible,
without breaking compatibility with the protocols implemented on the
components which transport the handshake.