Commit 67a99996 authored by Diederik van der Boor's avatar Diederik van der Boor
Browse files

Update documentation on sending files, given that ``wsgi.file_handler``...

Update documentation on sending files, given that ``wsgi.file_handler`` support lives in Djagno 1.8+
parent d8f6f430
...@@ -128,14 +128,21 @@ which has the following fields: ...@@ -128,14 +128,21 @@ which has the following fields:
Optimizing large file transfers Optimizing large file transfers
------------------------------- -------------------------------
By default, the files are served by the Django instance. Sending large files can be inefficient in some configurations.
This can be inefficient, since the whole file needs to be read in chunks
and passed through the WSGI buffers, OS kernel and webserver. In the worst case scenario, the whole file needs to be read in chunks
and passed as a whole through the WSGI buffers, OS kernel, webserver and proxy server.
In effect, the complete file is copied several times through memory buffers. In effect, the complete file is copied several times through memory buffers.
Hence, webservers offer a method to send the file on behalf of the backend application. There are more efficient ways to transfer files, such as the ``sendfile()`` system call on UNIX.
This happens with the ``sendfile()`` system call, Django uses such feature when the WSGI server provides ``wsgi.file_handler`` support.
which can be enabled with the following settings:
In some situations, this effect is nullified,
for example by by a local HTTP server sitting in front of the WSGI container.
A typical case would be running Gunicorn behind an Nginx or Apache webserver.
For such situation, the native support of the
webserver can be enabled with the following settings:
For apache For apache
~~~~~~~~~~ ~~~~~~~~~~
......
...@@ -33,7 +33,9 @@ def get_server_class(path): ...@@ -33,7 +33,9 @@ def get_server_class(path):
class DjangoStreamingServer(object): class DjangoStreamingServer(object):
""" """
Serve static files as streaming chunks in Django. Serve static files through ``wsgi.file_wrapper`` or streaming chunks.
This method also works for content that doesn't exist at the local filesystem, such as files on S3.
""" """
@staticmethod @staticmethod
...@@ -44,7 +46,9 @@ class DjangoStreamingServer(object): ...@@ -44,7 +46,9 @@ class DjangoStreamingServer(object):
if not was_modified_since(private_file.request.META.get('HTTP_IF_MODIFIED_SINCE'), mtime, size): if not was_modified_since(private_file.request.META.get('HTTP_IF_MODIFIED_SINCE'), mtime, size):
return HttpResponseNotModified() return HttpResponseNotModified()
# FileResponse will submit the file in 8KB chunks # As of Django 1.8, FileResponse triggers 'wsgi.file_wrapper' in Django's WSGIHandler.
# This uses efficient file streaming, such as sendfile() in uWSGI.
# When the WSGI container doesn't provide 'wsgi.file_wrapper', it submits the file in 4KB chunks.
response = FileResponse(private_file.open()) response = FileResponse(private_file.open())
response['Content-Type'] = private_file.content_type response['Content-Type'] = private_file.content_type
response['Content-Length'] = size response['Content-Length'] = size
...@@ -54,15 +58,24 @@ class DjangoStreamingServer(object): ...@@ -54,15 +58,24 @@ class DjangoStreamingServer(object):
class DjangoServer(DjangoStreamingServer): class DjangoServer(DjangoStreamingServer):
""" """
Serve static files from the local filesystem through Django. Serve static files from the local filesystem through Django or ``wsgi_file_wrapper``.
This is a bad idea for most situations other than testing.
The file data is copied multiple times; read by Django, written to WSGI, Django 1.8 and up support ``wsgi.file_wrapper``, which helps to send a file in the
read by webserver, outputted to client. most efficient way. When the WSGI server provides this feature,
the file is send using an efficient method such as ``sendfile()`` on UNIX.
Without ``file.file_wrapper``, the file will be streamed in 4K chunks,
causing the file data to be read and copied multiple times in kernel memory
as the file is read by Django, written to WSGI, read by webserver, and written to the socket.
In some situations, such as Gunicorn behind Nginx/Apache,
it's recommended to use the :class:`ApacheXSendfileServer`
or :class:`NginxXAccelRedirectServer` servers instead.
""" """
@staticmethod @staticmethod
def serve(private_file): def serve(private_file):
# This supports If-Modified-Since and sends the file in 8KB chunks # This supports If-Modified-Since and sends the file in 4KB chunks
try: try:
full_path = private_file.full_path full_path = private_file.full_path
except NotImplementedError: except NotImplementedError:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment