mirror of
https://github.com/jazzband/django-downloadview.git
synced 2026-03-16 22:40:25 +00:00
Refs #32 - Respect 'attachment' argument in X-Accel optimization.
This commit is contained in:
parent
eff185b858
commit
e8266615ed
7 changed files with 76 additions and 8 deletions
|
|
@ -31,20 +31,29 @@ class DownloadTestCase(TestCase):
|
|||
self.assertEquals(response['Content-Type'],
|
||||
'text/plain; charset=utf-8')
|
||||
self.assertFalse('ContentEncoding' in response)
|
||||
self.assertEquals(response['Content-Disposition'],
|
||||
'attachment; filename=hello-world.txt')
|
||||
if is_attachment:
|
||||
self.assertEquals(response['Content-Disposition'],
|
||||
'attachment; filename=hello-world.txt')
|
||||
else:
|
||||
self.assertFalse('Content-Disposition' in response)
|
||||
self.assertEqual(open(self.files['hello-world.txt']).read(),
|
||||
''.join(response.streaming_content))
|
||||
|
||||
|
||||
class PathDownloadViewTestCase(DownloadTestCase):
|
||||
"""Test "hello_world" view."""
|
||||
"""Test "hello_world" and "hello_world_inline" views."""
|
||||
def test_download_hello_world(self):
|
||||
"""hello_world view returns hello-world.txt as attachement."""
|
||||
download_url = reverse('hello_world')
|
||||
response = self.client.get(download_url)
|
||||
self.assertDownloadHelloWorld(response)
|
||||
|
||||
def test_download_hello_world_inline(self):
|
||||
"""hello_world view returns hello-world.txt as attachement."""
|
||||
download_url = reverse('hello_world_inline')
|
||||
response = self.client.get(download_url)
|
||||
self.assertDownloadHelloWorld(response, is_attachment=False)
|
||||
|
||||
|
||||
class CustomPathDownloadViewTestCase(DownloadTestCase):
|
||||
"""Test "fixture_from_path" view."""
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ urlpatterns = patterns(
|
|||
url(r'^hello-world\.txt$',
|
||||
'download_hello_world',
|
||||
name='hello_world'),
|
||||
url(r'^hello-world-inline\.txt$',
|
||||
'download_hello_world_inline',
|
||||
name='hello_world_inline'),
|
||||
url(r'^path/(?P<path>[a-zA-Z0-9_-]+\.[a-zA-Z0-9]{1,4})$',
|
||||
'download_fixture_from_path',
|
||||
name='fixture_from_path'),
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@ fixtures_storage = FileSystemStorage(location=fixtures_dir)
|
|||
download_document = views.ObjectDownloadView.as_view(model=Document)
|
||||
|
||||
|
||||
#: Same as download_document, but streamed inline, i.e. not as attachments.
|
||||
download_document_inline = views.ObjectDownloadView.as_view(model=Document,
|
||||
attachment=False)
|
||||
|
||||
|
||||
#: Pre-configured view using a storage.
|
||||
download_fixture_from_storage = views.StorageDownloadView.as_view(
|
||||
storage=fixtures_storage)
|
||||
|
|
@ -42,6 +47,12 @@ download_fixture_from_storage = views.StorageDownloadView.as_view(
|
|||
download_hello_world = views.PathDownloadView.as_view(path=hello_world_path)
|
||||
|
||||
|
||||
#: Direct download of one file, based on an absolute path, not as attachment.
|
||||
download_hello_world_inline = views.PathDownloadView.as_view(
|
||||
path=hello_world_path,
|
||||
attachment=False)
|
||||
|
||||
|
||||
class CustomPathDownloadView(views.PathDownloadView):
|
||||
"""Example of customized PathDownloadView."""
|
||||
def get_path(self):
|
||||
|
|
|
|||
|
|
@ -37,3 +37,26 @@ class XAccelRedirectDecoratorTestCase(DownloadTestCase):
|
|||
self.assertFalse('ContentEncoding' in response)
|
||||
self.assertEquals(response['Content-Disposition'],
|
||||
'attachment; filename=hello-world.txt')
|
||||
|
||||
|
||||
class InlineXAccelRedirectTestCase(DownloadTestCase):
|
||||
@temporary_media_root()
|
||||
def test_response(self):
|
||||
"""X-Accel optimization respects ``attachment`` attribute."""
|
||||
document = Document.objects.create(
|
||||
slug='hello-world',
|
||||
file=File(open(self.files['hello-world.txt'])),
|
||||
)
|
||||
download_url = reverse('download_document_nginx_inline',
|
||||
kwargs={'slug': 'hello-world'})
|
||||
response = self.client.get(download_url)
|
||||
assert_x_accel_redirect(
|
||||
self,
|
||||
response,
|
||||
content_type="text/plain; charset=utf-8",
|
||||
charset="utf-8",
|
||||
attachment=False,
|
||||
redirect_url="/download-optimized/document/hello-world.txt",
|
||||
expires=None,
|
||||
with_buffering=None,
|
||||
limit_rate=None)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@
|
|||
from django.conf.urls import patterns, url
|
||||
|
||||
|
||||
urlpatterns = patterns('demoproject.nginx.views',
|
||||
urlpatterns = patterns(
|
||||
'demoproject.nginx.views',
|
||||
url(r'^document-nginx/(?P<slug>[a-zA-Z0-9_-]+)/$',
|
||||
'download_document_nginx', name='download_document_nginx'),
|
||||
url(r'^document-nginx-inline/(?P<slug>[a-zA-Z0-9_-]+)/$',
|
||||
'download_document_nginx_inline',
|
||||
name='download_document_nginx_inline'),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
"""Views."""
|
||||
from django.conf import settings
|
||||
|
||||
from django_downloadview.nginx import x_accel_redirect
|
||||
|
||||
from demoproject.download import views
|
||||
|
|
@ -8,3 +10,9 @@ download_document_nginx = x_accel_redirect(
|
|||
views.download_document,
|
||||
source_dir='/var/www/files',
|
||||
destination_url='/download-optimized')
|
||||
|
||||
|
||||
download_document_nginx_inline = x_accel_redirect(
|
||||
views.download_document_inline,
|
||||
source_dir=settings.MEDIA_ROOT,
|
||||
destination_url='/download-optimized')
|
||||
|
|
|
|||
|
|
@ -103,11 +103,13 @@ if not hasattr(settings, 'NGINX_DOWNLOAD_MIDDLEWARE_DESTINATION_URL'):
|
|||
class XAccelRedirectResponse(HttpResponse):
|
||||
"""Http response that delegates serving file to Nginx."""
|
||||
def __init__(self, redirect_url, content_type, basename=None, expires=None,
|
||||
with_buffering=None, limit_rate=None):
|
||||
with_buffering=None, limit_rate=None, attachment=True):
|
||||
"""Return a HttpResponse with headers for Nginx X-Accel-Redirect."""
|
||||
super(XAccelRedirectResponse, self).__init__(content_type=content_type)
|
||||
self.basename = basename or redirect_url.split('/')[-1]
|
||||
self['Content-Disposition'] = 'attachment; filename=%s' % self.basename
|
||||
if attachment:
|
||||
self.basename = basename or redirect_url.split('/')[-1]
|
||||
self['Content-Disposition'] = 'attachment; filename={name}'.format(
|
||||
name=self.basename)
|
||||
self['X-Accel-Redirect'] = redirect_url
|
||||
self['X-Accel-Charset'] = content_type_to_charset(content_type)
|
||||
if with_buffering is not None:
|
||||
|
|
@ -203,6 +205,13 @@ class XAccelRedirectValidator(object):
|
|||
else:
|
||||
test_case.assertEqual(header, value)
|
||||
|
||||
def assert_attachment(self, test_case, response, value):
|
||||
header = 'Content-Disposition'
|
||||
if value:
|
||||
test_case.assertTrue(response[header].startswith('attachment'))
|
||||
else:
|
||||
test_case.assertFalse(header in response)
|
||||
|
||||
|
||||
def assert_x_accel_redirect(test_case, response, **assertions):
|
||||
"""Make ``test_case`` assert that ``response`` is a XAccelRedirectResponse.
|
||||
|
|
@ -345,7 +354,8 @@ class BaseXAccelRedirectMiddleware(BaseDownloadMiddleware):
|
|||
basename=response.basename,
|
||||
expires=expires,
|
||||
with_buffering=self.with_buffering,
|
||||
limit_rate=self.limit_rate)
|
||||
limit_rate=self.limit_rate,
|
||||
attachment=response.attachment)
|
||||
|
||||
|
||||
class XAccelRedirectMiddleware(BaseXAccelRedirectMiddleware):
|
||||
|
|
|
|||
Loading…
Reference in a new issue