Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #19321 -- Allowed redirect middleware HTTP responses to be over…

…ridden.

Thanks Melevir for the suggestion.
  • Loading branch information...
commit 8b0014869f666b44cd20692e38073ec0a0a8cb08 1 parent 36e220f
Ryan Kaskel authored May 20, 2013 timgraham committed October 04, 2013
12  django/contrib/redirects/middleware.py
@@ -8,6 +8,11 @@
8 8
 
9 9
 
10 10
 class RedirectFallbackMiddleware(object):
  11
+
  12
+    # Defined as class-level attributes to be subclassing-friendly.
  13
+    response_gone_class = http.HttpResponseGone
  14
+    response_redirect_class = http.HttpResponsePermanentRedirect
  15
+
11 16
     def __init__(self):
12 17
         if 'django.contrib.sites' not in settings.INSTALLED_APPS:
13 18
             raise ImproperlyConfigured(
@@ -16,8 +21,9 @@ def __init__(self):
16 21
             )
17 22
 
18 23
     def process_response(self, request, response):
  24
+        # No need to check for a redirect for non-404 responses.
19 25
         if response.status_code != 404:
20  
-            return response # No need to check for a redirect for non-404 responses.
  26
+            return response
21 27
 
22 28
         full_path = request.get_full_path()
23 29
         current_site = get_current_site(request)
@@ -37,8 +43,8 @@ def process_response(self, request, response):
37 43
                 pass
38 44
         if r is not None:
39 45
             if r.new_path == '':
40  
-                return http.HttpResponseGone()
41  
-            return http.HttpResponsePermanentRedirect(r.new_path)
  46
+                return self.response_gone_class()
  47
+            return self.response_redirect_class(r.new_path)
42 48
 
43 49
         # No redirect was found. Return the response.
44 50
         return response
30  django/contrib/redirects/tests.py
... ...
@@ -1,3 +1,4 @@
  1
+from django import http
1 2
 from django.conf import settings
2 3
 from django.contrib.sites.models import Site
3 4
 from django.core.exceptions import ImproperlyConfigured
@@ -61,3 +62,32 @@ def test_response_gone(self):
61 62
     def test_sites_not_installed(self):
62 63
         with self.assertRaises(ImproperlyConfigured):
63 64
             RedirectFallbackMiddleware()
  65
+
  66
+
  67
+class OverriddenRedirectFallbackMiddleware(RedirectFallbackMiddleware):
  68
+    # Use HTTP responses different from the defaults
  69
+    response_gone_class = http.HttpResponseForbidden
  70
+    response_redirect_class = http.HttpResponseRedirect
  71
+
  72
+
  73
+@override_settings(
  74
+    MIDDLEWARE_CLASSES=list(settings.MIDDLEWARE_CLASSES) +
  75
+        ['django.contrib.redirects.tests.OverriddenRedirectFallbackMiddleware'],
  76
+    SITE_ID=1,
  77
+)
  78
+class OverriddenRedirectMiddlewareTests(TestCase):
  79
+
  80
+    def setUp(self):
  81
+        self.site = Site.objects.get(pk=settings.SITE_ID)
  82
+
  83
+    def test_response_gone_class(self):
  84
+        Redirect.objects.create(
  85
+            site=self.site, old_path='/initial/', new_path='')
  86
+        response = self.client.get('/initial/')
  87
+        self.assertEqual(response.status_code, 403)
  88
+
  89
+    def test_response_redirect_class(self):
  90
+        Redirect.objects.create(
  91
+            site=self.site, old_path='/initial/', new_path='/new_target/')
  92
+        response = self.client.get('/initial/')
  93
+        self.assertEqual(response.status_code, 302)
39  docs/ref/contrib/redirects.txt
@@ -26,10 +26,11 @@ How it works
26 26
 ``manage.py migrate`` creates a ``django_redirect`` table in your database. This
27 27
 is a simple lookup table with ``site_id``, ``old_path`` and ``new_path`` fields.
28 28
 
29  
-The ``RedirectFallbackMiddleware`` does all of the work. Each time any Django
30  
-application raises a 404 error, this middleware checks the redirects database
31  
-for the requested URL as a last resort. Specifically, it checks for a redirect
32  
-with the given ``old_path`` with a site ID that corresponds to the
  29
+The :class:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware`
  30
+does all of the work. Each time any Django application raises a 404
  31
+error, this middleware checks the redirects database for the requested
  32
+URL as a last resort. Specifically, it checks for a redirect with the
  33
+given ``old_path`` with a site ID that corresponds to the
33 34
 :setting:`SITE_ID` setting.
34 35
 
35 36
 * If it finds a match, and ``new_path`` is not empty, it redirects to
@@ -43,8 +44,8 @@ The middleware only gets activated for 404s -- not for 500s or responses of any
43 44
 other status code.
44 45
 
45 46
 Note that the order of :setting:`MIDDLEWARE_CLASSES` matters. Generally, you
46  
-can put ``RedirectFallbackMiddleware`` at the end of the list, because it's a
47  
-last resort.
  47
+can put :class:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware`
  48
+at the end of the list, because it's a last resort.
48 49
 
49 50
 For more on middleware, read the :doc:`middleware docs
50 51
 </topics/http/middleware>`.
@@ -69,3 +70,29 @@ Via the Python API
69 70
     objects via the :doc:`Django database API </topics/db/queries>`.
70 71
 
71 72
 .. _django/contrib/redirects/models.py: https://github.com/django/django/blob/master/django/contrib/redirects/models.py
  73
+
  74
+Middleware
  75
+==========
  76
+
  77
+.. class:: middleware.RedirectFallbackMiddleware
  78
+
  79
+    You can change the :class:`~django.http.HttpResponse` classes used
  80
+    by the middleware by creating a subclass of
  81
+    :class:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware`
  82
+    and overriding ``response_gone_class`` and/or ``response_redirect_class``.
  83
+
  84
+    .. attribute:: response_gone_class
  85
+
  86
+        The :class:`~django.http.HttpResponse` class used when a
  87
+        :class:`~django.contrib.redirects.models.Redirect` is not
  88
+        found for the requested path or has a blank ``new_path``
  89
+        value.
  90
+
  91
+        Defaults to :class:`~django.http.HttpResponseGone`.
  92
+
  93
+    .. attribute:: response_redirect_class
  94
+
  95
+        The :class:`~django.http.HttpResponse` class that handles the
  96
+        redirect.
  97
+
  98
+        Defaults to :class:`~django.http.HttpResponsePermanentRedirect`.
11  docs/releases/1.7.txt
@@ -193,6 +193,17 @@ Minor features
193 193
   follow the :setting:`SESSION_COOKIE_SECURE` and
194 194
   :setting:`SESSION_COOKIE_HTTPONLY` settings.
195 195
 
  196
+:mod:`django.contrib.redirects`
  197
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  198
+
  199
+* :class:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware`
  200
+  has two new attributes
  201
+  (:attr:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware.response_gone_class`
  202
+  and
  203
+  :attr:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware.response_redirect_class`)
  204
+  that specify the types of :class:`~django.http.HttpResponse` instances the
  205
+  middleware returns.
  206
+
196 207
 :mod:`django.contrib.sessions`
197 208
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
198 209
 

0 notes on commit 8b00148

Please sign in to comment.
Something went wrong with that request. Please try again.