Summary
Update the HTTP Client API to support the HTTP/3 protocol. This will allow applications and libraries to interact with HTTP/3 servers and get the benefits of HTTP/3 with minimal code changes.
Problem
The HTTP Client API is protocol agnostic and currently supports versions HTTP/1.1 and HTTP/2 of the HTTP protocol. It is designed to support future HTTP protocol versions with minimal API changes. HTTP/3 was standardized in 2022 by the Internet Engineering Task Force (IETF). HTTP/3 is an evolution of HTTP/2 based on QUIC (pronounced "quick"), a new transport protocol over the User Datagram Protocol (UDP). Unfortunately, the HTTP Client API does not support this latest version of the HTTP protocol. Supporting HTTP/3 will enable applications using the HTTP Client API to benefit from the many improvements offered by the new protocol.
This CSR proposes to update the HTTP Client API to support the HTTP/3 protocol. This will allow applications and libraries to interact with HTTP/3 servers and get the benefits of HTTP/3 with minimal code changes. To achieve this goal several small API updates are needed.
The HttpClient.Version
enum currently only allows to choose between HTTP/1.1 and HTTP/2. In order to support HTTP/3, a new HTTP_3
constant is needed.
Unlike previous versions of the protocol, HTTP/3 doesn’t define a standard port for servers to be listening on. Though it is expected that most HTTP/3 servers deployed will listen on UDP port 443, this is neither guaranteed nor specified by the RFCs. Because HTTP/3 goes over UDP, and previous versions go over TCP, there is no way to define an upgrade mechanism or negotiate the HTTP version during the TLS handshake. Instead HTTP/3 advertises the use of HTTP Alternative Services (RFC 7838) to discover HTTP/3 endpoints. The RFC also allows to optimistically attempt an HTTP/3 connection at the authority (host:port) supplied in the URI. An API point that will allow some flexibility in how an HTTP/3 connection is established will be needed.
Compared to HTTP/2, HTTP/3 allows server pushes to be shared between several request/responses on the same connection. The PushPromiseHandler interface needs to be extended to support this. Also it should be possible to figure out whether two different requests were performed through the same, or through different connections, as it may have an impact on whether push promise responses can be shared between them.
Solution
The following API changes are proposed:
- extend the
HttpClient.Version
enum with a new constant value:HTTP_3
. - update the
HttpClient
class level API documentation to advertise and document HTTP/3 support, enhance theHttpClient.Builder.build
method API documentation - add a new sealed
HttpRequest.HttpRequestOption<T>
interface, to model options that can be set through theHttpRequest.Builder
. - add a new method
HttpRequest.Builder.setOption(HttpRequestOption<T> option, T value)
allowing to configure a request with options. - add a new method
Optional<T> HttpRequest.getOption(HttpRequestOption<T> option)
, to get the value of an option previously set on the request through theHttpRequest.Builder
. - define an
HttpRequestOption.H3_DISCOVERY
constant, (of typeHttpRequestOption<H3DiscoveryMode>
) to model an option that allows to configure how to select/establish an HTTP/3 connection for the request, if the selected protocol version isHTTP_3
. - define an
HttpRequest.H3DiscoveryMode
enum with three values,HTTP_3_ALT_SERVICES
,HTTP_3_ANY
, andHTTP_3_ONLY
that can be set as value for theH3_DISCOVERY
option, in order to change the default HttpClient behavior for a given request if needed. - modify
HttpResponse.PushPromiseHandler
with two new default methods that will be called in the event that an HTTP/3 push promise is received. A class implementingHttpResponse.PushPromiseHandler
could override these methods to take advantage of the improved push promise mechanism brought by HTTP/3. The default implementation of these method will call existing methods so that existing push promise handlers still work, though they may not be able to take full advantage of the push promise sharing defined by HTTP/3. To support this a sealedPushPromiseHandler.PushId
interface, implemented by aPushId.Http3PushId
record is also defined. - add a
String HttpResponse.connectionLabel()
method, that returns a string uniquely identifying the connection on which the request/response exchange was carried out. ThatconnectionLabel
can be matched with a correspondingconnectionLabel
provided by theHttp3PushId
. - add two new subclasses of IOException:
UnsupportedProtocolVersionException
, andStreamLimitException
- add and document in module-info a few jdk-specific system properties to help configure some coarse grain aspects of the HTTP/3 and underlying QUIC protocols implementation.
Note: having a way to distinguish whether two different request/responses were carried out on a same or different connection is generally useful, e.g. for debugging, regardless of the protocol version. Adding a String HttpResponse.connectionLabel() method would help with this, and may be carried out as a separate RFE in advance of this JEP implementation, in which case this CSR will be updated accordingly (see JDK-8352751).
Specification
See attached SpecDiff and ApiDiff
Changes to module-info.java are only visible in the ApiDiff
- blocks
-
JDK-8291976 HTTP/3 for the HTTP Client API
-
- Submitted
-
- csr of
-
JDK-8349910 Implement HTTP/3 for the HTTP Client API
-
- Open
-