diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index c00b0b9b96..3736e1f2ad 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -236,9 +236,13 @@ MEDIA_ROOT = '' # Example: "http://media.lawrence.com" MEDIA_URL = '' -# Header to use in HttpResponseSendFile to inform the handler to serve the -# file with efficient handler-specific routines. -HTTPRESPONSE_SENDFILE_HEADER = 'X-Sendfile' +# Header to use in HttpResponseSendFile to inform the handler to serve the +# file with efficient handler-specific routines. None causes HttpResponseSendFile +# to fall back to, first, mechanisms in the handler (wsgi.filewrapper and +# req.sendfile. +# Examples: 'X-Sendfile' (FastCGI, lighttpd, Apache with mod_xsendfile), +# 'X-Accel-Redirect' (nginx) +HTTPRESPONSE_SENDFILE_METHOD = None # List of upload handler classes to be applied in order. FILE_UPLOAD_HANDLERS = ( diff --git a/django/core/handlers/modpython.py b/django/core/handlers/modpython.py index 2517098366..9557e5860e 100644 --- a/django/core/handlers/modpython.py +++ b/django/core/handlers/modpython.py @@ -200,15 +200,15 @@ class ModPythonHandler(BaseHandler): for c in response.cookies.values(): req.headers_out.add('Set-Cookie', c.output(header='')) req.status = response.status_code - if isinstance(response, http.HttpResponseSendFile): - req.sendfile(response.sendfile_filename) + if isinstance(response, http.HttpResponseSendFile): + req.sendfile(response.sendfile_filename) else: - try: - for chunk in response: - req.write(chunk) - finally: - response.close() - + # If we are using a header to do sendfile, set the header and send empty content + if settings.RESPONSE_SENDFILE_METHOD: + response.set_empty_content() + response[settings.HTTPRESPONSE_SENDFILE_METHOD] = response.sendfile_filename + for chunk in response: + req.write(chunk) return 0 # mod_python.apache.OK def handler(req): diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py index b79d15fec9..22e65b8f24 100644 --- a/django/core/handlers/wsgi.py +++ b/django/core/handlers/wsgi.py @@ -243,14 +243,11 @@ class WSGIHandler(base.BaseHandler): start_response(status, response_headers) if isinstance(response, http.HttpResponseSendFile): - filelike = open(response.sendfile_filename, 'rb') - if 'wsgi.file_wrapper' in environ: + if settings.HTTPRESPONSE_SENDFILE_METHOD: + response[settings.HTTPRESPONSE_SENDFILE_METHOD] = response.sendfile_filename + elif 'wsgi.file_wrapper' in environ: + filelike = open(response.sendfile_filename, 'rb') return environ['wsgi.file_wrapper'](filelike, - response.block_size) - else: - # wraps close() as well - from django.core.servers.basehttp import FileWrapper - return FileWrapper(filelike, response.block_size) - + response.block_size) return response diff --git a/django/http/__init__.py b/django/http/__init__.py index a99c68045c..330a0e25e9 100644 --- a/django/http/__init__.py +++ b/django/http/__init__.py @@ -447,9 +447,14 @@ class HttpResponseSendFile(HttpResponse): self['Content-Length'] = os.path.getsize(path_to_file) self['Content-Disposition'] = ('attachment; filename=%s' % os.path.basename(path_to_file)) - self[settings.HTTPRESPONSE_SENDFILE_HEADER] = path_to_file + self._empty_content = False + + def set_empty_content(self): + self._empty_content = True def __iter__(self): + if self._empty_content: + return iter(['']) from django.core.servers.basehttp import FileWrapper return FileWrapper(self.get_file_handler(), self.block_size) diff --git a/tests/regressiontests/sendfile/tests.py b/tests/regressiontests/sendfile/tests.py index b28cb2ead8..7e38a7e0b1 100644 --- a/tests/regressiontests/sendfile/tests.py +++ b/tests/regressiontests/sendfile/tests.py @@ -18,8 +18,8 @@ class SendFileTests(TestCase): urllib.quote(file1.name)) self.assertEqual(response.status_code, 200) - self.assertEqual(response[settings.HTTPRESPONSE_SENDFILE_HEADER], - file1.name) + #self.assertEqual(response[settings.HTTPRESPONSE_SENDFILE_METHOD], + # file1.name) self.assertEqual(response['Content-Disposition'], 'attachment; filename=%s' % os.path.basename(file1.name)) self.assertEqual(response['Content-Length'], str(FILE_SIZE))