Anonymous avatar Anonymous committed 78ce29b

Fixed #1569 -- HttpResponse now accepts iterators. Thanks, Maniac

Comments (0)

Files changed (7)

     Eugene Lazutkin <http://lazutkin.com/blog/>
     limodou
     Martin Maney <http://www.chipy.org/Martin_Maney>
-    Maniac <http://www.softwaremaniacs.org/>
     Manuzhai
     Petar Marić
     mark@junklight.com
     J. Rademaker
     Brian Ray <http://brianray.chipy.org/>
     Oliver Rutherfurd <http://rutherfurd.net/>
+    Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
     David Schein
     sopel
     Radek Švarz <http://www.svarz.cz/translate/>

django/core/handlers/modpython.py

     for c in http_response.cookies.values():
         mod_python_req.headers_out.add('Set-Cookie', c.output(header=''))
     mod_python_req.status = http_response.status_code
-    mod_python_req.write(http_response.get_content_as_string(settings.DEFAULT_CHARSET))
+    for chunk in http_response.iterator:
+        mod_python_req.write(chunk)
 
 def handler(req):
     # mod_python hooks into this function.

django/core/handlers/wsgi.py

         response_headers = response.headers.items()
         for c in response.cookies.values():
             response_headers.append(('Set-Cookie', c.output(header='')))
-        output = [response.get_content_as_string(settings.DEFAULT_CHARSET)]
         start_response(status, response_headers)
-        return output
+        return response.iterator

django/middleware/common.py

 
         # Use ETags, if requested.
         if settings.USE_ETAGS:
-            etag = md5.new(response.get_content_as_string(settings.DEFAULT_CHARSET)).hexdigest()
+            etag = md5.new(response.content).hexdigest()
             if request.META.get('HTTP_IF_NONE_MATCH') == etag:
                 response = httpwrappers.HttpResponseNotModified()
             else:

django/utils/cache.py

         cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
     now = datetime.datetime.utcnow()
     if not response.has_header('ETag'):
-        response['ETag'] = md5.new(response.get_content_as_string('utf8')).hexdigest()
+        response['ETag'] = md5.new(response.content).hexdigest()
     if not response.has_header('Last-Modified'):
         response['Last-Modified'] = now.strftime('%a, %d %b %Y %H:%M:%S GMT')
     if not response.has_header('Expires'):

django/utils/httpwrappers.py

         cookiedict[key] = c.get(key).value
     return cookiedict
 
-class HttpResponse:
+class HttpResponse(object):
     "A basic HTTP response, with content and dictionary-accessed headers"
     def __init__(self, content='', mimetype=None):
+        from django.conf.settings import DEFAULT_CONTENT_TYPE, DEFAULT_CHARSET
+        self._charset = DEFAULT_CHARSET
         if not mimetype:
-            from django.conf.settings import DEFAULT_CONTENT_TYPE, DEFAULT_CHARSET
             mimetype = "%s; charset=%s" % (DEFAULT_CONTENT_TYPE, DEFAULT_CHARSET)
-        self.content = content
-        self.headers = {'Content-Type':mimetype}
+        if hasattr(content, '__iter__'):
+            self.iterator = content
+            self._is_string = False
+        else:
+            self.iterator = [content]
+            self._is_string = True
+        self.headers = {'Content-Type': mimetype}
         self.cookies = SimpleCookie()
         self.status_code = 200
 
         except KeyError:
             pass
 
-    def get_content_as_string(self, encoding):
-        """
-        Returns the content as a string, encoding it from a Unicode object if
-        necessary.
-        """
-        if isinstance(self.content, unicode):
-            return self.content.encode(encoding)
-        return self.content
+    def _get_content(self):
+        content = ''.join(self.iterator)
+        if isinstance(content, unicode):
+            content = content.encode(self._charset)
+        return content
+
+    def _set_content(self, value):
+        self.iterator = [value]
+        self._is_string = True
+
+    content = property(_get_content, _set_content)
 
     # The remaining methods partially implement the file-like object interface.
     # See http://docs.python.org/lib/bltin-file-objects.html
     def write(self, content):
-        self.content += content
+        if not self._is_string:
+            raise Exception, "This %s instance is not writable" % self.__class__
+        self.iterator.append(content)
 
     def flush(self):
         pass
 
     def tell(self):
-        return len(self.content)
+        if not self._is_string:
+            raise Exception, "This %s instance cannot tell its position" % self.__class__
+        return sum(len(chunk) for chunk in self.iterator)
 
 class HttpResponseRedirect(HttpResponse):
     def __init__(self, redirect_to):

docs/request_response.txt

     Instantiates an ``HttpResponse`` object with the given page content (a
     string) and MIME type. The ``DEFAULT_MIME_TYPE`` is ``"text/html"``.
 
+    **New in Django development version:** ``content`` can be an iterator
+    instead of a string. This iterator should return strings, and those strings
+    will be joined together to form the content of the response.
+
 ``__setitem__(header, value)``
     Sets the given header name to the given value. Both ``header`` and
     ``value`` should be strings.
 
 ``get_content_as_string(encoding)``
     Returns the content as a Python string, encoding it from a Unicode object
-    if necessary.
+    if necessary. **Removed in Django development version.**
+
+``content``
+    **New in Django development version.** Returns the content as a Python
+    string, encoding it from a Unicode object if necessary. Note this is a
+    property, not a method, so use ``r.content`` instead of ``r.content()``.
 
 ``write(content)``, ``flush()`` and ``tell()``
     These methods make an ``HttpResponse`` instance a file-like object.
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.