Skip to content

Consistently treat 0 as no timeout in HTTP client support #37425

Description

@sbrannen

Overview

While investigating #37423, it became apparent that our HTTP client support is inconsistent in how it handles a timeout of 0. This issue supersedes that issue, and instead of rejecting non-positive values in JettyClientHttpRequestFactory, we will consistently treat 0 as "no timeout" for all timeouts in our HTTP client support, which is the norm for socket timeout settings.

Rationale: 0 has no other sensible meaning for a timeout, and for setters that reject negative values, there is otherwise no way to configure "no timeout".

Connect Timeouts

The current state for connect timeouts (and the connection request timeout for Apache HttpComponents) is as follows.

  • SimpleClientHttpRequestFactory: 0 is infinite, but negative int values are silently ignored (falling back to the system default), and sub-millisecond Duration values are truncated to 0 and therefore treated as infinite.
  • HttpComponentsClientHttpRequestFactory: 0 is infinite, but sub-millisecond Duration values are truncated to 0 and therefore treated as infinite.
  • ReactorClientHttpRequestFactory: 0 is infinite, but sub-millisecond Duration values are truncated to 0 and therefore treated as infinite.
  • JettyClientHttpRequestFactory: 0 is infinite, but setConnectTimeout(Duration) accepts negative values, and sub-millisecond Duration values are truncated to 0 and therefore treated as infinite.

Note that JdkClientHttpRequestFactory does not support configuring a connect timeout, which is configured on the java.net.http.HttpClient instead.

Read Timeouts

The current state for read timeouts is as follows.

  • SimpleClientHttpRequestFactory: 0 is infinite (delegates to URLConnection), but negative values are silently ignored (falling back to the system default), and sub-millisecond Duration values are truncated to 0 and therefore treated as infinite.
  • HttpComponentsClientHttpRequestFactory: 0 is infinite, but sub-millisecond Duration values are truncated to 0 and therefore treated as infinite.
  • JdkClientHttpRequestFactory: 0 is infinite since #37234, but this is only documented for setReadTimeout(int).
  • JdkClientHttpConnector: 0 is infinite since #37412, but negative values are only rejected by the JDK when a request is executed.
  • ReactorClientHttpRequestFactory: 0 is rejected.
  • JettyClientHttpRequestFactory: setReadTimeout(long) rejects 0, whereas setReadTimeout(Duration) accepts Duration.ZERO, which then results in every request failing with IOException: Request timed out.

HTTP Service Clients

AbstractReactorHttpExchangeAdapter#setBlockTimeout(Duration) (used by HTTP Service clients) currently only supports null as "no timeout". A block timeout of Duration.ZERO results in every blocking request failing immediately with IllegalStateException: Timeout on blocking read.

Proposal

  • ReactorClientHttpRequestFactory: accept 0 for the read timeout and map it to HttpClient.responseTimeout(null). Note that Reactor Netty raises a Duration below 1ms to 1ms, so Duration.ZERO cannot simply be passed through. Since the default client is configured with a 10 second response timeout, 0 must explicitly reset it.
  • JettyClientHttpRequestFactory: accept 0 for both read timeout variants, and avoid the immediate timeout in JettyClientHttpRequest when waiting for the response.
  • AbstractReactorHttpExchangeAdapter: treat a block timeout of Duration.ZERO as "no timeout".
  • Only treat an actual zero value as "no timeout". Negative values are rejected for all timeouts, and sub-millisecond Duration values are rejected wherever they would otherwise be truncated to 0. The JDK-based implementations pass the Duration through as is, so they continue to accept sub-millisecond values.
  • Consistently document "A timeout value of 0 specifies an infinite timeout." for all timeout setters.

Note that this is a change in behavior for the following.

  • SimpleClientHttpRequestFactory: currently silently ignores negative values (falling back to the system default) and treats sub-millisecond Duration values as infinite.
  • HttpComponentsClientHttpRequestFactory: currently treats sub-millisecond Duration values as infinite for the read timeout and the connection request timeout.
  • ReactorClientHttpRequestFactory: currently treats sub-millisecond Duration values as infinite for the connect timeout.
  • JettyClientHttpRequestFactory: currently accepts negative Duration values and treats sub-millisecond Duration values as infinite for the connect timeout.
  • AbstractReactorHttpExchangeAdapter: currently accepts negative Duration values for the block timeout.

Related Issues

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

for: upgrade-attentionAn issue requiring extra attention when upgradingin: webIssues in web modules (web, webmvc, webflux, websocket)type: enhancementA general enhancement

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions