Show More
@@ -13,9 +13,7 b' except ImportError:' | |||||
13 | from urlparse import urlparse # Py 2 |
|
13 | from urlparse import urlparse # Py 2 | |
14 |
|
14 | |||
15 | import tornado |
|
15 | import tornado | |
16 | from tornado import ioloop |
|
16 | from tornado import gen, ioloop, web, websocket | |
17 | from tornado import web |
|
|||
18 | from tornado import websocket |
|
|||
19 |
|
17 | |||
20 | from IPython.kernel.zmq.session import Session |
|
18 | from IPython.kernel.zmq.session import Session | |
21 | from IPython.utils.jsonutil import date_default, extract_dates |
|
19 | from IPython.utils.jsonutil import date_default, extract_dates | |
@@ -197,7 +195,12 b' class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler):' | |||||
197 | """ |
|
195 | """ | |
198 | pass |
|
196 | pass | |
199 |
|
197 | |||
200 |
def get(self |
|
198 | def pre_get(self): | |
|
199 | """Run before finishing the GET request | |||
|
200 | ||||
|
201 | Extend this method to add logic that should fire before | |||
|
202 | the websocket finishes completing. | |||
|
203 | """ | |||
201 | # Check to see that origin matches host directly, including ports |
|
204 | # Check to see that origin matches host directly, including ports | |
202 | # Tornado 4 already does CORS checking |
|
205 | # Tornado 4 already does CORS checking | |
203 | if tornado.version_info[0] < 4: |
|
206 | if tornado.version_info[0] < 4: | |
@@ -213,15 +216,22 b' class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler):' | |||||
213 | self.session.session = cast_unicode(self.get_argument('session_id')) |
|
216 | self.session.session = cast_unicode(self.get_argument('session_id')) | |
214 | else: |
|
217 | else: | |
215 | self.log.warn("No session ID specified") |
|
218 | self.log.warn("No session ID specified") | |
|
219 | ||||
|
220 | @gen.coroutine | |||
|
221 | def get(self, *args, **kwargs): | |||
|
222 | # pre_get can be a coroutine in subclasses | |||
|
223 | yield gen.maybe_future(self.pre_get()) | |||
216 | # FIXME: only do super get on tornado β₯ 4 |
|
224 | # FIXME: only do super get on tornado β₯ 4 | |
217 | # tornado 3 has no get, will raise 405 |
|
225 | # tornado 3 has no get, will raise 405 | |
218 | if tornado.version_info >= (4,): |
|
226 | if tornado.version_info >= (4,): | |
219 |
|
|
227 | super(AuthenticatedZMQStreamHandler, self).get(*args, **kwargs) | |
220 |
|
228 | |||
221 | def initialize(self): |
|
229 | def initialize(self): | |
|
230 | self.log.debug("Initializing websocket connection %s", self.request.path) | |||
222 | self.session = Session(config=self.config) |
|
231 | self.session = Session(config=self.config) | |
223 |
|
232 | |||
224 | def open(self, *args, **kwargs): |
|
233 | def open(self, *args, **kwargs): | |
|
234 | self.log.debug("Opening websocket %s", self.request.path) | |||
225 | if tornado.version_info < (4,): |
|
235 | if tornado.version_info < (4,): | |
226 | try: |
|
236 | try: | |
227 | self.get(*self.open_args, **self.open_kwargs) |
|
237 | self.get(*self.open_args, **self.open_kwargs) |
@@ -7,6 +7,7 b' import json' | |||||
7 | import logging |
|
7 | import logging | |
8 | from tornado import gen, web |
|
8 | from tornado import gen, web | |
9 | from tornado.concurrent import Future |
|
9 | from tornado.concurrent import Future | |
|
10 | from tornado.ioloop import IOLoop | |||
10 |
|
11 | |||
11 | from IPython.utils.jsonutil import date_default |
|
12 | from IPython.utils.jsonutil import date_default | |
12 | from IPython.utils.py3compat import cast_unicode |
|
13 | from IPython.utils.py3compat import cast_unicode | |
@@ -85,6 +86,10 b' class KernelActionHandler(IPythonHandler):' | |||||
85 |
|
86 | |||
86 | class ZMQChannelHandler(AuthenticatedZMQStreamHandler): |
|
87 | class ZMQChannelHandler(AuthenticatedZMQStreamHandler): | |
87 |
|
88 | |||
|
89 | @property | |||
|
90 | def kernel_info_timeout(self): | |||
|
91 | return self.settings.get('kernel_info_timeout', 10) | |||
|
92 | ||||
88 | def __repr__(self): |
|
93 | def __repr__(self): | |
89 | return "%s(%s)" % (self.__class__.__name__, getattr(self, 'kernel_id', 'uninitialized')) |
|
94 | return "%s(%s)" % (self.__class__.__name__, getattr(self, 'kernel_id', 'uninitialized')) | |
90 |
|
95 | |||
@@ -150,7 +155,8 b' class ZMQChannelHandler(AuthenticatedZMQStreamHandler):' | |||||
150 | if protocol_version != kernel_protocol_version: |
|
155 | if protocol_version != kernel_protocol_version: | |
151 | self.session.adapt_version = int(protocol_version.split('.')[0]) |
|
156 | self.session.adapt_version = int(protocol_version.split('.')[0]) | |
152 | self.log.info("Kernel %s speaks protocol %s", self.kernel_id, protocol_version) |
|
157 | self.log.info("Kernel %s speaks protocol %s", self.kernel_id, protocol_version) | |
153 |
self._kernel_info_future. |
|
158 | if not self._kernel_info_future.done(): | |
|
159 | self._kernel_info_future.set_result(info) | |||
154 |
|
160 | |||
155 | def initialize(self): |
|
161 | def initialize(self): | |
156 | super(ZMQChannelHandler, self).initialize() |
|
162 | super(ZMQChannelHandler, self).initialize() | |
@@ -160,10 +166,29 b' class ZMQChannelHandler(AuthenticatedZMQStreamHandler):' | |||||
160 | self._kernel_info_future = Future() |
|
166 | self._kernel_info_future = Future() | |
161 |
|
167 | |||
162 | @gen.coroutine |
|
168 | @gen.coroutine | |
|
169 | def pre_get(self): | |||
|
170 | # authenticate first | |||
|
171 | super(ZMQChannelHandler, self).pre_get() | |||
|
172 | # then request kernel info, waiting up to a certain time before giving up. | |||
|
173 | # We don't want to wait forever, because browsers don't take it well when | |||
|
174 | # servers never respond to websocket connection requests. | |||
|
175 | future = self.request_kernel_info() | |||
|
176 | ||||
|
177 | def give_up(): | |||
|
178 | """Don't wait forever for the kernel to reply""" | |||
|
179 | if future.done(): | |||
|
180 | return | |||
|
181 | self.log.warn("Timeout waiting for kernel_info reply from %s", self.kernel_id) | |||
|
182 | future.set_result(None) | |||
|
183 | loop = IOLoop.current() | |||
|
184 | loop.add_timeout(loop.time() + self.kernel_info_timeout, give_up) | |||
|
185 | # actually wait for it | |||
|
186 | yield future | |||
|
187 | ||||
|
188 | @gen.coroutine | |||
163 | def get(self, kernel_id): |
|
189 | def get(self, kernel_id): | |
164 | self.kernel_id = cast_unicode(kernel_id, 'ascii') |
|
190 | self.kernel_id = cast_unicode(kernel_id, 'ascii') | |
165 | yield self.request_kernel_info() |
|
191 | yield super(ZMQChannelHandler, self).get(kernel_id=kernel_id) | |
166 | super(ZMQChannelHandler, self).get(kernel_id) |
|
|||
167 |
|
192 | |||
168 | def open(self, kernel_id): |
|
193 | def open(self, kernel_id): | |
169 | super(ZMQChannelHandler, self).open() |
|
194 | super(ZMQChannelHandler, self).open() |
General Comments 0
You need to be logged in to leave comments.
Login now