Daniel Fuchs e8db14f584 8349910: Implement JEP 517: HTTP/3 for the HTTP Client API
Co-authored-by: Aleksei Efimov <aefimov@openjdk.org>
Co-authored-by: Bradford Wetmore <wetmore@openjdk.org>
Co-authored-by: Daniel Jeliński <djelinski@openjdk.org>
Co-authored-by: Darragh Clarke <dclarke@openjdk.org>
Co-authored-by: Jaikiran Pai <jpai@openjdk.org>
Co-authored-by: Michael McMahon <michaelm@openjdk.org>
Co-authored-by: Volkan Yazici <vyazici@openjdk.org>
Co-authored-by: Conor Cleary <conor.cleary@oracle.com>
Co-authored-by: Patrick Concannon <patrick.concannon@oracle.com>
Co-authored-by: Rahul Yadav <rahul.r.yadav@oracle.com>
Co-authored-by: Daniel Fuchs <dfuchs@openjdk.org>
Reviewed-by: djelinski, jpai, aefimov, abarashev, michaelm
2025-09-22 10:12:12 +00:00

177 lines
8.4 KiB
Java

/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient.Version;
import java.net.http.HttpRequest.Builder;
/**
* This interface is used to provide additional request configuration
* option hints on how an HTTP request/response exchange should
* be carried out by the {@link HttpClient} implementation.
* Request configuration option hints can be provided to an
* {@link HttpRequest} with the {@link
* Builder#setOption(HttpOption, Object) HttpRequest.Builder
* setOption} method.
*
* <p> Concrete instances of this class and its subclasses are immutable.
*
* @apiNote
* In this version, the {@code HttpOption} interface is sealed and
* only allows the {@link #H3_DISCOVERY} option. However, it could be
* extended in the future to support additional options.
* <p>
* The {@link #H3_DISCOVERY} option can be used to help the
* {@link HttpClient} decide how to select or establish an
* HTTP/3 connection through which to carry out an HTTP/3
* request/response exchange.
*
* @param <T> The {@linkplain #type() type of the option value}
*
* @since 26
*/
public sealed interface HttpOption<T> permits HttpRequestOptionImpl {
/**
* {@return the option name}
*
* @implSpec Different options must have different names.
*/
String name();
/**
* {@return the type of the value associated with the option}
*
* @apiNote Different options may have the same type.
*/
Class<T> type();
/**
* An option that can be used to configure how the {@link HttpClient} will
* select or establish an HTTP/3 connection through which to carry out
* the request. If {@link Version#HTTP_3} is not selected either as
* the {@linkplain Builder#version(Version) request preferred version}
* or the {@linkplain HttpClient.Builder#version(Version) HttpClient
* preferred version} setting this option on the request has no effect.
* <p>
* The {@linkplain #name() name of this option} is {@code "H3_DISCOVERY"}.
*
* @implNote
* The JDK built-in implementation of the {@link HttpClient} understands the
* request option {@link #H3_DISCOVERY} hint.
* <br>
* If no {@code H3_DISCOVERY} hint is provided, and the {@linkplain Version#HTTP_3
* HTTP/3 version} is selected, either as {@linkplain Builder#version(Version)
* request preferred version} or {@linkplain HttpClient.Builder#version(Version)
* client preferred version}, the JDK built-in implementation will establish
* the exchange as per {@link Http3DiscoveryMode#ANY}.
* <p>
* In case of {@linkplain HttpClient.Redirect redirect}, the
* {@link #H3_DISCOVERY} option, if present, is always transferred to
* the new request.
* <p>
* In this implementation, HTTP/3 through proxies is not supported.
* Unless {@link Http3DiscoveryMode#HTTP_3_URI_ONLY} is specified, if
* a {@linkplain HttpClient.Builder#proxy(ProxySelector) proxy} is {@linkplain
* ProxySelector#select(URI) selected} for the {@linkplain HttpRequest#uri()
* request URI}, the protocol version is downgraded to HTTP/2 or
* HTTP/1.1 and the {@link #H3_DISCOVERY} option is ignored. If, on the
* other hand, {@link Http3DiscoveryMode#HTTP_3_URI_ONLY} is specified,
* the request will fail.
*
* @see Http3DiscoveryMode
* @see Builder#setOption(HttpOption, Object)
*/
HttpOption<Http3DiscoveryMode> H3_DISCOVERY =
new HttpRequestOptionImpl<>(Http3DiscoveryMode.class, "H3_DISCOVERY");
/**
* This enumeration can be used to help the {@link HttpClient} decide
* how an HTTP/3 exchange should be established, and can be provided
* as the value of the {@link HttpOption#H3_DISCOVERY} option
* to {@link Builder#setOption(HttpOption, Object) Builder.setOption}.
* <p>
* Note that if neither the {@linkplain Builder#version(Version) request preferred
* version} nor the {@linkplain HttpClient.Builder#version(Version) client preferred
* version} is {@linkplain Version#HTTP_3 HTTP/3}, no HTTP/3 exchange will
* be established and the {@code Http3DiscoveryMode} is ignored.
*
* @since 26
*/
enum Http3DiscoveryMode {
/**
* This instructs the {@link HttpClient} to use its own implementation
* specific algorithm to find or establish a connection for the exchange.
* Typically, if no connection was previously established with the origin
* server defined by the request URI, the {@link HttpClient} implementation
* may attempt to establish both an HTTP/3 connection over QUIC and an HTTP
* connection over TLS/TCP at the authority present in the request URI,
* and use the first that succeeds. The exchange may then be carried out with
* any of the {@linkplain Version
* three HTTP protocol versions}, depending on which method succeeded first.
*
* @implNote
* If the {@linkplain Builder#version(Version) request preferred version} is {@linkplain
* Version#HTTP_3 HTTP/3}, the {@code HttpClient} may give priority to HTTP/3 by
* attempting to establish an HTTP/3 connection, before attempting a TLS
* connection over TCP.
* <p>
* When attempting an HTTP/3 connection in this mode, the {@code HttpClient} may
* use any <a href="https://www.rfc-editor.org/rfc/rfc7838">HTTP Alternative Services</a>
* information it may have previously obtained from the origin server. If no
* such information is available, a direct HTTP/3 connection at the authority (host, port)
* present in the {@linkplain HttpRequest#uri() request URI} will be attempted.
*/
ANY,
/**
* This instructs the {@link HttpClient} to only use the
* <a href="https://www.rfc-editor.org/rfc/rfc7838">HTTP Alternative Services</a>
* to find or establish an HTTP/3 connection with the origin server.
* The exchange may then be carried out with any of the {@linkplain
* Version three HTTP protocol versions}, depending on
* whether an Alternate Service record for HTTP/3 could be found, and which HTTP version
* was negotiated with the origin server, if no such record could be found.
* <p>
* In this mode, requests sent to the origin server will be sent through HTTP/1.1 or HTTP/2
* until a {@code h3} <a href="https://www.rfc-editor.org/rfc/rfc7838">HTTP Alternative Services</a>
* endpoint for that server is advertised to the client. Usually, an alternate service is
* advertised by a server when responding to a request, so that subsequent requests can make
* use of that alternative service.
*/
ALT_SVC,
/**
* This instructs the {@link HttpClient} to only attempt an HTTP/3 connection
* with the origin server. The connection will only succeed if the origin server
* is listening for incoming HTTP/3 connections over QUIC at the same authority (host, port)
* as defined in the {@linkplain HttpRequest#uri() request URI}. In this mode,
* <a href="https://www.rfc-editor.org/rfc/rfc7838">HTTP Alternative Services</a>
* are not used.
*/
HTTP_3_URI_ONLY
}
}