mirror of
				https://github.com/django/django.git
				synced 2025-10-28 08:06:09 +00:00 
			
		
		
		
	Fixed #17734 -- Made sure to only redirect translated URLs if they can 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
This commit is contained in:
		| @@ -518,3 +518,17 @@ def get_urlconf(default=None): | ||||
|     changed from the default one. | ||||
|     """ | ||||
|     return getattr(_urlconfs, "value", default) | ||||
|  | ||||
| def is_valid_path(path, urlconf=None): | ||||
|     """ | ||||
|     Returns True if the given path resolves against the default URL resolver, | ||||
|     False otherwise. | ||||
|  | ||||
|     This is a convenience method to make working with "is this a match?" cases | ||||
|     easier, avoiding unnecessarily indented try...except blocks. | ||||
|     """ | ||||
|     try: | ||||
|         resolve(path, urlconf) | ||||
|         return True | ||||
|     except Resolver404: | ||||
|         return False | ||||
|   | ||||
| @@ -64,8 +64,8 @@ class CommonMiddleware(object): | ||||
|         # trailing slash and there is no pattern for the current path | ||||
|         if settings.APPEND_SLASH and (not old_url[1].endswith('/')): | ||||
|             urlconf = getattr(request, 'urlconf', None) | ||||
|             if (not _is_valid_path(request.path_info, urlconf) and | ||||
|                     _is_valid_path("%s/" % request.path_info, urlconf)): | ||||
|             if (not urlresolvers.is_valid_path(request.path_info, urlconf) and | ||||
|                     urlresolvers.is_valid_path("%s/" % request.path_info, urlconf)): | ||||
|                 new_url[1] = new_url[1] + '/' | ||||
|                 if settings.DEBUG and request.method == 'POST': | ||||
|                     raise RuntimeError(("" | ||||
| @@ -151,18 +151,3 @@ def _is_internal_request(domain, referer): | ||||
|     """ | ||||
|     # Different subdomains are treated as different domains. | ||||
|     return referer is not None and re.match("^https?://%s/" % re.escape(domain), referer) | ||||
|  | ||||
| def _is_valid_path(path, urlconf=None): | ||||
|     """ | ||||
|     Returns True if the given path resolves against the default URL resolver, | ||||
|     False otherwise. | ||||
|  | ||||
|     This is a convenience method to make working with "is this a match?" cases | ||||
|     easier, avoiding unnecessarily indented try...except blocks. | ||||
|     """ | ||||
|     try: | ||||
|         urlresolvers.resolve(path, urlconf) | ||||
|         return True | ||||
|     except urlresolvers.Resolver404: | ||||
|         return False | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,13 @@ | ||||
| "This is the locale selecting middleware that will look at accept headers" | ||||
|  | ||||
| from django.core.urlresolvers import get_resolver, LocaleRegexURLResolver | ||||
| from django.conf import settings | ||||
| from django.core.urlresolvers import (is_valid_path, get_resolver, | ||||
|                                       LocaleRegexURLResolver) | ||||
| from django.http import HttpResponseRedirect | ||||
| from django.utils.cache import patch_vary_headers | ||||
| from django.utils import translation | ||||
|  | ||||
|  | ||||
| class LocaleMiddleware(object): | ||||
|     """ | ||||
|     This is a very simple middleware that parses a request | ||||
| @@ -23,13 +26,17 @@ class LocaleMiddleware(object): | ||||
|  | ||||
|     def process_response(self, request, response): | ||||
|         language = translation.get_language() | ||||
|         translation.deactivate() | ||||
|  | ||||
|         if (response.status_code == 404 and | ||||
|                 not translation.get_language_from_path(request.path_info) | ||||
|                     and self.is_language_prefix_patterns_used()): | ||||
|             return HttpResponseRedirect( | ||||
|                 '/%s%s' % (language, request.get_full_path())) | ||||
|             urlconf = getattr(request, 'urlconf', None) | ||||
|             language_path = '/%s%s' % (language, request.path_info) | ||||
|             if settings.APPEND_SLASH and not language_path.endswith('/'): | ||||
|                 language_path = language_path + '/' | ||||
|             if is_valid_path(language_path, urlconf): | ||||
|                 return HttpResponseRedirect( | ||||
|                     '/%s%s' % (language, request.get_full_path())) | ||||
|         translation.deactivate() | ||||
|  | ||||
|         patch_vary_headers(response, ('Accept-Language',)) | ||||
|         if 'Content-Language' not in response: | ||||
|   | ||||
| @@ -144,37 +144,29 @@ class URLRedirectTests(URLTestCaseBase): | ||||
|  | ||||
|     def test_en_redirect(self): | ||||
|         response = self.client.get('/account/register/', HTTP_ACCEPT_LANGUAGE='en') | ||||
|         self.assertRedirects(response, 'http://testserver/en/account/register/') | ||||
|         self.assertRedirects(response, '/en/account/register/') | ||||
|  | ||||
|         response = self.client.get(response['location']) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|  | ||||
|     def test_en_redirect_wrong_url(self): | ||||
|         response = self.client.get('/profiel/registeren/', HTTP_ACCEPT_LANGUAGE='en') | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response['location'], 'http://testserver/en/profiel/registeren/') | ||||
|  | ||||
|         response = self.client.get(response['location']) | ||||
|         self.assertEqual(response.status_code, 404) | ||||
|  | ||||
|     def test_nl_redirect(self): | ||||
|         response = self.client.get('/profiel/registeren/', HTTP_ACCEPT_LANGUAGE='nl') | ||||
|         self.assertRedirects(response, 'http://testserver/nl/profiel/registeren/') | ||||
|         self.assertRedirects(response, '/nl/profiel/registeren/') | ||||
|  | ||||
|         response = self.client.get(response['location']) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|  | ||||
|     def test_nl_redirect_wrong_url(self): | ||||
|         response = self.client.get('/account/register/', HTTP_ACCEPT_LANGUAGE='nl') | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response['location'], 'http://testserver/nl/account/register/') | ||||
|  | ||||
|         response = self.client.get(response['location']) | ||||
|         self.assertEqual(response.status_code, 404) | ||||
|  | ||||
|     def test_pt_br_redirect(self): | ||||
|         response = self.client.get('/conta/registre-se/', HTTP_ACCEPT_LANGUAGE='pt-br') | ||||
|         self.assertRedirects(response, 'http://testserver/pt-br/conta/registre-se/') | ||||
|         self.assertRedirects(response, '/pt-br/conta/registre-se/') | ||||
|  | ||||
|         response = self.client.get(response['location']) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
| @@ -187,17 +179,15 @@ class URLRedirectWithoutTrailingSlashTests(URLTestCaseBase): | ||||
|     """ | ||||
|     def test_not_prefixed_redirect(self): | ||||
|         response = self.client.get('/not-prefixed', HTTP_ACCEPT_LANGUAGE='en') | ||||
|         self.assertEqual(response.status_code, 301) | ||||
|         self.assertEqual(response['location'], 'http://testserver/not-prefixed/') | ||||
|         self.assertRedirects(response, '/not-prefixed/', 301) | ||||
|  | ||||
|     def test_en_redirect(self): | ||||
|         response = self.client.get('/account/register', HTTP_ACCEPT_LANGUAGE='en') | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response['location'], 'http://testserver/en/account/register') | ||||
|         # target status code of 301 because of CommonMiddleware redirecting | ||||
|         self.assertRedirects(response, '/en/account/register', 302, target_status_code=301) | ||||
|  | ||||
|         response = self.client.get(response['location']) | ||||
|         self.assertEqual(response.status_code, 301) | ||||
|         self.assertEqual(response['location'], 'http://testserver/en/account/register/') | ||||
|         self.assertRedirects(response, '/en/account/register/', 301) | ||||
|  | ||||
|  | ||||
| class URLRedirectWithoutTrailingSlashSettingTests(URLTestCaseBase): | ||||
| @@ -208,20 +198,15 @@ class URLRedirectWithoutTrailingSlashSettingTests(URLTestCaseBase): | ||||
|     @override_settings(APPEND_SLASH=False) | ||||
|     def test_not_prefixed_redirect(self): | ||||
|         response = self.client.get('/not-prefixed', HTTP_ACCEPT_LANGUAGE='en') | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response['location'], 'http://testserver/en/not-prefixed') | ||||
|  | ||||
|         response = self.client.get(response['location']) | ||||
|         self.assertEqual(response.status_code, 404) | ||||
|  | ||||
|     @override_settings(APPEND_SLASH=False) | ||||
|     def test_en_redirect(self): | ||||
|         response = self.client.get('/account/register', HTTP_ACCEPT_LANGUAGE='en') | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response['location'], 'http://testserver/en/account/register') | ||||
|         response = self.client.get('/account/register-without-slash', HTTP_ACCEPT_LANGUAGE='en') | ||||
|         self.assertRedirects(response, '/en/account/register-without-slash', 302) | ||||
|  | ||||
|         response = self.client.get(response['location']) | ||||
|         self.assertEqual(response.status_code, 404) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|  | ||||
|  | ||||
| class URLResponseTests(URLTestCaseBase): | ||||
|   | ||||
| @@ -7,4 +7,5 @@ view = TemplateView.as_view(template_name='dummy.html') | ||||
|  | ||||
| urlpatterns = patterns('', | ||||
|     url(_(r'^register/$'), view, name='register'), | ||||
|     url(_(r'^register-without-slash$'), view, name='register-without-slash'), | ||||
| ) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user