diff options
| author | Khudyakov Artem <khudyak.artem@gmail.com> | 2024-07-29 22:05:10 +0300 |
|---|---|---|
| committer | nessita <124304+nessita@users.noreply.github.com> | 2025-03-27 08:57:03 -0300 |
| commit | 9aabe7eae3eeb3e64c5a0f3687118cd806158550 (patch) | |
| tree | bbc7cc8752b20fe850bc890d86e9df07b9d4958d /tests/utils_tests | |
| parent | 0d92428d77fafff373e05dd5a6cdb62bd1dfbda0 (diff) | |
Fixed #35440 -- Simplified parse_header_parameters by leveraging stdlid's Message.
The `parse_header_parameters` function historically used Python's `cgi`
module (now deprecated). In 34e2148fc725e7200050f74130d7523e3cd8507a,
the logic was inlined to work around this deprecation ( #33173). Later,
in d4d5427571b4bf3a21c902276c2a00215c2a37cc, the header parsing logic
was further cleaned up to align with `multipartparser.py` (#33697).
This change takes it a step further by replacing the copied `cgi` logic with
Python's `email.message.Message` API for a more robust and maintainable header
parsing implementation.
Thanks to Raphael Gaschignard for testing, and to Adam Johnson and Shai
Berger for reviews.
Co-authored-by: Ben Cail <bcail@crossway.org>
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
Diffstat (limited to 'tests/utils_tests')
| -rw-r--r-- | tests/utils_tests/test_http.py | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/tests/utils_tests/test_http.py b/tests/utils_tests/test_http.py index d18fb63c0c..3730c2fcf5 100644 --- a/tests/utils_tests/test_http.py +++ b/tests/utils_tests/test_http.py @@ -6,6 +6,7 @@ from unittest import mock from django.test import SimpleTestCase from django.utils.datastructures import MultiValueDict from django.utils.http import ( + MAX_HEADER_LENGTH, base36_to_int, content_disposition_header, escape_leading_slashes, @@ -424,6 +425,8 @@ class EscapeLeadingSlashesTests(unittest.TestCase): class ParseHeaderParameterTests(unittest.TestCase): def test_basic(self): tests = [ + ("", ("", {})), + (None, ("none", {})), ("text/plain", ("text/plain", {})), ("text/vnd.just.made.this.up ; ", ("text/vnd.just.made.this.up", {})), ("text/plain;charset=us-ascii", ("text/plain", {"charset": "us-ascii"})), @@ -448,9 +451,17 @@ class ParseHeaderParameterTests(unittest.TestCase): ("attachment", {"filename": "strange;name", "size": "123"}), ), ( + 'attachment; filename="strange;name";;;;size=123;;;', + ("attachment", {"filename": "strange;name", "size": "123"}), + ), + ( 'form-data; name="files"; filename="fo\\"o;bar"', ("form-data", {"name": "files", "filename": 'fo"o;bar'}), ), + ( + 'form-data; name="files"; filename="\\"fo\\"o;b\\\\ar\\""', + ("form-data", {"name": "files", "filename": '"fo"o;b\\ar"'}), + ), ] for header, expected in tests: with self.subTest(header=header): @@ -480,12 +491,13 @@ class ParseHeaderParameterTests(unittest.TestCase): """ Test wrongly formatted RFC 2231 headers (missing double single quotes). Parsing should not crash (#24209). + But stdlib email still decodes (#35440). """ test_data = ( ( "Content-Type: application/x-stuff; " "title*='This%20is%20%2A%2A%2Afun%2A%2A%2A", - "'This%20is%20%2A%2A%2Afun%2A%2A%2A", + "'This is ***fun***", ), ("Content-Type: application/x-stuff; title*='foo.html", "'foo.html"), ("Content-Type: application/x-stuff; title*=bar.html", "bar.html"), @@ -494,6 +506,37 @@ class ParseHeaderParameterTests(unittest.TestCase): parsed = parse_header_parameters(raw_line) self.assertEqual(parsed[1]["title"], expected_title) + def test_header_max_length(self): + base_header = "Content-Type: application/x-stuff; title*=" + base_header_len = len(base_header) + + test_data = [ + (MAX_HEADER_LENGTH, {}), + (MAX_HEADER_LENGTH, {"max_length": None}), + (MAX_HEADER_LENGTH + 1, {"max_length": None}), + (100, {"max_length": 100}), + ] + for line_length, kwargs in test_data: + with self.subTest(line_length=line_length, kwargs=kwargs): + title = "x" * (line_length - base_header_len) + line = base_header + title + assert len(line) == line_length + + parsed = parse_header_parameters(line, **kwargs) + + expected = ("content-type: application/x-stuff", {"title": title}) + self.assertEqual(parsed, expected) + + def test_header_too_long(self): + test_data = [ + ("x" * (MAX_HEADER_LENGTH + 1), {}), + ("x" * 101, {"max_length": 100}), + ] + for line, kwargs in test_data: + with self.subTest(line_length=len(line), kwargs=kwargs): + with self.assertRaises(ValueError): + parse_header_parameters(line, **kwargs) + class ContentDispositionHeaderTests(unittest.TestCase): def test_basic(self): |
