Fixed #30196 -- Made FileResponse set Content-Disposition inline if filename is available.

This commit is contained in:
ShingenPizza 2019-05-17 12:07:27 +02:00 committed by Carlton Gibson
parent 5c19274643
commit de4832c49b
3 changed files with 27 additions and 14 deletions

View File

@ -436,15 +436,17 @@ class FileResponse(StreamingHttpResponse):
else:
self['Content-Type'] = 'application/octet-stream'
if self.as_attachment:
filename = self.filename or os.path.basename(filename)
if filename:
try:
filename.encode('ascii')
file_expr = 'filename="{}"'.format(filename)
except UnicodeEncodeError:
file_expr = "filename*=utf-8''{}".format(quote(filename))
self['Content-Disposition'] = 'attachment; {}'.format(file_expr)
filename = self.filename or os.path.basename(filename)
if filename:
disposition = 'attachment' if self.as_attachment else 'inline'
try:
filename.encode('ascii')
file_expr = 'filename="{}"'.format(filename)
except UnicodeEncodeError:
file_expr = "filename*=utf-8''{}".format(quote(filename))
self['Content-Disposition'] = '{}; {}'.format(disposition, file_expr)
elif self.as_attachment:
self['Content-Disposition'] = 'attachment'
class HttpResponseRedirectBase(HttpResponse):

View File

@ -1107,15 +1107,17 @@ Attributes
optimized for binary files. It uses `wsgi.file_wrapper`_ if provided by the
wsgi server, otherwise it streams the file out in small chunks.
If ``as_attachment=True``, the ``Content-Disposition`` header is set, which
asks the browser to offer the file to the user as a download.
If ``as_attachment=True``, the ``Content-Disposition`` header is set to
``attachment``, which asks the browser to offer the file to the user as a
download. Otherwise, a ``Content-Disposition`` header with a value of
``inline`` (the browser default) will be set only if a filename is
available.
If ``open_file`` doesn't have a name or if the name of ``open_file`` isn't
appropriate, provide a custom file name using the ``filename`` parameter.
The ``Content-Length``, ``Content-Type``, and ``Content-Disposition``
headers are automatically set when they can be guessed from contents of
``open_file``.
The ``Content-Length`` and ``Content-Type`` headers are automatically set
when they can be guessed from contents of ``open_file``.
.. _wsgi.file_wrapper: https://www.python.org/dev/peps/pep-3333/#optional-platform-specific-file-handling

View File

@ -14,12 +14,21 @@ class FileResponseTests(SimpleTestCase):
response = FileResponse(open(__file__, 'rb'))
self.assertEqual(response['Content-Length'], str(os.path.getsize(__file__)))
self.assertIn(response['Content-Type'], ['text/x-python', 'text/plain'])
self.assertEqual(response['Content-Disposition'], 'inline; filename="test_fileresponse.py"')
response.close()
def test_file_from_buffer_response(self):
response = FileResponse(io.BytesIO(b'binary content'))
self.assertEqual(response['Content-Length'], '14')
self.assertEqual(response['Content-Type'], 'application/octet-stream')
self.assertFalse(response.has_header('Content-Disposition'))
self.assertEqual(list(response), [b'binary content'])
def test_file_from_buffer_unnamed_attachment(self):
response = FileResponse(io.BytesIO(b'binary content'), as_attachment=True)
self.assertEqual(response['Content-Length'], '14')
self.assertEqual(response['Content-Type'], 'application/octet-stream')
self.assertEqual(response['Content-Disposition'], 'attachment')
self.assertEqual(list(response), [b'binary content'])
@skipIf(sys.platform == 'win32', "Named pipes are Unix-only.")