Philipp Serafin wrote:

Asynchronous: Requests and responses can be pipelined, meaning requests and
responses can be transmitted simultaneously and are queued.


I think the problem is that this definition of "asynchronous" is very
narrow. Yes, you don't need to wait for a request to finish before you
issue a new one. But you'd still be bound to HTTP's request/response
scheme in general.

WebSockets uses HTTP so it is hardly immune to the request/response behaviour of its underlying protocol (including the stream nature of TCP).

Besides this statement appears to be based on the assumption that the server MUST wait for additional client requests to send each "message". However the specification allows the server to send "chunked" or "multipart" data in a variety of ways so full asynchronous communication is acheivable by making the response chunks part of one long HTTP multipart response and allowing the javascript API to access the incoming data while the response is incomplete. It can be simplified for the end-user by allowing the raw server response to be read by bytes, lines or "parts". If you need more channels (ie, to pass messages while sending a large file) then you simply open more WebSockets and let the server handle multiplexing via cookies or message ids.

However, web authors might want to employ other schemes as well, for
example server-sided asynchronous notifications ("pushing"),

Client opens a connection. handshakes, then leaves connection open listening for "pushed" parts in the response stream.

client-sided notifications that don't need to be replied

HTTP has a status code specifically for this purpose.

 or requests that can be answered out-of-order.

The order of data is controlled by the order it is sent by the application. There is no requirement for the requests and responses/parts to be synchronised. Especially if the server responses consist of a single multi-part "response".



I'm not advocating against WebSockets, just its current definition. In particular it tries to solve things that HTTP/1.1 already handles. I believe we should be thinking of WebSockets as a Javascript API, not a new communications protocol for the simple reason that HTTP is already a very suitable and widely deployed protocol. What authors (especially AJAX authors) are missing is a reliable way to use HTTP's existing asynchronous connection support.

Here are my issues with WebSockets as currently defined:

1.) Request must have a <scheme> component whose value is either "ws" or "wss"

The "scheme" should be HTTP(S). WebSockets should be the API.

2.) The message event is fired when when data is received for a connection.

What "data"? A byte, a line, a chunk, the whole response? The spec isn't clear. I'd also recommend adding a connection.read( max_bytes ) method as used by Python and most languages to let the author receive bytes at a frequency appropriate to the application (eg, a game might want to frequently poll for small updates).

3.) If the resulting absolute URL has a <port> component, then let port be that component's value; otherwise, if secure is false, let port be 81, otherwise let port be 815.

No, no, no! Don't let paranoia override common sense. Not all websocket applications will have the luxury to run on these ports (multiple web servers, shared host, tunnelled connections, 2 websocket apps on one host, etc...).

4.) The whole handshake is too complex.

There are many firewalls, proxies and servers that legimately insert, change, split, or remove HTTP headers or modify their order. This is also likely if the service being provided sits on top of a framework/server (such as Coldfusion/IIS). Also what happens if HTTP/1.2 is sent? These will break the WebSocket handshake as currently defined.

rfc 2616 section 3 says: The version of an HTTP message is indicated by an HTTP-Version field in the first line of the message.
HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT

How many non-http servers send this? Probably none. I recommend the handshake simply read about 256 bytes of the server response and check that it contains a valid HTTP version field and one or more valid HTTP headers and optional end-of-headers marker. If ALL headers semantically validate (ie, with the regex [A-Za-z-]: \s(.*?)\r\n) then it is reasonably safe to assume it is a real HTTP or WebSockets service. If the headers validate then the client repeats the process until the message body is reached. At this point we check our collected headers for at least one "Accept" header containing "WebSocket" (assuming that being a "WebSocket" rather than a basic pipelined HTTP connection is even useful).

5.) URI parsing specification

The current proposal spells out the URI/path parsing scheme. However this should be treated EXACTLY like HTTP so the need to define it in the spec is redundant. It is enough to say that the resource may be requested using a GET or POST request. Same with cookie handling, authorization and other HTTP headers. These should be handled by the webserver and/or application exactly as normal, there is no need to rewrite the rules simply because the information flow is asynchronous.

6.) Data framing specification

Redundant because HTTP already provides multiple methods of data segment encapsulation including "Content-Length", "Transfer-Encoding" and "Content-Type". Each of these have sub-types suitable for a range of possible WebSocket applications. Naturally it is not necessary for the client or server to support them all since there are HTTP headers explicitly designed for this kind of negotiation. The WebSocket should however define at least one fallback method that can be relied on (I recommend "Content-Length", "Transfer-Encoding: chunked" and "Content-Type: multipart/form-data" as MUST requirements).

7.) WebSockets needs a low-level interface as well

By "dumbing down" the data transfer into fired events and wrapping the data segments internally the websocket hides the true communication behind an abstract object. This is a good thing for simplicity but extremely limiting for authors wanting to fine-tune an application or adapt to future protocols. I strongly recommend that rawwrite() and rawread() methods be made available to an OPEN (ie, authenticated/handshaked) websocket to allow direct handling of the stream. It would be understood that authors using these methods must understand the nature of both HTTP and websockets. In the same way a settimeout() method should be provided to control blocking/non-blocking behaviour. I can't stress enough how important these interfaces are, as they may one day be required to implement WebSockets 2.0 on "legacy" or broken HTML5 browsers.

8.) Origin: / WebSocket-Origin:

Specifying clients allowed to originate a connection is a disaster waiting to happen for the simple reason that sending your origin is a privacy violation in the same vain as the referrer field. Any open-source browser or privacy plugin will simply disable or spoof this since it would allow advertising networks to track people by ad-serving via websockets. Such tracking undermines the security of anonymising proxies (as the "origin" may be a private site or contain a client id). Using origin as a required field essentially makes the use of "referrer" mandatory. If a websocket wants to restrict access then it will have to use credentials or IP ranges like everything else.

9.) WebSocket-Location

The scenario this is supposed to solve (that an application makes a mistake about what host it's on and somehow sends the wrong data) is contrived. What's more likely to happen is that a server application has trouble actually knowing its (virtual) hostname (due to a proxy, mod_rewrite, URL masking or other legitimate redirect) and therefore NO clients can connect. It isn't uncommon for the host value passed to a CGI script and the hostname returned by the environment (ie, via uname or OS library) to conflict. Then there is the matter of an SSL connection (no host header available). I'm having trouble determining why this should even matter. I suspect most simple applications/wrappers will just echo back the host header sent by the client so if a mistake is made it's likely to go unnoticed anyway.

10.) To close the Web Socket connection, either the user agent or the server closes the TCP/IP connection. There is no closing handshake.

HTTP provides a reliable way of closing a connection so that all parties (client, server and proxies) know why the connection ended. There is no reason for websockets to not follow this protocol and close the connection properly.


In conclusion, the current specification of WebSockets re-invents several wheels and does so in ways that are overly complex, error-prone and yet seriously limited in functionality. The whole concept needs to be approached from the position of making HTTP's features (which are already implemented in most UAs) available to Javascript (while preventing the exploit of non-HTTP services). I do not believe this is difficult if my recommendations above are followed. I do not wish to be overly critical without contributing a solution, so if there are no serious objections to the points I've made I will put time into reframing my objections as a compete specification proposal.


Shannon


Reply via email to