Overview
While investigating #37425, I noticed that some of our ClientHttpRequestFactory implementations convert a Duration timeout to an int via (int) duration.toMillis(). For any Duration greater than Integer.MAX_VALUE milliseconds (~24.8 days), this narrowing cast silently overflows.
This affects the following methods.
SimpleClientHttpRequestFactory#setConnectTimeout(Duration)
SimpleClientHttpRequestFactory#setReadTimeout(Duration)
ReactorClientHttpRequestFactory#setConnectTimeout(Duration)
Depending on the value, the result is either negative or an unrelated positive value. For example:
Duration.ofDays(25) results in -2134967296, which SimpleClientHttpRequestFactory silently ignores (falling back to the system default) and which ReactorClientHttpRequestFactory rejects with a misleading "Timeout must be a non-negative value" message.
Duration.ofDays(50) results in 25032704, so a timeout intended to be "practically infinite" silently becomes ~25 seconds.
Configuring a very large Duration is a plausible way to express "no timeout", especially since 0 has not been consistently supported prior to Spring Framework 7.1 (see #37425).
Note, however, that HttpComponentsClientHttpRequestFactory and JettyClientHttpRequestFactory store timeouts as long, and the JDK-based implementations pass the Duration through as is, so they are not affected.
Proposal
Limit the converted value to Integer.MAX_VALUE milliseconds (~24.8 days), so that a very large timeout remains a very large timeout instead of overflowing.
In addition, negative Duration values must be rejected before the conversion, since a large negative Duration (for example, Duration.ofDays(-25)) currently overflows to a positive value.
Related Issues
Overview
While investigating #37425, I noticed that some of our
ClientHttpRequestFactoryimplementations convert aDurationtimeout to anintvia(int) duration.toMillis(). For anyDurationgreater thanInteger.MAX_VALUEmilliseconds (~24.8 days), this narrowing cast silently overflows.This affects the following methods.
SimpleClientHttpRequestFactory#setConnectTimeout(Duration)SimpleClientHttpRequestFactory#setReadTimeout(Duration)ReactorClientHttpRequestFactory#setConnectTimeout(Duration)Depending on the value, the result is either negative or an unrelated positive value. For example:
Duration.ofDays(25)results in-2134967296, whichSimpleClientHttpRequestFactorysilently ignores (falling back to the system default) and whichReactorClientHttpRequestFactoryrejects with a misleading "Timeout must be a non-negative value" message.Duration.ofDays(50)results in25032704, so a timeout intended to be "practically infinite" silently becomes ~25 seconds.Configuring a very large
Durationis a plausible way to express "no timeout", especially since0has not been consistently supported prior to Spring Framework 7.1 (see #37425).Note, however, that
HttpComponentsClientHttpRequestFactoryandJettyClientHttpRequestFactorystore timeouts aslong, and the JDK-based implementations pass theDurationthrough as is, so they are not affected.Proposal
Limit the converted value to
Integer.MAX_VALUEmilliseconds (~24.8 days), so that a very large timeout remains a very large timeout instead of overflowing.In addition, negative
Durationvalues must be rejected before the conversion, since a large negativeDuration(for example,Duration.ofDays(-25)) currently overflows to a positive value.Related Issues
0as no timeout in HTTP client support #37425