Skip to content

Parse repeated Tornado headers as separate values (fixes #1109) - #1114

Closed
X6M-Work wants to merge 1 commit into
marshmallow-code:devfrom
X6M-Work:fix-tornado-multivalue-headers-1109
Closed

X6M-Work wants to merge 1 commit into
marshmallow-code:devfrom
X6M-Work:fix-tornado-multivalue-headers-1109

Conversation

@X6M-Work

@X6M-Work X6M-Work commented Nov 8, 2026

Copy link
Copy Markdown

Fixes #1109.

Summary

WebArgsTornadoMultiDictProxy.__getitem__ reads values with self.data.get(key). For a tornado.httputil.HTTPHeaders, get() joins repeated headers with commas. For a multi-value key, the proxy then iterates over that string, so a List field receives the joined header split into characters:

headers = tornado.httputil.HTTPHeaders()
headers.add("works", "Prometheus Bound")
headers.add("works", "Prometheus Unbound")
parser.parse({"works": fields.List(fields.Str())}, request, location="headers")
# dev:     {'works': ['P', 'r', 'o', 'm', ..., ',', 'P', 'r', ...]}
# this PR: {'works': ['Prometheus Bound', 'Prometheus Unbound']}

Changes

  • For multi-value keys, the proxy uses HTTPHeaders.get_list() when the data is an HTTPHeaders. Query, form and file arguments are already lists, so they are unchanged.
  • Single-value fields keep the comma-joined value, which is how HTTP allows repeated headers to be combined.

Tests

The existing header tests build the request from a plain dict, which is why they did not catch this. Two new tests in TestHeadersArgs use a real HTTPHeaders, with a repeated header and with a single header. Both fail on dev.

pytest: 505 passed, 4 skipped. pre-commit run --all-files passes (ruff, mypy, blacken-docs, ...).

…code#1109)

HTTPHeaders.get() joins repeated headers with commas, so a multi-value
field such as List received the joined string split into characters.
Use HTTPHeaders.get_list() for multi-value keys instead.
@sirosen

sirosen commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator

I hesitated about this because, unlike the others, the fix is at least plausible on the surface.

But upon consideration, this PR violates our AI Policy and there's no need to entertain it further.

@sirosen sirosen closed this Nov 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multi-value tornado headers are fetched with get() rather than get_list()

2 participants