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:
parent
0430883019
commit
d1b466ac56
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user