diff --git a/IPython/html/nbconvert/handlers.py b/IPython/html/nbconvert/handlers.py index 1460505..f173209 100644 --- a/IPython/html/nbconvert/handlers.py +++ b/IPython/html/nbconvert/handlers.py @@ -28,11 +28,17 @@ class NbconvertFileHandler(IPythonHandler): info = os.stat(os_path) self.set_header('Last-Modified', tz.utcfromtimestamp(info.st_mtime)) + + # Force download if requested if self.get_argument('download', 'false').lower() == 'true': filename = os.path.splitext(name)[0] + '.' + exporter.file_extension self.set_header('Content-Disposition', 'attachment; filename="%s"' % filename) + # MIME type + if exporter.mime_type: + self.set_header('Content-Type', '%s; charset=utf-8' % exporter.mime_type) + output, resources = exporter.from_filename(os_path) # TODO: If there are resources, combine them into a zip file @@ -49,8 +55,13 @@ class NbconvertPostHandler(IPythonHandler): model = self.get_json_body() nbnode = to_notebook_json(model['content']) - output, resources = exporter.from_notebook_node(nbnode) + # MIME type + if exporter.mime_type: + self.set_header('Content-Type', '%s; charset=utf-8' % exporter.mime_type) + + output, resources = exporter.from_notebook_node(nbnode) + # TODO: If there are resources, combine them into a zip file assert not has_resource_files(resources) diff --git a/IPython/html/nbconvert/tests/test_nbconvert_api.py b/IPython/html/nbconvert/tests/test_nbconvert_api.py index d57d2d0..3edf6fb 100644 --- a/IPython/html/nbconvert/tests/test_nbconvert_api.py +++ b/IPython/html/nbconvert/tests/test_nbconvert_api.py @@ -61,10 +61,12 @@ class APITest(NotebookTestBase): def test_from_file(self): r = self.nbconvert_api.from_file('html', 'foo', 'testnb.ipynb') self.assertEqual(r.status_code, 200) + self.assertIn(u'text/html', r.headers['Content-Type']) self.assertIn(u'Created by test', r.text) self.assertIn(u'print', r.text) - + r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb') + self.assertIn(u'text/x-python', r.headers['Content-Type']) self.assertIn(u'print(2*6)', r.text) def test_from_file_404(self): @@ -74,8 +76,8 @@ class APITest(NotebookTestBase): def test_from_file_download(self): r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb', download=True) content_disposition = r.headers['Content-Disposition'] - assert 'attachment' in content_disposition - assert 'testnb.py' in content_disposition + self.assertIn('attachment', content_disposition) + self.assertIn('testnb.py', content_disposition) def test_from_post(self): nbmodel_url = url_path_join(self.base_url(), 'api/notebooks/foo/testnb.ipynb') @@ -83,8 +85,10 @@ class APITest(NotebookTestBase): r = self.nbconvert_api.from_post(format='html', nbmodel=nbmodel) self.assertEqual(r.status_code, 200) + self.assertIn(u'text/html', r.headers['Content-Type']) self.assertIn(u'Created by test', r.text) self.assertIn(u'print', r.text) r = self.nbconvert_api.from_post(format='python', nbmodel=nbmodel) + self.assertIn(u'text/x-python', r.headers['Content-Type']) self.assertIn(u'print(2*6)', r.text) \ No newline at end of file diff --git a/IPython/nbconvert/exporters/exporter.py b/IPython/nbconvert/exporters/exporter.py index 3a594d0..c7c60d0 100644 --- a/IPython/nbconvert/exporters/exporter.py +++ b/IPython/nbconvert/exporters/exporter.py @@ -53,6 +53,10 @@ class Exporter(LoggingConfigurable): help="Extension of the file that should be written to disk" ) + mime_type = Unicode('', config=True, + help="MIME type of the result file, for HTTP response headers." + ) + #Configurability, allows the user to easily add filters and preprocessors. preprocessors = List(config=True, help="""List of preprocessors, by name or namespace, to enable.""") diff --git a/IPython/nbconvert/exporters/html.py b/IPython/nbconvert/exporters/html.py index bb63397..3a9147c 100644 --- a/IPython/nbconvert/exporters/html.py +++ b/IPython/nbconvert/exporters/html.py @@ -36,6 +36,10 @@ class HTMLExporter(TemplateExporter): help="Extension of the file that should be written to disk" ) + mime_type = Unicode('text/html', config=True, + help="MIME type of the result file, for HTTP response headers." + ) + default_template = Unicode('full', config=True, help="""Flavor of the data format to use. I.E. 'full' or 'basic'""") diff --git a/IPython/nbconvert/exporters/latex.py b/IPython/nbconvert/exporters/latex.py index a095262..369dcf5 100644 --- a/IPython/nbconvert/exporters/latex.py +++ b/IPython/nbconvert/exporters/latex.py @@ -40,6 +40,10 @@ class LatexExporter(TemplateExporter): 'tex', config=True, help="Extension of the file that should be written to disk") + mime_type = Unicode('application/x-tex', config=True, + help="MIME type of the result file, for HTTP response headers." + ) + default_template = Unicode('article', config=True, help="""Template of the data format to use. I.E. 'article' or 'report'""") diff --git a/IPython/nbconvert/exporters/markdown.py b/IPython/nbconvert/exporters/markdown.py index fb38539..da4900b 100644 --- a/IPython/nbconvert/exporters/markdown.py +++ b/IPython/nbconvert/exporters/markdown.py @@ -36,6 +36,10 @@ class MarkdownExporter(TemplateExporter): def _raw_mimetypes_default(self): return ['text/markdown', 'text/html'] + mime_type = Unicode('text/x-markdown', config=True, + help="MIME type of the result file, for HTTP response headers." + ) + @property def default_config(self): c = Config({'ExtractOutputPreprocessor':{'enabled':True}}) diff --git a/IPython/nbconvert/exporters/python.py b/IPython/nbconvert/exporters/python.py index 1d13bc3..d618cd7 100644 --- a/IPython/nbconvert/exporters/python.py +++ b/IPython/nbconvert/exporters/python.py @@ -32,3 +32,6 @@ class PythonExporter(TemplateExporter): def _raw_mimetype_default(self): return 'application/x-python' + mime_type = Unicode('text/x-python', config=True, + help="MIME type of the result file, for HTTP response headers." + ) diff --git a/IPython/nbconvert/exporters/rst.py b/IPython/nbconvert/exporters/rst.py index 22dfc82..34b9eca 100644 --- a/IPython/nbconvert/exporters/rst.py +++ b/IPython/nbconvert/exporters/rst.py @@ -32,7 +32,11 @@ class RSTExporter(TemplateExporter): def _raw_mimetype_default(self): return 'text/restructuredtext' - + + mime_type = Unicode('text/x-rst', config=True, + help="MIME type of the result file, for HTTP response headers." + ) + @property def default_config(self): c = Config({'ExtractOutputPreprocessor':{'enabled':True}}) diff --git a/IPython/nbconvert/exporters/slides.py b/IPython/nbconvert/exporters/slides.py index 6ecb5a9..7f8ab46 100644 --- a/IPython/nbconvert/exporters/slides.py +++ b/IPython/nbconvert/exporters/slides.py @@ -31,6 +31,10 @@ class SlidesExporter(HTMLExporter): help="Extension of the file that should be written to disk" ) + mime_type = Unicode('text/html', config=True, + help="MIME type of the result file, for HTTP response headers." + ) + default_template = Unicode('reveal', config=True, help="""Template of the data format to use. I.E. 'reveal'""")