Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -499,22 +499,28 @@ public CompletableFuture<Void> connectAsync(Exchange<?> exchange) {
}, exchange.parentExecutor.safeDelegate());
}

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

// In case of connection timeout, set up a timeout on the handshakeCfCf.
// Note: this is a different timeout than the direct connection timeout.
if (timeout.isPresent()) {
Duration timeout = client().connectTimeout().orElse(null);
if (timeout != null) {
// In case of timeout we need to close the quic connection
debug.log("setting up quic connect timeout: " + timeout.get().toMillis());
debug.log("setting up quic connect timeout: " + timeout);
long timeoutMillis;
try {
timeoutMillis = timeout.toMillis();
} catch (ArithmeticException _) {
timeoutMillis = Long.MAX_VALUE;
}
fxi = handshakeCfCf.completeOnTimeout(
MinimalFuture.failedFuture(new HttpConnectTimeoutException("quic connect timeout")),
timeout.get().toMillis(), TimeUnit.MILLISECONDS);
timeoutMillis, TimeUnit.MILLISECONDS);
}

// If we have set up any timeout, arrange to close the quicConnection
// if one of the timeout expires
if (timeout.isPresent() || directTimeout.isPresent()) {
if (timeout != null || directTimeout.isPresent()) {
fxi = fxi.handleAsync(this::handleTimeout, exchange.parentExecutor.safeDelegate());
}
return fxi.thenCompose(Function.identity());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -28,14 +28,22 @@
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;

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

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


/**
* Returns a copy of this deadline with the specified duration in nanoseconds added.
* {@return a deadline with the specified duration in nanoseconds added}
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On {@linkplain ##overflow numeric overflows}, this method will return
* {@link Deadline#MAX} if the provided duration is positive,
* {@link Deadline#MIN} otherwise.
*
* @param nanosToAdd the nanoseconds to add, positive or negative
* @return a {@code Deadline} based on this deadline with the specified nanoseconds added, not null
* @throws DateTimeException if the result exceeds the maximum or minimum deadline
* @throws ArithmeticException if numeric overflow occurs
*/
public Deadline plusNanos(long nanosToAdd) {
return new Deadline(deadline.plusNanos(nanosToAdd));
if (nanosToAdd == 0) return this;
try {
return new Deadline(deadline.plusNanos(nanosToAdd));
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
return nanosToAdd > 0 ? Deadline.MAX : Deadline.MIN;
}
}

/**
Expand Down Expand Up @@ -89,92 +104,116 @@ public Deadline truncatedTo(ChronoUnit unit) {
}

/**
* Returns a copy of this deadline with the specified amount subtracted.
* <p>
* This returns a {@code Deadline}, based on this one, with the specified amount subtracted.
* The amount is typically {@link Duration} but may be any other type implementing
* the {@link TemporalAmount} interface.
* {@return a deadline with the specified amount subtracted from this deadline}
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On {@linkplain ##overflow numeric overflows}, this method will return
* {@link Deadline#MIN} if the provided duration is positive,
* {@link Deadline#MAX} otherwise.
*
* @param amountToSubtract the amount to subtract, not null
* @return a {@code Deadline} based on this deadline with the subtraction made, not null
* @throws DateTimeException if the subtraction cannot be made
* @throws ArithmeticException if numeric overflow occurs
* @param duration the amount to subtract, not null
*/
public Deadline minus(TemporalAmount amountToSubtract) {
return Deadline.of(deadline.minus(amountToSubtract));
public Deadline minus(Duration duration) {
if (duration.isZero()) return this;
try {
return Deadline.of(deadline.minus(duration));
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
return duration.isPositive() ? Deadline.MIN : Deadline.MAX;
}
}

/**
* Returns a copy of this deadline with the specified amount added.
* {@return a deadline with the specified amount added to this deadline}
* <p>
* This returns a {@code Deadline}, based on this one, with the amount
* in terms of the unit added. If it is not possible to add the amount, because the
* unit is not supported or for some other reason, an exception is thrown.
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On {@linkplain ##overflow numeric overflows}, this method will return
* {@link Deadline#MAX} if the provided amount is positive,
* {@link Deadline#MIN} otherwise.
*
* @see Instant#plus(long, TemporalUnit)
*
* @param amountToAdd the amount of the unit to add to the result, may be negative
* @param unit the unit of the amount to add, not null
* @return a {@code Deadline} based on this deadline with the specified amount added, not null
* @throws DateTimeException if the addition cannot be made
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
public Deadline plus(long amountToAdd, TemporalUnit unit) {
if (amountToAdd == 0) return this;
return Deadline.of(deadline.plus(amountToAdd, unit));
try {
return Deadline.of(deadline.plus(amountToAdd, unit));
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
return amountToAdd > 0 ? Deadline.MAX : Deadline.MIN;
}
}

/**
* Returns a copy of this deadline with the specified duration in seconds added.
* {@return a deadline with the specified duration in seconds added to this deadline}
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On {@linkplain ##overflow numeric overflows}, this method will return
* {@link Deadline#MAX} if the provided duration is positive,
* {@link Deadline#MIN} otherwise.
*
* @param secondsToAdd the seconds to add, positive or negative
* @return a {@code Deadline} based on this deadline with the specified seconds added, not null
* @throws DateTimeException if the result exceeds the maximum or minimum deadline
* @throws ArithmeticException if numeric overflow occurs
*/
public Deadline plusSeconds(long secondsToAdd) {
if (secondsToAdd == 0) return this;
return Deadline.of(deadline.plusSeconds(secondsToAdd));
try {
return Deadline.of(deadline.plusSeconds(secondsToAdd));
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
return secondsToAdd > 0 ? Deadline.MAX : Deadline.MIN;
}
}

/**
* Returns a copy of this deadline with the specified duration in milliseconds added.
* {@return a deadline with the specified duration in milliseconds added to this deadline}
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On {@linkplain ##overflow numeric overflows}, this method will return
* {@link Deadline#MAX} if the provided duration is positive,
* {@link Deadline#MIN} otherwise.
*
* @param millisToAdd the milliseconds to add, positive or negative
* @return a {@code Deadline} based on this deadline with the specified milliseconds added, not null
* @throws DateTimeException if the result exceeds the maximum or minimum deadline
* @throws ArithmeticException if numeric overflow occurs
*/
public Deadline plusMillis(long millisToAdd) {
if (millisToAdd == 0) return this;
return Deadline.of(deadline.plusMillis(millisToAdd));
try {
return Deadline.of(deadline.plusMillis(millisToAdd));
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
return millisToAdd > 0 ? Deadline.MAX : Deadline.MIN;
}
}

/**
* Returns a copy of this deadline with the specified amount added.
* <p>
* This returns a {@code Deadline}, based on this one, with the specified amount added.
* The amount is typically {@link Duration} but may be any other type implementing
* the {@link TemporalAmount} interface.
* {@return a deadline with the specified duration added to this deadline}
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On {@linkplain ##overflow numeric overflows}, this method will return
* {@link Deadline#MAX} if the provided duration is positive,
* {@link Deadline#MIN} otherwise.
*
* @param amountToAdd the amount to add, not null
* @return a {@code Deadline} based on this deadline with the addition made, not null
* @throws DateTimeException if the addition cannot be made
* @throws ArithmeticException if numeric overflow occurs
* @param duration the duration to add, not null
*/
public Deadline plus(TemporalAmount amountToAdd) {
return Deadline.of(deadline.plus(amountToAdd));
public Deadline plus(Duration duration) {
if (duration.isZero()) return this;
try {
return Deadline.of(deadline.plus(duration));
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
return duration.isPositive() ? Deadline.MAX : Deadline.MIN;
}
}

/**
Expand All @@ -188,16 +227,24 @@ public Deadline plus(TemporalAmount amountToAdd) {
* complete units between the two deadlines.
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On {@linkplain ##overflow numeric overflows}, this method will return
* {@link Long#MAX_VALUE} if the current deadline is before the provided end
* deadline, {@link Long#MIN_VALUE} otherwise.
*
* @param endExclusive the end deadline, exclusive
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this deadline and the end deadline
* @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
public long until(Deadline endExclusive, TemporalUnit unit) {
return deadline.until(endExclusive.deadline, unit);
try {
return deadline.until(endExclusive.deadline, unit);
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
int delta = compareTo(endExclusive);
return delta < 0 ? Long.MAX_VALUE : Long.MIN_VALUE;
}
}

/**
Expand Down Expand Up @@ -266,10 +313,13 @@ static Deadline of(Instant instant) {
* @param startInclusive the start deadline, inclusive, not null
* @param endExclusive the end deadline, exclusive, not null
* @return a {@code Duration}, not null
* @throws DateTimeException if the seconds between the deadline cannot be obtained
* @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration}
*/
public static Duration between(Deadline startInclusive, Deadline endExclusive) {
if (startInclusive.equals(endExclusive)) return Duration.ZERO;
// `Deadline` works with `Instant` under the hood.
// Delta between `Instant.MIN` and `Instant.MAX` fits in a `Duration`.
// Hence, we should never receive a numeric overflow while calculating the delta between two deadlines.
return Duration.between(startInclusive.deadline, endExclusive.deadline);
}

}
Loading