-
CSR
-
Resolution: Approved
-
P3
-
None
-
behavioral
-
low
-
CompletableFuture::cancel specify that the `mayInterruptIfRunning` parameter is ignored. The `CompletableFuture` objects returned by the `HttpClient` override and redefine this behavior. This could be surprising for existing callers.
-
Java API
-
SE
Summary
There is no easy way to cancel a request sent through the java.net.http.HttpClient
. This change proposes to handle thread interruption (when in synchronous mode) and CompletableFuture.cancel(true)
(when in asynchronous mode) to release resources associated with an inflight request when the caller is no longer interested in the response.
Problem
There is no easy way to cancel a request sent through the java.net.http.HttpClient
. A natural way may seem to call Thread.interrupt()
on the thread waiting for the response, or to cancel the CompletableFuture
returned by the HttpClient
, but although both will cause an exception to be thrown, the actual request will typically continue in the background as if nothing had happened. This is typically an issue when using virtual threads, as HttpClient::send
will throw an InterruptedException
when interrupted but will not cancel the request.
Solution
This change proposes to handle thread interruption (when in synchronous mode) and CompletableFuture.cancel(true)
(when in asynchronous mode) to release resources associated with an inflight request when the caller is no longer interested in the response.
Specification
The concepts of default HttpClient
implementation and cancelable futures are introduced.
src/java.net.http/share/classes/java/net/http/HttpClient.java
A clarification is added to the class level API documentation:
*
* <p> An {@code HttpClient} can be used to send {@linkplain HttpRequest
* requests} and retrieve their {@linkplain HttpResponse responses}. An {@code
- * HttpClient} is created through a {@link HttpClient#newBuilder() builder}. The
- * builder can be used to configure per-client state, like: the preferred
+ * HttpClient} is created through a {@link HttpClient.Builder builder}.
+ * The {@link #newBuilder() newBuilder} method returns a builder that creates
+ * instances of the default {@code HttpClient} implementation.
+ * The builder can be used to configure per-client state, like: the preferred
* protocol version ( HTTP/1.1 or HTTP/2 ), whether to follow redirects, a
* proxy, an authenticator, etc. Once built, an {@code HttpClient} is immutable,
* and can be used to send multiple requests.
A paragraph is added to the API documentation of the newBuilder
method:
/**
* Creates a new {@code HttpClient} builder.
*
+ * <p> Builders returned by this method create instances
+ * of the default {@code HttpClient} implementation.
+ *
* @return an {@code HttpClient.Builder}
*/
public static Builder newBuilder() {
A paragraph is added to the API documentation of the HttpClient::send
method:
+ * <p> If the operation is interrupted, the default {@code HttpClient}
+ * implementation attempts to cancel the HTTP exchange and
+ * {@link InterruptedException} is thrown.
+ * No guarantee is made as to exactly <em>when</em> the cancellation request
+ * may be taken into account. In particular, the request might still get sent
+ * to the server, as its processing might already have started asynchronously
+ * in another thread, and the underlying resources may only be released
+ * asynchronously.
+ * <ul>
+ * <li>With HTTP/1.1, an attempt to cancel may cause the underlying
+ * connection to be closed abruptly.
+ * <li>With HTTP/2, an attempt to cancel may cause the stream to be reset,
+ * or in certain circumstances, may also cause the connection to be
+ * closed abruptly, if, for instance, the thread is currently trying
+ * to write to the underlying socket.
+ * </ul>
+ *
A paragraph is added to the API documentation of the three args HttpClient::sendAsync
method:
+ * <p> The default {@code HttpClient} implementation returns
+ * {@code CompletableFuture} objects that are <em>cancelable</em>.
+ * {@code CompletableFuture} objects {@linkplain CompletableFuture#newIncompleteFuture()
+ * derived} from cancelable futures are themselves <em>cancelable</em>.
+ * Invoking {@linkplain CompletableFuture#cancel(boolean) cancel(true)}
+ * on a cancelable future that is not completed, attempts to cancel the HTTP exchange
+ * in an effort to release underlying resources as soon as possible.
+ * No guarantee is made as to exactly <em>when</em> the cancellation request
+ * may be taken into account. In particular, the request might still get sent
+ * to the server, as its processing might already have started asynchronously
+ * in another thread, and the underlying resources may only be released
+ * asynchronously.
+ * <ul>
+ * <li>With HTTP/1.1, an attempt to cancel may cause the underlying connection
+ * to be closed abruptly.
+ * <li>With HTTP/2, an attempt to cancel may cause the stream to be reset.
+ * </ul>
+ *
- csr of
-
JDK-8245462 HttpClient send throws InterruptedException when interrupted but does not cancel request
- Closed
- relates to
-
JDK-8181784 JEP 321: HTTP Client API
- Closed