Skip to content

fix(http_parser): fix chunked size overflow and MediaType.toString quoting - #2001

Open
kevmoo wants to merge 3 commits into
masterfrom
fix-http_parser
Open

kevmoo wants to merge 3 commits into
masterfrom
fix-http_parser

Conversation

@kevmoo

@kevmoo kevmoo commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Rationale

  1. 64-bit chunk size overflow in ChunkedCodingDecoder (_Sink._decode): Chunk sizes were accumulated via _size = (_size << 4) + digit without checking for integer overflow, and chunk body bounds were computed as math.min(end, start + _size). A 16-digit hexadecimal chunk size >= 0x8000000000000000 (or start + _size when start > 0) overflowed signed 64-bit int to a negative index and threw RangeError in Uint8Buffer.addAll instead of FormatException, while 17+ hex digits truncated the declared chunk size.
  2. Unescaped backslashes and unquoted empty parameter values in MediaType.toString(): In 4.1.2, _quotedString in scan.dart was tightened to disallow unescaped \ in qdtext, but _escapedChar in media_type.dart remained RegExp(r'["\x00-\x1F\x7F]') (missing \\). Any parameter value containing \ (foo="bar\\baz" or trail="end\\") was serialized without escaping \, corrupting bar\baz to barbaz on re-parse and turning trailing backslashes (trail="end\\") into an unterminated quoted string (trail="end\") that threw FormatException in MediaType.parse(). Empty parameter values (foo="") also failed nonToken.hasMatch("") and serialized as foo=, throwing FormatException on re-parse.

Summary of Changes

  • pkgs/http_parser/lib/src/chunked_coding/decoder.dart: Check if (_size > _maxSizeBeforeShift) before accumulating _size = (_size * 16) + digit in _State.size, throwing FormatException('Chunk size is too large.', bytes, start), compute final bytesToRead = math.min(end - start, _size) in _State.body, and remove unused name/toString() members on private enum _State.
  • pkgs/http_parser/lib/src/media_type.dart: Add \\ to _escapedChar (RegExp(r'["\x00-\x1F\x7F\\]')) and quote empty parameter values (if (value.isEmpty || nonToken.hasMatch(value))).
  • pkgs/http_parser/test/chunked_coding_test.dart, pkgs/http_parser/test/media_type_test.dart, & pkgs/http_parser/CHANGELOG.md: Add regression tests for 64-bit chunk size overflows and MediaType.toString() / MediaType.parse() round-tripping (159 tests passing), and document under 4.1.3-wip.

Verification

  • dart analyze --fatal-infos: exit 0
  • dart format --output=none --set-exit-if-changed .: exit 0
  • dart test -p vm -c source & dart test -p node: exit 0 (159 tests passed)

…erflow

Check that shifting `_size` left by 4 bits does not overflow a signed 64-bit
integer in `_Sink._decode`, throwing a `FormatException` when a chunk size
exceeds `0x7fffffffffffffff` instead of overflowing to a negative bound or
wrapping to zero. Also compute `math.min(end - start, _size)` in `_State.body`
so `start + _size` cannot overflow on valid large chunk sizes.
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

PR Health

Coverage ✔️
File Coverage
pkgs/http_parser/lib/src/chunked_coding/decoder.dart 💚 96 % ⬆️ 3 %
pkgs/http_parser/lib/src/media_type.dart 💚 98 %

This check for test coverage is informational (issues shown here will not fail the PR).

This check can be disabled by tagging the PR with skip-coverage-check.

License Headers ✔️
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
Files
no missing headers

All source files should start with a license header.

Unrelated files missing license headers
Files
pkgs/http_multi_server/test/cert.dart

This check can be disabled by tagging the PR with skip-license-check.

Breaking changes ✔️
Package Change Current Version New Version Needed Version Looking good?
http_parser None 4.1.2 4.1.3-wip 4.1.3-wip ✔️

This check can be disabled by tagging the PR with skip-breaking-check.

Unused Dependencies ✔️
Package Status
http_parser ✔️ All dependencies utilized correctly.

For details on how to fix these, see dependency_validator.

This check can be disabled by tagging the PR with skip-unused-dependencies-check.

API leaks ✔️

The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.

Package Leaked API symbol Leaking sources

This check can be disabled by tagging the PR with skip-leaking-check.

Changelog Entry ✔️
Package Changed Files

Changes to files need to be accounted for in their respective changelogs.

This check can be disabled by tagging the PR with skip-changelog-check.

…ype.toString

Include `\` in `_escapedChar` so quoted parameter values containing backslashes
round-trip through `MediaType.parse(mediaType.toString())` without corrupting
escaped characters or leaving a trailing unescaped quote, and quote empty
parameter values (`value.isEmpty`) as `""` instead of emitting a bare `=`.
Also remove unused `name` and `toString()` members from private `enum _State`
in `chunked_coding/decoder.dart`.
@kevmoo kevmoo changed the title fix(http_parser): reject 64-bit chunk size overflow in chunked coding fix(http_parser): fix chunked size overflow and MediaType.toString quoting Oct 3, 2026
…ctly

Avoid passing `List<int>.addAll` tear-offs into `ByteConversionSink.withCallback`,
which triggers a `dart2wasm` TFA `RuntimeError: unreachable` trap when
`Uint8Buffer.addAll` is present in the same compilation unit.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant