Skip to content

Parse Content-Length as digits with surrounding whitespace only - #1221

Open
pjfanning wants to merge 1 commit into
apache:mainfrom
pjfanning:content-length
Open

Parse Content-Length as digits with surrounding whitespace only#1221
pjfanning wants to merge 1 commit into
apache:mainfrom
pjfanning:content-length

Conversation

@pjfanning

Copy link
Copy Markdown
Member

Motivation

ContentLengthParser skips whitespace anywhere in the field value:

if (DIGIT(c)) { ... } else if (WSP(c)) recurse(ix + 1, result)

So Content-Length: 1 2 is read as 12, Content-Length: 5 5 as 55, and an empty Content-Length: as 0. The field value is 1*DIGIT surrounded by optional whitespace (RFC 9110, section 8.6 and RFC 9112, section 5).

The other ways two implementations could disagree about a body length are already closed here — two Content-Length headers with different values are rejected, Transfer-Encoding accepts only a single chunked, and chunked together with a Content-Length is rejected — which is what makes this one worth tightening: it is the remaining case where pekko-http reads a length that a proxy or another server in the request path reads differently, or rejects.

Modification

Skip whitespace before and after the digits, require at least one digit, and end the value at the first non-digit.

Result

A value with whitespace between digits, or with no digit at all, is rejected with the same "Illegal `Content-Length` header value" error that other malformed values already produce. Leading and trailing whitespace still parse as before.

This rejects two inputs that were accepted before: whitespace inside the digits, and an empty value that used to be read as 0. Both are malformed per the grammar, but it is a behaviour change for anyone who was relying on the lenient reading.

Tests

  • sbt "http-core/testOnly org.apache.pekko.http.impl.engine.parsing.RequestParserCRLFSpec org.apache.pekko.http.impl.engine.parsing.RequestParserLFSpec org.apache.pekko.http.impl.engine.parsing.ResponseParserSpec" - pass, with 2 new tests, one for whitespace inside the value and one for an empty value; both fail without the change. Leading whitespace stays covered by the existing Content-length: 17 tests, so the accepted cases are pinned too.
  • sbt http-core/test - pass (1218 tests)
  • sbt http-tests/test - pass (1483 tests)
  • sbt http-core/mimaReportBinaryIssues - pass
  • sbt http-core/scalafmt http-core/Test/scalafmt - clean

References

None - tightens Content-Length parsing to the grammar

Motivation:
`ContentLengthParser` skipped whitespace anywhere in the field value, so
`Content-Length: 1 2` was read as 12 and `Content-Length: 5 5` as 55, and
an empty value was read as 0. The field value is `1*DIGIT` surrounded by
optional whitespace (RFC 9110, section 8.6 and RFC 9112, section 5). Every
other length ambiguity is rejected by this parser already: two differing
Content-Length headers, a Transfer-Encoding other than a single chunked,
and chunked together with a Content-Length. This was the remaining spot
where pekko-http could read a body length that another implementation in
the request path reads differently or rejects.

Modification:
Skip whitespace before and after the digits, but require at least one digit
and stop the value at the first non-digit.

Result:
A Content-Length value with whitespace between digits, or without any
digit, is rejected with the "Illegal `Content-Length` header value" error
that other malformed values already produce. Values with leading or
trailing whitespace keep parsing as before.

Note this rejects two inputs that were accepted before: whitespace inside
the digits, and an empty value that was read as 0.

Tests:
- sbt "http-core/testOnly org.apache.pekko.http.impl.engine.parsing.RequestParserCRLFSpec org.apache.pekko.http.impl.engine.parsing.RequestParserLFSpec org.apache.pekko.http.impl.engine.parsing.ResponseParserSpec" - pass, 2 new tests that both fail without the change; leading whitespace stays covered by the existing "Content-length:    17" tests
- sbt http-core/test - pass
- sbt http-tests/test - pass
- sbt http-core/mimaReportBinaryIssues - pass
- sbt http-core/scalafmt http-core/Test/scalafmt - clean

References:
None - tightens Content-Length parsing to the grammar
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