Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8350588

Implement HTTP/3 for the HTTP Client API

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Unresolved
    • Icon: P3 P3
    • tbd
    • core-libs
    • None
    • source, binary
    • low
    • Hide
      A new `HTTP_3` enum constant for `HttpClient.Version` is added. Code compiled on previous version of the JDK may not expect any other value than `HTTP_1_1` or `HTTP_2` , and may fail or misbehave if presented with the new value. To reduce the risk, `HTTP_2` remains the default preferred version of the HttpClient, and `HTTP_3` will not be used unless explicitly selected. Code written against previous versions of the JDK may fail to recompile on the newer JDK if it switches over the enum without a default clause.
      Some interfaces (`HttpRequest.Builder`, `HttpResponse.PushPromiseHandler` , `HttpResponse`) have acquired new default methods, and some abstract classes (`HttpRequest`) have acquired new methods with a default implementation. Except for `HttpResponse.connectionLabel()` which takes no parameter and returns a String, this is however unlikely to cause trouble since the new methods use new types added in this release in their parameter list. The name `connectionLabel` is hopefully a sufficiently uncommon name to avoid collision with potentially existing methods on subclasses. Some of these new methods may need to be overridden by subclasses to provide a non default implementation if the subclasses are to be used with HTTP/3.
      Show
      A new `HTTP_3` enum constant for `HttpClient.Version` is added. Code compiled on previous version of the JDK may not expect any other value than `HTTP_1_1` or `HTTP_2` , and may fail or misbehave if presented with the new value. To reduce the risk, `HTTP_2` remains the default preferred version of the HttpClient, and `HTTP_3` will not be used unless explicitly selected. Code written against previous versions of the JDK may fail to recompile on the newer JDK if it switches over the enum without a default clause. Some interfaces (`HttpRequest.Builder`, `HttpResponse.PushPromiseHandler` , `HttpResponse`) have acquired new default methods, and some abstract classes (`HttpRequest`) have acquired new methods with a default implementation. Except for `HttpResponse.connectionLabel()` which takes no parameter and returns a String, this is however unlikely to cause trouble since the new methods use new types added in this release in their parameter list. The name `connectionLabel` is hopefully a sufficiently uncommon name to avoid collision with potentially existing methods on subclasses. Some of these new methods may need to be overridden by subclasses to provide a non default implementation if the subclasses are to be used with HTTP/3.
    • Java API, System or security property
    • SE

      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 the HttpClient.Builder.build method API documentation
      • add a new sealed HttpRequest.HttpRequestOption<T> interface, to model options that can be set through the HttpRequest.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 the HttpRequest.Builder.
      • define an HttpRequestOption.H3_DISCOVERY constant, (of type HttpRequestOption<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 is HTTP_3.
      • define an HttpRequest.H3DiscoveryMode enum with three values, HTTP_3_ALT_SERVICES, HTTP_3_ANY, and HTTP_3_ONLY that can be set as value for the H3_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 implementing HttpResponse.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 sealed PushPromiseHandler.PushId interface, implemented by a PushId.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. That connectionLabel can be matched with a corresponding connectionLabel provided by the Http3PushId .
      • add two new subclasses of IOException: UnsupportedProtocolVersionException, and StreamLimitException
      • 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

            dfuchs Daniel Fuchs
            dfuchs Daniel Fuchs
            Jaikiran Pai
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: