Question

According to Wikipedia most browsers use RFC6455 or a slightly earlier version with an almost identical handshake. The server I'm using only supports RFC6455 or similar, where it accepts Origin: or Sec-WebSocket-Origin: depending on the specified version.

Safari 5 and iOS 5 uses the hixie version of WebSocket. I normally fall back to long-polling if WebSocket is missing. Safari 5 has a WebSocket object, but the handshake is vastly different.

Is there any way to detect if WebSocket is hixie, or belongs to Safari 5, so I can ignore it without trying the handshake? Are there any ways of checking if the browser is Safari 5 without relying on the user agent?

Was it helpful?

Solution

According to the WebSocket W3C draft in 2009 the CLOSED constant has a value of 2:

[Constructor(in DOMString url, in optional DOMString protocol)]
interface WebSocket {
  ...
  // ready state
  const unsigned short CONNECTING = 0;
  const unsigned short OPEN = 1;
  const unsigned short CLOSED = 2;
  ...
};
WebSocket implements EventTarget;

In the W3C draft dated in 2011 CLOSED has a value of 3:

[Constructor(in DOMString url, in optional DOMString protocols)]
[Constructor(in DOMString url, in optional DOMString[] protocols)]
interface WebSocket {
  ...
  // ready state
  const unsigned short CONNECTING = 0;
  const unsigned short OPEN = 1;
  const unsigned short CLOSING = 2;
  const unsigned short CLOSED = 3;
  ...
};

The 2009 draft corresponds to hixie/hibi-00 whereas the 2011 draft corresponds with hibi-07 and later, as seen on the Wikipedia chart.

With this information you can do a JavaScript check like this:

if("WebSocket" in window && WebSocket.CLOSED > 2) {
    // hibi-07 to RFC6455
} else {
    // No WebSocket, or hixie
}

I've used the following test page on a browser screen shot service:

<html>
<body>
<div id="test"></div>
<script>
var test = document.getElementById("test");
var text = "no soup for you!";
if ("WebSocket" in window) {
    text = "WebSocket " + WebSocket.CLOSED;
} else if("MozWebSocket" in window) {
    text = "MozWebSocket " + MozWebSocket.CLOSED;
}
test.appendChild(document.createTextNode(text));
</script>
</body>
</html>

Safari 5 and Chrome 12 and below return 2, whereas Safari 6 and Chrome 14 and above returns 3 for CLOSED.

Chrome 13 uses uses hixie, but returns 3. This is the only edge case I could find. Since Chrome auto-updates, Chrome 13 users should be zero.

NOTE: These constants are set on both the WebSocket constructor and WebSocket.prototype. Safari 5.0, prior to 5.1, only sets these constants on WebSocket.prototype. If you only plan to support RFC6455 and above, WebSocket.CLOSED > 2 or WebSocket.CLOSED === 3 is sufficient.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top