Skip to content

Commit 4a37891

Browse files
authored
Merge pull request #488 from Cycloctane/reject-duplicate-content-type
Reject requests with duplicate Content-Type
2 parents 3af6388 + 2d59444 commit 4a37891

3 files changed

Lines changed: 12 additions & 2 deletions

File tree

CONTRIBUTORS.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,5 @@ Contributors
152152
- Simon King, 2024-11-12
153153

154154
- Arun Raghunath, 2026-03-13
155+
156+
- Rui Xi, 2026-03-20

src/waitress/parser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
)
3535

3636
# A list of HEADERS that must not be duplicated per RFC 9112
37-
HEADERS_NO_DUPLICATES = frozenset({"HOST", "CONTENT_LENGTH"})
37+
SINGLETON_FIELDS = frozenset({"HOST", "CONTENT_LENGTH", "CONTENT_TYPE"})
3838

3939

4040
def unquote_bytes_to_wsgi(bytestring):
@@ -242,7 +242,7 @@ def parse_header(self, header_plus):
242242
key1 = key.upper().replace(b"-", b"_").decode("latin-1")
243243

244244
# Reject duplicate 'Host' headers as per RFC 9112 section 3.2
245-
if key1 in HEADERS_NO_DUPLICATES and key1 in headers:
245+
if key1 in SINGLETON_FIELDS and key1 in headers:
246246
raise ParsingError(f"Duplicate header: {key.decode('latin-1')}")
247247

248248
# If a header already exists, we append subsequent values

tests/test_parser.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ def test_received_duplicate_content_length_header(self):
8181
self.assertIsInstance(self.parser.error, BadRequest)
8282
self.assertTrue(self.parser.error.body.startswith("Duplicate header:"))
8383

84+
def test_received_duplicate_content_type_header(self):
85+
data = b"GET / HTTP/1.1\r\nHost: example.com\r\nContent-Type: text/plain\r\nContent-Type: text/html\r\n\r\n"
86+
result = self.parser.received(data)
87+
self.assertEqual(result, len(data))
88+
self.assertTrue(self.parser.completed)
89+
self.assertIsInstance(self.parser.error, BadRequest)
90+
self.assertTrue(self.parser.error.body.startswith("Duplicate header:"))
91+
8492
def test_received_bad_transfer_encoding(self):
8593
data = (
8694
b"GET /foobar HTTP/1.1\r\n"

0 commit comments

Comments
 (0)