Ticket #7581: 7581-Streaming-HttpResponse-1.3.1.diff

File 7581-Streaming-HttpResponse-1.3.1.diff, 6.6 KB (added by Chris Ghormley <chris@…>, 12 years ago)

Patch for Django 1.3.1 (uses md5_constructor instead of hashlib.md5)

  • django/http/__init__.py

     
    485485    status_code = 200
    486486
    487487    def __init__(self, content='', mimetype=None, status=None,
    488             content_type=None):
     488            content_type=None, stream_content=False):
    489489        # _headers is a mapping of the lower-case name to the original case of
    490490        # the header (required for working with legacy systems) and the header
    491491        # value.  Both the name of the header and its value are ASCII strings.
     
    496496        if not content_type:
    497497            content_type = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE,
    498498                    self._charset)
    499         if not isinstance(content, basestring) and hasattr(content, '__iter__'):
    500             self._container = content
    501             self._is_string = False
    502         else:
    503             self._container = [content]
    504             self._is_string = True
     499        self._stream_content = stream_content
     500        self.content = content
    505501        self.cookies = SimpleCookie()
    506502        if status:
    507503            self.status_code = status
     
    595591        self.set_cookie(key, max_age=0, path=path, domain=domain,
    596592                        expires='Thu, 01-Jan-1970 00:00:00 GMT')
    597593
     594    def _consume_content(self):
     595        if not self._is_string:
     596            self._container = [''.join(self._container)]
     597            self._is_string = True
     598
    598599    def _get_content(self):
     600        self._consume_content()
    599601        if self.has_header('Content-Encoding'):
    600602            return ''.join(self._container)
    601603        return smart_str(''.join(self._container), self._charset)
    602604
    603605    def _set_content(self, value):
    604         self._container = [value]
    605         self._is_string = True
     606        if not isinstance(value, basestring) and hasattr(value, '__iter__'):
     607            self._container = value
     608            self._is_string = False
     609            if not self._stream_content:
     610                self._consume_content()
     611        else:
     612            self._container = [value]
     613            self._is_string = True
    606614
    607615    content = property(_get_content, _set_content)
    608616
     617    def _get_content_generator(self):
     618        if not self._is_string:
     619            return (smart_str(item, self._charset) for item in self._container)
     620
     621    content_generator = property(_get_content_generator)
     622
    609623    def __iter__(self):
    610624        self._iterator = iter(self._container)
    611625        return self
  • django/utils/text.py

     
    187187    zfile.close()
    188188    return zbuf.getvalue()
    189189
     190# WARNING - be aware that compress_sequence does not achieve the same
     191# level of compression as compress_string
     192def compress_sequence(sequence):
     193    import cStringIO, gzip
     194    zbuf = cStringIO.StringIO()
     195    zfile = gzip.GzipFile(mode='wb', compresslevel=6, fileobj=zbuf)
     196    yield zbuf.getvalue()
     197    for item in sequence:
     198        position = zbuf.tell()
     199        zfile.write(item)
     200        zfile.flush()
     201        zbuf.seek(position)
     202        yield zbuf.read()
     203    position = zbuf.tell()
     204    zfile.close()
     205    zbuf.seek(position)
     206    yield zbuf.read()
     207
    190208ustring_re = re.compile(u"([\u0080-\uffff])")
    191209
    192210def javascript_quote(s, quote_double_quotes=False):
  • django/middleware/common.py

     
    112112        if settings.USE_ETAGS:
    113113            if response.has_header('ETag'):
    114114                etag = response['ETag']
    115             else:
     115            elif not response.content_generator:
    116116                etag = '"%s"' % md5_constructor(response.content).hexdigest()
    117             if response.status_code >= 200 and response.status_code < 300 and request.META.get('HTTP_IF_NONE_MATCH') == etag:
    118                 cookies = response.cookies
    119                 response = http.HttpResponseNotModified()
    120                 response.cookies = cookies
    121             else:
    122                 response['ETag'] = etag
    123117
     118            try:
     119                if response.status_code >= 200 and response.status_code < 300 and request.META.get('HTTP_IF_NONE_MATCH') == etag:
     120                    cookies = response.cookies
     121                    response = http.HttpResponseNotModified()
     122                    response.cookies = cookies
     123                else:
     124                    response['ETag'] = etag
     125            except NameError:
     126                pass
     127
    124128        return response
    125129
    126130def _is_ignorable_404(uri):
  • django/middleware/gzip.py

     
    11import re
    22
    3 from django.utils.text import compress_string
     3from django.utils.text import compress_sequence, compress_string
    44from django.utils.cache import patch_vary_headers
    55
    66re_accepts_gzip = re.compile(r'\bgzip\b')
     
    1313    """
    1414    def process_response(self, request, response):
    1515        # It's not worth compressing non-OK or really short responses.
    16         if response.status_code != 200 or len(response.content) < 200:
     16        if response.status_code != 200 or (not response.content_generator and len(response.content) < 200):
    1717            return response
    1818
    1919        patch_vary_headers(response, ('Accept-Encoding',))
     
    3232        if not re_accepts_gzip.search(ae):
    3333            return response
    3434
    35         response.content = compress_string(response.content)
     35        if response.content_generator:
     36            response.content = compress_sequence(response.content_generator)
     37            del response['Content-Length']
     38        else:
     39            response.content = compress_string(response.content)
     40            response['Content-Length'] = str(len(response.content))
    3641        response['Content-Encoding'] = 'gzip'
    37         response['Content-Length'] = str(len(response.content))
    3842        return response
  • django/middleware/http.py

     
    1111    """
    1212    def process_response(self, request, response):
    1313        response['Date'] = http_date()
    14         if not response.has_header('Content-Length'):
     14        if not response.has_header('Content-Length') and not response.content_generator:
    1515            response['Content-Length'] = str(len(response.content))
    1616
    1717        if response.has_header('ETag'):
Back to Top