Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01KqJyCidz3ZgRyHABv2GVJh
2.7 KiB
2.7 KiB
http3 — HTTP/3 in the Java HTTP Client (JEP 517, final in Java 26)
Companion code for the ankurm.com article HTTP/3 in the Java HTTP Client (JEP 517): Migrating from HttpClient 11. All explanation lives in the article; this folder holds the runnable sources, a local HTTP/3 test server, and the transcripts they produced.
What was tested against
| Thing | Version | Note |
|---|---|---|
| JDK 26 | Temurin 26.0.2.1+1 | JEP 517 is delivered in 26 (GA 2026-03-17); this is the only JDK that can run HTTP/3 here |
| JDK 25 | Temurin 25.0.4.1+1 | the "before": HttpClient.Version.HTTP_3 does not exist, plain Java 11 code behaves the same as on 26 |
| Test server | Hypercorn 0.18.0 (HTTP/1.1 + HTTP/2 on TCP) + aioquic 1.3.0 (HTTP/3 on UDP) | one Python process, same port number for both, Alt-Svc advertised. Hypercorn's own QUIC listener was dropped: it died on a KeyError under packet loss and the port went silent |
| Loss injection | iptables -m statistic --mode random on lo |
not tc netem (unavailable in the sandbox: Specified qdisc kind is unknown): loss only, no added delay |
The JDK 26 lane in the other modules of this repo uses Amazon Corretto 26.0.2.1; this module used Temurin because that is what the sandbox had. The API is the same.
Quickstart
pip install hypercorn==0.18.0 aioquic==1.3.0
JDK25=/path/to/jdk-25 JDK26=/path/to/jdk-26 ./run.sh # about 45 minutes: the `HTTP_3_URI_ONLY` failure demos wait a full minute each and the loss table is 600 trials; needs root for 05 and 07; ONLY=07 regenerates just the loss table
# or by hand:
./server/make-cert.sh && python3 server/serve.py h3 4433 & # h3 | h2 | h1
java src/OptIn.java https://localhost:4433/hello request
Layout
| Path | What is in it |
|---|---|
src/Tls.java |
trusts only the self-signed test certificate |
src/Basics.java |
plain Java 11 HttpClient code, no version set |
src/OptIn.java |
the JEP 517 opt-in, client-wide or per request |
src/Discovery.java |
the three H3_DISCOVERY modes |
src/Fallback.java |
first-request latency and version for each way of asking, against servers that cannot do HTTP/3 |
src/ViaProxy.java |
HTTP/3 and a proxy |
src/Bench.java |
HTTP/1.1 vs HTTP/2 vs HTTP/3 download times under packet loss |
server/ |
app.py (shared responses + ASGI wrapper), serve.py (h3 / h2 / h1 modes), h3server.py (aioquic HTTP/3), connect-proxy.py, make-cert.sh |
scripts/loss.sh |
adds and removes the iptables loss rules and the MTU change |
output/ |
every transcript quoted in the article (01-08) |
Timings are machine dependent and the loss is random: treat 07-packet-loss.txt as shape, not a benchmark of HTTP/3 implementations. The server is Python, the client is the JDK.