Ticket #7581: streaming_response.diff

File streaming_response.diff, 6.8 KB (added by Tai Lee, 16 years ago)

add HttpResponse.content_generator, consume generators only once, set Content-Length in WSGIHander.

  • django/http/__init__.py

     
    268268        if not content_type:
    269269            content_type = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE,
    270270                    settings.DEFAULT_CHARSET)
    271         if not isinstance(content, basestring) and hasattr(content, '__iter__'):
    272             self._container = content
    273             self._is_string = False
    274         else:
    275             self._container = [content]
    276             self._is_string = True
     271        self.content = content
    277272        self.cookies = SimpleCookie()
    278273        if status:
    279274            self.status_code = status
     
    345340                        expires='Thu, 01-Jan-1970 00:00:00 GMT')
    346341
    347342    def _get_content(self):
     343        if not self._is_string:
     344            self._container = [''.join(self._container)]
     345            self._is_string = True
    348346        if self.has_header('Content-Encoding'):
    349347            return ''.join(self._container)
    350348        return smart_str(''.join(self._container), self._charset)
    351349
    352350    def _set_content(self, value):
    353         self._container = [value]
    354         self._is_string = True
     351        if not isinstance(value, basestring) and hasattr(value, '__iter__'):
     352            self._container = value
     353            self._is_string = False
     354        else:
     355            self._container = [value]
     356            self._is_string = True
    355357
    356358    content = property(_get_content, _set_content)
    357359
     360    def _get_content_generator(self):
     361        if not self._is_string:
     362            return self._container
     363
     364    content_generator = property(_get_content_generator)
     365
    358366    def __iter__(self):
    359367        self._iterator = iter(self._container)
    360368        return self
  • django/http/utils.py

     
    3131    if request.method == 'HEAD':
    3232        response.content = ''
    3333    return response
     34
     35def set_content_length(request, response):
     36    """
     37    Ensures that we always have a Content-Length header, required by some
     38    handlers (WSGI), which don't permit chunked transfer encoding.
     39    """
     40    if not 'Content-Length' in response:
     41        response['Content-Length'] = str(len(response.content))
     42    return response
  • django/core/handlers/wsgi.py

     
    182182class WSGIHandler(BaseHandler):
    183183    initLock = Lock()
    184184    request_class = WSGIRequest
     185    response_fixes = [http.fix_location_header,
     186                      http.conditional_content_removal,
     187                      http.set_content_length]
    185188
    186189    def __call__(self, environ, start_response):
    187190        from django.conf import settings
  • django/utils/text.py

     
    175175    zfile.close()
    176176    return zbuf.getvalue()
    177177
     178def compress_sequence(sequence):
     179    import cStringIO, gzip
     180    zbuf = cStringIO.StringIO()
     181    zfile = gzip.GzipFile(mode='wb', compresslevel=6, fileobj=zbuf)
     182    yield zbuf.getvalue()
     183    for item in sequence:
     184        position = zbuf.tell()
     185        zfile.write(item)
     186        zfile.flush()
     187        zbuf.seek(position)
     188        yield zbuf.read()
     189
    178190ustring_re = re.compile(u"([\u0080-\uffff])")
    179191
    180192def javascript_quote(s, quote_double_quotes=False):
  • django/middleware/common.py

     
    107107        if settings.USE_ETAGS:
    108108            if response.has_header('ETag'):
    109109                etag = response['ETag']
    110             else:
     110            elif not response.content_generator:
    111111                etag = '"%s"' % md5.new(response.content).hexdigest()
    112             if response.status_code >= 200 and response.status_code < 300 and request.META.get('HTTP_IF_NONE_MATCH') == etag:
    113                 cookies = response.cookies
    114                 response = http.HttpResponseNotModified()
    115                 response.cookies = cookies
    116             else:
    117                 response['ETag'] = etag
     112            try:
     113                if response.status_code >= 200 and response.status_code < 300 and request.META.get('HTTP_IF_NONE_MATCH') == etag:
     114                    cookies = response.cookies
     115                    response = http.HttpResponseNotModified()
     116                    response.cookies = cookies
     117                else:
     118                    response['ETag'] = etag
     119            except NameError:
     120                pass
    118121
    119122        return response
    120123
  • 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',))
     
    3333        if not re_accepts_gzip.search(ae):
    3434            return response
    3535
    36         response.content = compress_string(response.content)
     36        if response.content_generator:
     37            response.content = compress_sequence(response.content_generator)
     38            del response['Content-Length']
     39        else:
     40            response.content = compress_string(response.content)
     41            response['Content-Length'] = str(len(response.content))
    3742        response['Content-Encoding'] = 'gzip'
    38         response['Content-Length'] = str(len(response.content))
    3943        return response
  • django/middleware/http.py

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