It is unfortunate that this has come up so late the JDK 11 lifecycle, but since this has API impact, and is the right thing to do, it is certainly worth addressing now ( rather than waiting to do something in a future release).
TL;DR provide API support for setting connection and response specific timeouts, while continuing to support a single overall request timeout. The following issue has been file to track this: https://bugs.openjdk.java.net/browse/JDK-8208391 Propose ------- In the `HttpRequest.Builder` class remove the single `timeout` method and replace it with a pair of `connectTimeout` and `responseTimeout`. The `connectTimeout` method can be used to set a timeout duration that is specific to the connection phase. The `responseTimeout` method can be used to set a timeout for the actual of the HTTP response. For example, HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://foo.com/")) .connectTimeout(Duration.ofSeconds(20)) .responseTimeout(Duration.ofMinutes(1)) .header("Content-Type", "application/json") .POST(BodyPublishers.ofFile(Paths.get("file.json"))) .build(); We consider the ability to be able to set a single timeout for the overall response to be important, so the `responseTimeout` method can be used to set an overall response timeout, in the absence of a more specific `connectTimeout`. This means that the newly named `responseTimeout` is semantically equivalent to the old `timeout` when used without the new `connectTimeout`. Add a new public exception type, `HttpConnectTimeoutException` that is thrown when a connection times out. This exception type will be a subtype of the existing `HttpTimeoutException`, thus allowing for more fine grained exception handling to discern connection timeouts from response timeouts, where desired. The use of a subtype reduces the exception handling overhead for those that do not wish to take that burden, a timeout is just a timeout. Appropriate accessors will be added to `HttpRequest` to retrieve the Optional containing the connect timeout duration, and the response timeout duration. A sketch of the javadoc ( in HttpRequest.Builder ): /** * Sets the response timeout duration for this request. * * <p> If the response headers are not received within the specified * duration, then an {@link HttpTimeoutException} is thrown from {@link * HttpClient#send(java.net.http.HttpRequest, * java.net.http.HttpResponse.BodyHandler) HttpClient::send}, or * {@link HttpClient#sendAsync(java.net.http.HttpRequest, * java.net.http.HttpResponse.BodyHandler) HttpClient::sendAsync} * completes exceptionally with an {@code HttpTimeoutException}. * * <p> If a {@linkplain #connectTimeout(Duration) connect timeout duration} * has also been specified, then this timeout duration starts after the * connection has been established, and the connection setup phase is * timed separately by the connect timeout duration. If no connect * timeout duration has been specified, then this timeout duration * covers both connection setup and receiving of the response. * * <p> The effect of not setting a timeout duration is the same as * setting an infinite duration, ie. block forever, or the Operating * System default. * * @param duration the duration to allow the response headers to be * received * @return this builder * @throws IllegalArgumentException if the duration is non-positive */ public abstract Builder responseTimeout(Duration duration); /** * Sets the connect timeout duration for this request. * * <p> In the case where a new connection needs to be established, if * the connection cannot be established within the given {@code * duration}, then a {@link HttpConnectTimeoutException} is thrown * from {@link HttpClient#send(java.net.http.HttpRequest, * java.net.http.HttpResponse.BodyHandler) HttpClient::send}, or * {@link HttpClient#sendAsync(java.net.http.HttpRequest, * java.net.http.HttpResponse.BodyHandler) HttpClient::sendAsync} * completes exceptionally with a {@code HttpConnectTimeoutException}. * If a new connection does not need to be established, for example * if a connection can be reused from a previous request, then this * timeout duration has no effect. * * <p> The effect of not setting a connect timeout duration is defined * in the method {@link #responseTimeout(Duration) responseTimeout}. * * @param duration the duration to allow the underlying connection to be * established * @return this builder * @throws IllegalArgumentException if the duration is non-positive */ public abstract Builder connectTimeout(Duration duration); New public exception type: public class HttpConnectTimeoutException extends HttpTimeoutException { ... } To HttpRequest add: /** * Returns an {@code Optional} containing this request's response timeout * duration. If the {@linkplain Builder#responseTimeout(Duration) response * timeout duration} was not set in the request's builder, then the * {@code Optional} is empty. * * @return an {@code Optional} containing this request's response timeout * duration */ public abstract Optional<Duration> responseTimeout(); /** * Returns an {@code Optional} containing this request's connect timeout * duration. If the {@linkplain Builder#connectTimeout(Duration) connect * timeout duration} was not set in the request's builder, then the * {@code Optional} is empty. * * @return an {@code Optional} containing this request's connect timeout * duration */ public abstract Optional<Duration> connectTimeout(); -Chris.