Backends

Backends are specified by setting SENDFILE_BACKEND to the dotted path of the backend you wish to use. E.g.:

settings.py
SENDFILE_BACKEND = "django_sendfile.backends.simple"

Development backend

django_sendfile.backends.development

The Development backend is only meant for use while writing code. It uses Django’s static file serving code to do the job, which is only meant for development. It reads the whole file into memory and the sends it down the wire - not good for big files, but OK when you are just testing things out.

It will work with the Django dev server and anywhere else you can run Django.

Simple backend

django_sendfile.backends.simple

This backend is one step up from the development backend. It uses Django’s django.core.files.base.File class to try and stream files from disk. However some middleware (e.g. GzipMiddleware) that rewrites content will causes the entire file to be loaded into memory. So only use this backend if you are not using middleware that rewrites content or you only have very small files.

mod_wsgi backend

django_sendfile.backends.mod_wsgi

The mod_wsgi backend will only work when using mod_wsgi in daemon mode, not in embedded mode. It requires a bit more work to get it to do the same job as xsendfile though. However some may find it easier to setup, as they don’t need to compile and install mod_xsendfile.

Firstly there one more Django setting that needs to be given:

  • SENDFILE_URL - internal URL prefix for all files served via sendfile

These settings are needed as this backend makes mod_wsgi send an internal redirect, so we have to convert a file path into a URL. This means that the files are visible via Apache by default too. So we need to get Apache to hide those files from anything that’s not an internal redirect. To so this we can use some mod_rewrite magic along these lines:

RewriteEngine On
# see if we're on an internal redirect or not
RewriteCond %{THE_REQUEST} ^[\S]+\ /private/
RewriteRule ^/private/ - [F]

Alias /private/ /home/john/Development/myapp/private/
<Directory /home/john/Development/myapp/private/>
    Order deny,allow
    Allow from all
</Directory>

In this case I have also set:

settings.py
SENDFILE_ROOT = '/home/john/Development/myapp/private/'
SENDFILE_URL = '/private'

All files are stored in a folder called ‘private’. We forbid access to this folder (RewriteRule ^/private/ - [F]) if someone tries to access it directly (RewriteCond %{THE_REQUEST} ^[\S]+\ /private/) by checking the original request (THE_REQUEST).

Allegedly IS_SUBREQ can be used to perform the same job, but I was unable to get this working.

Nginx backend

django_sendfile.backends.nginx

As with the mod_wsgi backend you need to set an extra settings:

  • SENDFILE_URL - internal URL prefix for all files served via sendfile

You then need to configure Nginx to only allow internal access to the files you wish to serve. More details on this are here.

For example though, if I use the Django settings:

settings.py
SENDFILE_ROOT = '/home/john/Development/django-sendfile/examples/protected_downloads/protected'
SENDFILE_URL = '/protected'

Then the matching location block in nginx.conf would be:

location /protected/ {
  internal;
  root   /home/john/Development/django-sendfile/examples/protected_downloads;
}

You need to pay attention to whether you have trailing slashes or not on the SENDFILE_URL and SENDFILE_ROOT values, otherwise you may not get the right URL being sent to Nginx and you may get 404s. You should be able to see what file Nginx is trying to load in the error.log if this happens. From there it should be fairly easy to work out what the right settings are.

xsendfile backend

django_sendfile.backends.xsendfile

Install either mod_xsendfile in Apache or use Lighthttpd. You may need to configure mod_xsendfile, but that should be as simple as:

XSendFile On

In your virtualhost file/conf file.