##// END OF EJS Templates
Mark version info with beta1 tag.
Mark version info with beta1 tag.

File last commit:

r7107:2caea259 merge
r7617:e382085c
Show More
handlers.py
737 lines | 25.0 KiB | text/x-python | PythonLexer
Brian E. Granger
More review changes....
r4609 """Tornado handlers for the notebook.
Authors:
* Brian Granger
"""
Brian E. Granger
Work to adapt routers to new Session message protocol.
r4346
#-----------------------------------------------------------------------------
Brian E. Granger
More review changes....
r4609 # Copyright (C) 2008-2011 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
Brian E. Granger
Work to adapt routers to new Session message protocol.
r4346 #-----------------------------------------------------------------------------
Brian E. Granger
More review changes....
r4609 #-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
Brian Granger
Work on the server side of the html notebook.
r4297
MinRK
authenticate Websockets with the session cookie...
r4707 import logging
import Cookie
MinRK
add first_beat delay to notebook heartbeats...
r5812 import time
MinRK
don't present meaningless username option in notebook...
r5101 import uuid
MinRK
authenticate Websockets with the session cookie...
r4707
Brian Granger
Work on the server side of the html notebook.
r4297 from tornado import web
from tornado import websocket
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 from zmq.eventloop import ioloop
from zmq.utils import jsonapi
MinRK
Allow notebook server to run in read-only mode...
r5191 from IPython.external.decorator import decorator
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 from IPython.zmq.session import Session
Stefan van der Walt
Integrate hashed passwords into the notebook.
r5321 from IPython.lib.security import passwd_check
MinRK
fix date objects in _reserialize_reply
r6870 from IPython.utils.jsonutil import date_default
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545
Brian E. Granger
Starting work on a Markdown cell.
r4507 try:
from docutils.core import publish_string
except ImportError:
publish_string = None
Fernando Perez
Monkeypatch Tornado 2.1.1 so it works with Google Chrome 16....
r5240 #-----------------------------------------------------------------------------
Fernando Perez
Update version check to work with tornado 2.1.0 or 2.1.1
r5241 # Monkeypatch for Tornado <= 2.1.1 - Remove when no longer necessary!
Fernando Perez
Monkeypatch Tornado 2.1.1 so it works with Google Chrome 16....
r5240 #-----------------------------------------------------------------------------
# Google Chrome, as of release 16, changed its websocket protocol number. The
# parts tornado cares about haven't really changed, so it's OK to continue
# accepting Chrome connections, but as of Tornado 2.1.1 (the currently released
# version as of Oct 30/2011) the version check fails, see the issue report:
# https://github.com/facebook/tornado/issues/385
# This issue has been fixed in Tornado post 2.1.1:
# https://github.com/facebook/tornado/commit/84d7b458f956727c3b0d6710
# Here we manually apply the same patch as above so that users of IPython can
# continue to work with an officially released Tornado. We make the
# monkeypatch version check as narrow as possible to limit its effects; once
# Tornado 2.1.1 is no longer found in the wild we'll delete this code.
import tornado
Fernando Perez
Update version check to work with tornado 2.1.0 or 2.1.1
r5241 if tornado.version_info <= (2,1,1):
Fernando Perez
Monkeypatch Tornado 2.1.1 so it works with Google Chrome 16....
r5240
def _execute(self, transforms, *args, **kwargs):
from tornado.websocket import WebSocketProtocol8, WebSocketProtocol76
self.open_args = args
self.open_kwargs = kwargs
# The difference between version 8 and 13 is that in 8 the
# client sends a "Sec-Websocket-Origin" header and in 13 it's
# simply "Origin".
if self.request.headers.get("Sec-WebSocket-Version") in ("7", "8", "13"):
self.ws_connection = WebSocketProtocol8(self)
self.ws_connection.accept_connection()
elif self.request.headers.get("Sec-WebSocket-Version"):
self.stream.write(tornado.escape.utf8(
"HTTP/1.1 426 Upgrade Required\r\n"
"Sec-WebSocket-Version: 8\r\n\r\n"))
self.stream.close()
else:
self.ws_connection = WebSocketProtocol76(self)
self.ws_connection.accept_connection()
Brian E. Granger
Massive work on the notebook document format....
r4484
Fernando Perez
Monkeypatch Tornado 2.1.1 so it works with Google Chrome 16....
r5240 websocket.WebSocketHandler._execute = _execute
del _execute
MinRK
Allow notebook server to run in read-only mode...
r5191 #-----------------------------------------------------------------------------
# Decorator for disabling read-only handlers
#-----------------------------------------------------------------------------
@decorator
def not_if_readonly(f, self, *args, **kwargs):
MinRK
move read_only flag to page-level...
r5213 if self.application.read_only:
MinRK
Allow notebook server to run in read-only mode...
r5191 raise web.HTTPError(403, "Notebook server is read-only")
else:
return f(self, *args, **kwargs)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545
MinRK
add read-only view for notebooks...
r5200 @decorator
def authenticate_unless_readonly(f, self, *args, **kwargs):
"""authenticate this page *unless* readonly view is active.
In read-only mode, the notebook list and print view should
be accessible without authentication.
"""
@web.authenticated
def auth_f(self, *args, **kwargs):
return f(self, *args, **kwargs)
MinRK
authenticate local file access...
r5824
MinRK
move read_only flag to page-level...
r5213 if self.application.read_only:
MinRK
add read-only view for notebooks...
r5200 return f(self, *args, **kwargs)
else:
return auth_f(self, *args, **kwargs)
Brian E. Granger
Work to adapt routers to new Session message protocol.
r4346 #-----------------------------------------------------------------------------
Brian E. Granger
Adding kernel/notebook associations.
r4494 # Top-level handlers
Brian E. Granger
Work to adapt routers to new Session message protocol.
r4346 #-----------------------------------------------------------------------------
Brian Granger
Initial draft of HTML5/JS/CSS3 notebook.
r4292
Stefan van der Walt
Use template inheritance.
r5324 class RequestHandler(web.RequestHandler):
"""RequestHandler with default variable setting."""
def render(*args, **kwargs):
kwargs.setdefault('message', '')
return web.RequestHandler.render(*args, **kwargs)
class AuthenticatedHandler(RequestHandler):
MinRK
Authenticate all notebook requests (except websockets)...
r4706 """A RequestHandler with an authenticated user."""
Brian E. Granger
Minor changes to handlers.
r5102
Satrajit Ghosh
enh: added authentication ability for webapp
r4690 def get_current_user(self):
MinRK
Renaming user cookie to username to better match usage.
r5115 user_id = self.get_secure_cookie("username")
Brian E. Granger
Minor changes to handlers.
r5102 # For now the user_id should not return empty, but it could eventually
MinRK
only store hashed user_id in notebook cookie...
r4724 if user_id == '':
user_id = 'anonymous'
if user_id is None:
# prevent extra Invalid cookie sig warnings:
MinRK
Renaming user cookie to username to better match usage.
r5115 self.clear_cookie('username')
MinRK
move read_only flag to page-level...
r5213 if not self.application.password and not self.application.read_only:
MinRK
only store hashed user_id in notebook cookie...
r4724 user_id = 'anonymous'
return user_id
Stefan van der Walt
Improve three-state read-only logic.
r5721
MinRK
move read_only flag to page-level...
r5213 @property
Stefan van der Walt
Split read-only logic into three functions: read_only, logged_in, and login_available. Move display logic from javascript into templates.
r5722 def logged_in(self):
"""Is a user currently logged in?
"""
user = self.get_current_user()
return (user and not user == 'anonymous')
@property
def login_available(self):
"""May a user proceed to log in?
This returns True if login capability is available, irrespective of
whether the user is already logged in or not.
"""
return bool(self.application.password)
@property
MinRK
move read_only flag to page-level...
r5213 def read_only(self):
Stefan van der Walt
Improve three-state read-only logic.
r5721 """Is the notebook read-only?
"""
Stefan van der Walt
Split read-only logic into three functions: read_only, logged_in, and login_available. Move display logic from javascript into templates.
r5722 return self.application.read_only
Stefan van der Walt
Improve three-state read-only logic.
r5721
MinRK
remove superfluous ws-hostname parameter from notebook...
r5252 @property
def ws_url(self):
"""websocket url matching the current request
Andrew Straw
let websocket server be traited config option
r6006
MinRK
don't use Origin header to determine ws_url
r5300 turns http[s]://host[:port] into
ws[s]://host[:port]
MinRK
remove superfluous ws-hostname parameter from notebook...
r5252 """
MinRK
don't use Origin header to determine ws_url
r5300 proto = self.request.protocol.replace('http', 'ws')
Andrew Straw
let websocket server be traited config option
r6006 host = self.application.ipython_app.websocket_host # default to config value
if host == '':
host = self.request.host # get from request
return "%s://%s" % (proto, host)
Bernardo B. Marques
remove all trailling spaces
r4872
Satrajit Ghosh
enh: added authentication ability for webapp
r4690
MinRK
authenticate local file access...
r5824 class AuthenticatedFileHandler(AuthenticatedHandler, web.StaticFileHandler):
"""static files should only be accessible when logged in"""
@authenticate_unless_readonly
def get(self, path):
return web.StaticFileHandler.get(self, path)
Brian E. Granger
Renaming NBBrowserHandler->ProjectDashboardHandler.
r5112 class ProjectDashboardHandler(AuthenticatedHandler):
Brian E. Granger
Minor changes to handlers.
r5102
MinRK
add read-only view for notebooks...
r5200 @authenticate_unless_readonly
Brian E. Granger
Implemented basic notebook browser and fixed numerous bugs.
r4488 def get(self):
nbm = self.application.notebook_manager
project = nbm.notebook_dir
Brian E. Granger
Adding data-project to the body data attribs.
r5105 self.render(
Brian E. Granger
Further cleanup and renaming of notebook.
r5111 'projectdashboard.html', project=project,
Andrew Straw
allow setting base_project_url and base_kernel_url to non-default values
r6004 base_project_url=self.application.ipython_app.base_project_url,
base_kernel_url=self.application.ipython_app.base_kernel_url,
MinRK
move read_only flag to page-level...
r5213 read_only=self.read_only,
Stefan van der Walt
Split read-only logic into three functions: read_only, logged_in, and login_available. Move display logic from javascript into templates.
r5722 logged_in=self.logged_in,
login_available=self.login_available
Brian E. Granger
Adding data-project to the body data attribs.
r5105 )
Brian E. Granger
Implemented basic notebook browser and fixed numerous bugs.
r4488
Brian E. Granger
Minor changes to handlers.
r5102
MinRK
Authenticate all notebook requests (except websockets)...
r4706 class LoginHandler(AuthenticatedHandler):
Brian E. Granger
Minor changes to handlers.
r5102
Stefan van der Walt
Add info, error and warning message boxes.
r5326 def _render(self, message=None):
MinRK
move read_only flag to page-level...
r5213 self.render('login.html',
next=self.get_argument('next', default='/'),
read_only=self.read_only,
Stefan van der Walt
Split read-only logic into three functions: read_only, logged_in, and login_available. Move display logic from javascript into templates.
r5722 logged_in=self.logged_in,
login_available=self.login_available,
Brian Granger
Refactoring templates and top level js/css organization.
r6192 base_project_url=self.application.ipython_app.base_project_url,
Stefan van der Walt
Notify user about invalid password.
r5323 message=message
MinRK
move read_only flag to page-level...
r5213 )
Satrajit Ghosh
enh: added authentication ability for webapp
r4690
Stefan van der Walt
Notify user about invalid password.
r5323 def get(self):
Stefan van der Walt
Only show logout button if logged in.
r5327 if self.current_user:
self.redirect(self.get_argument('next', default='/'))
else:
self._render()
Stefan van der Walt
Notify user about invalid password.
r5323
Satrajit Ghosh
enh: added authentication ability for webapp
r4690 def post(self):
Brian E. Granger
Simplifying logic on login page.
r5109 pwd = self.get_argument('password', default=u'')
Stefan van der Walt
Notify user about invalid password.
r5323 if self.application.password:
if passwd_check(self.application.password, pwd):
self.set_secure_cookie('username', str(uuid.uuid4()))
else:
Stefan van der Walt
Add info, error and warning message boxes.
r5326 self._render(message={'error': 'Invalid password'})
Stefan van der Walt
Notify user about invalid password.
r5323 return
MinRK
move read_only flag to page-level...
r5213 self.redirect(self.get_argument('next', default='/'))
Brian E. Granger
Implemented basic notebook browser and fixed numerous bugs.
r4488
Brian E. Granger
Minor changes to handlers.
r5102
Stefan van der Walt
Add logout button.
r5325 class LogoutHandler(AuthenticatedHandler):
def get(self):
self.clear_cookie('username')
Stefan van der Walt
Split read-only logic into three functions: read_only, logged_in, and login_available. Move display logic from javascript into templates.
r5722 if self.login_available:
message = {'info': 'Successfully logged out.'}
else:
message = {'warning': 'Cannot log out. Notebook authentication '
'is disabled.'}
self.render('logout.html',
read_only=self.read_only,
logged_in=self.logged_in,
login_available=self.login_available,
Brian Granger
Refactoring templates and top level js/css organization.
r6192 base_project_url=self.application.ipython_app.base_project_url,
Stefan van der Walt
Split read-only logic into three functions: read_only, logged_in, and login_available. Move display logic from javascript into templates.
r5722 message=message)
Stefan van der Walt
Add logout button.
r5325
MinRK
Authenticate all notebook requests (except websockets)...
r4706 class NewHandler(AuthenticatedHandler):
Brian E. Granger
Minor changes to handlers.
r5102
MinRK
Authenticate all notebook requests (except websockets)...
r4706 @web.authenticated
Brian Granger
Initial draft of HTML5/JS/CSS3 notebook.
r4292 def get(self):
Brian E. Granger
Adding data-project to the body data attribs.
r5105 nbm = self.application.notebook_manager
project = nbm.notebook_dir
notebook_id = nbm.new_notebook()
self.render(
'notebook.html', project=project,
notebook_id=notebook_id,
Andrew Straw
allow setting base_project_url and base_kernel_url to non-default values
r6004 base_project_url=self.application.ipython_app.base_project_url,
base_kernel_url=self.application.ipython_app.base_kernel_url,
MinRK
move read_only flag to page-level...
r5213 kill_kernel=False,
read_only=False,
Stefan van der Walt
Split read-only logic into three functions: read_only, logged_in, and login_available. Move display logic from javascript into templates.
r5722 logged_in=self.logged_in,
login_available=self.login_available,
MinRK
adjust missing mathjax handling per review...
r5557 mathjax_url=self.application.ipython_app.mathjax_url,
Brian E. Granger
Adding data-project to the body data attribs.
r5105 )
Brian E. Granger
Massive work on the notebook document format....
r4484
MinRK
Authenticate all notebook requests (except websockets)...
r4706 class NamedNotebookHandler(AuthenticatedHandler):
Brian E. Granger
Minor changes to handlers.
r5102
MinRK
add read-only view for notebooks...
r5200 @authenticate_unless_readonly
Brian E. Granger
Massive work on the notebook document format....
r4484 def get(self, notebook_id):
nbm = self.application.notebook_manager
Brian E. Granger
Adding data-project to the body data attribs.
r5105 project = nbm.notebook_dir
Brian E. Granger
Massive work on the notebook document format....
r4484 if not nbm.notebook_exists(notebook_id):
Brian E. Granger
Adding messages to HTTPError raising....
r4676 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
MinRK
move read_only flag to page-level...
r5213
Brian E. Granger
Adding data-project to the body data attribs.
r5105 self.render(
'notebook.html', project=project,
notebook_id=notebook_id,
Andrew Straw
allow setting base_project_url and base_kernel_url to non-default values
r6004 base_project_url=self.application.ipython_app.base_project_url,
base_kernel_url=self.application.ipython_app.base_kernel_url,
MinRK
move read_only flag to page-level...
r5213 kill_kernel=False,
read_only=self.read_only,
Stefan van der Walt
Split read-only logic into three functions: read_only, logged_in, and login_available. Move display logic from javascript into templates.
r5722 logged_in=self.logged_in,
login_available=self.login_available,
MinRK
adjust missing mathjax handling per review...
r5557 mathjax_url=self.application.ipython_app.mathjax_url,
Brian E. Granger
Adding data-project to the body data attribs.
r5105 )
Brian Granger
Initial draft of HTML5/JS/CSS3 notebook.
r4292
Brian Granger
Created new print view for notebook printing.
r5875 class PrintNotebookHandler(AuthenticatedHandler):
@authenticate_unless_readonly
def get(self, notebook_id):
nbm = self.application.notebook_manager
project = nbm.notebook_dir
if not nbm.notebook_exists(notebook_id):
raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
self.render(
'printnotebook.html', project=project,
notebook_id=notebook_id,
Andrew Straw
allow setting base_project_url and base_kernel_url to non-default values
r6004 base_project_url=self.application.ipython_app.base_project_url,
base_kernel_url=self.application.ipython_app.base_kernel_url,
Brian Granger
Created new print view for notebook printing.
r5875 kill_kernel=False,
read_only=self.read_only,
logged_in=self.logged_in,
login_available=self.login_available,
mathjax_url=self.application.ipython_app.mathjax_url,
)
Brian E. Granger
Adding kernel/notebook associations.
r4494 #-----------------------------------------------------------------------------
# Kernel handlers
#-----------------------------------------------------------------------------
MinRK
Authenticate all notebook requests (except websockets)...
r4706 class MainKernelHandler(AuthenticatedHandler):
Brian Granger
Work on the server side of the html notebook.
r4297
MinRK
Authenticate all notebook requests (except websockets)...
r4706 @web.authenticated
Brian Granger
Work on the server side of the html notebook.
r4297 def get(self):
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 km = self.application.kernel_manager
self.finish(jsonapi.dumps(km.kernel_ids))
Brian Granger
Basic server for htmlnotebook working.
r4298
MinRK
Authenticate all notebook requests (except websockets)...
r4706 @web.authenticated
Brian Granger
Different clients now share a single zmq session....
r4306 def post(self):
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 km = self.application.kernel_manager
Brian E. Granger
Adding kernel/notebook associations.
r4494 notebook_id = self.get_argument('notebook', default=None)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 kernel_id = km.start_kernel(notebook_id)
MinRK
remove superfluous ws-hostname parameter from notebook...
r5252 data = {'ws_url':self.ws_url,'kernel_id':kernel_id}
Brian E. Granger
Massive work on the notebook document format....
r4484 self.set_header('Location', '/'+kernel_id)
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 self.finish(jsonapi.dumps(data))
Brian Granger
Work on the server side of the html notebook.
r4297
MinRK
Authenticate all notebook requests (except websockets)...
r4706 class KernelHandler(AuthenticatedHandler):
Brian E. Granger
Adding kernel/notebook associations.
r4494
SUPPORTED_METHODS = ('DELETE')
MinRK
Authenticate all notebook requests (except websockets)...
r4706 @web.authenticated
Brian E. Granger
Adding kernel/notebook associations.
r4494 def delete(self, kernel_id):
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 km = self.application.kernel_manager
km.kill_kernel(kernel_id)
Brian E. Granger
Adding kernel/notebook associations.
r4494 self.set_status(204)
self.finish()
MinRK
Authenticate all notebook requests (except websockets)...
r4706 class KernelActionHandler(AuthenticatedHandler):
Brian Granger
Interrupt and restart work for kernels.
r4308
MinRK
Authenticate all notebook requests (except websockets)...
r4706 @web.authenticated
Brian Granger
Cleaned up kernel action interface....
r4309 def post(self, kernel_id, action):
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 km = self.application.kernel_manager
Brian Granger
Cleaned up kernel action interface....
r4309 if action == 'interrupt':
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 km.interrupt_kernel(kernel_id)
Brian E. Granger
Adding kernel/notebook associations.
r4494 self.set_status(204)
Brian Granger
Cleaned up kernel action interface....
r4309 if action == 'restart':
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 new_kernel_id = km.restart_kernel(kernel_id)
MinRK
remove superfluous ws-hostname parameter from notebook...
r5252 data = {'ws_url':self.ws_url,'kernel_id':new_kernel_id}
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 self.set_header('Location', '/'+new_kernel_id)
self.write(jsonapi.dumps(data))
Brian E. Granger
Improvements to file uploaded, mime types and .py reader....
r4493 self.finish()
Brian Granger
Interrupt and restart work for kernels.
r4308
Brian Granger
Different clients now share a single zmq session....
r4306 class ZMQStreamHandler(websocket.WebSocketHandler):
Brian Granger
Work on the server side of the html notebook.
r4297
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 def _reserialize_reply(self, msg_list):
"""Reserialize a reply message using JSON.
This takes the msg list from the ZMQ socket, unserializes it using
self.session and then serializes the result using JSON. This method
should be used by self._on_zmq_reply to build messages that can
be sent back to the browser.
"""
idents, msg_list = self.session.feed_identities(msg_list)
msg = self.session.unserialize(msg_list)
Brian E. Granger
Date is properly removed from JSON reply before WebSocket forward....
r4561 try:
msg['header'].pop('date')
except KeyError:
pass
try:
msg['parent_header'].pop('date')
except KeyError:
pass
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 msg.pop('buffers')
MinRK
fix date objects in _reserialize_reply
r6870 return jsonapi.dumps(msg, default=date_default)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545
Brian E. Granger
Date is properly removed from JSON reply before WebSocket forward....
r4561 def _on_zmq_reply(self, msg_list):
try:
msg = self._reserialize_reply(msg_list)
MinRK
fix date objects in _reserialize_reply
r6870 except Exception:
self.application.log.critical("Malformed message: %r" % msg_list, exc_info=True)
Brian E. Granger
Date is properly removed from JSON reply before WebSocket forward....
r4561 else:
self.write_message(msg)
MinRK
allow draft76 websockets (Safari)...
r6070 def allow_draft76(self):
"""Allow draft 76, until browsers such as Safari update to RFC 6455.
This has been disabled by default in tornado in release 2.2.0, and
support will be removed in later versions.
"""
return True
Brian E. Granger
Minor changes to the notebook handlers.
r5114
MinRK
authenticate Websockets with the session cookie...
r4707 class AuthenticatedZMQStreamHandler(ZMQStreamHandler):
Brian E. Granger
Minor changes to the notebook handlers.
r5114
MinRK
authenticate Websockets with the session cookie...
r4707 def open(self, kernel_id):
Thomas Kluyver
Fix for notebook in Python 3.
r4839 self.kernel_id = kernel_id.decode('ascii')
MinRK
enable HMAC message signing by default in notebook kernels...
r4963 try:
cfg = self.application.ipython_app.config
except AttributeError:
# protect from the case where this is run from something other than
# the notebook app:
cfg = None
self.session = Session(config=cfg)
MinRK
authenticate Websockets with the session cookie...
r4707 self.save_on_message = self.on_message
self.on_message = self.on_first_message
Bernardo B. Marques
remove all trailling spaces
r4872
MinRK
authenticate Websockets with the session cookie...
r4707 def get_current_user(self):
MinRK
Renaming user cookie to username to better match usage.
r5115 user_id = self.get_secure_cookie("username")
MinRK
only store hashed user_id in notebook cookie...
r4724 if user_id == '' or (user_id is None and not self.application.password):
user_id = 'anonymous'
return user_id
Bernardo B. Marques
remove all trailling spaces
r4872
MinRK
authenticate Websockets with the session cookie...
r4707 def _inject_cookie_message(self, msg):
"""Inject the first message, which is the document cookie,
for authentication."""
if isinstance(msg, unicode):
# Cookie can't constructor doesn't accept unicode strings for some reason
msg = msg.encode('utf8', 'replace')
try:
Brian E. Granger
Using self.request._cookies in WS handlers.
r5119 self.request._cookies = Cookie.SimpleCookie(msg)
MinRK
authenticate Websockets with the session cookie...
r4707 except:
logging.warn("couldn't parse cookie string: %s",msg, exc_info=True)
Bernardo B. Marques
remove all trailling spaces
r4872
MinRK
authenticate Websockets with the session cookie...
r4707 def on_first_message(self, msg):
self._inject_cookie_message(msg)
if self.get_current_user() is None:
logging.warn("Couldn't authenticate WebSocket connection")
raise web.HTTPError(403)
self.on_message = self.save_on_message
Bernardo B. Marques
remove all trailling spaces
r4872
MinRK
authenticate Websockets with the session cookie...
r4707
class IOPubHandler(AuthenticatedZMQStreamHandler):
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545
def initialize(self, *args, **kwargs):
self._kernel_alive = True
self._beating = False
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 self.iopub_stream = None
self.hb_stream = None
Bernardo B. Marques
remove all trailling spaces
r4872
MinRK
authenticate Websockets with the session cookie...
r4707 def on_first_message(self, msg):
try:
super(IOPubHandler, self).on_first_message(msg)
except web.HTTPError:
self.close()
return
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 km = self.application.kernel_manager
self.time_to_dead = km.time_to_dead
MinRK
add first_beat delay to notebook heartbeats...
r5812 self.first_beat = km.first_beat
MinRK
authenticate Websockets with the session cookie...
r4707 kernel_id = self.kernel_id
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 try:
self.iopub_stream = km.create_iopub_stream(kernel_id)
self.hb_stream = km.create_hb_stream(kernel_id)
except web.HTTPError:
# WebSockets don't response to traditional error codes so we
# close the connection.
if not self.stream.closed():
self.stream.close()
MinRK
authenticate Websockets with the session cookie...
r4707 self.close()
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 else:
self.iopub_stream.on_recv(self._on_zmq_reply)
self.start_hb(self.kernel_died)
Bernardo B. Marques
remove all trailling spaces
r4872
MinRK
authenticate Websockets with the session cookie...
r4707 def on_message(self, msg):
pass
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545
def on_close(self):
Bernardo B. Marques
remove all trailling spaces
r4872 # This method can be called twice, once by self.kernel_died and once
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 # from the WebSocket close event. If the WebSocket connection is
# closed before the ZMQ streams are setup, they could be None.
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 self.stop_hb()
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 if self.iopub_stream is not None and not self.iopub_stream.closed():
self.iopub_stream.on_recv(None)
self.iopub_stream.close()
if self.hb_stream is not None and not self.hb_stream.closed():
self.hb_stream.close()
Bernardo B. Marques
remove all trailling spaces
r4872
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 def start_hb(self, callback):
"""Start the heartbeating and call the callback if the kernel dies."""
if not self._beating:
self._kernel_alive = True
def ping_or_dead():
MinRK
add first_beat delay to notebook heartbeats...
r5812 self.hb_stream.flush()
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 if self._kernel_alive:
self._kernel_alive = False
self.hb_stream.send(b'ping')
MinRK
flush outgoing heartbeats...
r5952 # flush stream to force immediate socket send
self.hb_stream.flush()
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 else:
try:
callback()
except:
pass
finally:
MinRK
prevent delayed heartbeat from starting on closed sessions
r5835 self.stop_hb()
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545
def beat_received(msg):
self._kernel_alive = True
self.hb_stream.on_recv(beat_received)
MinRK
add first_beat delay to notebook heartbeats...
r5812 loop = ioloop.IOLoop.instance()
self._hb_periodic_callback = ioloop.PeriodicCallback(ping_or_dead, self.time_to_dead*1000, loop)
MinRK
prevent delayed heartbeat from starting on closed sessions
r5835 loop.add_timeout(time.time()+self.first_beat, self._really_start_hb)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 self._beating= True
MinRK
prevent delayed heartbeat from starting on closed sessions
r5835
def _really_start_hb(self):
"""callback for delayed heartbeat start
Only start the hb loop if we haven't been closed during the wait.
"""
if self._beating and not self.hb_stream.closed():
self._hb_periodic_callback.start()
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545
def stop_hb(self):
"""Stop the heartbeating and cancel all related callbacks."""
if self._beating:
MinRK
prevent delayed heartbeat from starting on closed sessions
r5835 self._beating = False
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 self._hb_periodic_callback.stop()
if not self.hb_stream.closed():
self.hb_stream.on_recv(None)
def kernel_died(self):
Brian E. Granger
Kernel/notebook mapping is removed when a kernel dies....
r4563 self.application.kernel_manager.delete_mapping_for_kernel(self.kernel_id)
MinRK
log heartbeat failure in notebook
r5836 self.application.log.error("Kernel %s failed to respond to heartbeat", self.kernel_id)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 self.write_message(
{'header': {'msg_type': 'status'},
'parent_header': {},
'content': {'execution_state':'dead'}
}
)
self.on_close()
MinRK
authenticate Websockets with the session cookie...
r4707 class ShellHandler(AuthenticatedZMQStreamHandler):
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545
def initialize(self, *args, **kwargs):
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 self.shell_stream = None
Brian Granger
Work on the server side of the html notebook.
r4297
MinRK
authenticate Websockets with the session cookie...
r4707 def on_first_message(self, msg):
try:
super(ShellHandler, self).on_first_message(msg)
except web.HTTPError:
self.close()
return
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 km = self.application.kernel_manager
self.max_msg_size = km.max_msg_size
MinRK
authenticate Websockets with the session cookie...
r4707 kernel_id = self.kernel_id
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 try:
self.shell_stream = km.create_shell_stream(kernel_id)
except web.HTTPError:
# WebSockets don't response to traditional error codes so we
# close the connection.
if not self.stream.closed():
self.stream.close()
MinRK
authenticate Websockets with the session cookie...
r4707 self.close()
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 else:
self.shell_stream.on_recv(self._on_zmq_reply)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545
Brian Granger
Different clients now share a single zmq session....
r4306 def on_message(self, msg):
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 if len(msg) < self.max_msg_size:
msg = jsonapi.loads(msg)
self.session.send(self.shell_stream, msg)
Brian Granger
Work on the server side of the html notebook.
r4297
Brian Granger
Different clients now share a single zmq session....
r4306 def on_close(self):
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 # Make sure the stream exists and is not already closed.
if self.shell_stream is not None and not self.shell_stream.closed():
self.shell_stream.close()
Brian Granger
Work on the server side of the html notebook.
r4297
Brian E. Granger
Adding kernel/notebook associations.
r4494 #-----------------------------------------------------------------------------
# Notebook web service handlers
#-----------------------------------------------------------------------------
MinRK
Authenticate all notebook requests (except websockets)...
r4706 class NotebookRootHandler(AuthenticatedHandler):
Brian Granger
Server side of file based notebook store implemented.
r4301
MinRK
add read-only view for notebooks...
r5200 @authenticate_unless_readonly
Brian Granger
Server side of file based notebook store implemented.
r4301 def get(self):
Brian E. Granger
Massive work on the notebook document format....
r4484 nbm = self.application.notebook_manager
Matthias BUSSONNIER
kernel status
r6841 km = self.application.kernel_manager
Brian E. Granger
Massive work on the notebook document format....
r4484 files = nbm.list_notebooks()
Matthias BUSSONNIER
kernel status
r6841 for f in files :
Matthias BUSSONNIER
Check for null rather than undefined...
r6848 f['kernel_id'] = km.kernel_for_notebook(f['notebook_id'])
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 self.finish(jsonapi.dumps(files))
Brian Granger
Server side of file based notebook store implemented.
r4301
MinRK
Authenticate all notebook requests (except websockets)...
r4706 @web.authenticated
Brian E. Granger
Massive work on the notebook document format....
r4484 def post(self):
nbm = self.application.notebook_manager
body = self.request.body.strip()
format = self.get_argument('format', default='json')
Brian E. Granger
File upload/import working from notebook browser.
r4491 name = self.get_argument('name', default=None)
Brian E. Granger
Massive work on the notebook document format....
r4484 if body:
Brian E. Granger
File upload/import working from notebook browser.
r4491 notebook_id = nbm.save_new_notebook(body, name=name, format=format)
Brian E. Granger
Massive work on the notebook document format....
r4484 else:
notebook_id = nbm.new_notebook()
self.set_header('Location', '/'+notebook_id)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 self.finish(jsonapi.dumps(notebook_id))
Brian Granger
Server side of file based notebook store implemented.
r4301
MinRK
Authenticate all notebook requests (except websockets)...
r4706 class NotebookHandler(AuthenticatedHandler):
Brian Granger
Server side of file based notebook store implemented.
r4301
Brian E. Granger
Massive work on the notebook document format....
r4484 SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE')
MinRK
add read-only view for notebooks...
r5200 @authenticate_unless_readonly
Brian E. Granger
Massive work on the notebook document format....
r4484 def get(self, notebook_id):
nbm = self.application.notebook_manager
format = self.get_argument('format', default='json')
last_mod, name, data = nbm.get_notebook(notebook_id, format)
MinRK
add read-only view for notebooks...
r5200
Brian E. Granger
Massive work on the notebook document format....
r4484 if format == u'json':
self.set_header('Content-Type', 'application/json')
Brian E. Granger
Converting notebooks to JSON format.
r4634 self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name)
Brian E. Granger
Massive work on the notebook document format....
r4484 elif format == u'py':
Brian E. Granger
Improvements to file uploaded, mime types and .py reader....
r4493 self.set_header('Content-Type', 'application/x-python')
Brian E. Granger
Export works with filenames having spaces....
r4558 self.set_header('Content-Disposition','attachment; filename="%s.py"' % name)
Brian E. Granger
Massive work on the notebook document format....
r4484 self.set_header('Last-Modified', last_mod)
self.finish(data)
MinRK
Authenticate all notebook requests (except websockets)...
r4706 @web.authenticated
Brian E. Granger
Massive work on the notebook document format....
r4484 def put(self, notebook_id):
nbm = self.application.notebook_manager
format = self.get_argument('format', default='json')
Brian E. Granger
File upload/import working from notebook browser.
r4491 name = self.get_argument('name', default=None)
nbm.save_notebook(notebook_id, self.request.body, name=name, format=format)
Brian E. Granger
Massive work on the notebook document format....
r4484 self.set_status(204)
Brian Granger
Server side of file based notebook store implemented.
r4301 self.finish()
MinRK
Authenticate all notebook requests (except websockets)...
r4706 @web.authenticated
Brian E. Granger
Massive work on the notebook document format....
r4484 def delete(self, notebook_id):
nbm = self.application.notebook_manager
nbm.delete_notebook(notebook_id)
Brian Granger
Server side of file based notebook store implemented.
r4301 self.set_status(204)
self.finish()
Brian Granger
Beginning work on notebook duplication.
r5860
class NotebookCopyHandler(AuthenticatedHandler):
@web.authenticated
def get(self, notebook_id):
nbm = self.application.notebook_manager
project = nbm.notebook_dir
notebook_id = nbm.copy_notebook(notebook_id)
self.render(
'notebook.html', project=project,
notebook_id=notebook_id,
Andrew Straw
allow setting base_project_url and base_kernel_url to non-default values
r6004 base_project_url=self.application.ipython_app.base_project_url,
base_kernel_url=self.application.ipython_app.base_kernel_url,
Brian Granger
Beginning work on notebook duplication.
r5860 kill_kernel=False,
read_only=False,
logged_in=self.logged_in,
login_available=self.login_available,
mathjax_url=self.application.ipython_app.mathjax_url,
)
Brian Granger
First version of cluster web service....
r6191
#-----------------------------------------------------------------------------
# Cluster handlers
#-----------------------------------------------------------------------------
class MainClusterHandler(AuthenticatedHandler):
@web.authenticated
def get(self):
cm = self.application.cluster_manager
self.finish(jsonapi.dumps(cm.list_profiles()))
class ClusterProfileHandler(AuthenticatedHandler):
@web.authenticated
def get(self, profile):
cm = self.application.cluster_manager
self.finish(jsonapi.dumps(cm.profile_info(profile)))
class ClusterActionHandler(AuthenticatedHandler):
@web.authenticated
def post(self, profile, action):
cm = self.application.cluster_manager
if action == 'start':
Brian Granger
Notebook cluster manager now uses proper launchers.
r6199 n = self.get_argument('n',default=None)
if n is None:
data = cm.start_cluster(profile)
else:
data = cm.start_cluster(profile,int(n))
Brian Granger
First version of cluster web service....
r6191 if action == 'stop':
Brian Granger
Cluster management is now working....
r6197 data = cm.stop_cluster(profile)
self.finish(jsonapi.dumps(data))
Brian Granger
First version of cluster web service....
r6191
Brian E. Granger
Starting work on a Markdown cell.
r4507 #-----------------------------------------------------------------------------
# RST web service handlers
#-----------------------------------------------------------------------------
MinRK
Authenticate all notebook requests (except websockets)...
r4706 class RSTHandler(AuthenticatedHandler):
Brian E. Granger
Starting work on a Markdown cell.
r4507
MinRK
Authenticate all notebook requests (except websockets)...
r4706 @web.authenticated
Brian E. Granger
Starting work on a Markdown cell.
r4507 def post(self):
if publish_string is None:
Brian E. Granger
Adding messages to HTTPError raising....
r4676 raise web.HTTPError(503, u'docutils not available')
Brian E. Granger
Starting work on a Markdown cell.
r4507 body = self.request.body.strip()
Brian E. Granger
Adding tracebacks, evalue and etype to the nbformat and notebook.
r4540 source = body
# template_path=os.path.join(os.path.dirname(__file__), u'templates', u'rst_template.html')
Brian E. Granger
Starting work on a Markdown cell.
r4507 defaults = {'file_insertion_enabled': 0,
'raw_enabled': 0,
'_disable_config': 1,
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 'stylesheet_path': 0
Brian E. Granger
Adding tracebacks, evalue and etype to the nbformat and notebook.
r4540 # 'template': template_path
Brian E. Granger
Starting work on a Markdown cell.
r4507 }
try:
html = publish_string(source, writer_name='html',
settings_overrides=defaults
)
except:
Brian E. Granger
Adding messages to HTTPError raising....
r4676 raise web.HTTPError(400, u'Invalid RST')
Brian E. Granger
Starting work on a Markdown cell.
r4507 print html
self.set_header('Content-Type', 'text/html')
self.finish(html)