Commit 24234555 authored by Jannis Leidel's avatar Jannis Leidel
Browse files

Merge pull request #885 from loic/ticket19541

Fixed #19541 -- Fixed BaseHandler to enable reversing URLs in response middlewares...
parents 0e0eb8a9 521765f6
Loading
Loading
Loading
Loading
+94 −95
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ class BaseHandler(object):

    def get_response(self, request):
        "Returns an HttpResponse object for the given HttpRequest"
        try:

        # Setup default url resolver for this thread, this code is outside
        # the try/except so we don't get a spurious "unbound local
        # variable" exception in the event an exception is raised before
@@ -152,6 +152,7 @@ class BaseHandler(object):
                except:
                    signals.got_request_exception.send(sender=self.__class__, request=request)
                    response = self.handle_uncaught_exception(request, resolver, sys.exc_info())

        except PermissionDenied:
            logger.warning(
                'Forbidden (Permission denied): %s', request.path,
@@ -167,17 +168,15 @@ class BaseHandler(object):
                        sender=self.__class__, request=request)
                response = self.handle_uncaught_exception(request,
                        resolver, sys.exc_info())

        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.
            signals.got_request_exception.send(sender=self.__class__, request=request)
            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
+3 −1
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ from django.core.management import call_command
from django.core.management.color import no_style
from django.core.servers.basehttp import (WSGIRequestHandler, WSGIServer,
    WSGIServerException)
from django.core.urlresolvers import clear_url_caches
from django.core.urlresolvers import clear_url_caches, set_urlconf
from django.db import connection, connections, DEFAULT_DB_ALIAS, transaction
from django.forms.fields import CharField
from django.http import QueryDict
@@ -497,6 +497,7 @@ class TransactionTestCase(SimpleTestCase):
                             **{'verbosity': 0, 'database': db_name, 'skip_validation': True})

    def _urlconf_setup(self):
        set_urlconf(None)
        if hasattr(self, 'urls'):
            self._old_root_urlconf = settings.ROOT_URLCONF
            settings.ROOT_URLCONF = self.urls
@@ -527,6 +528,7 @@ class TransactionTestCase(SimpleTestCase):
                         skip_validation=True, reset_sequences=False)

    def _urlconf_teardown(self):
        set_urlconf(None)
        if hasattr(self, '_old_root_urlconf'):
            settings.ROOT_URLCONF = self._old_root_urlconf
            clear_url_caches()
+23 −0
Original line number Diff line number Diff line
from __future__ import absolute_import

from django.core.urlresolvers import reverse
from django.http import HttpResponse, StreamingHttpResponse

from . import urlconf_inner


@@ -10,3 +13,23 @@ class ChangeURLconfMiddleware(object):
class NullChangeURLconfMiddleware(object):
    def process_request(self, request):
        request.urlconf = None

class ReverseInnerInResponseMiddleware(object):
    def process_response(self, *args, **kwargs):
        return HttpResponse(reverse('inner'))

class ReverseOuterInResponseMiddleware(object):
    def process_response(self, *args, **kwargs):
        return HttpResponse(reverse('outer'))

class ReverseInnerInStreaming(object):
    def process_view(self, *args, **kwargs):
        def stream():
            yield reverse('inner')
        return StreamingHttpResponse(stream())

class ReverseOuterInStreaming(object):
    def process_view(self, *args, **kwargs):
        def stream():
            yield reverse('outer')
        return StreamingHttpResponse(stream())
+53 −0
Original line number Diff line number Diff line
@@ -462,6 +462,59 @@ class RequestURLconfTests(TestCase):
        )
        self.assertRaises(ImproperlyConfigured, self.client.get, '/test/me/')

    def test_reverse_inner_in_response_middleware(self):
        """
        Test reversing an URL from the *overridden* URLconf from inside
        a response middleware.
        """
        settings.MIDDLEWARE_CLASSES += (
            '%s.ChangeURLconfMiddleware' % middleware.__name__,
            '%s.ReverseInnerInResponseMiddleware' % middleware.__name__,
        )
        response = self.client.get('/second_test/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, b'/second_test/')

    def test_reverse_outer_in_response_middleware(self):
        """
        Test reversing an URL from the *default* URLconf from inside
        a response middleware.
        """
        settings.MIDDLEWARE_CLASSES += (
            '%s.ChangeURLconfMiddleware' % middleware.__name__,
            '%s.ReverseOuterInResponseMiddleware' % middleware.__name__,
        )
        message = "Reverse for 'outer' with arguments '()' and keyword arguments '{}' not found."
        with self.assertRaisesMessage(NoReverseMatch, message):
            self.client.get('/second_test/')

    def test_reverse_inner_in_streaming(self):
        """
        Test reversing an URL from the *overridden* URLconf from inside
        a streaming response.
        """
        settings.MIDDLEWARE_CLASSES += (
            '%s.ChangeURLconfMiddleware' % middleware.__name__,
            '%s.ReverseInnerInStreaming' % middleware.__name__,
        )
        response = self.client.get('/second_test/')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(b''.join(response), b'/second_test/')

    def test_reverse_outer_in_streaming(self):
        """
        Test reversing an URL from the *default* URLconf from inside
        a streaming response.
        """
        settings.MIDDLEWARE_CLASSES += (
            '%s.ChangeURLconfMiddleware' % middleware.__name__,
            '%s.ReverseOuterInStreaming' % middleware.__name__,
        )
        message = "Reverse for 'outer' with arguments '()' and keyword arguments '{}' not found."
        with self.assertRaisesMessage(NoReverseMatch, message):
            self.client.get('/second_test/')
            b''.join(self.client.get('/second_test/'))

class ErrorHandlerResolutionTests(TestCase):
    """Tests for handler404 and handler500"""