Commit a8ab309f authored by Cristi Vîjdea's avatar Cristi Vîjdea
Browse files

Support X-Accel-Redirect in nginx >=1.5.9

Newer versions of nginx require a properly encoded URI in the X-Accel-Redirected response. According to research done by people on the django-sendfile issue tracker, the specific version number seems to be 1.5.9.

The ``PRIVATE_STORAGE_NGINX_VERSION`` setting is used to determine the proper encoding (defaults to current behaviour of not quoting).

https://github.com/adnrs96/django-sendfile/commit/4488e520f04661136e88be38281e789ae50a260c
parent 967be0df
...@@ -202,6 +202,7 @@ For Nginx ...@@ -202,6 +202,7 @@ For Nginx
PRIVATE_STORAGE_SERVER = 'nginx' PRIVATE_STORAGE_SERVER = 'nginx'
PRIVATE_STORAGE_INTERNAL_URL = '/private-x-accel-redirect/' PRIVATE_STORAGE_INTERNAL_URL = '/private-x-accel-redirect/'
PRIVATE_STORAGE_NGINX_VERSION = 'your.nginx.version'
Add the following location block in the server config: Add the following location block in the server config:
...@@ -212,6 +213,10 @@ Add the following location block in the server config: ...@@ -212,6 +213,10 @@ Add the following location block in the server config:
alias /path/to/private-media/; alias /path/to/private-media/;
} }
The ``PRIVATE_STORAGE_NGINX_VERSION`` setting is used to determine the proper encoding of the ``X-Accel-Redirect``
header when dealing with non-ascii file names. Specifically, versions starting with ``1.5.9`` expect the value of the
header to be URL encoded, while older versions require the raw/MIME encoded file path.
Other webservers Other webservers
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
......
...@@ -7,5 +7,6 @@ PRIVATE_STORAGE_AUTH_FUNCTION = getattr(settings, 'PRIVATE_STORAGE_AUTH_FUNCTION ...@@ -7,5 +7,6 @@ PRIVATE_STORAGE_AUTH_FUNCTION = getattr(settings, 'PRIVATE_STORAGE_AUTH_FUNCTION
# For Nginx X-Accel-Redirect # For Nginx X-Accel-Redirect
PRIVATE_STORAGE_INTERNAL_URL = getattr(settings, 'PRIVATE_STORAGE_INTERNAL_URL', '/private-x-accel-redirect/') PRIVATE_STORAGE_INTERNAL_URL = getattr(settings, 'PRIVATE_STORAGE_INTERNAL_URL', '/private-x-accel-redirect/')
PRIVATE_STORAGE_NGINX_VERSION = getattr(settings, 'PRIVATE_STORAGE_NGINX_VERSION', None)
PRIVATE_STORAGE_S3_REVERSE_PROXY = getattr(settings, 'PRIVATE_STORAGE_S3_REVERSE_PROXY', False) PRIVATE_STORAGE_S3_REVERSE_PROXY = getattr(settings, 'PRIVATE_STORAGE_S3_REVERSE_PROXY', False)
...@@ -14,6 +14,13 @@ from django.utils.lru_cache import lru_cache ...@@ -14,6 +14,13 @@ from django.utils.lru_cache import lru_cache
from django.utils.module_loading import import_string from django.utils.module_loading import import_string
from django.views.static import serve, was_modified_since from django.views.static import serve, was_modified_since
try:
# python 3
from urllib.parse import quote
except ImportError:
# python 2
from urllib import quote
@lru_cache() @lru_cache()
def get_server_class(path): def get_server_class(path):
...@@ -45,6 +52,7 @@ def add_no_cache_headers(func): ...@@ -45,6 +52,7 @@ def add_no_cache_headers(func):
response['Expires'] = 'Thu, 01 Jan 1970 00:00:00 GMT' # HTTP 1.0 proxies response['Expires'] = 'Thu, 01 Jan 1970 00:00:00 GMT' # HTTP 1.0 proxies
response['Cache-Control'] = 'max-age=0, no-cache, must-revalidate, proxy-revalidate' # HTTP 1.1 response['Cache-Control'] = 'max-age=0, no-cache, must-revalidate, proxy-revalidate' # HTTP 1.1
return response return response
return _dec return _dec
...@@ -135,10 +143,30 @@ class NginxXAccelRedirectServer(object): ...@@ -135,10 +143,30 @@ class NginxXAccelRedirectServer(object):
Or update the ``PRIVATE_STORAGE_INTERNAL_URL`` setting to use a different URL prefix. Or update the ``PRIVATE_STORAGE_INTERNAL_URL`` setting to use a different URL prefix.
""" """
@staticmethod
def should_quote():
# newer versions of nginx require a properly encoded URI in the X-Accel-Redirected response
# according to research done by people on the django-sendfile issue tracker, the specific
# version number seems to be 1.5.9
# https://github.com/adnrs96/django-sendfile/commit/4488e520f04661136e88be38281e789ae50a260c
nginx_version = getattr(settings, 'PRIVATE_STORAGE_NGINX_VERSION', None)
if nginx_version:
nginx_version = tuple(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
return nginx_version >= (1, 5, 9)
# preserve old behaviour by default to avoid breaking compatibility
return False
@staticmethod @staticmethod
@add_no_cache_headers @add_no_cache_headers
def serve(private_file): def serve(private_file):
internal_url = os.path.join(settings.PRIVATE_STORAGE_INTERNAL_URL, private_file.relative_name) internal_url = os.path.join(settings.PRIVATE_STORAGE_INTERNAL_URL, private_file.relative_name)
if NginxXAccelRedirectServer.should_quote():
internal_url = quote(internal_url)
response = HttpResponse() response = HttpResponse()
response['X-Accel-Redirect'] = internal_url response['X-Accel-Redirect'] = internal_url
response['Content-Type'] = private_file.content_type response['Content-Type'] = private_file.content_type
......
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