From c3d7aad6d0911bb84120d7c8d41923c895784b21 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Fri, 22 Sep 2006 12:32:00 +0000 Subject: [PATCH] Fixed #2560 -- Add close() support to HttpResponse iterators. Thanks, Ivan Sagalaev. git-svn-id: http://code.djangoproject.com/svn/django/trunk@3791 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/core/handlers/modpython.py | 7 +++++-- django/core/handlers/wsgi.py | 2 +- django/http/__init__.py | 31 ++++++++++++++++++------------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/django/core/handlers/modpython.py b/django/core/handlers/modpython.py index 07c98e3b59..db3c33147b 100644 --- a/django/core/handlers/modpython.py +++ b/django/core/handlers/modpython.py @@ -155,8 +155,11 @@ def populate_apache_request(http_response, mod_python_req): 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 - for chunk in http_response.iterator: - mod_python_req.write(chunk) + try: + for chunk in http_response: + mod_python_req.write(chunk) + finally: + http_response.close() def handler(req): # mod_python hooks into this function. diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py index 5c48c9dace..bf9df57cd6 100644 --- a/django/core/handlers/wsgi.py +++ b/django/core/handlers/wsgi.py @@ -163,4 +163,4 @@ class WSGIHandler(BaseHandler): for c in response.cookies.values(): response_headers.append(('Set-Cookie', c.output(header=''))) start_response(status, response_headers) - return response.iterator + return response diff --git a/django/http/__init__.py b/django/http/__init__.py index c4ac302ec5..bb0e973aae 100644 --- a/django/http/__init__.py +++ b/django/http/__init__.py @@ -161,10 +161,10 @@ class HttpResponse(object): if not mimetype: mimetype = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE, settings.DEFAULT_CHARSET) if hasattr(content, '__iter__'): - self._iterator = content + self._container = content self._is_string = False else: - self._iterator = [content] + self._container = [content] self._is_string = True self.headers = {'Content-Type': mimetype} self.cookies = SimpleCookie() @@ -213,32 +213,37 @@ class HttpResponse(object): self.cookies[key]['max-age'] = 0 def _get_content(self): - content = ''.join(self._iterator) + content = ''.join(self._container) if isinstance(content, unicode): content = content.encode(self._charset) return content def _set_content(self, value): - self._iterator = [value] + self._container = [value] self._is_string = True content = property(_get_content, _set_content) - def _get_iterator(self): - "Output iterator. Converts data into client charset if necessary." - for chunk in self._iterator: - if isinstance(chunk, unicode): - chunk = chunk.encode(self._charset) - yield chunk + def __iter__(self): + self._iterator = self._container.__iter__() + return self - iterator = property(_get_iterator) + def next(self): + chunk = self._iterator.next() + if isinstance(chunk, unicode): + chunk = chunk.encode(self._charset) + return chunk + + def close(self): + if hasattr(self._container, 'close'): + self._container.close() # The remaining methods partially implement the file-like object interface. # See http://docs.python.org/lib/bltin-file-objects.html def write(self, content): if not self._is_string: raise Exception, "This %s instance is not writable" % self.__class__ - self._iterator.append(content) + self._container.append(content) def flush(self): pass @@ -246,7 +251,7 @@ class HttpResponse(object): def tell(self): 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]) + return sum([len(chunk) for chunk in self._container]) class HttpResponseRedirect(HttpResponse): def __init__(self, redirect_to):