diff --git a/django/urls/base.py b/django/urls/base.py index 6cf75d3a3f..8c26a3880b 100644 --- a/django/urls/base.py +++ b/django/urls/base.py @@ -1,4 +1,4 @@ -from urllib.parse import urlsplit, urlunsplit +from urllib.parse import unquote, urlsplit, urlunsplit from asgiref.local import Local @@ -163,7 +163,8 @@ def translate_url(url, lang_code): """ parsed = urlsplit(url) try: - match = resolve(parsed.path) + # URL may be encoded. + match = resolve(unquote(parsed.path)) except Resolver404: pass else: diff --git a/django/views/i18n.py b/django/views/i18n.py index ecb30a45f1..3a93c30d0a 100644 --- a/django/views/i18n.py +++ b/django/views/i18n.py @@ -2,7 +2,6 @@ import itertools import json import os import re -from urllib.parse import unquote from django.apps import apps from django.conf import settings @@ -39,8 +38,6 @@ def set_language(request): ) ): next_url = request.META.get('HTTP_REFERER') - # HTTP_REFERER may be encoded. - next_url = next_url and unquote(next_url) if not url_has_allowed_host_and_scheme( url=next_url, allowed_hosts={request.get_host()}, diff --git a/tests/view_tests/tests/test_i18n.py b/tests/view_tests/tests/test_i18n.py index 091df959fc..b4c27a296e 100644 --- a/tests/view_tests/tests/test_i18n.py +++ b/tests/view_tests/tests/test_i18n.py @@ -169,12 +169,14 @@ class SetLanguageTests(TestCase): def test_setlang_decodes_http_referer_url(self): """ - The set_language view decodes the HTTP_REFERER URL. + The set_language view decodes the HTTP_REFERER URL and preserves an + encoded query string. """ # The URL & view must exist for this to work as a regression test. self.assertEqual(reverse('with_parameter', kwargs={'parameter': 'x'}), '/test-setlang/x/') lang_code = self._get_inactive_language_code() - encoded_url = '/test-setlang/%C3%A4/' # (%C3%A4 decodes to ä) + # %C3%A4 decodes to ä, %26 to &. + encoded_url = '/test-setlang/%C3%A4/?foo=bar&baz=alpha%26omega' response = self.client.post('/i18n/setlang/', {'language': lang_code}, HTTP_REFERER=encoded_url) self.assertRedirects(response, encoded_url, fetch_redirect_response=False) self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code)