HttpClient API expectations for connection failures
Jaikiran Pai
jai.forums2013 at gmail.com
Sun Jun 3 02:55:10 UTC 2018
Consider the following code:
public class HttpClientTest {
public static void main(final String[] args) {
final HttpClient httpClient = HttpClient.newBuilder().build();
final String targetURL = "http://unknown.host.foo.bar.com.nowhere";
final HttpRequest request =
HttpRequest.newBuilder().uri(URI.create(targetURL))
.method("HEAD",
HttpRequest.BodyPublishers.noBody())
.build();
try {
httpClient.send(request,
HttpResponse.BodyHandlers.discarding());
} catch(IOException | InterruptedException e) {
// intentionally ignore
System.out.println("Caught an intentionally ignored
exception");
} catch (Exception e) {
e.printStackTrace();
}
}
}
which tries to send a request to (in this case an intentional)
non-existent address. The exception that gets thrown is:
java.nio.channels.UnresolvedAddressException
at java.base/sun.nio.ch.Net.checkAddress(Net.java:130)
at
java.base/sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:674)
at
java.net.http/jdk.internal.net.http.PlainHttpConnection.lambda$connectAsync$0(PlainHttpConnection.java:113)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at
java.net.http/jdk.internal.net.http.PlainHttpConnection.connectAsync(PlainHttpConnection.java:115)
at
java.net.http/jdk.internal.net.http.Http1Exchange.sendHeadersAsync(Http1Exchange.java:261)
at
java.net.http/jdk.internal.net.http.Exchange.lambda$responseAsyncImpl0$8(Exchange.java:385)
at
java.net.http/jdk.internal.net.http.Exchange.checkFor407(Exchange.java:320)
at
java.net.http/jdk.internal.net.http.Exchange.lambda$responseAsyncImpl0$9(Exchange.java:389)
at
java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:930)
at
java.base/java.util.concurrent.CompletableFuture.uniHandleStage(CompletableFuture.java:946)
at
java.base/java.util.concurrent.CompletableFuture.handle(CompletableFuture.java:2266)
at
java.net.http/jdk.internal.net.http.Exchange.responseAsyncImpl0(Exchange.java:389)
at
java.net.http/jdk.internal.net.http.Exchange.responseAsyncImpl(Exchange.java:299)
at
java.net.http/jdk.internal.net.http.Exchange.responseAsync(Exchange.java:291)
at
java.net.http/jdk.internal.net.http.MultiExchange.responseAsyncImpl(MultiExchange.java:240)
at
java.net.http/jdk.internal.net.http.MultiExchange.lambda$responseAsync0$1(MultiExchange.java:205)
at
java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1072)
at
java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
at
java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1705)
at
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:832)
It's a different matter that this stacktrace is missing the caller's
stack frames and that's being tracked in [1]. The javadoc of send method
doesn't mention anything about what specific exception gets thrown in
case of connection failures. It does say:
* @throws IllegalArgumentException if the {@code request} argument
is not
* a request that could have been validly built as
specified by {@link
* HttpRequest.Builder HttpRequest.Builder}.
and the thrown java.nio.channels.UnresolvedAddressException indeed
extends IllegalArgumentException. However, given that the API itself
doesn't say anything about exceptions that get thrown on connection
failures, adding a catch block specifically for
java.nio.channels.UnresolvedAddressException seems like relying on the
implementation detail. Can these APIs make it explicit what exception(s)
can be expected to be thrown in case of connection failures, so that
it's part of the contract?
[1] https://bugs.openjdk.java.net/browse/JDK-8203298
-Jaikiran
More information about the net-dev
mailing list