From b34d9eb76a96970046b86a6c759b12bf0126e9a0 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 12 Feb 2015 16:20:50 -0800 Subject: [PATCH 1/2] backport WebSocket.send_error from tornado 4.1 raising an exception in a websocket results in "Method not supported" on tornado 4.0 --- IPython/html/base/zmqhandlers.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/IPython/html/base/zmqhandlers.py b/IPython/html/base/zmqhandlers.py index 8d7a2dc1f..4ddcb5e5f 100644 --- a/IPython/html/base/zmqhandlers.py +++ b/IPython/html/base/zmqhandlers.py @@ -94,6 +94,19 @@ if os.environ.get('IPYTHON_ALLOW_DRAFT_WEBSOCKETS_FOR_PHANTOMJS', False): 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. From 07e5f78ef2c87132907433f9d4cdbcd670132fe7 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 12 Feb 2015 16:21:36 -0800 Subject: [PATCH 2/2] handle message arriving when sockets are closed check both the incoming and outgoing streams before proceeding to send messages --- IPython/html/base/zmqhandlers.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/IPython/html/base/zmqhandlers.py b/IPython/html/base/zmqhandlers.py index 4ddcb5e5f..f1159e830 100644 --- a/IPython/html/base/zmqhandlers.py +++ b/IPython/html/base/zmqhandlers.py @@ -106,12 +106,11 @@ class ZMQStreamHandler(WebSocketHandler): # 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 @@ -173,7 +172,10 @@ class ZMQStreamHandler(WebSocketHandler): 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)