# Copied from django-sendfile 0.3.6 and tweaked to allow a backend to be passed # to sendfile() # See: https://github.com/johnsensible/django-sendfile/pull/33 import os.path from mimetypes import guess_type VERSION = (0, 3, 6) __version__ = ".".join(map(str, VERSION)) def _lazy_load(fn): _cached = [] def _decorated(): if not _cached: _cached.append(fn()) return _cached[0] def clear(): while _cached: _cached.pop() _decorated.clear = clear return _decorated @_lazy_load def _get_sendfile(): from importlib import import_module from django.conf import settings from django.core.exceptions import ImproperlyConfigured backend = getattr(settings, "SENDFILE_BACKEND", None) if not backend: raise ImproperlyConfigured("You must specify a value for SENDFILE_BACKEND") module = import_module(backend) return module.sendfile def sendfile( request, filename, attachment=False, attachment_filename=None, mimetype=None, encoding=None, backend=None, ): """ create a response to send file using backend configured in SENDFILE_BACKEND If attachment is True the content-disposition header will be set. This will typically prompt the user to download the file, rather than view it. The content-disposition filename depends on the value of attachment_filename: None (default): Same as filename False: No content-disposition filename String: Value used as filename If no mimetype or encoding are specified, then they will be guessed via the filename (using the standard python mimetypes module) """ _sendfile = backend or _get_sendfile() if not os.path.exists(filename): from django.http import Http404 raise Http404('"%s" does not exist' % filename) guessed_mimetype, guessed_encoding = guess_type(filename) if mimetype is None: if guessed_mimetype: mimetype = guessed_mimetype else: mimetype = "application/octet-stream" response = _sendfile(request, filename, mimetype=mimetype) if attachment: parts = ["attachment"] else: parts = ["inline"] if attachment_filename is None: attachment_filename = os.path.basename(filename) if attachment_filename: from django.utils.encoding import force_str from wagtail.coreutils import string_to_ascii attachment_filename = force_str(attachment_filename) ascii_filename = string_to_ascii(attachment_filename) parts.append('filename="%s"' % ascii_filename) if ascii_filename != attachment_filename: from urllib.parse import quote quoted_filename = quote(attachment_filename) parts.append("filename*=UTF-8''%s" % quoted_filename) response["Content-Disposition"] = "; ".join(parts) response["Content-length"] = os.path.getsize(filename) response["Content-Type"] = mimetype response["Content-Encoding"] = encoding or guessed_encoding return response