use RFC5987 encoding for filenames

as described in RFC 6266 describing Content-Disposition
pull/2767/head
Min RK 9 years ago
parent 64ed6e439c
commit d6a534ec5b

@ -279,6 +279,20 @@ class IPythonHandler(AuthenticatedHandler):
if self.allow_credentials:
self.set_header("Access-Control-Allow-Credentials", 'true')
def set_attachment_header(self, filename):
"""Set Content-Disposition: attachment header
As a method to ensure handling of filename encoding
"""
escaped_filename = url_escape(filename)
self.set_header('Content-Disposition',
'attachment;'
" filename*=utf-8''{utf8}"
.format(
utf8=escaped_filename,
)
)
def get_origin(self):
# Handle WebSocket Origin naming convention differences
# The difference between version 8 and 13 is that in 8 the
@ -478,7 +492,7 @@ class AuthenticatedFileHandler(IPythonHandler, web.StaticFileHandler):
def get(self, path):
if os.path.splitext(path)[1] == '.ipynb' or self.get_argument("download", False):
name = path.rsplit('/', 1)[-1]
self.set_header('Content-Disposition','attachment; filename="%s"' % name)
self.set_attachment_header(name)
return web.StaticFileHandler.get(self, path)

@ -39,10 +39,9 @@ def bundle(handler, model):
with io.BytesIO() as tar_buffer:
with tarfile.open(tar_filename, "w:gz", fileobj=tar_buffer) as tar:
tar.addfile(info, io.BytesIO(notebook_content))
handler.set_header('Content-Disposition',
'attachment; filename="{}"'.format(tar_filename))
handler.set_attachment_header(tar_filename)
handler.set_header('Content-Type', 'application/gzip')
# Return the buffer value as the response
handler.finish(tar_buffer.getvalue())

@ -35,8 +35,7 @@ def bundle(handler, model):
# Headers
zip_filename = os.path.splitext(notebook_name)[0] + '.zip'
handler.set_header('Content-Disposition',
'attachment; filename="%s"' % zip_filename)
handler.set_attachment_header(zip_filename)
handler.set_header('Content-Type', 'application/zip')
# Get associated files

@ -46,7 +46,7 @@ class FilesHandler(IPythonHandler):
model = cm.get(path, type='file', content=include_body)
if self.get_argument("download", False):
self.set_header('Content-Disposition','attachment; filename="%s"' % name)
self.set_attachment_header(name)
# get mimetype from filename
if name.endswith('.ipynb'):

@ -38,8 +38,7 @@ def respond_zip(handler, name, output, resources):
# Headers
zip_filename = os.path.splitext(name)[0] + '.zip'
handler.set_header('Content-Disposition',
'attachment; filename="%s"' % zip_filename)
handler.set_attachment_header(zip_filename)
handler.set_header('Content-Type', 'application/zip')
# Prepare the zip file
@ -114,8 +113,7 @@ class NbconvertFileHandler(IPythonHandler):
# Force download if requested
if self.get_argument('download', 'false').lower() == 'true':
filename = os.path.splitext(name)[0] + resources['output_extension']
self.set_header('Content-Disposition',
'attachment; filename="%s"' % filename)
self.set_attachment_header(filename)
# MIME type
if exporter.output_mimetype:

@ -112,7 +112,7 @@ class FilesTest(NotebookTestBase):
r = self.request('GET', 'files/test.txt?download=1')
disposition = r.headers.get('Content-Disposition', '')
self.assertIn('attachment', disposition)
self.assertIn('filename="test.txt"', disposition)
self.assertIn("filename*=utf-8''test.txt", disposition)
def test_view_html(self):
nbdir = self.notebook_dir

Loading…
Cancel
Save