Skip to content

Commit

Permalink
backends-nginx: Add support for Nginx versions older than 1.5.9.
Browse files Browse the repository at this point in the history
In this commit we are adding support for Nginx version older than
1.5.9. This is achieved through conditionally quoting the URL's in
X-Accel-Redirect headers according to compatibility with Nginx.
Since newer versions of Nginx expect URL's in X-Accel-Redirect to
be quoted unlike the versions older that Nginx 1.5.9. From this commit
onwards we start to expect a 'NGINX_VERSION' config setting to be setup
in the django settings in order to facilitate decision making regarding
quoting URL's. If such a setting is not found we just assume Nginx version
to be greater then 1.5.9 and make decision accordingly and then cache the
decision by making use of a decorator. Using this result we decide whether
the outgoing URL should be quoted or not.
Fixes: johnsensible#56, johnsensible#58. Closes johnsensible#45.
  • Loading branch information
adnrs96 committed Apr 13, 2017
1 parent b99f963 commit d69f33f
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 4 deletions.
11 changes: 8 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ The interface is a single function `sendfile(request, filename, attachment=False
::

from sendfile import sendfile

# send myfile.pdf to user
return sendfile(request, '/home/john/myfile.pdf')

# send myfile.pdf as an attachment (with name myfile.pdf)
return sendfile(request, '/home/john/myfile.pdf', attachment=True)

# send myfile.pdf as an attachment with a different name
return sendfile(request, '/home/john/myfile.pdf', attachment=True, attachment_filename='full-name.pdf')

Expand Down Expand Up @@ -134,8 +134,13 @@ Then the matching location block in nginx.conf would be:

You need to pay attention to whether you have trailing slashes or not on the SENDFILE_URL and 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.

Also if you are willing to use django-sendfile with Nginx older than 1.5.9, you need to setup the configuration setting in django settings for specifying Nginx version like this:

::

NGINX_VERSION = '1.4.6'

.. _mod_xsendfile: https://tn123.org/mod_xsendfile/
.. _Apache: http://httpd.apache.org/
.. _Lighthttpd: http://www.lighttpd.net/
.. _mod_wsgi: http://code.google.com/p/modwsgi/

28 changes: 27 additions & 1 deletion sendfile/backends/_internalredirect.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,36 @@

from django.conf import settings
from django.utils.encoding import smart_text, smart_bytes
from django.conf import settings

try:
from urllib.parse import quote
except ImportError:
from urllib import quote


def _decision(fn):
_cached_decision = []
def _decorated():
if not _cached_decision:
_cached_decision.append(fn())
return _cached_decision[0]
return _decorated

@_decision
def should_be_quoted():
backend = getattr(settings, 'SENDFILE_BACKEND', None)
if backend == 'sendfile.backends.nginx':
nginx_version = getattr(settings, 'NGINX_VERSION', None)
if nginx_version:
nginx_version = map(int, nginx_version.split('.'))
# Since Starting with Nginx 1.5.9, quoted url's are expected to be
# sent with X-Accel-Redirect headers, we will not quote url's for
# versions of Nginx before 1.5.9
if nginx_version < [1, 5, 9]:
return False
return True

def _convert_file_to_url(filename):
relpath = os.path.relpath(filename, settings.SENDFILE_ROOT)

Expand All @@ -21,4 +44,7 @@ def _convert_file_to_url(filename):
# Python3 urllib.parse.quote accepts both unicode and bytes, while Python2 urllib.quote only accepts bytes.
# So use bytes for quoting and then go back to unicode.
url = [smart_bytes(url_component) for url_component in url]
return smart_text(quote(b'/'.join(url)))
if should_be_quoted():
return smart_text(quote(b'/'.join(url)))
else:
return smart_text(b'/'.join(url))

0 comments on commit d69f33f

Please sign in to comment.