Repository: ipython/ipython

Issue:
Reconnecting error messages with master(-ish)
Version: ee6223ab74eb

My situation is that I set up a remote notebook on a server that I only can reach when in a VPN. Now, my Wifi is shaky for some reason, that's possibly how my VPN get's shaky.
So I needed to close my notebook after a VPN reconnect and the dashboard still reported it as 'running'. When I clicked on the 'running' notebook, I got this error in the console:

``` python
RunTimeError: Method not supported by Web Sockets
```

Full error log here:
https://gist.github.com/23ed2e252897d96804a5

Working on OSX 10.9.5 using conda and Python 3.4

Reconnecting error messages with master(-ish)
Version: ee6223ab74eb

My situation is that I set up a remote notebook on a server that I only can reach when in a VPN. Now, my Wifi is shaky for some reason, that's possibly how my VPN get's shaky.
So I needed to close my notebook after a VPN reconnect and the dashboard still reported it as 'running'. When I clicked on the 'running' notebook, I got this error in the console:

``` python
RunTimeError: Method not supported by Web Sockets
```

Full error log here:
https://gist.github.com/23ed2e252897d96804a5

Working on OSX 10.9.5 using conda and Python 3.4



Discussion:
@michaelaye what tornado version?

I just updated today, so I can't be 100% sure, but if I had the previous `conda` version, then it was 4.0.2.

@michaelaye what tornado version?

I just updated today, so I can't be 100% sure, but if I had the previous `conda` version, then it was 4.0.2.


Resolving patch:
diff --git a/IPython/html/base/zmqhandlers.py b/IPython/html/base/zmqhandlers.py
--- a/IPython/html/base/zmqhandlers.py
+++ b/IPython/html/base/zmqhandlers.py
@@ -94,11 +94,23 @@ def deserialize_binary_message(bmsg):
 
 class ZMQStreamHandler(WebSocketHandler):
     
+    if tornado.version_info < (4,1):
+        """Backport send_error from tornado 4.1 to 4.0"""
+        def send_error(self, *args, **kwargs):
+            if self.stream is None:
+                super(WebSocketHandler, self).send_error(*args, **kwargs)
+            else:
+                # If we get an uncaught exception during the handshake,
+                # we have no choice but to abruptly close the connection.
+                # TODO: for uncaught exceptions after the handshake,
+                # we can close the connection more gracefully.
+                self.stream.close()
+
+    
     def check_origin(self, origin):
         """Check Origin == Host or Access-Control-Allow-Origin.
         
         Tornado >= 4 calls this method automatically, raising 403 if it returns False.
-        We call it explicitly in `open` on Tornado < 4.
         """
         if self.allow_origin == '*':
             return True
@@ -160,7 +172,10 @@ def _reserialize_reply(self, msg_list, channel=None):
     def _on_zmq_reply(self, stream, msg_list):
         # Sometimes this gets triggered when the on_close method is scheduled in the
         # eventloop but hasn't been called.
-        if stream.closed(): return
+        if self.stream.closed() or stream.closed():
+            self.log.warn("zmq message arrived on closed channel")
+            self.close()
+            return
         channel = getattr(stream, 'channel', None)
         try:
             msg = self._reserialize_reply(msg_list, channel=channel)


Test patch: