Skip to content

Commit 600d6c6

Browse files
committed
Update contribution
Closes gh-34721
1 parent 7a55ce4 commit 600d6c6

File tree

3 files changed

+101
-129
lines changed

3 files changed

+101
-129
lines changed

spring-web/src/main/java/org/springframework/http/client/JdkClientHttpRequest.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,11 @@ protected ClientHttpResponse executeInternal(HttpHeaders headers, @Nullable Body
122122
catch (ExecutionException ex) {
123123
Throwable cause = ex.getCause();
124124

125-
if (cause instanceof CancellationException) {
126-
if (timeoutHandler != null && timeoutHandler.isTimeout()) {
127-
throw new HttpTimeoutException("Request timed out");
125+
if (cause instanceof CancellationException ce) {
126+
if (timeoutHandler != null) {
127+
timeoutHandler.handleCancellationException(ce);
128128
}
129-
throw new IOException("Request was cancelled");
129+
throw new IOException("Request cancelled", cause);
130130
}
131131
if (cause instanceof UncheckedIOException uioEx) {
132132
throw uioEx.getCause();
@@ -142,10 +142,10 @@ else if (cause instanceof IOException ioEx) {
142142
}
143143
}
144144
catch (CancellationException ex) {
145-
if (timeoutHandler != null && timeoutHandler.isTimeout()) {
146-
throw new HttpTimeoutException("Request timed out");
145+
if (timeoutHandler != null) {
146+
timeoutHandler.handleCancellationException(ex);
147147
}
148-
throw new IOException("Request was cancelled");
148+
throw new IOException("Request cancelled", ex);
149149
}
150150
}
151151

@@ -244,16 +244,17 @@ public ByteBuffer map(byte[] b, int off, int len) {
244244
private static final class TimeoutHandler {
245245

246246
private final CompletableFuture<Void> timeoutFuture;
247-
private final AtomicBoolean isTimeout = new AtomicBoolean(false);
247+
248+
private final AtomicBoolean timeout = new AtomicBoolean(false);
248249

249250
private TimeoutHandler(CompletableFuture<HttpResponse<InputStream>> future, Duration timeout) {
250251

251252
this.timeoutFuture = new CompletableFuture<Void>()
252253
.completeOnTimeout(null, timeout.toMillis(), TimeUnit.MILLISECONDS);
253254

254255
this.timeoutFuture.thenRun(() -> {
256+
this.timeout.set(true);
255257
if (future.cancel(true) || future.isCompletedExceptionally() || !future.isDone()) {
256-
isTimeout.set(true);
257258
return;
258259
}
259260
try {
@@ -263,7 +264,6 @@ private TimeoutHandler(CompletableFuture<HttpResponse<InputStream>> future, Dura
263264
// ignore
264265
}
265266
});
266-
267267
}
268268

269269
@Nullable
@@ -282,8 +282,10 @@ public void close() throws IOException {
282282
};
283283
}
284284

285-
public boolean isTimeout() {
286-
return isTimeout.get();
285+
public void handleCancellationException(CancellationException ex) throws HttpTimeoutException {
286+
if (this.timeout.get()) {
287+
throw new HttpTimeoutException(ex.getMessage());
288+
}
287289
}
288290
}
289291

spring-web/src/test/java/org/springframework/http/client/JdkClientHttpRequestTest.java

Lines changed: 0 additions & 117 deletions
This file was deleted.
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2002-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.http.client;
18+
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
import java.net.URI;
22+
import java.net.http.HttpClient;
23+
import java.net.http.HttpRequest;
24+
import java.net.http.HttpResponse;
25+
import java.net.http.HttpTimeoutException;
26+
import java.time.Duration;
27+
import java.util.concurrent.CompletableFuture;
28+
import java.util.concurrent.ExecutorService;
29+
import java.util.concurrent.Executors;
30+
31+
import org.junit.jupiter.api.AfterEach;
32+
import org.junit.jupiter.api.BeforeEach;
33+
import org.junit.jupiter.api.Test;
34+
35+
import org.springframework.http.HttpHeaders;
36+
import org.springframework.http.HttpMethod;
37+
38+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
39+
import static org.mockito.Mockito.any;
40+
import static org.mockito.Mockito.mock;
41+
import static org.mockito.Mockito.when;
42+
43+
/**
44+
* Unit tests for {@link JdkClientHttpRequest}.
45+
*/
46+
class JdkClientHttpRequestTests {
47+
48+
private final HttpClient client = mock(HttpClient.class);
49+
50+
private ExecutorService executor;
51+
52+
53+
@BeforeEach
54+
void setup() {
55+
executor = Executors.newSingleThreadExecutor();
56+
}
57+
58+
@AfterEach
59+
void tearDown() {
60+
executor.shutdownNow();
61+
}
62+
63+
64+
@Test
65+
void futureCancelledAfterTimeout() {
66+
CompletableFuture<HttpResponse<InputStream>> future = new CompletableFuture<>();
67+
when(client.sendAsync(any(HttpRequest.class), any(HttpResponse.BodyHandler.class))).thenReturn(future);
68+
69+
assertThatThrownBy(() -> createRequest(Duration.ofMillis(10)).executeInternal(new HttpHeaders(), null))
70+
.isExactlyInstanceOf(HttpTimeoutException.class);
71+
}
72+
73+
@Test
74+
void futureCancelled() {
75+
CompletableFuture<HttpResponse<InputStream>> future = new CompletableFuture<>();
76+
future.cancel(true);
77+
when(client.sendAsync(any(HttpRequest.class), any(HttpResponse.BodyHandler.class))).thenReturn(future);
78+
79+
assertThatThrownBy(() -> createRequest(null).executeInternal(new HttpHeaders(), null))
80+
.isExactlyInstanceOf(IOException.class);
81+
}
82+
83+
private JdkClientHttpRequest createRequest(Duration timeout) {
84+
return new JdkClientHttpRequest(client, URI.create("http://abc.com"), HttpMethod.GET, executor, timeout);
85+
}
86+
87+
}

0 commit comments

Comments
 (0)