summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Walls <jacobtylerwalls@gmail.com>2026-05-12 15:27:59 -0400
committerJacob Walls <jacobtylerwalls@gmail.com>2026-05-12 15:58:53 -0400
commit335c6d0129400eda792f3bec5c71bb28af5e5d37 (patch)
tree0f36258b6f3a69a2b2e731ad95a7eec6cdabae7c
parented13a58bf63df94508c8a0fe779da0b6a2bc26bb (diff)
Fixed #37095 -- Checked maximum redirect lengths against percent-encoded URLs.
-rw-r--r--django/http/response.py5
-rw-r--r--tests/httpwrappers/tests.py13
2 files changed, 15 insertions, 3 deletions
diff --git a/django/http/response.py b/django/http/response.py
index 45fb0177d1..17b8da4da1 100644
--- a/django/http/response.py
+++ b/django/http/response.py
@@ -642,12 +642,11 @@ class HttpResponseRedirectBase(HttpResponse):
):
super().__init__(*args, **kwargs)
self["Location"] = iri_to_uri(redirect_to)
- redirect_to_str = str(redirect_to)
- if max_length is not None and len(redirect_to_str) > max_length:
+ if max_length is not None and len(self["Location"]) > max_length:
raise DisallowedRedirect(
f"Unsafe redirect exceeding {max_length} characters"
)
- parsed = urlsplit(redirect_to_str)
+ parsed = urlsplit(str(redirect_to))
if preserve_request:
self.status_code = self.status_code_preserve_request
if parsed.scheme and parsed.scheme not in self.allowed_schemes:
diff --git a/tests/httpwrappers/tests.py b/tests/httpwrappers/tests.py
index b990e9f816..151088909c 100644
--- a/tests/httpwrappers/tests.py
+++ b/tests/httpwrappers/tests.py
@@ -24,6 +24,7 @@ from django.http import (
parse_cookie,
)
from django.test import SimpleTestCase
+from django.utils.encoding import iri_to_uri
from django.utils.functional import lazystr
from django.utils.http import MAX_URL_REDIRECT_LENGTH
@@ -498,6 +499,18 @@ class HttpResponseTests(SimpleTestCase):
response = response_class(long_url)
self.assertEqual(response.url, long_url)
+ def test_redirect_url_max_length_checks_encoded_location(self):
+ long_url = "/" + "é" * (MAX_URL_REDIRECT_LENGTH - 1)
+ self.assertLessEqual(len(long_url), MAX_URL_REDIRECT_LENGTH)
+ self.assertGreater(len(iri_to_uri(long_url)), MAX_URL_REDIRECT_LENGTH)
+ for response_class in (HttpResponseRedirect, HttpResponsePermanentRedirect):
+ msg = f"Unsafe redirect exceeding {MAX_URL_REDIRECT_LENGTH} characters"
+ with (
+ self.subTest(response_class=response_class),
+ self.assertRaisesMessage(DisallowedRedirect, msg),
+ ):
+ response_class(long_url)
+
def test_redirect_url_max_length_override_via_param(self):
base_url = "https://example.com/"
for (max_length, length), response_class in itertools.product(