<br><br><div class="gmail_quote">On Mon, Jul 6, 2009 at 9:30 PM, Ian Hickson <span dir="ltr"><<a href="mailto:ian@hixie.ch">ian@hixie.ch</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="it">On Fri, 26 Jun 2009, James Robinson wrote:<br>
><br>
> 0) postMessage() looks as if it is intended to mimic<br>
</div>> MessagePort.postMessage(), but the arguments and error conditions are<br>
<div class="it">> different.  While it would be conceptually nice to treat a web socket in<br>
> the same way as a message port, it's not possible to treat the two<br>
> postMessage() functions in the same way.  I'd recommend the WebSocket<br>
> version be renamed to something like "send()" to avoid confusion and<br>
> false expectations.<br>
<br>
</div>Fair enough. Done.<br>
<div class="it"><br>
<br>
<br>
> There's similar oddness with receiving events that satisfy the MessageEvent<br>
> interface - since all fields except 'data' will necessarily be invalid I<br>
> don't see the value in receiving something more complex.<br>
<br>
</div>I would like to avoid introducing four different event types for the four<br>
different types of 'message' events being introduced, which is why I<br>
overloaded the same interface for all four. I don't think it's a problem.<br>
<div class="it"><br>
<br>
> 1) The 'readyState' attribute can never actually be used by an application<br>
> and is redundant.<br>
><br>
> Initially, the 'readyState' attribute is set to CONNECTING, but while<br>
> the object is in this state the user is not permitted to interact with<br>
> the WebSocket in any way.  The only useful thing that a user could do is<br>
> set event handlers and wait for the 'open' event to fire.  When the<br>
> WebSocket becomes connected, the readyState becomes 1 and the 'open'<br>
> event is fired. Once the WebSocket is open, the spec states that<br>
> whenever the connection is closed the readyState changes to CLOSED and a<br>
</div>> 'close' event is enqueued. However, users can't usefully check the<br>
<div class="it">> readyState to see if the WebSocket is still open because there are not<br>
> and cannot be any synchronization guarantees about when the WebSocket<br>
</div><div class="it">> may close.  A user will have to wrap all calls to postMessage() (or<br>
> send() if the function is renamed) in a try/catch block in order to<br>
> handle INVALID_STATE_ERRs.  Once the 'close' event has been received the<br>
> readyState attribute is useless since the state of the WebSocket is<br>
> known and can never change.<br>
><br>
> I think 'readyState' should just go away since an application will have<br>
> to keep track of state updates through the fired events and use<br>
> try/catch blocks around all API calls anyway.<br>
<br>
</div>The attribute is mostly present for debugging purposes. I wouldn't expect<br>
anyone to actually use it for production work.<br>
<div class="it"><br>
<br>
On Fri, 26 Jun 2009, Drew Wilson wrote:<br>
><br>
> Yes, but the "closed" state of a given WebSocket doesn't have to exactly<br>
> match the state of the underlying TCP connection, in the same way that<br>
> document.cookies doesn't exactly match the current set of cookies that<br>
> the network stack may be tracking (they can differ when HTTP responses<br>
> are received in the background while JS is executing).<br>
><br>
> So if the remote server closes the TCP connection, it generates a<br>
> "close" event which marks the WebSocket as closed. It means that you<br>
> could have a situation where you post messages to a WebSocket which<br>
> aren't received by the server because the connection is closed, but<br>
> that's true regardless due to the asynchronous nature of the networking<br>
> protocol.<br>
<br>
</div>I've changed the spec to not throw an exception on send() if the<br>
connection is closed.<br>
<div class="it"><br>
<br>
On Fri, 26 Jun 2009, Kelly Norton wrote:<br>
><br>
> One thing about postMessage that I'm curious about. Since it has to<br>
> report failure synchronously by throwing an INVALID_STATE_ERR, that<br>
> seems to imply that all data must be written to a socket before<br>
> returning and cannot be asynchronously delivered to an I/O thread<br>
> without adding some risk of silently dropping messages. Seems like the<br>
> right choice would be to allow outbound messages to drop, which would<br>
> mean that developers would be forced to do their own handshaking.<br>
<br>
</div>send() doesn't report I/O errors, it only throws an exception if the<br>
connection isn't open yet (and previously, if the connection had died<br>
prior to it being called, though that is no longer the case), or if the<br>
input is invalid.<br>
<div class="it"><br>
<br>
> I'm also not sure there is good coverage of error conditions in the<br>
> spec. The only methods of error notification are exceptions in<br>
> postMessage and onclose.<br>
<br>
</div>In fact, only onclose actually reports an error; the exception from send()<br>
now only reports a misuse of the API, not a network error.<br>
<div class="it"><br>
<br>
> I had assumed that a WebSocket that fails to connect would invoke<br>
> onclose asynchronously, but I didn't see that in the spec.<br>
<br>
</div>It's there, though subtle. :-)<br>
<br>
The constructor in the API spec invokes the "Establish a Web Socket<br>
connection" algorithm from the protocol spec. That algorithm then invokes<br>
the "fail the Web Socket connection" algorithm upon failure, and that<br>
algorithm says to invoke the "close the Web Socket connection" algorithm,<br>
and that algorithm says that this means that "Web Socket connection is<br>
closed", and the API spec says "When the Web Socket connection is closed,<br>
the readyState attribute's value must be changed to CLOSED (2), and the<br>
<div class="it">user agent must queue a task to fire a simple event called close at the<br>
WebSocket object".<br>
<br>
</div>I've added a note that says this.<br>
<div class="it"><br>
<br>
> Without that you don't even have the ability to know if a<br>
> socket failed to establish a connection (short of readyState polling).<br>
> The spec also doesn't indicate that the readyState should transition to<br>
> CLOSED on connection failure.<br>
<br>
</div>This is part of the same sequence of events as described above.<br>
<div class="it"><br>
<br>
On Fri, 26 Jun 2009, Kelly Norton wrote:<br>
><br>
> Doesn't it seem strange that disconnect() causes an onclose event to be<br>
> dispatched? Should the method not be close() to be consistent with<br>
> open(), onopen, onclose?<br>
<br>
</div>I've renamed disconnect() to close() in both EventSource and WebSocket.<br>
<br>
<br>
On Fri, 26 Jun 2009, Michael Nordman wrote:<br>
><br>
> Does disconnect() attempt to flush pending messages or drop them? There<br>
<div class="it">> isn't a way to determine if the WebSocket is successfully sending the<br>
> postMessage data? For all the caller knows, its just backing up and not<br>
> going anywhere.<br>
><br>
</div><div class="it">> Something that might add value is an onmessagesent event that fires<br>
> after a postMessage has put the bits on the wire.<br>
<br>
</div>If you want acknowledgements, implement app-level acks -- in practice,<br>
there's not much difference between hitting the network or not, if the<br>
other side hasn't yet received the packets.<br>
<div class="it"><br>
<br>
> postMessage() may want another exception condition... 'too much data<br>
> pending exception'... consider calling postMessage in a while(true)<br>
> loop... at some point the system is going to have to give up queing the<br>
> data if its not actually making its way out on the wire.<br>
<br>
</div>The spec doesn't specify how UAs are to handle hitting hardware<br>
limitations or system limitations, because it's often difficult to truly<br>
control how those cases are handled.<br>
<div class="it"><br>
<br>
On Fri, 26 Jun 2009, James Robinson wrote:<br>
><br>
> Not changing variables out from under executing JavaScript makes a lot<br>
> of sense, but if that was the case then it's not clear when the<br>
> readyState could be updated.  The spec states "When the *Web Socket<br>
</div>> connection is closed*, the readyState attribute's value must be changed<br>
<div class="it">> to CLOSED (2), and the user agent must queue a task to fire a simple<br>
> event called close at the WebSocket object." If the browser cannot<br>
> mutate the readyState until JavaScript stops running then it would<br>
> either have to either enqueue a second task to change readyState at some<br>
> point in the future or set the readyState right before dispatching the<br>
> 'close' event.  The latter would be much nicer to implement - but then<br>
> it does make the readyState completely useless as it would always be<br>
> exactly equivalent to the last event that was fired on a given<br>
> WebSocket.<br>
<br>
</div>I've left it as is (the attribute changes on the fly), which is possibly<br>
risky, but more consistent with how such attributes are handled in<br>
general.<br>
<div class="it"><br>
<br>
> I think a better way to do error handling is to have an asynchronous<br>
> onerror callback or event when the browser notes that a message did not<br>
> make it to the other side.<br>
<br>
</div>The client can't really always know this anyway. I think it's better to do<br>
app-level acking if you care enough.<br>
<div class="it"><br>
<br>
On Fri, 26 Jun 2009, James Robinson wrote:<br>
><br>
> The concept of a port being in a closed state is not very well defined -<br>
> if the state means only the readyState status, then when can the state<br>
> legally be updated?  If it has some meaning closer to the state of the<br>
> underlying connection, then it can't be queried synchronously without<br>
> very expensive synching to the I/O thread or process.<br>
><br>
</div><div class="it">> Forcing applications to build their own send/ack functionality would be<br>
> pretty tragic considering that WebSockets are built on top of TCP.<br>
<br>
</div>If we had access to the underlying TCP packets, I guess we could return a<br>
number with each send() and have some way to query the number of the<br>
mesage that the most recent packet that got all the way to other side<br>
contained, but in practice I don't think that implementations are always<br>
going to have access to that, and also it's not just that the other stack<br>
got the message that matters, but that the remote server actually got the<br>
messages and processed it.<br>
<div class="it"><br>
<br>
On Fri, 26 Jun 2009, Michael Nordman wrote:<br>
><br>
> If you're uploading a large data set incrementally across many distinct<br>
> postMessage calls (perhaps to leave room for other control messages<br>
> interspersed amoungst them, or to present progress info), how do you<br>
> know when to queue more data to be sent.<br>
<br>
</div>I think when we add support for file upload, we'll make it so that it<br>
automagically supports this case. That is, you'll say "upload this file in<br>
small bits" and then if you later say "send this text message", the text<br>
message will be sent before any pending file bits. We can use a separate<br>
type of packet in the WebSocket stream to do this.</blockquote><div><br></div><div>Sounds like that would require a protocol change. Is the message framing spec'd in such a way that a new 'packet type' can be introduced in a backward compatible fashion? </div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><br>
<font color="#888888"><br>
--<br>
Ian Hickson               U+1047E                )\._.,--....,'``.    fL<br>
<a href="http://ln.hixie.ch/" target="_blank">http://ln.hixie.ch/</a>       U+263A                /,   _.. \   _\  ;`._ ,.<br>
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'<br>
</font></blockquote></div><br>