Re: [hybi] Redesigning the Web Socket handshake

Jamie Lokier <jamie@shareable.org> Wed, 03 February 2010 21:55 UTC

Return-Path: <jamie@shareable.org>
X-Original-To: hybi@core3.amsl.com
Delivered-To: hybi@core3.amsl.com
Received: from localhost (localhost [127.0.0.1]) by core3.amsl.com (Postfix) with ESMTP id 679BA3A6957 for <hybi@core3.amsl.com>; Wed, 3 Feb 2010 13:55:34 -0800 (PST)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -2.613
X-Spam-Level:
X-Spam-Status: No, score=-2.613 tagged_above=-999 required=5 tests=[AWL=-0.014, BAYES_00=-2.599]
Received: from mail.ietf.org ([64.170.98.32]) by localhost (core3.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 5m0QBT8kXdev for <hybi@core3.amsl.com>; Wed, 3 Feb 2010 13:55:33 -0800 (PST)
Received: from mail2.shareable.org (mail2.shareable.org [80.68.89.115]) by core3.amsl.com (Postfix) with ESMTP id 5163E3A685F for <hybi@ietf.org>; Wed, 3 Feb 2010 13:55:33 -0800 (PST)
Received: from jamie by mail2.shareable.org with local (Exim 4.63) (envelope-from <jamie@shareable.org>) id 1NcnCk-0007Kf-VV; Wed, 03 Feb 2010 21:56:10 +0000
Date: Wed, 03 Feb 2010 21:56:10 +0000
From: Jamie Lokier <jamie@shareable.org>
To: Maciej Stachowiak <mjs@apple.com>
Message-ID: <20100203215610.GF19037@shareable.org>
References: <Pine.LNX.4.64.1002012305000.21600@ps20323.dreamhostps.com> <20100203025736.GS32743@shareable.org> <4B68FD77.7020107@webtide.com> <20100203163359.GA19037@shareable.org> <49D9192C-349B-4353-B48A-E95B27E3CC30@apple.com>
MIME-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: inline
In-Reply-To: <49D9192C-349B-4353-B48A-E95B27E3CC30@apple.com>
User-Agent: Mutt/1.5.13 (2006-08-11)
Cc: hybi@ietf.org
Subject: Re: [hybi] Redesigning the Web Socket handshake
X-BeenThere: hybi@ietf.org
X-Mailman-Version: 2.1.9
Precedence: list
List-Id: Server-Initiated HTTP <hybi.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/listinfo/hybi>, <mailto:hybi-request@ietf.org?subject=unsubscribe>
List-Archive: <http://www.ietf.org/mail-archive/web/hybi>
List-Post: <mailto:hybi@ietf.org>
List-Help: <mailto:hybi-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/hybi>, <mailto:hybi-request@ietf.org?subject=subscribe>
X-List-Received-Date: Wed, 03 Feb 2010 21:55:34 -0000

Maciej Stachowiak wrote:
> 
> On Feb 3, 2010, at 8:33 AM, Jamie Lokier wrote:
> 
> > Nice!  But that's not really what I meant.
> > 
> > What I meant is two things, I suppose.  One protocol, one client API:
> > 
> > Protocol: Establishing a connection, and then each proxy in the chain
> > either opts in to making it a WebSocket (or similar in style)
> > resulting in single connection with bidirectional messaging, or if
> > there are any proxies detected which won't participate, there will be
> > HTTP long-polling - at least for the hops on either side of that proxy
> > (perhaps not the other hops).
> > 
> > I *think* what you described is: Use WebSocket if the whole path
> > supports it, otherwise long-polling for the whole path.
> > 
> > The difference from what that is the intentional proxy-friendliness
> > and friendliness to all other deployed HTTP infrastructure.  It'll
> > pass through everything, including the internals of xrandomhttpd <->
> > CGI, etc. and upgrade to WebSocket opportunistically on those hops
> > where it can, while working transparently to the user where it can't.
> > 
> > For the API, you've probably understood that it'd be nice if the
> > WebSocket API had a fallback to HTTP long-polling implementation,
> > Of course that can be written in Javascript today.
> 
>
> That would be cool if it worked. But I'm not sure how you would
> detect that all your intermediaries understand WebSocket.

The main idea is opportunistic upgrade at each hop _without_ requiring
it for every hop.  So you could possibly have HTTP long-polling from
your client to your local proxy, for example, because one of the other
doesn't support the upgrade, but somewhere along the path it gets
converted to and from WebSocket.  (And other things, such as
opportunistic multiplexing (must be done very carefully)).

You don't try to check if every intermediary supports it - in fact,
they don't have to.  The idea is that agents/intermediaries recognise
a particular style of HTTP request passing through, and opt in by
adding something to say "I'm up for upgrading to the more efficient
method".  The next hop (in either direction) picks up the added note,
and if it understands it, then that specific hop can upgrade,
transparently to the other hops.

If hops on both sides of an intermediary upgrade, then the
intermediary would probably switch into a more efficient mode, because
it wouldn't need to translate between the different framing styles.

It can't quite be a single HTTP header, because we're talking about
bidirectional HTTP long-polling here which needs multiple connections,
so the intermediaries need to be able to recognise those connections.

The reliability problem comes from that added note being picked up
further away.  But that's not necessarily a problem, as long as the
intermediaries it passes through are able to carry the byte stream
reliably.  For which:

> Our best idea so far was hop-by-hop headers. But as someone else
> mentioned, there are intermediaries out there that just pass along
> hop-by-hop headers, but won't deal with arbitrary bidirectional
> non-HTTP traffic. So there doesn't seem to be a reliable mechanism
> for this.

There is and there isn't...

What we want from "dumb" intermediaries is that they _either_ are
detectable as regular HTTP proxies who would mangle, _or_ they behave
as a transparent TCP relay, after setting up.  ("Smart" intermediaries
are upgrade participants).

It's not possible to guarantee that, so sometimes there will be problems.

_But_, that is exactly the same problem which WebSocket faces already:
If a proxy cannot be detected and it mangles bidirectional binary
data, then basic (i.e. current draft) WebSocket is screwed as well.

The two problems are equivalent.  Anything which helps basic
WebSocket, helps with opportunistic participation.  Any time the
latter wouldn't work, would also break basic WebSocket.

All strategies used to make basic WebSocket work reliably apply:
Detecting bad proxies with rigid header checks, putting good proxies
into a helpful state (i.e. CONNECT?).

So it's the same problem and has the same expected success and failure
rate, and the same strategies to minimise that failure rate and
try something else when it's detected.


The idea of deliberately inserting your own "smart" proxies, at the
client or server end, offers an interesting alternative approach to
implementation too.  Existing HTTP long-poll clients and servers could
be used, where that is all infrastructure can handle for the time
being, and "smart" proxies would upgrade itto WebSocket over the
Internet, where it detects that is possible.

Conversely, standalone and simple "micro" WebSocket clients and
servers would be able to use non-WebSocket routes over the Internet
too, by virtue of that same "smart" proxy - making their
implementation a lot simpler.  (That's not dissimilar to cometd as a
way of deploying web apps, but this applies at the client side too.)

-- Jamie