Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #17734 -- Made sure to only redirect translated URLs if they ca…

…n actually be resolved to prevent unwanted redirects. Many thanks to Orne Brocaar and Anssi Kääriäinen for input.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17621 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 746987f916bfb24a0671429d9993ad727dc7c8bc 1 parent a255d39
Jannis Leidel authored
14  django/core/urlresolvers.py
@@ -518,3 +518,17 @@ def get_urlconf(default=None):
518 518
     changed from the default one.
519 519
     """
520 520
     return getattr(_urlconfs, "value", default)
  521
+
  522
+def is_valid_path(path, urlconf=None):
  523
+    """
  524
+    Returns True if the given path resolves against the default URL resolver,
  525
+    False otherwise.
  526
+
  527
+    This is a convenience method to make working with "is this a match?" cases
  528
+    easier, avoiding unnecessarily indented try...except blocks.
  529
+    """
  530
+    try:
  531
+        resolve(path, urlconf)
  532
+        return True
  533
+    except Resolver404:
  534
+        return False
19  django/middleware/common.py
@@ -64,8 +64,8 @@ def process_request(self, request):
64 64
         # trailing slash and there is no pattern for the current path
65 65
         if settings.APPEND_SLASH and (not old_url[1].endswith('/')):
66 66
             urlconf = getattr(request, 'urlconf', None)
67  
-            if (not _is_valid_path(request.path_info, urlconf) and
68  
-                    _is_valid_path("%s/" % request.path_info, urlconf)):
  67
+            if (not urlresolvers.is_valid_path(request.path_info, urlconf) and
  68
+                    urlresolvers.is_valid_path("%s/" % request.path_info, urlconf)):
69 69
                 new_url[1] = new_url[1] + '/'
70 70
                 if settings.DEBUG and request.method == 'POST':
71 71
                     raise RuntimeError((""
@@ -151,18 +151,3 @@ def _is_internal_request(domain, referer):
151 151
     """
152 152
     # Different subdomains are treated as different domains.
153 153
     return referer is not None and re.match("^https?://%s/" % re.escape(domain), referer)
154  
-
155  
-def _is_valid_path(path, urlconf=None):
156  
-    """
157  
-    Returns True if the given path resolves against the default URL resolver,
158  
-    False otherwise.
159  
-
160  
-    This is a convenience method to make working with "is this a match?" cases
161  
-    easier, avoiding unnecessarily indented try...except blocks.
162  
-    """
163  
-    try:
164  
-        urlresolvers.resolve(path, urlconf)
165  
-        return True
166  
-    except urlresolvers.Resolver404:
167  
-        return False
168  
-
17  django/middleware/locale.py
... ...
@@ -1,10 +1,13 @@
1 1
 "This is the locale selecting middleware that will look at accept headers"
2 2
 
3  
-from django.core.urlresolvers import get_resolver, LocaleRegexURLResolver
  3
+from django.conf import settings
  4
+from django.core.urlresolvers import (is_valid_path, get_resolver,
  5
+                                      LocaleRegexURLResolver)
4 6
 from django.http import HttpResponseRedirect
5 7
 from django.utils.cache import patch_vary_headers
6 8
 from django.utils import translation
7 9
 
  10
+
8 11
 class LocaleMiddleware(object):
9 12
     """
10 13
     This is a very simple middleware that parses a request
@@ -23,13 +26,17 @@ def process_request(self, request):
23 26
 
24 27
     def process_response(self, request, response):
25 28
         language = translation.get_language()
26  
-        translation.deactivate()
27  
-
28 29
         if (response.status_code == 404 and
29 30
                 not translation.get_language_from_path(request.path_info)
30 31
                     and self.is_language_prefix_patterns_used()):
31  
-            return HttpResponseRedirect(
32  
-                '/%s%s' % (language, request.get_full_path()))
  32
+            urlconf = getattr(request, 'urlconf', None)
  33
+            language_path = '/%s%s' % (language, request.path_info)
  34
+            if settings.APPEND_SLASH and not language_path.endswith('/'):
  35
+                language_path = language_path + '/'
  36
+            if is_valid_path(language_path, urlconf):
  37
+                return HttpResponseRedirect(
  38
+                    '/%s%s' % (language, request.get_full_path()))
  39
+        translation.deactivate()
33 40
 
34 41
         patch_vary_headers(response, ('Accept-Language',))
35 42
         if 'Content-Language' not in response:
35  tests/regressiontests/i18n/patterns/tests.py
@@ -144,37 +144,29 @@ def test_no_prefix_response(self):
144 144
 
145 145
     def test_en_redirect(self):
146 146
         response = self.client.get('/account/register/', HTTP_ACCEPT_LANGUAGE='en')
147  
-        self.assertRedirects(response, 'http://testserver/en/account/register/')
  147
+        self.assertRedirects(response, '/en/account/register/')
148 148
 
149 149
         response = self.client.get(response['location'])
150 150
         self.assertEqual(response.status_code, 200)
151 151
 
152 152
     def test_en_redirect_wrong_url(self):
153 153
         response = self.client.get('/profiel/registeren/', HTTP_ACCEPT_LANGUAGE='en')
154  
-        self.assertEqual(response.status_code, 302)
155  
-        self.assertEqual(response['location'], 'http://testserver/en/profiel/registeren/')
156  
-
157  
-        response = self.client.get(response['location'])
158 154
         self.assertEqual(response.status_code, 404)
159 155
 
160 156
     def test_nl_redirect(self):
161 157
         response = self.client.get('/profiel/registeren/', HTTP_ACCEPT_LANGUAGE='nl')
162  
-        self.assertRedirects(response, 'http://testserver/nl/profiel/registeren/')
  158
+        self.assertRedirects(response, '/nl/profiel/registeren/')
163 159
 
164 160
         response = self.client.get(response['location'])
165 161
         self.assertEqual(response.status_code, 200)
166 162
 
167 163
     def test_nl_redirect_wrong_url(self):
168 164
         response = self.client.get('/account/register/', HTTP_ACCEPT_LANGUAGE='nl')
169  
-        self.assertEqual(response.status_code, 302)
170  
-        self.assertEqual(response['location'], 'http://testserver/nl/account/register/')
171  
-
172  
-        response = self.client.get(response['location'])
173 165
         self.assertEqual(response.status_code, 404)
174 166
 
175 167
     def test_pt_br_redirect(self):
176 168
         response = self.client.get('/conta/registre-se/', HTTP_ACCEPT_LANGUAGE='pt-br')
177  
-        self.assertRedirects(response, 'http://testserver/pt-br/conta/registre-se/')
  169
+        self.assertRedirects(response, '/pt-br/conta/registre-se/')
178 170
 
179 171
         response = self.client.get(response['location'])
180 172
         self.assertEqual(response.status_code, 200)
@@ -187,17 +179,15 @@ class URLRedirectWithoutTrailingSlashTests(URLTestCaseBase):
187 179
     """
188 180
     def test_not_prefixed_redirect(self):
189 181
         response = self.client.get('/not-prefixed', HTTP_ACCEPT_LANGUAGE='en')
190  
-        self.assertEqual(response.status_code, 301)
191  
-        self.assertEqual(response['location'], 'http://testserver/not-prefixed/')
  182
+        self.assertRedirects(response, '/not-prefixed/', 301)
192 183
 
193 184
     def test_en_redirect(self):
194 185
         response = self.client.get('/account/register', HTTP_ACCEPT_LANGUAGE='en')
195  
-        self.assertEqual(response.status_code, 302)
196  
-        self.assertEqual(response['location'], 'http://testserver/en/account/register')
  186
+        # target status code of 301 because of CommonMiddleware redirecting
  187
+        self.assertRedirects(response, '/en/account/register', 302, target_status_code=301)
197 188
 
198 189
         response = self.client.get(response['location'])
199  
-        self.assertEqual(response.status_code, 301)
200  
-        self.assertEqual(response['location'], 'http://testserver/en/account/register/')
  190
+        self.assertRedirects(response, '/en/account/register/', 301)
201 191
 
202 192
 
203 193
 class URLRedirectWithoutTrailingSlashSettingTests(URLTestCaseBase):
@@ -208,20 +198,15 @@ class URLRedirectWithoutTrailingSlashSettingTests(URLTestCaseBase):
208 198
     @override_settings(APPEND_SLASH=False)
209 199
     def test_not_prefixed_redirect(self):
210 200
         response = self.client.get('/not-prefixed', HTTP_ACCEPT_LANGUAGE='en')
211  
-        self.assertEqual(response.status_code, 302)
212  
-        self.assertEqual(response['location'], 'http://testserver/en/not-prefixed')
213  
-
214  
-        response = self.client.get(response['location'])
215 201
         self.assertEqual(response.status_code, 404)
216 202
 
217 203
     @override_settings(APPEND_SLASH=False)
218 204
     def test_en_redirect(self):
219  
-        response = self.client.get('/account/register', HTTP_ACCEPT_LANGUAGE='en')
220  
-        self.assertEqual(response.status_code, 302)
221  
-        self.assertEqual(response['location'], 'http://testserver/en/account/register')
  205
+        response = self.client.get('/account/register-without-slash', HTTP_ACCEPT_LANGUAGE='en')
  206
+        self.assertRedirects(response, '/en/account/register-without-slash', 302)
222 207
 
223 208
         response = self.client.get(response['location'])
224  
-        self.assertEqual(response.status_code, 404)
  209
+        self.assertEqual(response.status_code, 200)
225 210
 
226 211
 
227 212
 class URLResponseTests(URLTestCaseBase):
1  tests/regressiontests/i18n/patterns/urls/namespace.py
@@ -7,4 +7,5 @@
7 7
 
8 8
 urlpatterns = patterns('',
9 9
     url(_(r'^register/$'), view, name='register'),
  10
+    url(_(r'^register-without-slash$'), view, name='register-without-slash'),
10 11
 )

0 notes on commit 746987f

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