Skip to content

Fix _parse_http_header crash on a valueless media-type parameter - #1532

Open
uttam12331 wants to merge 1 commit into
bottlepy:masterfrom
uttam12331:fix-parse-http-header-valueless-param
Open

uttam12331 wants to merge 1 commit into
bottlepy:masterfrom
uttam12331:fix-parse-http-header-valueless-param

Conversation

@uttam12331

Copy link
Copy Markdown

Summary

_parse_http_header crashes on a media-type parameter that has no value (a "flag" parameter), e.g. Content-Type: text/plain; charset.

The function has two branches. The fast path (no " in the header) unpacks each parameter directly:

if '"' not in h:  # INFO: Fast path without regexp (~2x faster)
    for value in h.split(','):
        parts = value.split(';')
        values.append((parts[0].strip(), {}))
        for attr in parts[1:]:
            name, value = attr.split('=', 1)      # <-- ValueError if no '='
            values[-1][1][name.strip().lower()] = value.strip()

When attr has no =, attr.split('=', 1) returns a 1-element list and the tuple unpack raises ValueError: not enough values to unpack. The slow path (quotes present) already tolerates this and stores an empty value, and the docstring says the parser should return partial results for broken input.

Impact

request.POST / request.forms / request.params call _parse_http_header on the request Content-Type before any multipart check, so a request like:

Content-Type: text/plain; charset

raises inside the POST property, which surfaces to the client as a 500 Internal Server Error (with a traceback in wsgi.errors) instead of being parsed as [('text/plain', {'charset': ''})] and handled normally.

Fix

Use str.partition('='), which always returns a 3-tuple (empty value for a valueless parameter) — matching the slow path:

-                name, value = attr.split('=', 1)
+                name, _, value = attr.partition('=')

Tests

Added test_valueless_parameter (in test/test_html_helper.py), asserting a valueless parameter degrades to an empty value on both the fast and slow paths. It fails on the current code (ValueError) and passes with the fix.

The fast path (no quotes) unpacked `name, value = attr.split('=', 1)`, which
raises `ValueError: not enough values to unpack` when a parameter has no `=`
(a flag parameter). The slow path already tolerates this and stores an empty
value, and the function's docstring promises graceful handling of broken
input.

For example a request with `Content-Type: text/plain; charset` reaches this
via `request.POST`/`forms`/`params` and raises, surfacing as a 500 instead of
being parsed as `[('text/plain', {'charset': ''})]`.

Use `str.partition('=')`, which always returns a 3-tuple (empty value for a
valueless parameter), matching the slow path. Add a regression test.
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.

1 participant