FrankChen021 opened a new pull request, #20717:
URL: https://github.com/apache/druid/pull/20717
### Description
Brokers and Historicals always declare `Trailer: X-Druid-Response-Complete`
and send that trailer after the last chunk of every streamed `/druid/v2` and
`/druid/v2/sql` response.
JDK-8383439 ("Enhance HTTP Client Response Handling", October 2026 CPU)
shipped in JDK 17.0.21, 21.0.13 and 25.0.5. It makes `java.net.http.HttpClient`
require CRLF right after the last chunk (new `ChunkedBodyParser.tryConsumeCRLF`
in `jdk.internal.net.http.ResponseContent`). A trailer section now fails the
response with `java.net.ProtocolException: CR expected`. Older JDKs skipped
those 2 bytes without checking them. So on current JDKs, any `java.net.http`
client that queries a Broker or Historical directly fails at the end of the
response. That includes the Druid JDBC driver (`DruidHttpClientImpl`) and
`ResponseIdentityHeaderTest`, which now fails deterministically on CI since
`setup-java` picked up Zulu 25.0.5. RFC 9112 §7.1 says recipients should accept
trailers, so this looks like a JDK regression. I found no public OpenJDK
report; JDK-8383439 itself is not public.
#### Fix
`QueryResultPusher` now declares and sends trailers only when the request
has `TE: trailers`, which is how RFC 9110 §10.1.4 has a client say it accepts
trailers. Without that header, responses are unchanged apart from the missing
`Trailer` header and trailer section.
No Druid code reads `X-Druid-Response-Complete` or `X-Error-Message`
(`DirectDruidClient` doesn't). The Router drops trailers anyway, because
Jetty's proxy treats `TE` and `Trailer` as hop-by-hop headers. So
Broker→Historical and Router traffic behaves the same as before.
#### Evidence
- **CI on Zulu 25.0.5 fails.** [This
job](https://github.com/apache/druid/actions/runs/40058080998/job/120765742115)
resolved `Zulu 25.0.5+8` (2026-10-24 03:25 UTC). In
`ResponseIdentityHeaderTest`, the three query tests (Broker native, Broker SQL,
Historical native) fail with `java.net.ProtocolException: CR expected`; the
four GET tests pass.
- **CI on Zulu 25.0.4 passes.** [This master
job](https://github.com/apache/druid/actions/runs/40051516682/job/120745017496)
resolved `Zulu 25.0.4+1.1` (01:49 UTC the same day) and
`ResponseIdentityHeaderTest` passed 7/7. Master is green only because nothing
has merged since `setup-java` switched to 25.0.5. It will also start failing on
the 17 and 21 jobs once they resolve 17.0.21 and 21.0.13.
- **Wire format.** A raw-socket capture of a Broker `/druid/v2/sql` response
ends with `0\r\nX-Druid-Response-Complete: true\r\n\r\n`.
- **JDK change.** JDK-8383439 was committed to openjdk `jdk17u`, `jdk21u`
and `jdk25u` on 2026-10-16. The first GA tags that contain it are
`jdk-17.0.21-ga`, `jdk-21.0.13-ga` and `jdk-25.0.5-ga`.
#### Release note
Brokers and Historicals now send the `X-Druid-Response-Complete` and
`X-Error-Message` HTTP trailers only when the request includes the `TE:
trailers` header. Clients that read these trailers must send that header. This
fixes query failures (`java.net.ProtocolException: CR expected`) in
`java.net.http.HttpClient`-based clients, including the Druid JDBC driver, on
JDK 17.0.21, 21.0.13 and 25.0.5.
<hr>
##### Key changed/added classes in this PR
* `QueryResultPusher`
* `QueryResponseTrailerTest` (new embedded test: raw-socket wire check with
and without `TE: trailers`, plus `HttpClient` reads from Broker and Historical)
<hr>
This PR has:
- [x] been self-reviewed.
- [x] added unit tests or modified existing tests to cover new code paths.
- [x] added integration tests.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]