diff options
| author | Dinesh <dineshthumma15@gmail.com> | 2026-03-21 22:51:11 +0530 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2026-04-22 14:25:08 -0400 |
| commit | dc467fdc3b5744cec71fab876c23a14013e2510b (patch) | |
| tree | 5702150cc3838f3e97af78599614f257ea950cf0 | |
| parent | e1bdebc84ee7cacd40b820e862fd504054619403 (diff) | |
Fixed #36991 -- Raised BadRequest for invalid encodings in Content-Type headers.
| -rw-r--r-- | django/http/request.py | 9 | ||||
| -rw-r--r-- | django/utils/http.py | 6 | ||||
| -rw-r--r-- | tests/requests_tests/tests.py | 14 | ||||
| -rw-r--r-- | tests/utils_tests/test_http.py | 14 |
4 files changed, 39 insertions, 4 deletions
diff --git a/django/http/request.py b/django/http/request.py index f871ea15e8..44bf09450b 100644 --- a/django/http/request.py +++ b/django/http/request.py @@ -155,9 +155,12 @@ class HttpRequest: def _set_content_type_params(self, meta): """Set content_type, content_params, and encoding.""" - self.content_type, self.content_params = parse_header_parameters( - meta.get("CONTENT_TYPE", "") - ) + try: + self.content_type, self.content_params = parse_header_parameters( + meta.get("CONTENT_TYPE", "") + ) + except ValueError as exc: + raise BadRequest("Invalid Content-Type header.") from exc if "charset" in self.content_params: try: codecs.lookup(self.content_params["charset"]) diff --git a/django/utils/http.py b/django/utils/http.py index f72f54e958..f6cce96206 100644 --- a/django/utils/http.py +++ b/django/utils/http.py @@ -366,7 +366,11 @@ def parse_header_parameters(line, max_length=MAX_HEADER_LENGTH): value = value.replace("\\\\", "\\").replace('\\"', '"') if has_encoding: encoding, lang, value = value.split("'") - value = unquote(value, encoding=encoding) + try: + value = unquote(value, encoding=encoding) + except (LookupError, UnicodeDecodeError): + msg = f"Invalid encoding {encoding!r} for RFC 2231 param." + raise ValueError(msg) pdict[name] = value return key, pdict diff --git a/tests/requests_tests/tests.py b/tests/requests_tests/tests.py index b15d954cb3..c25dd913cf 100644 --- a/tests/requests_tests/tests.py +++ b/tests/requests_tests/tests.py @@ -456,6 +456,20 @@ class RequestsTests(SimpleTestCase): with self.assertRaises(RawPostDataException): request.body + def test_malformed_header(self): + tests = [ + # Invalid encoding name with percent-encoded value + "text/plain; charset*=BOGUS''%20", + # Another invalid encoding with different value + "text/plain; filename*=INVALID''%s%s%s", + # Invalid encoding with multi-line encoded content + "text/plain; title*=NOTACODEC''%E2%80%A6", + ] + msg = "Invalid Content-Type header." + for header in tests: + with self.subTest(header=header), self.assertRaisesMessage(BadRequest, msg): + WSGIRequest({"REQUEST_METHOD": "GET", "CONTENT_TYPE": header}) + def test_malformed_multipart_header(self): tests = [ ('Content-Disposition : form-data; name="name"', {"name": ["value"]}), diff --git a/tests/utils_tests/test_http.py b/tests/utils_tests/test_http.py index 58a4b40f3e..f18deb7c70 100644 --- a/tests/utils_tests/test_http.py +++ b/tests/utils_tests/test_http.py @@ -521,6 +521,20 @@ class ParseHeaderParameterTests(unittest.TestCase): parsed = parse_header_parameters(raw_line) self.assertEqual(parsed[1]["title"], expected_title) + def test_rfc2231_invalid_encoding(self): + test_data = [ + # Invalid encoding name with percent-encoded value + "text/plain; charset*=BOGUS''%20", + # Another invalid encoding with different value + "text/plain; filename*=INVALID''%s%s%s", + # Invalid encoding with multi-line encoded content + "text/plain; title*=NOTACODEC''%E2%80%A6", + ] + msg = "Invalid encoding" + for header in test_data: + with self.subTest(raw_line=header), self.assertRaisesRegex(ValueError, msg): + parse_header_parameters(header) + def test_header_max_length(self): base_header = "Content-Type: application/x-stuff; title*=" base_header_len = len(base_header) |
