https://bz.apache.org/bugzilla/show_bug.cgi?id=70288
Bug ID: 70288
Summary: HTTP/2 request-body completion can return true while
DATA remains buffered
Product: Tomcat 11
Version: unspecified
Hardware: PC
OS: other
Status: NEW
Severity: normal
Priority: P2
Component: Connectors
Assignee: [email protected]
Reporter: [email protected]
Target Milestone: -------
Created attachment 40236
--> https://bz.apache.org/bugzilla/attachment.cgi?id=40236&action=edit
Standalone Maven reproducer project, one-line candidate fix, and validation
(save as repro.patch; git apply repro.patch)
Stream.StandardStreamInputBuffer.isRequestBodyFullyRead() can return true while
its input buffer contains unread DATA. An immediate second call returns false
without consuming any bytes. This can cause premature request-body completion
for HTTP/2 non-blocking consumers. The attached test directly exercises the
internal predicate; it does not itself reproduce a Servlet callback or an
HTTP exchange.
Environment: Oracle JDK 25.0.4+7-LTS-189, Windows 11, amd64. The 11.0.27
release is not currently offered in the Bugzilla Version selector.
The attached standalone Maven reproducer uses the real Tomcat Stream and state
machine. Only Http2UpgradeHandler is mocked. It needs no application framework,
server, network, database or load generator. The reproducer runs with JDK 25.
REPRODUCTION
Save the attached text as repro.patch. In a Git checkout, run:
git apply repro.patch
cd tomcat-http2-read-completion-reproducer
mvn test
Expected: isRequestBodyFullyRead() remains false while one body byte is unread.
Actual on unmodified 11.0.27:
first=true, unread=1, second=false, expectedFirst=false
The default command intentionally fails on the affected version. For a
diagnostic assertion of the faulty result over 20 forced interleavings, run:
mvn -DexpectOriginalRace=true test
This diagnostic mode passes on the affected version and prints:
{"iterations":20,"finishedWithUnreadData":20,"expectedOriginalRace":true}
The Maven test fork is bounded to 30 seconds. Dependencies and their versions
are pinned in the POM; no Tomcat binary or modified dependency is included.
FORCED INTERLEAVING AND CANDIDATE CAUSE
The stream is open, with content length 1 and an allocated empty input buffer.
The producer holds the stream state monitor so the consumer can be paused
while entering the state-machine check. With the original expression:
return (inBuffer == null || inBuffer.position() == 0) && isInputFinished();
1. The consumer observes an empty buffer.
2. Before the consumer obtains the state monitor, the producer buffers one byte
and processes END_STREAM.
3. The consumer obtains the monitor and observes that input has finished.
4. The method returns true although the byte remains buffered.
The real parser also writes DATA before publishing END_STREAM. The state
machine publishes and reads that transition through synchronized methods on
the same state object. However, in the current expression the empty-buffer
observation has already happened before acquiring that monitor.
The proposed one-line patch checks isInputFinished() first, then checks the
buffer. On the normal END_STREAM path, if the first check returns true, the
state-monitor acquire precedes the buffer observation. If it returns false,
the method conservatively reports that the body is not yet fully read.
This is a proposed correction for maintainer review, not a claim that all
HTTP/2 completion/reset paths have been independently audited.
PATCH AND VALIDATION
The attached unified diff targets the 11.0.27 Stream.java source. A short JUnit
wrapper invokes the standalone reproducer. The default test must pass after
the candidate fix and fail before it. See validation.txt for fresh package
verification, including the exact runtime and command results.
The source and patch are generic; they contain no product configuration or
customer data. The source expression was also checked in the published
11.0.x source branch on 2026-10-26. An authenticated Bugzilla search across
open and closed reports for isRequestBodyFullyRead and isFinished did not
identify a matching report. Bug 64974 concerns HTTP pipelining rather than
this HTTP/2 Stream completion interleaving.
--
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]