Browse Source

[5.0.x] Fixed #35627 -- Raised a LookupError rather than an unhandled ValueError in get_supported_language_variant().

LocaleMiddleware didn't handle the ValueError raised by
get_supported_language_variant() when language codes were
over 500 characters.

Regression in 9e9792228a6bb5d6402a5d645bc3be4cf364aefb.

Backport of 0e94f292cda632153f2b3d9a9037eb0141ae9c2e from main.
Lorenzo Peña 8 months ago
parent
commit
e18601273a

+ 1 - 1
django/utils/translation/trans_real.py

@@ -517,7 +517,7 @@ def get_supported_language_variant(lang_code, strict=False):
                 # There is a generic variant under the maximum length accepted length.
                 lang_code = lang_code[:index]
             else:
-                raise ValueError("'lang_code' exceeds the maximum accepted length")
+                raise LookupError(lang_code)
         # If 'zh-hant-tw' is not supported, try special fallback or subsequent
         # language codes i.e. 'zh-hant' and 'zh'.
         possible_lang_codes = [lang_code]

+ 3 - 3
docs/ref/utils.txt

@@ -1114,7 +1114,7 @@ For a complete discussion on the usage of the following see the
     ``'es-ar'`` isn't.
 
     ``lang_code`` has a maximum accepted length of 500 characters. A
-    :exc:`ValueError` is raised if ``lang_code`` exceeds this limit and
+    :exc:`LookupError` is raised if ``lang_code`` exceeds this limit and
     ``strict`` is ``True``, or if there is no generic variant and ``strict``
     is ``False``.
 
@@ -1126,10 +1126,10 @@ For a complete discussion on the usage of the following see the
 
     Raises :exc:`LookupError` if nothing is found.
 
-    .. versionchanged:: 4.2.14
+    .. versionchanged:: 4.2.15
 
         In older versions, ``lang_code`` values over 500 characters were
-        processed without raising a :exc:`ValueError`.
+        processed without raising a :exc:`LookupError`.
 
 .. function:: to_locale(language)
 

+ 14 - 0
docs/releases/4.2.15.txt

@@ -0,0 +1,14 @@
+===========================
+Django 4.2.15 release notes
+===========================
+
+*Expected August 6, 2024*
+
+Django 4.2.15 fixes a regression in 4.2.14.
+
+Bugfixes
+========
+
+* Fixed a regression in Django 4.2.14 that caused a crash in
+  ``LocaleMiddleware`` when processing a language code over 500 characters
+  (:ticket:`35627`).

+ 4 - 0
docs/releases/5.0.8.txt

@@ -19,3 +19,7 @@ Bugfixes
 * Fixed a crash when creating a model with a ``Field.db_default`` and a
   ``Meta.constraints`` constraint composed of ``__endswith``, ``__startswith``,
   or ``__contains`` lookups (:ticket:`35625`).
+
+* Fixed a regression in Django 5.0.7 that caused a crash in
+  ``LocaleMiddleware`` when processing a language code over 500 characters
+  (:ticket:`35627`).

+ 1 - 0
docs/releases/index.txt

@@ -41,6 +41,7 @@ versions of the documentation contain the release notes for any later releases.
 .. toctree::
    :maxdepth: 1
 
+   4.2.15
    4.2.14
    4.2.13
    4.2.12

+ 8 - 3
tests/i18n/tests.py

@@ -1673,14 +1673,13 @@ class MiscTests(SimpleTestCase):
             g("xyz")
         with self.assertRaises(LookupError):
             g("xy-zz")
-        msg = "'lang_code' exceeds the maximum accepted length"
         with self.assertRaises(LookupError):
             g("x" * LANGUAGE_CODE_MAX_LENGTH)
-        with self.assertRaisesMessage(ValueError, msg):
+        with self.assertRaises(LookupError):
             g("x" * (LANGUAGE_CODE_MAX_LENGTH + 1))
         # 167 * 3 = 501 which is LANGUAGE_CODE_MAX_LENGTH + 1.
         self.assertEqual(g("en-" * 167), "en")
-        with self.assertRaisesMessage(ValueError, msg):
+        with self.assertRaises(LookupError):
             g("en-" * 167, strict=True)
         self.assertEqual(g("en-" * 30000), "en")  # catastrophic test
 
@@ -1734,6 +1733,7 @@ class MiscTests(SimpleTestCase):
             ("/i-mingo/", "i-mingo"),
             ("/kl-tunumiit/", "kl-tunumiit"),
             ("/nan-hani-tw/", "nan-hani-tw"),
+            (f"/{'a' * 501}/", None),
         ]
         for path, language in tests:
             with self.subTest(path=path):
@@ -2012,6 +2012,11 @@ class CountrySpecificLanguageTests(SimpleTestCase):
         lang = get_language_from_request(request)
         self.assertEqual("bg", lang)
 
+    def test_get_language_from_request_code_too_long(self):
+        request = self.rf.get("/", headers={"accept-language": "a" * 501})
+        lang = get_language_from_request(request)
+        self.assertEqual("en-us", lang)
+
     def test_get_language_from_request_null(self):
         lang = trans_null.get_language_from_request(None)
         self.assertEqual(lang, "en")