Subject: [hybi] Races in websocket API?

From: Greg Wilkins <[email-masked]>
Date: Thu, 19 Nov 2009 15:00:22 +1100

Is there a race in the websocket API.

When you do:

  var ws = new WebSocket("ws://mysite.com","myprotocol");

then the spec says:

   Return a new WebSocket object, and continue these steps in the
   background (without blocking scripts).

   Establish a Web Socket connection to a host host, on port port
   (if one was specified), from origin, with the flag secure, with
   resource name as the resource name, and with protocol as the
   protocol (if it is present).

So if the next line in the script is

  ws.onopen=myopenfunc;

there is a race between if the onopen function will
be assigned and if the background connection has been established?

OK it is currently unlikely that the connect will happen that
quick - however if I'm running in a rhino test environment
or a on a browser that is multiplexing the websocket onto an
already existing connection, then the onopen may indeed be fast.

Similar races exist for onmessage and onclose.  Setting onmessage
might miss a message that is delivered quickly after the websocket
is opened.

regards

---

From: Fumitoshi Ukai (鵜飼文敏) <[email-masked]>
Date: Thu, 19 Nov 2009 13:24:26 +0900

> be assigned and if the background connection has been established?

I believe open event  is just queued at the moment, and it will be fired
later when javascript becomes idle.

When the Web Socket connection is established, the user agent must run the
following steps:
 Change the readyState attribute's value to OPEN (1).
 Queue a task to fire a simple event named open at the WebSocket object.

-- 
ukai

> _______________________________________________
> hybi mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/hybi
>

---

From: Fumitoshi Ukai (鵜飼文敏) <[email-masked]>
Date: Thu, 19 Nov 2009 13:26:04 +0900

-- 
ukai

---

From: Fumitoshi Ukai (鵜飼文敏) <[email-masked]>
Date: Fri, 20 Nov 2009 14:08:45 +0900

On Fri, Nov 20, 2009 at 1:10 PM, Greg Wilkins <[email-masked]> wrote:

> Fumitoshi Ukai (鵜飼文敏) wrote:
> > On Thu, Nov 19, 2009 at 1:00 PM, Greg Wilkins <[email-masked]
> >
> >      var ws = new WebSocket("ws://mysite.com
> >     <http://mysite.com>","myprotocol");
> > ...
> Unfortunately this does not appear to be the implementation in chrome
> at least.  If you step through with a debugger, then the close happens
> before my ws.onclose function is assigned, as thus it is never called.
>

Really?
I couldn't reproduce the case.  I put long for loop between new WebSocket
and ws.onopen =, and/or ws.onclose, it will fire onopen and onclose as
expected after chrome showing the page is unresponsive.

 var ws = new WebSocket("ws://localhost:8880/websocket/tests/simple");
debug("wait");
for (var j = 0; j < 50000; j++) {
 for (var i = 0 ; i < 100000; i++) {
  ;
 }
}
debug("wait done");

ws.onopen = function()
{
    debug("Connected.");
};

ws.onmessage = function(messageEvent)
{
    debug("Received: '" + messageEvent.data + "'");
};

ws.onclose = function()
{
    debug("Closed.");
    endTest();
};

-- 
ukai

> Even if it was implemented as you say, I'm wondering if the API should
> be less dependent on the single threaded nature of current javascript
> implementations.
>
> cheers
>

---

From: John Fallows <[email-masked]>
Date: Thu, 19 Nov 2009 21:33:56 -0800

Greg,

We raised this as a potential issue during the API design for
WebSocket (back when it was called TCPConnection), indicating that a
separate method might be desirable that could be called after the
WebSocket was constructed and event handlers attached.

But the decision was made that a single-threaded execution environment
made a separate method unnecessary, because the execution of the
onopen handler (for example) could not preempt the execution of the
following 2 lines of JavaScript code:

var ws = new WebSocket("ws://kaazing.net/echo");
ws.onopen = function() { console.log("OPEN"); }

Therefore, by the time the open event is delivered, the onopen handler
would have already been attached.

Kind Regards,
John Fallows.

-- 
>|< Kaazing Corporation >|<
John Fallows | CTO | +1.650.960.8148
888 Villa St, Ste 410 | Mountain View, CA 94041, USA

---

From: Jamie Lokier <[email-masked]>
Date: Fri, 20 Nov 2009 15:16:42 +0000

> would have already been attached.

Unfortunately the single-threaded assumption is not correct.

First, it's already been mentioned that when running Javascript under
a debugger under at least one browser, events can be sent and lost
before the second line executes.

Second, all recent browsers have multi-threaded Javascript, under
either Google's WorkerPool API, or WHATWG's Web Workers.

Web Workers have been suggested as a way to use WebSocket effectively,
but this single-threaded assumption might make that combination
difficult to use.  What happens when you create a new WebSocket object
in a Web Worker?  Can that be done safely?

I'm surprised at that, given WHATWG is involved with both WebSocket
and Web Workers.

An obvious solution is a connect() method, similar to XmlHttpRequest's
send() method.

-- Jamie

---

From: John Fallows <[email-masked]>
Date: Fri, 20 Nov 2009 11:58:29 -0800

> before the second line executes.

Is that behavior considered a bug in the debugger or a design
constraint for JavaScript APIs in general?

> either Google's WorkerPool API, or WHATWG's Web Workers.

How could WorkerPool or Web Workers be used to preemptively schedule
notification of the "open" event after the first line executes but
before the second line executes in the same JavaScript execution
context?

> in a Web Worker?  Can that be done safely?

My understanding is that although Web Workers provide multiple threads
of execution for JavaScript, they work with independent state and
communicate via serialized messages.  So, from the perspective of each
Web Worker, the execution model is still single-threaded.

If this was not the case, then locking primitives would be necessary
in JavaScript to support multiple threads of execution accessing the
same shared state.

I believe the correct mental model for this is the following:

[single-threaded perspective]
  var ws = new WebSocket("ws://kaazing.net/echo");
  ws.onopen = function() { console.log("OPEN"); }
  [yield control to deliver pending events such as "open"]

> An obvious solution is a connect() method, similar to XmlHttpRequest's

This was the proposal we made for TCPConnection at the time, because
it mirrored the disconnect() call.  Given the current WebSocket API,
the natural equivalent today would probably be open() rather than
connect().

Kind Regards,
John Fallows
--

---

From: Maciej Stachowiak <[email-masked]>
Date: Sun, 22 Nov 2009 19:50:46 -0800

> in a Web Worker?  Can that be done safely?

Short version: yes, WebSocket can work fine in a Web Worker.

Slightly longer version: "Single-threaded" is perhaps a misleading way  
to characterize the required condition. Here's a slightly more precise  
description: all WebSocket events are delivered on the logical  
"thread" of JavaScript execution that spawned them (either a UI thread  
or a Worker or what have you). The event delivery is not re-entrant -  
the event will only be sent the next time that thread of execution  
drops back into the event loop. And you can't pass a WebSocket from  
one thread to another. This means that any time you do a sequence like  
this:

You can be guaranteed that no "open" event will fire before the  
"onopen" attribute is set - the WebSocket object cannot deliver events  
until the event loop on the thread that created it is free.

  -  Maciej

---

From: Greg Wilkins <[email-masked]>
Date: Fri, 20 Nov 2009 15:10:34 +1100

cheers