Ticket #2131: httpresponsesendfile-no-default-content_bypass-middleware_with-header_with-docs-and-tests.diff
File httpresponsesendfile-no-default-content_bypass-middleware_with-header_with-docs-and-tests.diff, 12.3 KB (added by , 16 years ago) |
---|
-
django/http/__init__.py
393 393 raise Exception("This %s instance cannot tell its position" % self.__class__) 394 394 return sum([len(chunk) for chunk in self._container]) 395 395 396 class HttpResponseSendFile(HttpResponse): 397 def __init__(self, path_to_file, content_type=None, block_size=8192): 398 if not content_type: 399 from mimetypes import guess_type 400 content_type = guess_type(path_to_file)[0] 401 if content_type is None: 402 content_type = "application/octet-stream" 403 super(HttpResponseSendFile, self).__init__(None, 404 content_type=content_type) 405 self.sendfile_filename = path_to_file 406 self.block_size = block_size 407 self['Content-Length'] = os.path.getsize(path_to_file) 408 self['Content-Disposition'] = ('attachment; filename=%s' % 409 os.path.basename(path_to_file)) 410 self[settings.HTTPRESPONSE_SENDFILE_HEADER] = path_to_file 411 396 412 class HttpResponseRedirect(HttpResponse): 397 413 status_code = 302 398 414 -
django/conf/global_settings.py
239 239 # Example: "http://media.lawrence.com" 240 240 MEDIA_URL = '' 241 241 242 # Header to use in HttpResponseSendFile to inform the handler to serve the 243 # file with efficient handler-specific routines. 244 HTTPRESPONSE_SENDFILE_HEADER = 'X-Sendfile' 245 242 246 # List of upload handler classes to be applied in order. 243 247 FILE_UPLOAD_HANDLERS = ( 244 248 'django.core.files.uploadhandler.MemoryFileUploadHandler', -
django/core/servers/basehttp.py
313 313 in the event loop to iterate over the data, and to call 314 314 'self.close()' once the response is finished. 315 315 """ 316 if not self.result_is_file() and not self.sendfile(): 317 for data in self.result: 318 self.write(data) 319 self.finish_content() 316 for data in self.result: 317 self.write(data) 318 self.finish_content() 320 319 self.close() 321 320 322 321 def get_scheme(self): -
django/core/handlers/wsgi.py
231 231 self.initLock.release() 232 232 233 233 set_script_prefix(base.get_script_name(environ)) 234 signals.request_started.send(sender=self.__class__)235 try:236 try:237 request = self.request_class(environ)238 except UnicodeDecodeError:239 response = http.HttpResponseBadRequest()240 else:241 response = self.get_response(request)242 234 243 # Apply response middleware 244 for middleware_method in self._response_middleware: 245 response = middleware_method(request, response) 246 response = self.apply_response_fixes(request, response) 247 finally: 248 signals.request_finished.send(sender=self.__class__) 235 response = self.process_request(environ) 249 236 250 237 try: 251 238 status_text = STATUS_CODE_TEXT[response.status_code] 252 239 except KeyError: 253 240 status_text = 'UNKNOWN STATUS CODE' 254 241 status = '%s %s' % (response.status_code, status_text) 242 255 243 response_headers = [(str(k), str(v)) for k, v in response.items()] 256 244 for c in response.cookies.values(): 257 245 response_headers.append(('Set-Cookie', str(c.output(header='')))) 246 258 247 start_response(status, response_headers) 248 249 if isinstance(response, http.HttpResponseSendFile): 250 filelike = open(response.sendfile_filename, 'rb') 251 if 'wsgi.file_wrapper' in environ: 252 return environ['wsgi.file_wrapper'](filelike, 253 response.block_size) 254 else: 255 # wraps close() as well 256 from django.core.servers.basehttp import FileWrapper 257 return FileWrapper(filelike, response.block_size) 258 259 259 return response 260 260 -
django/core/handlers/base.py
63 63 # as a flag for initialization being complete. 64 64 self._request_middleware = request_middleware 65 65 66 def process_request(self, request_env): 67 signals.request_started.send(sender=self.__class__) 68 try: 69 try: 70 request = self.request_class(request_env) 71 except UnicodeDecodeError: 72 response = http.HttpResponseBadRequest() 73 else: 74 response = self.get_response(request) 75 76 # Apply response middleware 77 if not isinstance(response, http.HttpResponseSendFile): 78 for middleware_method in self._response_middleware: 79 response = middleware_method(request, response) 80 response = self.apply_response_fixes(request, response) 81 finally: 82 signals.request_finished.send(sender=self.__class__) 83 84 return response 85 66 86 def get_response(self, request): 67 87 "Returns an HttpResponse object for the given HttpRequest" 68 88 from django.core import exceptions, urlresolvers -
django/core/handlers/modpython.py
2 2 from pprint import pformat 3 3 4 4 from django import http 5 from django.core import signals6 5 from django.core.handlers.base import BaseHandler 7 6 from django.core.urlresolvers import set_script_prefix 8 7 from django.utils import datastructures … … 191 190 self.load_middleware() 192 191 193 192 set_script_prefix(req.get_options().get('django.root', '')) 194 signals.request_started.send(sender=self.__class__)195 try:196 try:197 request = self.request_class(req)198 except UnicodeDecodeError:199 response = http.HttpResponseBadRequest()200 else:201 response = self.get_response(request)202 193 203 # Apply response middleware 204 for middleware_method in self._response_middleware: 205 response = middleware_method(request, response) 206 response = self.apply_response_fixes(request, response) 207 finally: 208 signals.request_finished.send(sender=self.__class__) 194 response = self.process_request(req) 209 195 210 196 # Convert our custom HttpResponse object back into the mod_python req. 211 197 req.content_type = response['Content-Type'] … … 215 201 for c in response.cookies.values(): 216 202 req.headers_out.add('Set-Cookie', c.output(header='')) 217 203 req.status = response.status_code 218 try:219 for chunk in response:220 req.write(chunk)221 finally:222 response.close()223 204 205 if isinstance(response, http.HttpResponseSendFile): 206 req.sendfile(response.sendfile_filename) 207 else: 208 try: 209 for chunk in response: 210 req.write(chunk) 211 finally: 212 response.close() 213 224 214 return 0 # mod_python.apache.OK 225 215 226 216 def handler(req): -
tests/regressiontests/sendfile/views.py
1 import urllib 2 3 from django.http import HttpResponseSendFile 4 5 def serve_file(request, filename): 6 filename = urllib.unquote(filename) 7 return HttpResponseSendFile(filename) -
tests/regressiontests/sendfile/tests.py
1 import urllib, os 2 3 from django.test import TestCase 4 from django.conf import settings 5 from django.core.files import temp as tempfile 6 7 FILE_SIZE = 2 ** 10 8 CONTENT = 'a' * FILE_SIZE 9 10 class SendFileTests(TestCase): 11 def test_sendfile(self): 12 tdir = tempfile.gettempdir() 13 14 file1 = tempfile.NamedTemporaryFile(suffix=".pdf", dir=tdir) 15 file1.write(CONTENT) 16 file1.seek(0) 17 18 response = self.client.get('/sendfile/serve_file/%s/' % 19 urllib.quote(file1.name)) 20 21 file1.close() 22 23 self.assertEqual(response.status_code, 200) 24 self.assertEqual(response[settings.HTTPRESPONSE_SENDFILE_HEADER], 25 file1.name) 26 self.assertEqual(response['Content-Disposition'], 27 'attachment; filename=%s' % os.path.basename(file1.name)) 28 self.assertEqual(response['Content-Length'], str(FILE_SIZE)) 29 self.assertEqual(response['Content-Type'], 'application/pdf') 30 31 # *if* the degraded case is to be supported, add this instead: 32 # self.assertEqual(response.content, CONTENT) 33 get_content = lambda: response.content 34 self.assertRaises(TypeError, get_content) 35 36 # TODO: test middleware bypass etc -
tests/regressiontests/sendfile/urls.py
1 from django.conf.urls.defaults import patterns 2 3 import views 4 5 urlpatterns = patterns('', 6 (r'^serve_file/(?P<filename>.*)/$', views.serve_file), 7 ) -
tests/urls.py
20 20 21 21 # test urlconf for middleware tests 22 22 (r'^middleware/', include('regressiontests.middleware.urls')), 23 23 24 24 # admin view tests 25 25 (r'^test_admin/', include('regressiontests.admin_views.urls')), 26 26 (r'^generic_inline_admin/', include('regressiontests.generic_inline_admin.urls')), 27 27 28 28 # admin widget tests 29 29 (r'widget_admin/', include('regressiontests.admin_widgets.urls')), 30 30 … … 32 32 33 33 # test urlconf for syndication tests 34 34 (r'^syndication/', include('regressiontests.syndication.urls')), 35 36 # HttpResponseSendfile tests 37 (r'^sendfile/', include('regressiontests.sendfile.urls')), 35 38 ) -
docs/ref/request-response.txt
538 538 HttpResponse subclasses 539 539 ----------------------- 540 540 541 Django includes a number of ``HttpResponse`` subclasses that handle different542 types of HTTP responses. Like ``HttpResponse``, these subclasses live in 543 :mod:`django.http`.541 Django includes a number of :class:`HttpResponse` subclasses that handle 542 different types of HTTP responses. Like :class:`HttpResponse`, these subclasses 543 live in :mod:`django.http`. 544 544 545 .. class:: HttpResponseSendFile 546 547 .. versionadded:: 1.1 548 549 A special response class for efficient file serving. It informs the HTTP 550 protocol handler to use platform-specific file serving mechanism (if 551 available). The constructor takes three arguments -- the file path and, 552 optionally, the file's content type and block size hint for handlers that 553 need it. 554 555 Note that response middleware will be bypassed if you use 556 :class:`HttpResponseSendFile`. 557 545 558 .. class:: HttpResponseRedirect 546 559 547 560 The constructor takes a single argument -- the path to redirect to. This