Subject: Re: [hybi] Reducing the constraints on the HTTP part of WebSockets

From: Greg Wilkins <[email-masked]>
Date: Mon, 01 Mar 2010 09:24:53 +0100

Jamie Lokier wrote:

> All true, no doubt, but doesn't GET + Upgrade: meet the same design clash?
>
> A new HTTP method (plus Upgrade header) seems less likely to tickle
> browser and (unfortunately) proxy issues to me than using GET.

I think the point is that the handling should be tied to the Upgrade
header rather than adding new meanings to existing methods.

I don't have a big problem with having a new method, other than to
note that I've seen many implementations break with unexpected
method names.  Even Servlet2.5 security constraints are constrained
by the XSLT to only work with standard method names.

But please don't reuse CONNECT in a new/strange way.

The problem with using CONNECT, is that it is more often than
not handled completely differently to GET, POST, PUT, HEAD.

The later methods are not normally used to switch handling,
instead the URL provided with them is used to pick a handler,
which then will interpret the method.    So the URL can
be used to route the request to a handler that will
know websocket is supported at that URL and it can handle
the Upgrade header (and perhaps check the method).

But with CONNECT, it is the method that determines the handling
and thus it is often handled differently in a server.  There
is no URL to select a handler - which may interpret websocket
stuff.

It's the wrong verb to be using.

Perhaps POST is the better method to use - as at least that
will not be retried by HTTP layers.

cheers

---

From: Jamie Lokier <[email-masked]>
Date: Mon, 1 Mar 2010 08:41:45 +0000

> the Upgrade header (and perhaps check the method).

A request handler is usually different from the component which does
transport framing, i.e. chunking the response body, parsing the
request body according to Content-Length.

For example with CGI handlers invoked from Apache httpd, they cannot
process Upgrade: can they?  For non-Upgrade requests, Apache itself
will be chunking the response body output from the CGI handler, and
looking for the end of the request body if the header indicate one.  I
would be very surprised if Apache works with Upgrade: and a CGI
handler the way we would need it to - and the same for most other servers.

More concerning are proxies - those which don't mangle headers enough
to block the connection, but are still looking for HTTP message
framing and don't check for the Upgrade: header - because that header
has never been used before (has it?).  Or if they do, it's a code path
that nobody ever tested before.

> It's the wrong verb to be using.

I agree that it's the wrong verb from a HTTP perspective.

I just wonder which choice is likely to trigger bugs - especially I'm
concerned about proxies passing the handshake and mangling subsequent
data.

> will not be retried by HTTP layers.

A few years ago, I did some tests sending a POST and reading back the
response body at the same time as sending the request body.  By not
specifying a length, or by making it large, you could actually get a
two-way connection.  This was without an Upgrade: header.
Unfortunately it wasn't reliable in all clients that I tried.  But I
didn't notice any problem with proxies or servers (not that I tried
many).

-- Jamie

---

From: Greg Wilkins <[email-masked]>
Date: Mon, 01 Mar 2010 11:01:25 +0100

> request body according to Content-Length.

In the jetty handling of websocket, we treat the Upgrade request
like any other request and route it via authentication,
authorization, filters eventually to a servlet.

It is only within the servlet context, that a servlet
has all the information required to instantiate a websocket
endpoint (which is an application entity):

  + an authenticated/authorized HTTP upgrade request
  + the application context initialized (with applicable
    class loaders and JEE security realms etc)
  + other application objects and data created as part
    of the prior interaction with the website.
  + the sources of the server generated events that
    are to be sent (eg JMS endpoints).

So the servlet can analyse the request, decide if it wants to
accept the update and if so it creates the WebSocket endpoint
and sends a 101 response.

The 101 response goes back out via the normal servlet container
path to the HTTP engine and is logged and flushed normally.

This flushing may even be held up by a busy IO layer
and completed asynchronously at a later time.
It is only when the 101 response is completely flushed that
the jetty server triggers it's upgrade handling and looks
for the new connection handler (the WebSocket endpoint
created by the application in this case).

For a java web server, this is entirely the correct approach.
The upgrade request is a HTTP request and should be
handled as such.

The endpoint that we wish to connect the websocket with
is an application entity - and the Jetty HTTP layer has
no idea how to create such an application end point (and
no access to the classloaders and other contexts needed
to do so).

Of course other servers may have entirely different
application architectures.

But the point that I'm making, is that at websocket
upgrade request is a HTTP request and it is not unreasonable
for a server to handle it as such- and only start
websocket processing after the HTTP 101 response is
sent.

Any requirement to handle HTTP upgrade in unusual
non-normal ways, is going to cause grief to containers
such as Jetty - who have a reasonable desire to
handle HTTP as HTTP, up until the 101 is sent.

> process Upgrade: can they?  

They certainly can - and they can indicate their acceptance by
sending a 101.   It is what happens after the 101 that is tricky.

> For non-Upgrade requests, Apache itself

Obviously apache will need to be updated to respect 101 responses and
allow the connection to be handled differently AFTER the 101 response
is sent.

> that nobody ever tested before.

Upgrade is not well utilized - but I expect we will see more of it
in the future - eg to Upgrade http to https Also things like SPDY
are using this approach.

So Jetty (for example), had half hearted upgrade support and now
we have good upgrade support.   We can use this for upgrade
to SSL, SPDY, BWTP etc. etc.

I expect many other web infrastructure will be the same. Once
they support Upgrade for one of these reasons, then they will
utilize that support for the other use-cases.

I REALLY REALLY REALLY REALLY don't want to have to implement
something special for every new use-case.

> concerned about proxies passing the handshake and mangling subsequent

I'm a bit cautious about GET - because it can be retried.
Using something like POST would probably be better.

Using something like WSTP would probably trigger bugs...
but maybe only in the cases that we want fail fast?

I believe that using CONNECT will also generate bugs
and incorrectly trigger proxy actions.  It will also
generate a long series of complaints from me :)

cheers

---

From: Maciej Stachowiak <[email-masked]>
Date: Mon, 01 Mar 2010 02:39:47 -0800

On Mar 1, 2010, at 2:01 AM, Greg Wilkins wrote:

> and incorrectly trigger proxy actions.

Let's be agnostic about it in the requirements document (I hope we  
have rough consensus on that), and determine which approach generates  
more bugs using empirical methods for purposes of the spec.

> It will also generate a long series of complaints from me :)

At this point, I'm not sure there is a plausible design for the  
WebSocket protocol that avoids this problem.

Regards,
Maciej

---

From: Greg Wilkins <[email-masked]>
Date: Mon, 01 Mar 2010 12:48:30 +0100

Maciej Stachowiak wrote:
> Let's be agnostic about it in the requirements document (I hope we have
> rough consensus on that), and determine which approach generates more
> bugs using empirical methods for purposes of the spec.

If we agree on the requirement text that says something
along the lines of "possible and practical to use existing HTTP
code", then I think that captures the concerns
about the use of CONNECT.

> WebSocket protocol that avoids this problem.

Gee - no smiley?

Note, in this case I'm arguing in support of the current design
of websocket.

cheers

---

From: Scott Ferguson <[email-masked]>
Date: Mon, 01 Mar 2010 09:19:47 -0800

> authorization, filters eventually to a servlet.
...
> The upgrade request is a HTTP request and should be
Resin's approach is essentially the same. The initial request is a 
normal Java servlet request, letting applications use their full 
framework/security/etc infrastructure to handle/dispatch the request. We 
upgrade the request based on the application servlet's direction.

Once the web socket handler is launched the processing is different, of 
course. But by that point, web sockets just looks like an 
<InputStream,OutputStream> pair with associated threading/event issues.

-- Scott

---

From: Justin Erenkrantz <[email-masked]>
Date: Mon, 1 Mar 2010 18:45:07 +0000

On Mon, Mar 1, 2010 at 5:19 PM, Scott Ferguson <[email-masked]> wrote:
> Resin's approach is essentially the same. The initial request is a normal
> Java servlet request, letting applications use their full

By and large, even though it's implemented in C, I would expect Apache
httpd to be similar - once the 101 is accepted and sent by the server,
all HTTP filters would be flushed and replaced with WebSocket filters
- which would abstract out the framing and other
useless-to-application bits.  -- justin