Skip to content

Commit c754e3e

Browse files
committed
8368528: HttpClient.Builder.connectTimeout should accept arbitrarily large values
Reviewed-by: dfuchs
1 parent 3f40f4c commit c754e3e

File tree

5 files changed

+621
-57
lines changed

5 files changed

+621
-57
lines changed

src/java.net.http/share/classes/jdk/internal/net/http/HttpQuicConnection.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -499,22 +499,28 @@ public CompletableFuture<Void> connectAsync(Exchange<?> exchange) {
499499
}, exchange.parentExecutor.safeDelegate());
500500
}
501501

502-
Optional<Duration> timeout = client().connectTimeout();
503502
CompletableFuture<CompletableFuture<Void>> fxi = handshakeCfCf;
504503

505504
// In case of connection timeout, set up a timeout on the handshakeCfCf.
506505
// Note: this is a different timeout than the direct connection timeout.
507-
if (timeout.isPresent()) {
506+
Duration timeout = client().connectTimeout().orElse(null);
507+
if (timeout != null) {
508508
// In case of timeout we need to close the quic connection
509-
debug.log("setting up quic connect timeout: " + timeout.get().toMillis());
509+
debug.log("setting up quic connect timeout: " + timeout);
510+
long timeoutMillis;
511+
try {
512+
timeoutMillis = timeout.toMillis();
513+
} catch (ArithmeticException _) {
514+
timeoutMillis = Long.MAX_VALUE;
515+
}
510516
fxi = handshakeCfCf.completeOnTimeout(
511517
MinimalFuture.failedFuture(new HttpConnectTimeoutException("quic connect timeout")),
512-
timeout.get().toMillis(), TimeUnit.MILLISECONDS);
518+
timeoutMillis, TimeUnit.MILLISECONDS);
513519
}
514520

515521
// If we have set up any timeout, arrange to close the quicConnection
516522
// if one of the timeout expires
517-
if (timeout.isPresent() || directTimeout.isPresent()) {
523+
if (timeout != null || directTimeout.isPresent()) {
518524
fxi = fxi.handleAsync(this::handleTimeout, exchange.parentExecutor.safeDelegate());
519525
}
520526
return fxi.thenCompose(Function.identity());

src/java.net.http/share/classes/jdk/internal/net/http/common/Deadline.java

Lines changed: 102 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -28,14 +28,22 @@
2828
import java.time.Duration;
2929
import java.time.Instant;
3030
import java.time.temporal.ChronoUnit;
31-
import java.time.temporal.Temporal;
32-
import java.time.temporal.TemporalAccessor;
33-
import java.time.temporal.TemporalAmount;
3431
import java.time.temporal.TemporalUnit;
3532
import java.time.temporal.UnsupportedTemporalTypeException;
3633

3734
/**
38-
* A Deadline represents an instant on a {@linkplain TimeLine time line}.
35+
* An instantaneous point on the {@linkplain TimeLine time-line}.
36+
* <p>
37+
* This class is immutable and thread-safe.
38+
* <p id="overflow">
39+
* Operations that add or subtract durations to a {@code Deadline}, whether
40+
* represented as a {@link Duration} or as a {@code long} time increment (such
41+
* as seconds or nanoseconds) do not throw on numeric overflow if the resulting
42+
* {@code Deadline} would exceed {@link #MAX} or be less than {@link #MIN}.
43+
* Instead, {@code MAX} or {@code MIN} is returned, respectively. Similarly,
44+
* methods that return a duration as a {@code long} will either return
45+
* {@link Long#MAX_VALUE} or {@link Long#MIN_VALUE} if the returned quantity
46+
* would exceed the capacity of a {@code long}.
3947
*/
4048
public final class Deadline implements Comparable<Deadline> {
4149

@@ -49,17 +57,24 @@ private Deadline(Instant deadline) {
4957

5058

5159
/**
52-
* Returns a copy of this deadline with the specified duration in nanoseconds added.
60+
* {@return a deadline with the specified duration in nanoseconds added}
5361
* <p>
5462
* This instance is immutable and unaffected by this method call.
63+
* <p>
64+
* On {@linkplain ##overflow numeric overflows}, this method will return
65+
* {@link Deadline#MAX} if the provided duration is positive,
66+
* {@link Deadline#MIN} otherwise.
5567
*
5668
* @param nanosToAdd the nanoseconds to add, positive or negative
57-
* @return a {@code Deadline} based on this deadline with the specified nanoseconds added, not null
58-
* @throws DateTimeException if the result exceeds the maximum or minimum deadline
59-
* @throws ArithmeticException if numeric overflow occurs
6069
*/
6170
public Deadline plusNanos(long nanosToAdd) {
62-
return new Deadline(deadline.plusNanos(nanosToAdd));
71+
if (nanosToAdd == 0) return this;
72+
try {
73+
return new Deadline(deadline.plusNanos(nanosToAdd));
74+
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
75+
ArithmeticException _) { // "long overflow"
76+
return nanosToAdd > 0 ? Deadline.MAX : Deadline.MIN;
77+
}
6378
}
6479

6580
/**
@@ -89,92 +104,116 @@ public Deadline truncatedTo(ChronoUnit unit) {
89104
}
90105

91106
/**
92-
* Returns a copy of this deadline with the specified amount subtracted.
93-
* <p>
94-
* This returns a {@code Deadline}, based on this one, with the specified amount subtracted.
95-
* The amount is typically {@link Duration} but may be any other type implementing
96-
* the {@link TemporalAmount} interface.
107+
* {@return a deadline with the specified amount subtracted from this deadline}
97108
* <p>
98109
* This instance is immutable and unaffected by this method call.
110+
* <p>
111+
* On {@linkplain ##overflow numeric overflows}, this method will return
112+
* {@link Deadline#MIN} if the provided duration is positive,
113+
* {@link Deadline#MAX} otherwise.
99114
*
100-
* @param amountToSubtract the amount to subtract, not null
101-
* @return a {@code Deadline} based on this deadline with the subtraction made, not null
102-
* @throws DateTimeException if the subtraction cannot be made
103-
* @throws ArithmeticException if numeric overflow occurs
115+
* @param duration the amount to subtract, not null
104116
*/
105-
public Deadline minus(TemporalAmount amountToSubtract) {
106-
return Deadline.of(deadline.minus(amountToSubtract));
117+
public Deadline minus(Duration duration) {
118+
if (duration.isZero()) return this;
119+
try {
120+
return Deadline.of(deadline.minus(duration));
121+
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
122+
ArithmeticException _) { // "long overflow"
123+
return duration.isPositive() ? Deadline.MIN : Deadline.MAX;
124+
}
107125
}
108126

109127
/**
110-
* Returns a copy of this deadline with the specified amount added.
128+
* {@return a deadline with the specified amount added to this deadline}
111129
* <p>
112130
* This returns a {@code Deadline}, based on this one, with the amount
113131
* in terms of the unit added. If it is not possible to add the amount, because the
114132
* unit is not supported or for some other reason, an exception is thrown.
115133
* <p>
116134
* This instance is immutable and unaffected by this method call.
135+
* <p>
136+
* On {@linkplain ##overflow numeric overflows}, this method will return
137+
* {@link Deadline#MAX} if the provided amount is positive,
138+
* {@link Deadline#MIN} otherwise.
117139
*
118140
* @see Instant#plus(long, TemporalUnit)
119141
*
120142
* @param amountToAdd the amount of the unit to add to the result, may be negative
121143
* @param unit the unit of the amount to add, not null
122-
* @return a {@code Deadline} based on this deadline with the specified amount added, not null
123-
* @throws DateTimeException if the addition cannot be made
124144
* @throws UnsupportedTemporalTypeException if the unit is not supported
125-
* @throws ArithmeticException if numeric overflow occurs
126145
*/
127146
public Deadline plus(long amountToAdd, TemporalUnit unit) {
128147
if (amountToAdd == 0) return this;
129-
return Deadline.of(deadline.plus(amountToAdd, unit));
148+
try {
149+
return Deadline.of(deadline.plus(amountToAdd, unit));
150+
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
151+
ArithmeticException _) { // "long overflow"
152+
return amountToAdd > 0 ? Deadline.MAX : Deadline.MIN;
153+
}
130154
}
131155

132156
/**
133-
* Returns a copy of this deadline with the specified duration in seconds added.
157+
* {@return a deadline with the specified duration in seconds added to this deadline}
134158
* <p>
135159
* This instance is immutable and unaffected by this method call.
160+
* <p>
161+
* On {@linkplain ##overflow numeric overflows}, this method will return
162+
* {@link Deadline#MAX} if the provided duration is positive,
163+
* {@link Deadline#MIN} otherwise.
136164
*
137165
* @param secondsToAdd the seconds to add, positive or negative
138-
* @return a {@code Deadline} based on this deadline with the specified seconds added, not null
139-
* @throws DateTimeException if the result exceeds the maximum or minimum deadline
140-
* @throws ArithmeticException if numeric overflow occurs
141166
*/
142167
public Deadline plusSeconds(long secondsToAdd) {
143168
if (secondsToAdd == 0) return this;
144-
return Deadline.of(deadline.plusSeconds(secondsToAdd));
169+
try {
170+
return Deadline.of(deadline.plusSeconds(secondsToAdd));
171+
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
172+
ArithmeticException _) { // "long overflow"
173+
return secondsToAdd > 0 ? Deadline.MAX : Deadline.MIN;
174+
}
145175
}
146176

147177
/**
148-
* Returns a copy of this deadline with the specified duration in milliseconds added.
178+
* {@return a deadline with the specified duration in milliseconds added to this deadline}
149179
* <p>
150180
* This instance is immutable and unaffected by this method call.
181+
* <p>
182+
* On {@linkplain ##overflow numeric overflows}, this method will return
183+
* {@link Deadline#MAX} if the provided duration is positive,
184+
* {@link Deadline#MIN} otherwise.
151185
*
152186
* @param millisToAdd the milliseconds to add, positive or negative
153-
* @return a {@code Deadline} based on this deadline with the specified milliseconds added, not null
154-
* @throws DateTimeException if the result exceeds the maximum or minimum deadline
155-
* @throws ArithmeticException if numeric overflow occurs
156187
*/
157188
public Deadline plusMillis(long millisToAdd) {
158189
if (millisToAdd == 0) return this;
159-
return Deadline.of(deadline.plusMillis(millisToAdd));
190+
try {
191+
return Deadline.of(deadline.plusMillis(millisToAdd));
192+
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
193+
ArithmeticException _) { // "long overflow"
194+
return millisToAdd > 0 ? Deadline.MAX : Deadline.MIN;
195+
}
160196
}
161197

162198
/**
163-
* Returns a copy of this deadline with the specified amount added.
164-
* <p>
165-
* This returns a {@code Deadline}, based on this one, with the specified amount added.
166-
* The amount is typically {@link Duration} but may be any other type implementing
167-
* the {@link TemporalAmount} interface.
199+
* {@return a deadline with the specified duration added to this deadline}
168200
* <p>
169201
* This instance is immutable and unaffected by this method call.
202+
* <p>
203+
* On {@linkplain ##overflow numeric overflows}, this method will return
204+
* {@link Deadline#MAX} if the provided duration is positive,
205+
* {@link Deadline#MIN} otherwise.
170206
*
171-
* @param amountToAdd the amount to add, not null
172-
* @return a {@code Deadline} based on this deadline with the addition made, not null
173-
* @throws DateTimeException if the addition cannot be made
174-
* @throws ArithmeticException if numeric overflow occurs
207+
* @param duration the duration to add, not null
175208
*/
176-
public Deadline plus(TemporalAmount amountToAdd) {
177-
return Deadline.of(deadline.plus(amountToAdd));
209+
public Deadline plus(Duration duration) {
210+
if (duration.isZero()) return this;
211+
try {
212+
return Deadline.of(deadline.plus(duration));
213+
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
214+
ArithmeticException _) { // "long overflow"
215+
return duration.isPositive() ? Deadline.MAX : Deadline.MIN;
216+
}
178217
}
179218

180219
/**
@@ -188,16 +227,24 @@ public Deadline plus(TemporalAmount amountToAdd) {
188227
* complete units between the two deadlines.
189228
* <p>
190229
* This instance is immutable and unaffected by this method call.
230+
* <p>
231+
* On {@linkplain ##overflow numeric overflows}, this method will return
232+
* {@link Long#MAX_VALUE} if the current deadline is before the provided end
233+
* deadline, {@link Long#MIN_VALUE} otherwise.
191234
*
192235
* @param endExclusive the end deadline, exclusive
193236
* @param unit the unit to measure the amount in, not null
194237
* @return the amount of time between this deadline and the end deadline
195-
* @throws DateTimeException if the amount cannot be calculated
196238
* @throws UnsupportedTemporalTypeException if the unit is not supported
197-
* @throws ArithmeticException if numeric overflow occurs
198239
*/
199240
public long until(Deadline endExclusive, TemporalUnit unit) {
200-
return deadline.until(endExclusive.deadline, unit);
241+
try {
242+
return deadline.until(endExclusive.deadline, unit);
243+
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
244+
ArithmeticException _) { // "long overflow"
245+
int delta = compareTo(endExclusive);
246+
return delta < 0 ? Long.MAX_VALUE : Long.MIN_VALUE;
247+
}
201248
}
202249

203250
/**
@@ -266,10 +313,13 @@ static Deadline of(Instant instant) {
266313
* @param startInclusive the start deadline, inclusive, not null
267314
* @param endExclusive the end deadline, exclusive, not null
268315
* @return a {@code Duration}, not null
269-
* @throws DateTimeException if the seconds between the deadline cannot be obtained
270-
* @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration}
271316
*/
272317
public static Duration between(Deadline startInclusive, Deadline endExclusive) {
318+
if (startInclusive.equals(endExclusive)) return Duration.ZERO;
319+
// `Deadline` works with `Instant` under the hood.
320+
// Delta between `Instant.MIN` and `Instant.MAX` fits in a `Duration`.
321+
// Hence, we should never receive a numeric overflow while calculating the delta between two deadlines.
273322
return Duration.between(startInclusive.deadline, endExclusive.deadline);
274323
}
324+
275325
}

0 commit comments

Comments
 (0)