From 4397416220525eb7e4dea6e2c4c97f2185bd64f9 Mon Sep 17 00:00:00 2001 From: lejuho <52308082+lejuho@users.noreply.github.com> Date: Wed, 7 Oct 2026 19:48:02 +0900 Subject: [PATCH] Handle zero readTimeout in JdkClientHttpConnector Prior to this commit, JdkClientHttpConnector#setReadTimeout(Duration) passed Duration.ZERO through to HttpRequest.Builder#timeout, which rejects non-positive durations. As a result, every request failed with an IllegalArgumentException ("Invalid duration: PT0S"). gh-37234 already treats a zero read timeout as an infinite timeout in JdkClientHttpRequestFactory, which is backed by the same JDK HttpClient API. This commit applies the same handling to the reactive JdkClientHttpConnector so that a zero Duration results in no timeout being set on the underlying request. See gh-37232 Closes gh-37412 Signed-off-by: lejuho <52308082+lejuho@users.noreply.github.com> --- .../client/reactive/JdkClientHttpConnector.java | 3 ++- .../client/reactive/ClientHttpConnectorTests.java | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/spring-web/src/main/java/org/springframework/http/client/reactive/JdkClientHttpConnector.java b/spring-web/src/main/java/org/springframework/http/client/reactive/JdkClientHttpConnector.java index 5ab354b41ba..35e86847ec8 100644 --- a/spring-web/src/main/java/org/springframework/http/client/reactive/JdkClientHttpConnector.java +++ b/spring-web/src/main/java/org/springframework/http/client/reactive/JdkClientHttpConnector.java @@ -101,13 +101,14 @@ public class JdkClientHttpConnector implements ClientHttpConnector { /** * Set the underlying {@code HttpClient} read timeout as a {@code Duration}. + * A timeout value of 0 specifies an infinite timeout. *

Default is the system's default timeout. * @since 6.2 * @see java.net.http.HttpRequest.Builder#timeout */ public void setReadTimeout(Duration readTimeout) { Assert.notNull(readTimeout, "readTimeout is required"); - this.readTimeout = readTimeout; + this.readTimeout = (Duration.ZERO.equals(readTimeout) ? null : readTimeout); } /** diff --git a/spring-web/src/test/java/org/springframework/http/client/reactive/ClientHttpConnectorTests.java b/spring-web/src/test/java/org/springframework/http/client/reactive/ClientHttpConnectorTests.java index 1a5d3411ada..e99bfcea905 100644 --- a/spring-web/src/test/java/org/springframework/http/client/reactive/ClientHttpConnectorTests.java +++ b/spring-web/src/test/java/org/springframework/http/client/reactive/ClientHttpConnectorTests.java @@ -241,6 +241,19 @@ class ClientHttpConnectorTests { } + @Test + void readTimeoutZeroWithJdk() { + JdkClientHttpConnector connector = new JdkClientHttpConnector(); + connector.setReadTimeout(Duration.ZERO); + + prepareResponse(builder -> builder.code(200)); + Mono futureResponse = + connector.connect(HttpMethod.GET, this.server.url("/").uri(), ReactiveHttpOutputMessage::setComplete); + StepVerifier.create(futureResponse) + .assertNext(response -> assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK)) + .verifyComplete(); + } + private Buffer randomBody(int size) { Buffer responseBody = new Buffer(); Random rnd = new Random();