mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
[1.5.x] Fixed #19519 -- Fired request_finished in the WSGI iterable's close().
Backport of acc5396.
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -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", PendingDeprecationWarning)
|
||||
@@ -225,7 +229,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:
|
||||
closable.close()
|
||||
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__)
|
||||
|
||||
@@ -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,18 +99,20 @@ 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
|
||||
# required for backwards compatibility with external tests against
|
||||
# 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)
|
||||
request = WSGIRequest(environ)
|
||||
# sneaky little hack so that we can easily get round
|
||||
# CsrfViewMiddleware. This makes life easier, and is probably
|
||||
# required for backwards compatibility with external tests against
|
||||
# admin views.
|
||||
request._dont_enforce_csrf_checks = not self.enforce_csrf_checks
|
||||
response = self.get_response(request)
|
||||
# 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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user