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

JEP 517: HTTP/3 for the HTTP Client API

XMLWordPrintable

    • Icon: JEP JEP
    • Resolution: Unresolved
    • Icon: P3 P3
    • None
    • core-libs
    • None
    • Daniel Fuchs
    • Feature
    • Open
    • SE
    • net dash dev at openjdk dot org
    • L
    • L
    • 517

      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

      • Update the HTTP Client API to send and receive HTTP/3 requests and responses.

      • Require only minor changes to the HTTP Client API and to application code.

      • Do not change the default protocol version from HTTP/2 to HTTP/3 but, rather, enable developers to opt-in to HTTP/3.

      Non-Goals

      • It is not a goal to provide an API for the QUIC protocol, upon which HTTP/3 is based.

      • It is not a goal to support third-party secure-socket providers.

      • It is not a goal to provide a server-side implementation of the HTTP/3 protocol.

      • It is not a goal to update the protocol handler used by the legacy java.net.URL API, which only supports HTTP/1.1.

      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

      • Potentially faster handshakes,
      • Avoidance of network congestion issues such as head-of-line blocking, and
      • More reliable transport, especially in environments with high rates of packet loss.

      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 [<code class="prettyprint" >HttpClient</code>] 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 [<code class="prettyprint" >HttpRequest</code>] 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:

      • Send the first request using HTTP/2 or HTTP/1.1. If the response from the server indicates that HTTP/3 is available as an alternative service then use HTTP/3 for all subsequent requests. (This is what happens when the HttpClient object has a preferred version of HTTP_3 and the HttpRequest object does not have a preferred version.)

      • Send the first request using HTTP/3. If an HTTP/3 response is not received in a reasonable time then fall back to HTTP/1.1 or HTTP/2. (This is what happens when the HttpRequest object has a preferred version of HTTP_3.)

      • Send the first request twice, once using HTTP/3 and once using HTTP/2 or HTTP/1.1. Use the protocol of the first response received. (This is what happens when you specify [<code class="prettyprint" >Http3DiscoveryMode.ANY</code>] as the value of the [<code class="prettyprint" >H3_DISCOVERY</code>] request option, the HttpClient object has a preferred version of HTTP_3, and the HttpRequest object does not have a preferred version.)

      • Send all requests using HTTP/3. If the server does not reply via HTTP/3 then fail; do not fall back to HTTP/1.1 or HTTP/2. (This is what happens when you specify [<code class="prettyprint" >Http3DiscoveryMode.HTTP_3_URI_ONLY</code>] as the value of the [<code class="prettyprint" >H3_DISCOVERY</code>] request option and at least one of the HttpClient or HttpRequest objects has a preferred version of HTTP_3.)

      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

      • Enable limited configuration and tuning of the HTTP/3 implementation, for instance by means of JDK-specific system properties or, possibly, small new APIs.

      • Define new subclasses of IOException and SSLException for HTTP/3-specific exception conditions.

      • Enhance the [<code class="prettyprint" >PushPromiseHandler</code>] interface to support HTTP/3's ability to share promise responses across distinct request/response streams within the same connection.

      • Add configuration options to the [<code class="prettyprint" >HttpClient.Builder</code>] and [<code class="prettyprint" >HttpRequest.Builder</code>] APIs to control discovery of the target server.

      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:

      • RFC 8999: Version-Independent Properties of QUIC
      • RFC 9000: A UDP-Based Multiplexed and Secure Transport
      • RFC 9001: Using TLS to Secure QUIC
      • RFC 9002: QUIC Loss Detection and Congestion Control

      The HTTP/3 protocol is defined by:

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

      • RFC 7838: HTTP Alternative Services
      • RFC 8899: Packetization Layer Path MTU Discovery for Datagram Transports
      • RFC 4821: Packetization Layer Path MTU Discovery

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

            dfuchs Daniel Fuchs
            dfuchs Daniel Fuchs
            Daniel Fuchs Daniel Fuchs
            Alan Bateman, Bradford Wetmore, Paul Sandoz
            Votes:
            0 Vote for this issue
            Watchers:
            20 Start watching this issue

              Created:
              Updated: