From 1717ef715c028662321515cfdb386cf1ad120450 Mon Sep 17 00:00:00 2001 From: giampaolo Date: Sat, 5 Apr 2025 14:19:06 +0200 Subject: [PATCH] Fix throws only ResourceAccessException on timeout CancellationExceptions are thrown instead of the expected ResourceAccessException during timeout scenarios. Handle the CancellationExceptions in order to throw an ResourceAccessException when timeout occurred Closes gh-33973 Signed-off-by: giampaolo --- .../springframework/http/client/JdkClientHttpRequest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java index 060bef8dde..1e7068263d 100644 --- a/spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java @@ -96,12 +96,13 @@ class JdkClientHttpRequest extends AbstractStreamingClientHttpRequest { @Override protected ClientHttpResponse executeInternal(HttpHeaders headers, @Nullable Body body) throws IOException { CompletableFuture> responseFuture = null; + TimeoutHandler timeoutHandler = null; try { HttpRequest request = buildRequest(headers, body); responseFuture = this.httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream()); if (this.timeout != null) { - TimeoutHandler timeoutHandler = new TimeoutHandler(responseFuture, this.timeout); + timeoutHandler = new TimeoutHandler(responseFuture, this.timeout); HttpResponse response = responseFuture.get(); InputStream inputStream = timeoutHandler.wrapInputStream(response); return new JdkClientHttpResponse(response, inputStream); @@ -136,6 +137,9 @@ class JdkClientHttpRequest extends AbstractStreamingClientHttpRequest { throw (message == null ? new IOException(cause) : new IOException(message, cause)); } } + catch (CancellationException ex) { + throw new HttpTimeoutException("Request timed out"); + } } private HttpRequest buildRequest(HttpHeaders headers, @Nullable Body body) { @@ -224,6 +228,7 @@ class JdkClientHttpRequest extends AbstractStreamingClientHttpRequest { private static final class TimeoutHandler { private final CompletableFuture timeoutFuture; + private boolean isTimeout=false; private TimeoutHandler(CompletableFuture> future, Duration timeout) { @@ -232,6 +237,7 @@ class JdkClientHttpRequest extends AbstractStreamingClientHttpRequest { this.timeoutFuture.thenRun(() -> { if (future.cancel(true) || future.isCompletedExceptionally() || !future.isDone()) { + this.isTimeout = true; return; } try {