Commit 52e0bcbc authored by Russell Keith-Magee's avatar Russell Keith-Magee
Browse files

Fixed #14588 -- Corrected r14393 to ensure that response middlewares are are...

Fixed #14588 -- Corrected r14393 to ensure that response middlewares 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
parent 20e09ca8
Loading
Loading
Loading
Loading
+46 −37
Original line number Diff line number Diff line
@@ -78,13 +78,15 @@ class BaseHandler(object):
                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 response is None:
                    if hasattr(request, "urlconf"):
                        # Reset url resolver with a custom urlconf.
                        urlconf = request.urlconf
@@ -98,8 +100,9 @@ class BaseHandler(object):
                    for middleware_method in self._view_middleware:
                        response = middleware_method(request, callback, callback_args, callback_kwargs)
                        if response:
                        return response
                            break

                if response is None:
                    try:
                        response = callback(request, *callback_args, **callback_kwargs)
                    except Exception, e:
@@ -109,7 +112,8 @@ class BaseHandler(object):
                        for middleware_method in self._exception_middleware:
                            response = middleware_method(request, e)
                            if response:
                            return response
                                break
                        if response is None:
                            raise

                # Complain if the view returned None (a common error).
@@ -120,12 +124,6 @@ class BaseHandler(object):
                        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={
@@ -134,14 +132,14 @@ class BaseHandler(object):
                            })
                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:
@@ -150,19 +148,30 @@ class BaseHandler(object):
                                '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
+0 −5
Original line number Diff line number Diff line
@@ -81,11 +81,6 @@ class ClientHandler(BaseHandler):
            # 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__)
+664 −19

File changed.

Preview size limit exceeded, changes collapsed.

+5 −1
Original line number Diff line number Diff line
@@ -4,5 +4,9 @@ from django.conf.urls.defaults import *
import views

urlpatterns = patterns('',
    (r'^$', views.index),
    (r'^view/$', views.normal_view),
    (r'^not_found/$', views.not_found),
    (r'^error/$', views.server_error),
    (r'^null_view/$', views.null_view),
    (r'^permission_denied/$', views.permission_denied),
)
+15 −2
Original line number Diff line number Diff line
from django import http
from django.core.exceptions import PermissionDenied

def index(request):
    return http.HttpResponse('')
def normal_view(request):
    return http.HttpResponse('OK')

def not_found(request):
    raise http.Http404()

def server_error(request):
    raise Exception('Error in view')

def null_view(request):
    return None

def permission_denied(request):
    raise PermissionDenied()