JEP 517: HTTP/3 for the HTTP Client API

OwnerDaniel Fuchs
TypeFeature
ScopeSE
StatusCandidate
Componentcore-libs / java.net
Discussionnet dash dev at openjdk dot org
EffortL
DurationL
Relates toJEP 321: HTTP Client API
Reviewed byAlan Bateman, Bradford Wetmore, Paul Sandoz
Created2022/08/05 14:58
Updated2025/05/02 16:09
Issue8291976

Summary

Update the HTTP Client API to support the HTTP/3 protocol, so that libraries and applications can interact with HTTP/3 servers with minimal code change.

Goals

Non-Goals

Motivation

JEP 321 (JDK 11) added a modern HTTP Client API to the Java Platform. The API supports HTTP/1.1 and HTTP/2, and was designed to support future protocol versions with minimal change. The API prefers HTTP/2 by default, but transparently downgrades to HTTP/1.1 if the target server does not support HTTP/2.

The HTTP Client API makes it easy to write code that interacts with HTTP servers. For example, to send a GET request to https://openjdk.org/ and receive the response as a string:

import java.net.http.*;

...

var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://openjdk.org/"))
                         .GET().build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
assert response.statusCode() == 200;
String htmlText = response.body();

Here there is nothing explicit in the use of the API that depends on the HTTP protocol version. The application code is agnostic to the protocol.

Unfortunately, the HTTP Client API does not support the latest version of the HTTP protocol. HTTP/3 was standardized in 2022 by the Internet Engineering Task Force (IETF). HTTP/3 is a successor to HTTP/2 which uses the QUIC reliable transport-layer protocol rather than TCP. QUIC is secured with Transport Layer Security (TLS) version 1.3.

Supporting HTTP/3 would enable applications using the HTTP Client API to benefit from the many improvements offered by the HTTP/3 protocol, including

HTTP/3 is already supported by most web browsers and deployed on about a third of all web sites. The Java Platform should support it for client-side use.

Description

To send a request using HTTP/3, you must opt-in to using it.

You can do this by setting the protocol version of an HttpClient object to HTTP/3, which will cause all requests sent with the client to prefer HTTP/3 by default:

var client = HttpClient.newBuilder()
                       .version(HttpClient.Version.HTTP_3)
                       .build();

Alternatively, you can set the preferred protocol version of an individual HttpRequest object:

var request = HttpRequest.newBuilder(URI.create("https://openjdk.org/"))
                         .version(HttpClient.Version.HTTP_3)
                         .GET().build();

No other changes are needed. After selecting HTTP/3 as the preferred version, either in the request or in the client, you send the request in the usual way. If the target server does not support HTTP/3 then the request will, by default, be transparently downgraded to HTTP/2 or even HTTP/1.1, as appropriate.

Negotiating HTTP protocol versions

It is impossible to determine, in advance, whether a target server supports HTTP/3. It is also impossible to upgrade an existing HTTP/1.1 or HTTP/2 connection to an HTTP/3 connection, since HTTP/1.1 and HTTP/2 are built on top of TCP streams while HTTP/3's QUIC is built on top of UDP datagrams.

How, then, does the HTTP Client API determine whether it can use HTTP/3 for a given target server? There are four basic approaches:

These approaches have tradeoffs: The first requires using HTTP/2 or HTTP/1.1 initially, the second requires waiting for a timeout, the third may load the HTTP/3 implementation but never again use it, and the fourth works only if you know in advance that the target server supports HTTP/3.

Because HTTP/3 is not yet widely deployed, no single approach will work for all circumstances. Therefore we are not proposing to make HTTP/3 the default at this time, though we may do so in the future.

Further potential enhancements

Testing

We will do extensive unit and integration testing. We will also test interoperation with server-side HTTP/3 implementations including Netty, quic-go, quiche, Neqo, and nghttp3.

Risks and Assumptions

This first implementation of HTTP/3 will not support secure-socket providers other than the default provider, SunJSSE. Support for third-party secure-socket providers would require adding methods to the provider SPI, and then the maintainers of such providers would have to implement those methods. We may address this in future work.

Dependencies

The QUIC Protocol is defined by:

The HTTP/3 protocol is defined by:

These RFCs are of interest for discovering QUIC endpoints and measuring network path MTU:

Two additional RFCs are of interest but may not be supported by the first implementation: