While investigating an issue reported against the Pusher JavaScript library I gathered the following information. Posting in the hope that it can save someone else going through the laborious process I went through!
The crash is 100% reproducible, and affects iOS devices (tested on iPhone & iPad) running versions 5.0.x & 5.1. There is a simple workaround described below, and the code to reproduce the crash.
Summary: calling send()
on a closed WebSocket object which reports an open readyState
causes a crash. This scenario can occur when returning to a backgrounded page which received data and then closed when in the backgrounded state.
-
Visit a page which connects to a WebSocket server. That page should periodically send out WebSocket messages.
-
In the page bind to onmessage, and send a message back to the server
ws.onmessage(function(evt) { ws.send("foo"); });
-
Switch away from the page (either by changing tabs or backgrounding Safari)
-
The WebSocket connection will stay open for some time. Wait for the server to send a message to the page. You should not receive a reply in the server (since JavaScript is not executing on the backgrounded page)
-
Close the WebSocket connection. You could either kill the server, or wait for the connection to be closed by iOS (often this is 1 minute for background pages, but it seems to vary)
-
Switch back to the page. Safari will crash
This gist includes a simple WebSocket server and web page which you can use. You just need to serve the html page somewhere, and change localhost to your IP address.
Call ws.send
in a setTimeout
. When you do this the readyState
will be correctly set to closed, and Safari won't crash
ws.onmessage(function(evt) {
setTimeout(function() {
ws.send("foo");
});
});
When the onmessage event is called, the readyState
is still 1 (open), even at this point in time the WebSocket is in fact closed.
The onclose
event is fired after the onmessage
events, so you can't manage your own connected state.
The issue also affects earlier iOS versions, but you have to background Safari since JavaScript continues to execute in background tabs.
Posted to the WebKit tracker: https://bugs.webkit.org/show_bug.cgi?id=81517