diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index b634b56..1497d43 100644
a
|
b
|
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 |
diff --git a/django/middleware/common.py b/django/middleware/common.py
index aaa094d..d894ec8 100644
a
|
b
|
class CommonMiddleware(object):
|
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(("" |
… |
… |
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 | | |
diff --git a/django/middleware/locale.py b/django/middleware/locale.py
index 2a71f3d..0ed8ec1 100644
a
|
b
|
|
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 |
… |
… |
class LocaleMiddleware(object):
|
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 | | and self.is_language_prefix_patterns_used()): |
31 | | return HttpResponseRedirect( |
32 | | '/%s%s' % (language, request.get_full_path())) |
| 31 | and self.is_language_prefix_patterns_used()): |
| 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())) |
33 | 39 | |
| 40 | translation.deactivate() |
34 | 41 | patch_vary_headers(response, ('Accept-Language',)) |
35 | 42 | if 'Content-Language' not in response: |
36 | 43 | response['Content-Language'] = language |
diff --git a/tests/regressiontests/i18n/patterns/tests.py b/tests/regressiontests/i18n/patterns/tests.py
index 1cc4520..1216d0b 100644
a
|
b
|
class URLRedirectTests(URLTestCaseBase):
|
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) |
… |
… |
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): |
… |
… |
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): |
diff --git a/tests/regressiontests/i18n/patterns/urls/namespace.py b/tests/regressiontests/i18n/patterns/urls/namespace.py
index bf43949..3a2467b 100644
a
|
b
|
view = TemplateView.as_view(template_name='dummy.html')
|
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 | ) |