Skip to content
Browse files

[soc2009/http-wsgi-improvements] Establish the priorities and fallbac…

…ks for HttpResponseSendFile methods.

Change the setting to settings.HTTPRESPONSE_SENDFILE_METHOD. If this is set to None, we use handler methods,
but otherwise the header gets set, and we do not send any content. If neither of these are available,
use the FileWrapper fallback in HttpResponseSendFile.

This passes the test suite, but is untested on mod_python. I am still trying to figure out how to
view the headers of a response with the Content-Disposition "attachment."

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/http-wsgi-improvements@11268 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent b0e3819 commit 94a94bee3b56b1a8c54065020a461dc645c4d238 @ccahoon ccahoon committed Jul 18, 2009
View
10 django/conf/global_settings.py
@@ -236,9 +236,13 @@
# 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 = (
View
16 django/core/handlers/modpython.py
@@ -200,15 +200,15 @@ def __call__(self, req):
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):
View
13 django/core/handlers/wsgi.py
@@ -243,14 +243,11 @@ def __call__(self, environ, start_response):
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
View
7 django/http/__init__.py
@@ -447,9 +447,14 @@ def __init__(self, path_to_file, content_type=None, block_size=8192):
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)
View
4 tests/regressiontests/sendfile/tests.py
@@ -18,8 +18,8 @@ def test_sendfile(self):
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))

0 comments on commit 94a94be

Please sign in to comment.
Something went wrong with that request. Please try again.