Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01B38FGKKam5SCGgwgduVAh3
54 lines
2.9 KiB
Java
54 lines
2.9 KiB
Java
import com.sun.net.httpserver.HttpsConfigurator;
|
|
import com.sun.net.httpserver.HttpsServer;
|
|
import java.io.FileInputStream;
|
|
import java.net.InetSocketAddress;
|
|
import java.net.URI;
|
|
import java.net.http.HttpClient;
|
|
import java.net.http.HttpOption;
|
|
import java.net.http.HttpRequest;
|
|
import java.net.http.HttpResponse;
|
|
import java.security.KeyStore;
|
|
import javax.net.ssl.KeyManagerFactory;
|
|
import javax.net.ssl.SSLContext;
|
|
import javax.net.ssl.TrustManagerFactory;
|
|
|
|
/**
|
|
* JEP 517 (Java 26): HTTP/3 for the HTTP Client API. The sandbox cannot reach a real HTTP/3 server (no UDP egress),
|
|
* so this shows the half that is checkable everywhere: a client that PREFERS HTTP/3 talking to a server that does not
|
|
* speak it (the JDK's own HttpsServer, HTTP/1.1) quietly falls back, and says so in response.version().
|
|
* args: keystore path, password
|
|
* Chapter: docs/11-recap-26.md
|
|
*/
|
|
public class Http3Fallback {
|
|
public static void main(String[] args) throws Exception {
|
|
KeyStore ks = KeyStore.getInstance("PKCS12");
|
|
try (var in = new FileInputStream(args[0])) { ks.load(in, args[1].toCharArray()); }
|
|
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, args[1].toCharArray());
|
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks);
|
|
SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
|
|
|
HttpsServer server = HttpsServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
|
|
server.setHttpsConfigurator(new HttpsConfigurator(ctx));
|
|
server.createContext("/", ex -> { byte[] b = "hello".getBytes(); ex.sendResponseHeaders(200, b.length); ex.getResponseBody().write(b); ex.close(); });
|
|
server.start();
|
|
int port = server.getAddress().getPort();
|
|
try (HttpClient client = HttpClient.newBuilder().sslContext(ctx).version(HttpClient.Version.HTTP_3).build()) {
|
|
HttpRequest req = HttpRequest.newBuilder(URI.create("https://localhost:" + port + "/")).GET().build();
|
|
HttpResponse<String> r = client.send(req, HttpResponse.BodyHandlers.ofString());
|
|
System.out.println("client asked for : " + client.version());
|
|
System.out.println("server answered : " + r.version() + " " + r.statusCode() + " " + r.body());
|
|
|
|
HttpRequest strict = HttpRequest.newBuilder(URI.create("https://localhost:" + port + "/")).GET()
|
|
.setOption(HttpOption.H3_DISCOVERY, HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY).build();
|
|
try {
|
|
client.send(strict, HttpResponse.BodyHandlers.ofString());
|
|
System.out.println("HTTP_3_URI_ONLY : unexpectedly succeeded");
|
|
} catch (Exception e) {
|
|
System.out.println("HTTP_3_URI_ONLY : " + e.getClass().getName() + ": " + e.getMessage());
|
|
}
|
|
} finally {
|
|
server.stop(0);
|
|
}
|
|
}
|
|
}
|