diff --git a/README.rst b/README.rst index 76ccf99..1be3897 100644 --- a/README.rst +++ b/README.rst @@ -2,6 +2,8 @@ Django Sendfile =============== +Please use https://github.com/davidfischer-ch/django-sendfile2 instead. + This is a wrapper around web-server specific methods for sending files to web clients. This is useful when Django needs to check permissions associated files, but does not want to serve the actual bytes of the file itself. i.e. as serving large files is not what Django is made for. Note this should not be used for regular file serving (e.g. css etc), only for cases where you need Django to do some work before serving the actual file. diff --git a/sendfile/__init__.py b/sendfile/__init__.py index 1cc9809..5d92131 100644 --- a/sendfile/__init__.py +++ b/sendfile/__init__.py @@ -1,17 +1,21 @@ -VERSION = (0, 3, 11) -__version__ = '.'.join(map(str, VERSION)) - import os.path from mimetypes import guess_type import unicodedata +VERSION = (0, 3, 11) +__version__ = '.'.join(map(str, VERSION)) + +_guess = object() + def _lazy_load(fn): _cached = [] + def _decorated(): if not _cached: _cached.append(fn()) return _cached[0] + def clear(): while _cached: _cached.pop() @@ -23,7 +27,7 @@ def clear(): def _get_sendfile(): try: from importlib import import_module - except ImportError: + except ImportError: # Django < 1.9 from django.utils.importlib import import_module from django.conf import settings from django.core.exceptions import ImproperlyConfigured @@ -35,10 +39,10 @@ def _get_sendfile(): return module.sendfile - -def sendfile(request, filename, attachment=False, attachment_filename=None, mimetype=None, encoding=None): - ''' - create a response to send file using backend configured in SENDFILE_BACKEND +def sendfile(request, filename, check_exist=False, attachment=False, attachment_filename=None, + encoding=_guess, filesize=_guess, mimetype=_guess): + """ + 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 @@ -49,22 +53,28 @@ def sendfile(request, filename, attachment=False, attachment_filename=None, mime 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) - ''' + Any of encoding, filesize and mimetype left to _guess will be + guessed via the filename (using the standard python mimetypes + and os.path modules). + + Any of encoding, filesize and mimetype set to None will not + be set into the response headers. + """ _sendfile = _get_sendfile() - if not os.path.exists(filename): + if check_exist and 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' - + if filesize is _guess: + filesize = os.path.getsize(filename) + if mimetype is _guess or encoding is _guess: + guessed_mimetype, guessed_encoding = guess_type(filename) + if mimetype is _guess: + mimetype = guessed_mimetype or 'application/octet-stream' + if encoding is _guess: + encoding = guessed_encoding + response = _sendfile(request, filename, mimetype=mimetype) if attachment: if attachment_filename is None: @@ -85,11 +95,11 @@ def sendfile(request, filename, attachment=False, attachment_filename=None, mime parts.append('filename*=UTF-8\'\'%s' % quoted_filename) response['Content-Disposition'] = '; '.join(parts) - response['Content-length'] = os.path.getsize(filename) - response['Content-Type'] = mimetype - if not encoding: - encoding = guessed_encoding - if encoding: + if encoding is not None: response['Content-Encoding'] = encoding + if filesize is not None: + response['Content-Length'] = filesize + if mimetype is not None: + response['Content-Type'] = mimetype return response diff --git a/sendfile/tests.py b/sendfile/tests.py index 0643cae..1602266 100644 --- a/sendfile/tests.py +++ b/sendfile/tests.py @@ -3,7 +3,7 @@ from django.conf import settings from django.test import TestCase from django.http import HttpResponse, Http404, HttpRequest -from django.utils.encoding import smart_str +from django.utils.encoding import smart_bytes, smart_str import os.path from tempfile import mkdtemp import shutil @@ -90,7 +90,9 @@ def test_attachment_filename(self): def test_attachment_filename_unicode(self): response = real_sendfile(HttpRequest(), self._get_readme(), attachment=True, attachment_filename='test’s.txt') self.assertTrue(response is not None) - self.assertEqual('attachment; filename="tests.txt"; filename*=UTF-8\'\'test%E2%80%99s.txt', response['Content-Disposition']) + self.assertEqual( + 'attachment; filename="test\'s.txt"; filename*=UTF-8\'\'test%E2%80%99s.txt', + response['Content-Disposition']) class TestXSendfileBackend(TempFileTestCase): @@ -110,7 +112,7 @@ def test_xsendfile_header_containing_unicode(self): filepath = self.ensure_file(u'péter_là_gueule.txt') response = real_sendfile(HttpRequest(), filepath) self.assertTrue(response is not None) - self.assertEqual(smart_str(filepath), response['X-Sendfile']) + self.assertEqual(smart_bytes(filepath), response['X-Sendfile']) class TestNginxBackend(TempFileTestCase):