Skip to content

report the byte limit when response headers exceed it - #9642

Open
HDPark95 wants to merge 2 commits into
lysine-dev:mainfrom
HDPark95:fix/issue-9233-header-limit-message
Open

report the byte limit when response headers exceed it#9642
HDPark95 wants to merge 2 commits into
lysine-dev:mainfrom
HDPark95:fix/issue-9233-header-limit-message

Conversation

@HDPark95

@HDPark95 HDPark95 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

When a response head exceeds the 256 KiB limit, HeadersReader let okio's raw
EOFException propagate (\n not found: limit=... content=<hex>), which gives no
hint that the header size limit was the cause (#9233).

This translates that case into a ProtocolException that names the limit.
readUtf8LineStrict() throws EOFException both when the line exceeds the byte
limit and when the stream ends before a line terminator, so the exception is only
rewritten when the buffer actually reached the limit
(source.buffer.size >= headerLimit). A genuinely truncated response still
surfaces as an EOFException, keeping that distinct failure mode intact, and the
original exception is retained as the cause.

Testing

New HeadersReaderTest:

  • an oversized header line fails with ProtocolException("response headers exceed the 256 KiB limit")
  • a response truncated before the limit still fails with EOFException
  • normal headers parse unchanged

./gradlew :okhttp:jvmTest --tests "okhttp3.internal.http1.HeadersReaderTest" and
the existing okhttp3.CallLimitsTest both pass.

Fixes #9233

readUtf8LineStrict() surfaces an oversized response head as a raw okio
EOFException ("\n not found: limit=... content=<hex>"), giving no hint
that the 256 KiB header limit was reached. Translate that case into a
ProtocolException that names the limit, while still rethrowing the
original EOFException when the stream is genuinely truncated before the
limit so truncation is not misreported as an oversized header.

Fixes lysine-dev#9233
@HDPark95

HDPark95 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

For anyone reviewing: the failing checks here are pre-existing on main and unrelated to this change, which only touches HeadersReader (the header-limit exception message) and a new HeadersReaderTest.

  • jvm (17) / jvm (21): the only failure is ThreadInterruptTest.forciblyStopDispatcher (expected to start with "canceled due to" but was "interrupted"), a timing-sensitive interrupt test. The new HeadersReaderTest cases pass in the same run (3746 tests, 1 unrelated failure).
  • testwindows: HttpOverHttp2Test.noRecoveryWhenRoutesExhausted (expected 1 but was 0).
  • loom: org.mockserver.client.ClientException across BasicMockServerTest / BasicProxyTest (mock server startup).
  • android (23, x86, default): OkHttpClientTest.get fails with ConnectException ... ENETUNREACH reaching google.com from the emulator.

testwindows and loom also fail on the latest main push build (run 31290194391), so they are not introduced by this branch. Happy to rebase once a green base build is available.

@kdelay kdelay left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rewrite is guarded on "the buffer actually reached the limit", but >= claims one input size that is a genuine truncation.

A header line of exactly HEADER_LIMIT bytes is legal: okio's readUtf8LineStrict(limit) accepts a line of limit bytes followed by CRLF. So a stream that ends after exactly HEADER_LIMIT bytes with no terminator is a truncated legal line, and it now gets the limit message instead of EOFException.

Measured on this branch (aac154e) with a probe test that writes one header line into a Buffer and then reads headers, JDK 17, :okhttp:jvmTest:

truncated line of 262143 bytes -> java.io.EOFException: \n not found: limit=262143 ...
truncated line of 262144 bytes -> java.net.ProtocolException: response headers exceed the 256 KiB limit
truncated line of 262145 bytes -> java.net.ProtocolException: response headers exceed the 256 KiB limit
complete line of 262144 bytes + CRLF CRLF -> OK headers.size=1
complete line of 262145 bytes + CRLF CRLF -> java.net.ProtocolException: response headers exceed the 256 KiB limit

(The limit= in okio's message is min(buffer.size, limit), not the argument.)

Rows 4 and 5 are the control: 262144 bytes parses fine, 262145 is the first size that is genuinely over the limit. That makes row 2 a truncation of a line the parser accepts, which the comment in readLine() says should stay an EOFException. The discriminator wants a strict comparison:

if (source.buffer.size > headerLimit) {

With that one character changed, row 2 becomes EOFException: \n not found: limit=262144 and rows 1, 3, 4, 5 are unchanged. HeadersReaderTest still passes as written (3 tests, 0 failures).

truncatedHeadersBeforeLimitStillThrowEof feeds a 21-byte buffer, so it cannot see this boundary. A case at exactly HEADER_LIMIT bytes would pin it.

readUtf8LineStrict(headerLimit) accepts a header line of exactly
headerLimit bytes followed by a terminator, so a stream that ends after
headerLimit bytes with no terminator is a truncated legal line rather
than an oversized header. The discriminator compared buffer.size with
`>= headerLimit`, which reported that boundary truncation as the limit
error; tighten it to `> headerLimit` so only a strictly larger buffer
maps to the ProtocolException. Add a HeadersReaderTest case at exactly
HEADER_LIMIT bytes to pin the boundary.
@HDPark95

Copy link
Copy Markdown
Contributor Author

Good catch — a line of exactly HEADER_LIMIT bytes is legal (okio accepts limit bytes plus a terminator), so a truncation there is a truncated legal line and should stay an EOFException. Tightened the discriminator to source.buffer.size > headerLimit so only a strictly larger buffer maps to the ProtocolException, and added truncatedHeadersAtLimitStillThrowEof (exactly HEADER_LIMIT bytes, no terminator) to pin the boundary. :okhttp:jvmTest --tests HeadersReaderTest is green (4 tests, 0 failures). Done in b5394ce.

@JakeWharton

Copy link
Copy Markdown
Collaborator

Please refrain from posting LLM-generated text. It is about to be banned from the project, and future posts will be deleted and LLM-generated PRs will be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Better error messages when headers length exceed their limits

3 participants