Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01KqJyCidz3ZgRyHABv2GVJh
97 lines
5.0 KiB
Bash
Executable File
97 lines
5.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# HTTP/3 in the JDK HttpClient (JEP 517, final in JDK 26). Regenerates every file in output/.
|
|
# JDK25=/path JDK26=/path [TRIALS=20] ./run.sh
|
|
# Needs: python3 with `pip install "hypercorn[h3]"`, openssl, and (for 05/06) root with iptables + ip.
|
|
# The loss tests change the loopback MTU and add iptables rules; both are undone on exit.
|
|
set -uo pipefail
|
|
unset JAVA_TOOL_OPTIONS
|
|
HERE="$(cd "$(dirname "$0")" && pwd)"; cd "$HERE"
|
|
JDK25="${JDK25:-/opt/jdks/jdk-25.0.4.1+1}"; JDK26="${JDK26:-/opt/jdks/jdk26}"; TRIALS="${TRIALS:-20}"
|
|
OUT="$HERE/output"; mkdir -p "$OUT"
|
|
URL=https://localhost:4433/hello
|
|
[ -f certs/cert.pem ] || ./server/make-cert.sh
|
|
SPID=""; PPID_=""
|
|
start() { python3 server/serve.py "$1" 4433 >/dev/null 2>&1 & SPID=$!; sleep 2; }
|
|
stop() { [ -n "$SPID" ] && kill -9 "$SPID" 2>/dev/null; wait "$SPID" 2>/dev/null; SPID=""; }
|
|
cleanup() { stop; [ -n "$PPID_" ] && kill -9 "$PPID_" 2>/dev/null; scripts/loss.sh off 2>/dev/null; }
|
|
trap cleanup EXIT
|
|
v() { "$1/bin/java" -version 2>&1 | sed -n 2p; }
|
|
J25="$JDK25/bin/java"; J26="$JDK26/bin/java"
|
|
|
|
ONLY="${ONLY:-}" # ONLY=07 regenerates just the loss table
|
|
if [ -z "$ONLY" ]; then
|
|
# 01 - plain Java 11 code: same source, JDK 25 and 26, server offers HTTP/3. Nothing changes.
|
|
start h3
|
|
{
|
|
for j in "$JDK25" "$JDK26"; do echo "\$ java src/Basics.java $URL ($(v $j))"; "$j/bin/java" src/Basics.java $URL 2>&1; echo; done
|
|
echo "# the alt-svc value above is the server advertising h3 on UDP 4433; nobody asked the client to use it."
|
|
} > "$OUT/01-java11-code-unchanged.txt"
|
|
|
|
# 02 - the opt-in, client level and request level; and the JDK 25 failure
|
|
{
|
|
echo "\$ java src/OptIn.java $URL client ($(v $JDK26))"; "$J26" src/OptIn.java $URL client 2>&1
|
|
echo; echo "\$ java src/OptIn.java $URL request ($(v $JDK26))"; "$J26" src/OptIn.java $URL request 2>&1
|
|
echo; echo "\$ java src/OptIn.java $URL client ($(v $JDK25))"; "$J25" src/OptIn.java $URL client 2>&1 | head -6
|
|
echo; echo "\$ first request of a fresh client-level HTTP_3 client, 8 fresh JVMs ($(v $JDK26))"
|
|
for i in 1 2 3 4 5 6 7 8; do "$J26" src/OptIn.java $URL client 2>&1 | sed -n 1p; done
|
|
} > "$OUT/02-opt-in.txt"
|
|
|
|
# 03 - the three discovery modes against a server that speaks HTTP/3 (h3 server still running)
|
|
{ echo "\$ java src/Discovery.java $URL (server: h1.1 + h2 on TCP, h3 on UDP, Alt-Svc advertised)"; "$J26" src/Discovery.java $URL 2>&1; } > "$OUT/03-discovery-modes.txt"
|
|
stop
|
|
|
|
# 04 - fallback: servers that do not speak HTTP/3 at all
|
|
{
|
|
start h2
|
|
echo "\$ java src/Fallback.java $URL 120 (server: h2 + h1.1 on TCP only; nothing listens on UDP 4433)"
|
|
"$J26" src/Fallback.java $URL 120 2>&1
|
|
echo; echo "\$ java -Djdk.httpclient.http3.maxDirectConnectionTimeout=1 src/Fallback.java $URL 120 (same server)"
|
|
"$J26" -Djdk.httpclient.http3.maxDirectConnectionTimeout=1 src/Fallback.java $URL 120 2>&1
|
|
echo; echo "\$ java -Djdk.httpclient.quic.maxInitialTimeout=3 src/Fallback.java $URL 120 (same server)"
|
|
"$J26" -Djdk.httpclient.quic.maxInitialTimeout=3 src/Fallback.java $URL 120 2>&1
|
|
stop; start h1
|
|
echo; echo "\$ java src/Discovery.java $URL (server: HTTP/1.1 only, TCP)"
|
|
"$J26" src/Discovery.java $URL 2>&1
|
|
stop
|
|
} > "$OUT/04-fallback.txt"
|
|
|
|
# 05 - a firewall that drops all UDP to 4433 (common in offices): the server is h3-capable but unreachable over QUIC
|
|
start h3; scripts/loss.sh 100 udp
|
|
{
|
|
echo "\$ iptables: DROP 100% of UDP to/from port 4433 (TCP untouched); server is the h3 server"
|
|
echo "\$ java src/Fallback.java $URL 120"
|
|
"$J26" src/Fallback.java $URL 120 2>&1
|
|
} > "$OUT/05-udp-blocked.txt"
|
|
scripts/loss.sh off; stop
|
|
|
|
# 06 - a proxy: HTTP/3 is not sent through it
|
|
start h3; python3 server/connect-proxy.py 4480 > "$OUT/.proxy.log" 2>&1 & PPID_=$!; sleep 1
|
|
{
|
|
echo "\$ java src/ViaProxy.java $URL 4480 (client.proxy(...) points at a CONNECT proxy on 4480)"
|
|
"$J26" src/ViaProxy.java $URL 4480 2>&1
|
|
echo; echo "\$ proxy log"; cat "$OUT/.proxy.log"
|
|
} > "$OUT/06-proxy.txt"
|
|
kill $PPID_ 2>/dev/null; PPID_=""; rm -f "$OUT/.proxy.log"; stop
|
|
|
|
fi
|
|
# 07 - HTTP/1.1 vs HTTP/2 vs HTTP/3 under random packet loss (same h3-capable server process for all three)
|
|
python3 server/serve.py h3 4433 2> "$OUT/.srv.err" >/dev/null & SPID=$!; sleep 2
|
|
{
|
|
echo "# loss = per-packet drop probability, applied in EACH direction, TCP and UDP port 4433, by iptables -m statistic on lo (MTU 1500)."
|
|
echo "# no added latency (loopback RTT is microseconds). $TRIALS trials per row after one discarded warm-up; $(v $JDK26)"
|
|
echo "# one = fresh client, 1 download of 1 MiB. many = fresh client, 10 parallel downloads of 100 KiB."
|
|
for L in 0 1 2 5 10; do
|
|
scripts/loss.sh $L
|
|
for w in one many; do for p in h1 h2 h3; do
|
|
timeout 600 "$J26" src/Bench.java $p $w $TRIALS $L 2>&1
|
|
done; done
|
|
echo
|
|
done
|
|
} > "$OUT/07-packet-loss.txt"
|
|
scripts/loss.sh off; stop
|
|
{
|
|
echo "# what the Hypercorn/aioquic server wrote to stderr during 07 (the loss run), exception lines only, counted"
|
|
grep -E "(Error|Exception)[:(]" "$OUT/.srv.err" | sed "s/^[ |+-]*//" | sort | uniq -c | sort -rn
|
|
} > "$OUT/08-server-errors.txt"; rm -f "$OUT/.srv.err"
|
|
echo "wrote $OUT"
|