diff --git a/demo/demoproject/apache/tests.py b/demo/demoproject/apache/tests.py index 4ac4fec..e3afbbc 100644 --- a/demo/demoproject/apache/tests.py +++ b/demo/demoproject/apache/tests.py @@ -43,3 +43,19 @@ def test_response(self): basename="hello-world.txt", file_path="/apache-optimized-by-decorator/hello-world.txt", ) + + +class ModifiedHeadersTestCase(django.test.TestCase): + def test_response(self): + """'apache:modified_headers' returns X-Sendfile response.""" + setup_file() + url = reverse("apache:modified_headers") + response = self.client.get(url) + assert_x_sendfile( + self, + response, + content_type="text/plain; charset=utf-8", + basename="hello-world.txt", + file_path="/apache-modified-headers/hello-world.txt", + ) + self.assertEqual(response['X-Test'], 'header') diff --git a/demo/demoproject/apache/urls.py b/demo/demoproject/apache/urls.py index 497d57f..8994f8c 100644 --- a/demo/demoproject/apache/urls.py +++ b/demo/demoproject/apache/urls.py @@ -15,4 +15,9 @@ views.optimized_by_decorator, name="optimized_by_decorator", ), + path( + "modified_headers/", + views.modified_headers, + name="modified_headers", + ), ] diff --git a/demo/demoproject/apache/views.py b/demo/demoproject/apache/views.py index a248e5e..00df043 100644 --- a/demo/demoproject/apache/views.py +++ b/demo/demoproject/apache/views.py @@ -22,3 +22,17 @@ source_url=storage.base_url, destination_dir="/apache-optimized-by-decorator/", ) + + +def _modified_headers(request): + view = StorageDownloadView.as_view(storage=storage, path="hello-world.txt") + response = view(request) + response["X-Test"] = 'header' + return response + + +modified_headers = x_sendfile( + _modified_headers, + source_url=storage.base_url, + destination_dir="/apache-modified-headers/", +) diff --git a/demo/demoproject/lighttpd/tests.py b/demo/demoproject/lighttpd/tests.py index 3eb8533..97b9d84 100644 --- a/demo/demoproject/lighttpd/tests.py +++ b/demo/demoproject/lighttpd/tests.py @@ -43,3 +43,19 @@ def test_response(self): basename="hello-world.txt", file_path="/lighttpd-optimized-by-decorator/hello-world.txt", ) + + +class ModifiedHeadersTestCase(django.test.TestCase): + def test_response(self): + """'lighttpd:modified_headers' returns X-Sendfile response.""" + setup_file() + url = reverse("lighttpd:modified_headers") + response = self.client.get(url) + assert_x_sendfile( + self, + response, + content_type="text/plain; charset=utf-8", + basename="hello-world.txt", + file_path="/lighttpd-modified-headers/hello-world.txt", + ) + self.assertEqual(response['X-Test'], 'header') diff --git a/demo/demoproject/lighttpd/urls.py b/demo/demoproject/lighttpd/urls.py index 237338e..40c58f2 100644 --- a/demo/demoproject/lighttpd/urls.py +++ b/demo/demoproject/lighttpd/urls.py @@ -15,4 +15,9 @@ views.optimized_by_decorator, name="optimized_by_decorator", ), + path( + "modified_headers/", + views.modified_headers, + name="modified_headers", + ), ] diff --git a/demo/demoproject/lighttpd/views.py b/demo/demoproject/lighttpd/views.py index e57b56e..8f5a4c0 100644 --- a/demo/demoproject/lighttpd/views.py +++ b/demo/demoproject/lighttpd/views.py @@ -22,3 +22,17 @@ source_url=storage.base_url, destination_dir="/lighttpd-optimized-by-decorator/", ) + + +def _modified_headers(request): + view = StorageDownloadView.as_view(storage=storage, path="hello-world.txt") + response = view(request) + response["X-Test"] = 'header' + return response + + +modified_headers = x_sendfile( + _modified_headers, + source_url=storage.base_url, + destination_dir="/lighttpd-modified-headers/", +) diff --git a/demo/demoproject/nginx/tests.py b/demo/demoproject/nginx/tests.py index 1b26340..1f38f5a 100644 --- a/demo/demoproject/nginx/tests.py +++ b/demo/demoproject/nginx/tests.py @@ -51,3 +51,23 @@ def test_response(self): with_buffering=None, limit_rate=None, ) + + +class ModifiedHeadersTestCase(django.test.TestCase): + def test_response(self): + """'nginx:modified_headers' returns X-Sendfile response.""" + setup_file() + url = reverse("nginx:modified_headers") + response = self.client.get(url) + assert_x_accel_redirect( + self, + response, + content_type="text/plain; charset=utf-8", + charset="utf-8", + basename="hello-world.txt", + redirect_url="/nginx-modified-headers/hello-world.txt", + expires=None, + with_buffering=None, + limit_rate=None, + ) + self.assertEqual(response['X-Test'], 'header') diff --git a/demo/demoproject/nginx/urls.py b/demo/demoproject/nginx/urls.py index 01c9b88..7590109 100644 --- a/demo/demoproject/nginx/urls.py +++ b/demo/demoproject/nginx/urls.py @@ -16,4 +16,9 @@ views.optimized_by_decorator, name="optimized_by_decorator", ), + path( + "modified_headers/", + views.modified_headers, + name="modified_headers", + ), ] diff --git a/demo/demoproject/nginx/views.py b/demo/demoproject/nginx/views.py index e8546cc..e293b1e 100644 --- a/demo/demoproject/nginx/views.py +++ b/demo/demoproject/nginx/views.py @@ -22,3 +22,17 @@ source_url=storage.base_url, destination_url="/nginx-optimized-by-decorator/", ) + + +def _modified_headers(request): + view = StorageDownloadView.as_view(storage=storage, path="hello-world.txt") + response = view(request) + response["X-Test"] = 'header' + return response + + +modified_headers = x_accel_redirect( + _modified_headers, + source_url=storage.base_url, + destination_url="/nginx-modified-headers/", +) diff --git a/django_downloadview/apache/middlewares.py b/django_downloadview/apache/middlewares.py index cada074..d09cc89 100644 --- a/django_downloadview/apache/middlewares.py +++ b/django_downloadview/apache/middlewares.py @@ -32,4 +32,5 @@ def process_download_response(self, request, response): content_type=response["Content-Type"], basename=response.basename, attachment=response.attachment, + headers=response.headers, ) diff --git a/django_downloadview/apache/response.py b/django_downloadview/apache/response.py index b4ad826..94b1132 100644 --- a/django_downloadview/apache/response.py +++ b/django_downloadview/apache/response.py @@ -7,9 +7,12 @@ class XSendfileResponse(ProxiedDownloadResponse): "Delegates serving file to Apache via X-Sendfile header." - def __init__(self, file_path, content_type, basename=None, attachment=True): + def __init__(self, file_path, content_type, basename=None, attachment=True, headers=None): """Return a HttpResponse with headers for Apache X-Sendfile.""" - super().__init__(content_type=content_type) + # content-type must be provided only as keyword argument to response + if headers and content_type: + headers.pop('Content-Type', None) + super().__init__(content_type=content_type, headers=headers) if attachment: self.basename = basename or os.path.basename(file_path) self["Content-Disposition"] = content_disposition(self.basename) diff --git a/django_downloadview/apache/tests.py b/django_downloadview/apache/tests.py index 0792918..7fa96ef 100644 --- a/django_downloadview/apache/tests.py +++ b/django_downloadview/apache/tests.py @@ -1,7 +1,7 @@ from django_downloadview.apache.response import XSendfileResponse -class XSendfileValidator(object): +class XSendfileValidator: """Utility class to validate XSendfileResponse instances. See also :py:func:`assert_x_sendfile` shortcut function. diff --git a/django_downloadview/lighttpd/middlewares.py b/django_downloadview/lighttpd/middlewares.py index 136bdb0..f36913c 100644 --- a/django_downloadview/lighttpd/middlewares.py +++ b/django_downloadview/lighttpd/middlewares.py @@ -19,9 +19,7 @@ def __init__( self, get_response=None, source_dir=None, source_url=None, destination_dir=None ): """Constructor.""" - super(XSendfileMiddleware, self).__init__( - get_response, source_dir, source_url, destination_dir - ) + super().__init__(get_response, source_dir, source_url, destination_dir) def process_download_response(self, request, response): """Replace DownloadResponse instances by XSendfileResponse ones.""" @@ -34,4 +32,5 @@ def process_download_response(self, request, response): content_type=response["Content-Type"], basename=response.basename, attachment=response.attachment, + headers=response.headers, ) diff --git a/django_downloadview/lighttpd/response.py b/django_downloadview/lighttpd/response.py index 219ee99..97cc8b4 100644 --- a/django_downloadview/lighttpd/response.py +++ b/django_downloadview/lighttpd/response.py @@ -7,9 +7,12 @@ class XSendfileResponse(ProxiedDownloadResponse): "Delegates serving file to Lighttpd via X-Sendfile header." - def __init__(self, file_path, content_type, basename=None, attachment=True): + def __init__(self, file_path, content_type, basename=None, attachment=True, headers=None): """Return a HttpResponse with headers for Lighttpd X-Sendfile.""" - super(XSendfileResponse, self).__init__(content_type=content_type) + # content-type must be porvided only as keyword argument to response + if headers and content_type: + headers.pop('Content-Type', None) + super().__init__(content_type=content_type, headers=headers) if attachment: self.basename = basename or os.path.basename(file_path) self["Content-Disposition"] = content_disposition(self.basename) diff --git a/django_downloadview/nginx/middlewares.py b/django_downloadview/nginx/middlewares.py index cf70750..afceca3 100644 --- a/django_downloadview/nginx/middlewares.py +++ b/django_downloadview/nginx/middlewares.py @@ -85,6 +85,7 @@ def process_download_response(self, request, response): with_buffering=self.with_buffering, limit_rate=self.limit_rate, attachment=response.attachment, + headers=response.headers, ) diff --git a/django_downloadview/nginx/response.py b/django_downloadview/nginx/response.py index 1785549..d789b64 100644 --- a/django_downloadview/nginx/response.py +++ b/django_downloadview/nginx/response.py @@ -19,9 +19,13 @@ def __init__( with_buffering=None, limit_rate=None, attachment=True, + headers=None, ): """Return a HttpResponse with headers for Nginx X-Accel-Redirect.""" - super(XAccelRedirectResponse, self).__init__(content_type=content_type) + # content-type must be porvided only as keyword argument to response + if headers and content_type: + headers.pop('Content-Type', None) + super().__init__(content_type=content_type, headers=headers) if attachment: self.basename = basename or url_basename(redirect_url, content_type) self["Content-Disposition"] = content_disposition(self.basename) diff --git a/django_downloadview/nginx/tests.py b/django_downloadview/nginx/tests.py index d538b6a..63e1129 100644 --- a/django_downloadview/nginx/tests.py +++ b/django_downloadview/nginx/tests.py @@ -1,7 +1,7 @@ from django_downloadview.nginx.response import XAccelRedirectResponse -class XAccelRedirectValidator(object): +class XAccelRedirectValidator: """Utility class to validate XAccelRedirectResponse instances. See also :py:func:`assert_x_accel_redirect` shortcut function.