0
0
mirror of https://github.com/wagtail/wagtail.git synced 2024-12-01 11:41:20 +01:00

Restore ability to serve docs from non-local storage backends

Fixes #1415.
The sendfile mechanism added in #1176 relies on the ability to access file.path, which is not guaranteed for all storage backends - in particular, remote storage backends such as storages.backends.s3boto.S3BotoStorage won't support it. Therefore, if accessing file.path fails, we fall back on the old StreamingHttpResponse code.
This commit is contained in:
Matt Westcott 2015-06-17 15:14:03 +01:00
parent 0430883019
commit d1b466ac56

View File

@ -1,5 +1,9 @@
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.conf import settings from django.conf import settings
from django.http import StreamingHttpResponse, BadHeaderError
from unidecode import unidecode
from wsgiref.util import FileWrapper
from wagtail.utils.sendfile import sendfile from wagtail.utils.sendfile import sendfile
from wagtail.utils import sendfile_streaming_backend from wagtail.utils import sendfile_streaming_backend
@ -13,8 +17,40 @@ def serve(request, document_id, document_filename):
# Send document_served signal # Send document_served signal
document_served.send(sender=Document, instance=doc, request=request) document_served.send(sender=Document, instance=doc, request=request)
try:
local_path = doc.file.path
except NotImplementedError:
local_path = None
if local_path:
# Use wagtail.utils.sendfile to serve the file;
# this provides support for mimetypes, if-modified-since and django-sendfile backends
if hasattr(settings, 'SENDFILE_BACKEND'): if hasattr(settings, 'SENDFILE_BACKEND'):
return sendfile(request, doc.file.path, attachment=True, attachment_filename=doc.filename) return sendfile(request, local_path, attachment=True, attachment_filename=doc.filename)
else: else:
# Fallback to streaming backend if user hasn't specified SENDFILE_BACKEND # Fallback to streaming backend if user hasn't specified SENDFILE_BACKEND
return sendfile(request, doc.file.path, attachment=True, attachment_filename=doc.filename, backend=sendfile_streaming_backend.sendfile) return sendfile(request, local_path, attachment=True, attachment_filename=doc.filename, backend=sendfile_streaming_backend.sendfile)
else:
# We are using a storage backend which does not expose filesystem paths
# (e.g. storages.backends.s3boto.S3BotoStorage).
# Fall back on pre-sendfile behaviour of reading the file content and serving it
# as a StreamingHttpResponse
wrapper = FileWrapper(doc.file)
response = StreamingHttpResponse(wrapper, content_type='application/octet-stream')
try:
response['Content-Disposition'] = 'attachment; filename=%s' % doc.filename
except BadHeaderError:
# Unicode filenames can fail on Django <1.8, Python 2 due to
# https://code.djangoproject.com/ticket/20889 - try with an ASCIIfied version of the name
response['Content-Disposition'] = 'attachment; filename=%s' % unidecode(doc.filename)
# FIXME: storage backends are not guaranteed to implement 'size'
response['Content-Length'] = doc.file.size
return response