Commit acc5396e authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

Fixed #19519 -- Fired request_finished in the WSGI iterable's close().

parent a53c4740
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -253,8 +253,8 @@ class WSGIHandler(base.BaseHandler):
            response = http.HttpResponseBadRequest()
        else:
            response = self.get_response(request)
        finally:
            signals.request_finished.send(sender=self.__class__)

        response._handler_class = self.__class__

        try:
            status_text = STATUS_CODE_TEXT[response.status_code]
+9 −1
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ except ImportError:
    from urlparse import urlparse

from django.conf import settings
from django.core import signals
from django.core import signing
from django.core.exceptions import SuspiciousOperation
from django.http.cookie import SimpleCookie
@@ -40,6 +41,9 @@ class HttpResponseBase(six.Iterator):
        self._headers = {}
        self._charset = settings.DEFAULT_CHARSET
        self._closable_objects = []
        # This parameter is set by the handler. It's necessary to preserve the
        # historical behavior of request_finished.
        self._handler_class = None
        if mimetype:
            warnings.warn("Using mimetype keyword argument is deprecated, use"
                          " content_type instead",
@@ -226,7 +230,11 @@ class HttpResponseBase(six.Iterator):
    # See http://blog.dscpl.com.au/2012/10/obligations-for-calling-close-on.html
    def close(self):
        for closable in self._closable_objects:
            try:
                closable.close()
            except Exception:
                pass
        signals.request_finished.send(sender=self._handler_class)

    def write(self, content):
        raise Exception("This %s instance is not writable" % self.__class__.__name__)
+22 −13
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ from django.utils.http import urlencode
from django.utils.importlib import import_module
from django.utils.itercompat import is_iterable
from django.utils import six
from django.db import close_connection
from django.test.utils import ContextList

__all__ = ('Client', 'RequestFactory', 'encode_file', 'encode_multipart')
@@ -72,6 +71,14 @@ class FakePayload(object):
        self.__len += len(content)


def closing_iterator_wrapper(iterable, close):
    try:
        for item in iterable:
            yield item
    finally:
        close()


class ClientHandler(BaseHandler):
    """
    A HTTP Handler that can be used for testing purposes.
@@ -92,7 +99,6 @@ class ClientHandler(BaseHandler):
            self.load_middleware()

        signals.request_started.send(sender=self.__class__)
        try:
        request = WSGIRequest(environ)
        # sneaky little hack so that we can easily get round
        # CsrfViewMiddleware.  This makes life easier, and is probably
@@ -100,10 +106,13 @@ class ClientHandler(BaseHandler):
        # admin views.
        request._dont_enforce_csrf_checks = not self.enforce_csrf_checks
        response = self.get_response(request)
        finally:
            signals.request_finished.disconnect(close_connection)
            signals.request_finished.send(sender=self.__class__)
            signals.request_finished.connect(close_connection)
        # We're emulating a WSGI server; we must call the close method
        # on completion.
        if response.streaming:
            response.streaming_content = closing_iterator_wrapper(
                response.streaming_content, response.close)
        else:
            response.close()

        return response

+7 −1
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@ from xml.dom.minidom import parseString, Node

from django.conf import settings, UserSettingsHolder
from django.core import mail
from django.core.signals import request_finished
from django.db import close_connection
from django.test.signals import template_rendered, setting_changed
from django.template import Template, loader, TemplateDoesNotExist
from django.template.loaders import cached
@@ -68,8 +70,10 @@ def setup_test_environment():
    """Perform any global pre-test setup. This involves:

        - Installing the instrumented test renderer
        - Set the email backend to the locmem email backend.
        - Setting the email backend to the locmem email backend.
        - Setting the active locale to match the LANGUAGE_CODE setting.
        - Disconnecting the request_finished signal to avoid closing
          the database connection within tests.
    """
    Template.original_render = Template._render
    Template._render = instrumented_test_render
@@ -81,6 +85,8 @@ def setup_test_environment():

    deactivate()

    request_finished.disconnect(close_connection)


def teardown_test_environment():
    """Perform any global post-test teardown. This involves:
+2 −0
Original line number Diff line number Diff line
@@ -790,6 +790,8 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
    :class:`~django.template.response.SimpleTemplateResponse`, and the
    ``render`` method must itself return a valid response object.

.. _httpresponse-streaming:

StreamingHttpResponse objects
=============================

Loading