Fixed #30196 -- Made FileResponse set Content-Disposition inline if filename is available.
This commit is contained in:
parent
5c19274643
commit
de4832c49b
|
@ -436,15 +436,17 @@ class FileResponse(StreamingHttpResponse):
|
||||||
else:
|
else:
|
||||||
self['Content-Type'] = 'application/octet-stream'
|
self['Content-Type'] = 'application/octet-stream'
|
||||||
|
|
||||||
if self.as_attachment:
|
filename = self.filename or os.path.basename(filename)
|
||||||
filename = self.filename or os.path.basename(filename)
|
if filename:
|
||||||
if filename:
|
disposition = 'attachment' if self.as_attachment else 'inline'
|
||||||
try:
|
try:
|
||||||
filename.encode('ascii')
|
filename.encode('ascii')
|
||||||
file_expr = 'filename="{}"'.format(filename)
|
file_expr = 'filename="{}"'.format(filename)
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
file_expr = "filename*=utf-8''{}".format(quote(filename))
|
file_expr = "filename*=utf-8''{}".format(quote(filename))
|
||||||
self['Content-Disposition'] = 'attachment; {}'.format(file_expr)
|
self['Content-Disposition'] = '{}; {}'.format(disposition, file_expr)
|
||||||
|
elif self.as_attachment:
|
||||||
|
self['Content-Disposition'] = 'attachment'
|
||||||
|
|
||||||
|
|
||||||
class HttpResponseRedirectBase(HttpResponse):
|
class HttpResponseRedirectBase(HttpResponse):
|
||||||
|
|
|
@ -1107,15 +1107,17 @@ Attributes
|
||||||
optimized for binary files. It uses `wsgi.file_wrapper`_ if provided by the
|
optimized for binary files. It uses `wsgi.file_wrapper`_ if provided by the
|
||||||
wsgi server, otherwise it streams the file out in small chunks.
|
wsgi server, otherwise it streams the file out in small chunks.
|
||||||
|
|
||||||
If ``as_attachment=True``, the ``Content-Disposition`` header is set, which
|
If ``as_attachment=True``, the ``Content-Disposition`` header is set to
|
||||||
asks the browser to offer the file to the user as a download.
|
``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
|
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.
|
appropriate, provide a custom file name using the ``filename`` parameter.
|
||||||
|
|
||||||
The ``Content-Length``, ``Content-Type``, and ``Content-Disposition``
|
The ``Content-Length`` and ``Content-Type`` headers are automatically set
|
||||||
headers are automatically set when they can be guessed from contents of
|
when they can be guessed from contents of ``open_file``.
|
||||||
``open_file``.
|
|
||||||
|
|
||||||
.. _wsgi.file_wrapper: https://www.python.org/dev/peps/pep-3333/#optional-platform-specific-file-handling
|
.. _wsgi.file_wrapper: https://www.python.org/dev/peps/pep-3333/#optional-platform-specific-file-handling
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,21 @@ class FileResponseTests(SimpleTestCase):
|
||||||
response = FileResponse(open(__file__, 'rb'))
|
response = FileResponse(open(__file__, 'rb'))
|
||||||
self.assertEqual(response['Content-Length'], str(os.path.getsize(__file__)))
|
self.assertEqual(response['Content-Length'], str(os.path.getsize(__file__)))
|
||||||
self.assertIn(response['Content-Type'], ['text/x-python', 'text/plain'])
|
self.assertIn(response['Content-Type'], ['text/x-python', 'text/plain'])
|
||||||
|
self.assertEqual(response['Content-Disposition'], 'inline; filename="test_fileresponse.py"')
|
||||||
response.close()
|
response.close()
|
||||||
|
|
||||||
def test_file_from_buffer_response(self):
|
def test_file_from_buffer_response(self):
|
||||||
response = FileResponse(io.BytesIO(b'binary content'))
|
response = FileResponse(io.BytesIO(b'binary content'))
|
||||||
self.assertEqual(response['Content-Length'], '14')
|
self.assertEqual(response['Content-Length'], '14')
|
||||||
self.assertEqual(response['Content-Type'], 'application/octet-stream')
|
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'])
|
self.assertEqual(list(response), [b'binary content'])
|
||||||
|
|
||||||
@skipIf(sys.platform == 'win32', "Named pipes are Unix-only.")
|
@skipIf(sys.platform == 'win32', "Named pipes are Unix-only.")
|
||||||
|
|
Loading…
Reference in New Issue