Skip to content

Commit

Permalink
Fixed #14588 -- Corrected r14393 to ensure that response middlewares …
Browse files Browse the repository at this point in the history
…are are always applied. Includes a battery of tests to validate the expected behavior of the middleware cycle. Thanks to Petr Marhoun for the report.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14398 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
freakboy3742 committed Oct 30, 2010
1 parent 20e09ca commit 52e0bcb
Show file tree
Hide file tree
Showing 5 changed files with 730 additions and 64 deletions.
83 changes: 46 additions & 37 deletions django/core/handlers/base.py
Expand Up @@ -78,39 +78,43 @@ def get_response(self, request):
urlconf = settings.ROOT_URLCONF
urlresolvers.set_urlconf(urlconf)
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
response = None

# Apply request middleware
for middleware_method in self._request_middleware:
response = middleware_method(request)
if response:
return response
break

if hasattr(request, "urlconf"):
# Reset url resolver with a custom urlconf.
urlconf = request.urlconf
urlresolvers.set_urlconf(urlconf)
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)

callback, callback_args, callback_kwargs = resolver.resolve(
request.path_info)

# Apply view middleware
for middleware_method in self._view_middleware:
response = middleware_method(request, callback, callback_args, callback_kwargs)
if response:
return response

try:
response = callback(request, *callback_args, **callback_kwargs)
except Exception, e:
# If the view raised an exception, run it through exception
# middleware, and if the exception middleware returns a
# response, use that. Otherwise, reraise the exception.
for middleware_method in self._exception_middleware:
response = middleware_method(request, e)
if response is None:
if hasattr(request, "urlconf"):
# Reset url resolver with a custom urlconf.
urlconf = request.urlconf
urlresolvers.set_urlconf(urlconf)
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)

callback, callback_args, callback_kwargs = resolver.resolve(
request.path_info)

# Apply view middleware
for middleware_method in self._view_middleware:
response = middleware_method(request, callback, callback_args, callback_kwargs)
if response:
return response
raise
break

if response is None:
try:
response = callback(request, *callback_args, **callback_kwargs)
except Exception, e:
# If the view raised an exception, run it through exception
# middleware, and if the exception middleware returns a
# response, use that. Otherwise, reraise the exception.
for middleware_method in self._exception_middleware:
response = middleware_method(request, e)
if response:
break
if response is None:
raise

# Complain if the view returned None (a common error).
if response is None:
Expand All @@ -120,12 +124,6 @@ def get_response(self, request):
view_name = callback.__class__.__name__ + '.__call__' # If it's a class
raise ValueError("The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name))

# Apply response middleware
for middleware_method in self._response_middleware:
response = middleware_method(request, response)
response = self.apply_response_fixes(request, response)

return response
except http.Http404, e:
logger.warning('Not Found: %s' % request.path,
extra={
Expand All @@ -134,14 +132,14 @@ def get_response(self, request):
})
if settings.DEBUG:
from django.views import debug
return debug.technical_404_response(request, e)
response = debug.technical_404_response(request, e)
else:
try:
callback, param_dict = resolver.resolve404()
return callback(request, **param_dict)
response = callback(request, **param_dict)
except:
try:
return self.handle_uncaught_exception(request, resolver, sys.exc_info())
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
finally:
receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
except exceptions.PermissionDenied:
Expand All @@ -150,19 +148,30 @@ def get_response(self, request):
'status_code': 403,
'request': request
})
return http.HttpResponseForbidden('<h1>Permission denied</h1>')
response = http.HttpResponseForbidden('<h1>Permission denied</h1>')
except SystemExit:
# Allow sys.exit() to actually exit. See tickets #1023 and #4701
raise
except: # Handle everything else, including SuspiciousOperation, etc.
# Get the exception info now, in case another exception is thrown later.
receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
return self.handle_uncaught_exception(request, resolver, sys.exc_info())
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
finally:
# Reset URLconf for this thread on the way out for complete
# isolation of request.urlconf
urlresolvers.set_urlconf(None)

try:
# Apply response middleware, regardless of the response
for middleware_method in self._response_middleware:
response = middleware_method(request, response)
response = self.apply_response_fixes(request, response)
except: # Any exception should be gathered and handled
receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())

return response

def handle_uncaught_exception(self, request, resolver, exc_info):
"""
Processing for any otherwise uncaught exceptions (those that will
Expand Down
5 changes: 0 additions & 5 deletions django/test/client.py
Expand Up @@ -81,11 +81,6 @@ def __call__(self, environ):
# admin views.
request._dont_enforce_csrf_checks = not self.enforce_csrf_checks
response = self.get_response(request)

# Apply response middleware.
for middleware_method in self._response_middleware:
response = middleware_method(request, response)
response = self.apply_response_fixes(request, response)
finally:
signals.request_finished.disconnect(close_connection)
signals.request_finished.send(sender=self.__class__)
Expand Down

0 comments on commit 52e0bcb

Please sign in to comment.