Created
March 16, 2012 19:27
-
-
Save mloughran/2052006 to your computer and use it in GitHub Desktop.
Revisions
-
mloughran revised this gist
Mar 16, 2012 . 2 changed files with 17 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,10 @@ # Mobile Safari crash when returning to WebSocket page 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. ## Steps to reproduce @@ -13,11 +17,15 @@ The crash occurs due to the order in which WebSocket events are handled by the b }); * 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. ## Workaround Call `ws.send` in a `setTimeout`. When you do this the `readyState` will be correctly set to closed, and Safari won't crash This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,10 @@ # This example required em-websocket. Install em-websocket using # # gem install em-websocket # # Run this server # # ruby server.rb require 'rubygems' require 'em-websocket' -
mloughran revised this gist
Mar 16, 2012 . 2 changed files with 47 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,27 @@ <html> <head> <script> function debug(string) { var element = document.getElementById("debug"); var p = document.createElement("p"); p.appendChild(document.createTextNode(string)); element.appendChild(p); } var ws = new WebSocket("ws://localhost:8080/"); ws.onopen = function() { debug("WebSocket open") }; ws.onmessage = function(event) { debug("WebSocket open, readyState = " + ws.readyState) ws.send("foo") }; ws.onclose = function(event) { debug("WebSocket closed") } </script> </head> <body> <div id="debug"></div> </body> </html> This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,20 @@ # This example required em-websocket. Install using # gem install em-websocket require 'rubygems' require 'em-websocket' EM::WebSocket.start(:host => "0.0.0.0", :port => 8080, :debug => true) do |ws| ws.onopen { puts "WebSocket open" EM.add_periodic_timer(5) { ws.send('bar') } } ws.onmessage { |msg| puts "Received #{msg}" } ws.onclose { puts "WebSocket closed" } end -
Martyn Loughran created this gist
Mar 16, 2012 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,37 @@ The following outlines a crashing bug which affects iOS devices running versions 5.0.x & 5.1 (iPhone & iPad), and a workaround for the crash. The crash occurs due to the order in which WebSocket events are handled by the browser, and that calling `send()` on a closed WebSocket object causes a crash. ## Steps to reproduce * 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) * Close the WebSocket connection. You could either kill the server, or wait for the connection to time out (often this is 1 minute, but it seems to vary) * Switch back to the page. **Safari will crash** ## Workaround 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"); }); }); ## Extra notes 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.