Anonymous committed 294bd99

[soc2009/http-wsgi-improvements] HttpResponseSendFile now uses django.core.servers.basehttp.FileWrapper inside __iter__ to provide fallback.

regressiontests.sendfile uses this now, and passes. The fallback was tested
using guppy and apache2 with mod_wsgi for heap issues, and it appears to be
fine. We can go back and look at this again if it becomes an issue.

Comments (0)

Files changed (2)


         return sum([len(chunk) for chunk in self._container])
 class HttpResponseSendFile(HttpResponse): 
+    sendfile_fh = None
     def __init__(self, path_to_file, content_type=None, block_size=8192): 
  	    if not content_type: 
  	        from mimetypes import guess_type 
  	    self[settings.HTTPRESPONSE_SENDFILE_HEADER] = path_to_file 
-    def _get_content(self):
-        return open(self.sendfile_filename).read()
+    def __iter__(self):
+        from django.core.servers.basehttp import FileWrapper
+        return FileWrapper(self.get_file_handler(), self.block_size)
-    content = property(_get_content)
+    def get_file_handler(self):
+        if not self.sendfile_fh:
+            self.sendfile_fh = open(self.sendfile_filename, 'rb')
+        return self.sendfile_fh
 class HttpResponseRedirect(HttpResponse):
     _status_code = 302


         self.assertEqual(response['Content-Length'], str(FILE_SIZE))
         self.assertEqual(response['Content-Type'], 'application/pdf')
-        # *if* the degraded case is to be supported, add this instead:
-        self.assertEqual(response.content, CONTENT)
+        # Test the fallback file transfer -- we use FileWrapper to iterate through
+        # the file, this also wraps close(). This appears to mitigate performance
+        # issues.
+        self.assertEqual("".join(iter(response)), CONTENT)
         get_content = lambda:
-        #self.assertRaises(TypeError, get_content)
         # TODO: test middleware bypass etc