handlers.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. """Serve files directly from the ContentsManager."""
  2. # Copyright (c) Jupyter Development Team.
  3. # Distributed under the terms of the Modified BSD License.
  4. import mimetypes
  5. import json
  6. try: #PY3
  7. from base64 import decodebytes
  8. except ImportError: #PY2
  9. from base64 import decodestring as decodebytes
  10. from tornado import web
  11. from notebook.base.handlers import IPythonHandler
  12. class FilesHandler(IPythonHandler):
  13. """serve files via ContentsManager
  14. Normally used when ContentsManager is not a FileContentsManager.
  15. FileContentsManager subclasses use AuthenticatedFilesHandler by default,
  16. a subclass of StaticFileHandler.
  17. """
  18. @property
  19. def content_security_policy(self):
  20. # In case we're serving HTML/SVG, confine any Javascript to a unique
  21. # origin so it can't interact with the notebook server.
  22. return super(FilesHandler, self).content_security_policy + \
  23. "; sandbox allow-scripts"
  24. @web.authenticated
  25. def head(self, path):
  26. self.check_xsrf_cookie()
  27. return self.get(path, include_body=False)
  28. @web.authenticated
  29. def get(self, path, include_body=True):
  30. # /files/ requests must originate from the same site
  31. self.check_xsrf_cookie()
  32. cm = self.contents_manager
  33. if cm.is_hidden(path) and not cm.allow_hidden:
  34. self.log.info("Refusing to serve hidden file, via 404 Error")
  35. raise web.HTTPError(404)
  36. path = path.strip('/')
  37. if '/' in path:
  38. _, name = path.rsplit('/', 1)
  39. else:
  40. name = path
  41. model = cm.get(path, type='file', content=include_body)
  42. if self.get_argument("download", False):
  43. self.set_attachment_header(name)
  44. # get mimetype from filename
  45. if name.endswith('.ipynb'):
  46. self.set_header('Content-Type', 'application/x-ipynb+json')
  47. else:
  48. cur_mime = mimetypes.guess_type(name)[0]
  49. if cur_mime == 'text/plain':
  50. self.set_header('Content-Type', 'text/plain; charset=UTF-8')
  51. elif cur_mime is not None:
  52. self.set_header('Content-Type', cur_mime)
  53. else:
  54. if model['format'] == 'base64':
  55. self.set_header('Content-Type', 'application/octet-stream')
  56. else:
  57. self.set_header('Content-Type', 'text/plain; charset=UTF-8')
  58. if include_body:
  59. if model['format'] == 'base64':
  60. b64_bytes = model['content'].encode('ascii')
  61. self.write(decodebytes(b64_bytes))
  62. elif model['format'] == 'json':
  63. self.write(json.dumps(model['content']))
  64. else:
  65. self.write(model['content'])
  66. self.flush()
  67. default_handlers = []