Merge pull request #212 from sevdog/xaccel-headers

Allow XResponses to keep original headers provided to base response
This commit is contained in:
Rémy HUBSCHER 2024-08-05 10:23:48 +02:00 committed by GitHub
commit 1b294f00fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 130 additions and 10 deletions

View file

@ -43,3 +43,19 @@ class OptimizedByDecoratorTestCase(django.test.TestCase):
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')

View file

@ -15,4 +15,9 @@ urlpatterns = [
views.optimized_by_decorator,
name="optimized_by_decorator",
),
path(
"modified_headers/",
views.modified_headers,
name="modified_headers",
),
]

View file

@ -22,3 +22,17 @@ optimized_by_decorator = x_sendfile(
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/",
)

View file

@ -43,3 +43,19 @@ class OptimizedByDecoratorTestCase(django.test.TestCase):
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')

View file

@ -15,4 +15,9 @@ urlpatterns = [
views.optimized_by_decorator,
name="optimized_by_decorator",
),
path(
"modified_headers/",
views.modified_headers,
name="modified_headers",
),
]

View file

@ -22,3 +22,17 @@ optimized_by_decorator = x_sendfile(
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/",
)

View file

@ -51,3 +51,23 @@ class OptimizedByDecoratorTestCase(django.test.TestCase):
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')

View file

@ -16,4 +16,9 @@ urlpatterns = [
views.optimized_by_decorator,
name="optimized_by_decorator",
),
path(
"modified_headers/",
views.modified_headers,
name="modified_headers",
),
]

View file

@ -22,3 +22,17 @@ optimized_by_decorator = x_accel_redirect(
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/",
)

View file

@ -32,4 +32,5 @@ class XSendfileMiddleware(ProxiedDownloadMiddleware):
content_type=response["Content-Type"],
basename=response.basename,
attachment=response.attachment,
headers=response.headers,
)

View file

@ -7,9 +7,12 @@ from django_downloadview.response import ProxiedDownloadResponse, content_dispos
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)

View file

@ -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.

View file

@ -19,9 +19,7 @@ class XSendfileMiddleware(ProxiedDownloadMiddleware):
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 @@ class XSendfileMiddleware(ProxiedDownloadMiddleware):
content_type=response["Content-Type"],
basename=response.basename,
attachment=response.attachment,
headers=response.headers,
)

View file

@ -7,9 +7,12 @@ from django_downloadview.response import ProxiedDownloadResponse, content_dispos
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)

View file

@ -85,6 +85,7 @@ class XAccelRedirectMiddleware(ProxiedDownloadMiddleware):
with_buffering=self.with_buffering,
limit_rate=self.limit_rate,
attachment=response.attachment,
headers=response.headers,
)

View file

@ -19,9 +19,13 @@ class XAccelRedirectResponse(ProxiedDownloadResponse):
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)

View file

@ -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.