Skip to content

Commit ce72c8c

Browse files
committed
add per-stream idle timeout and suppress CancelledKeyException on cancel
; Handle cancelled SelectionKey in interestOps access
1 parent 5842310 commit ce72c8c

File tree

7 files changed

+393
-151
lines changed

7 files changed

+393
-151
lines changed

httpcore5-h2/src/main/java/org/apache/hc/core5/http2/H2StreamTimeoutException.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*/
2727
package org.apache.hc.core5.http2;
2828

29-
import java.net.SocketTimeoutException;
29+
import java.io.InterruptedIOException;
3030

3131
import org.apache.hc.core5.util.Timeout;
3232

@@ -51,7 +51,7 @@
5151
*
5252
* @since 5.4
5353
*/
54-
public class H2StreamTimeoutException extends SocketTimeoutException {
54+
public class H2StreamTimeoutException extends InterruptedIOException {
5555

5656
private static final long serialVersionUID = 1L;
5757

httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java

Lines changed: 16 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -439,10 +439,6 @@ public final void onInput(final ByteBuffer src) throws HttpException, IOExceptio
439439
for (;;) {
440440
final RawFrame frame = inputBuffer.read(src, ioSession);
441441
if (frame != null) {
442-
if (connState.compareTo(ConnectionHandshake.SHUTDOWN) < 0) {
443-
checkStreamTimeouts(System.nanoTime());
444-
}
445-
446442
if (streamListener != null) {
447443
streamListener.onFrameInput(this, frame.getStreamId(), frame);
448444
}
@@ -655,7 +651,6 @@ private void executeRequest(final RequestExecutionCommand requestExecutionComman
655651
requestExecutionCommand.getExchangeHandler(),
656652
requestExecutionCommand.getPushHandlerFactory(),
657653
requestExecutionCommand.getContext()));
658-
initializeStreamTimeouts(stream);
659654

660655
if (streamListener != null) {
661656
final int initInputWindow = stream.getInputWindow().get();
@@ -1377,9 +1372,12 @@ H2StreamChannel createChannel(final int streamId) {
13771372
}
13781373

13791374
private void initializeStreamTimeouts(final H2Stream stream) {
1380-
final Timeout socketTimeout = ioSession.getSocketTimeout();
1381-
if (socketTimeout != null && socketTimeout.isEnabled()) {
1382-
stream.setIdleTimeout(socketTimeout);
1375+
final Timeout streamIdleTimeout = stream.getIdleTimeout();
1376+
if (streamIdleTimeout == null || !streamIdleTimeout.isEnabled()) {
1377+
final Timeout socketTimeout = ioSession.getSocketTimeout();
1378+
if (socketTimeout != null && socketTimeout.isEnabled()) {
1379+
stream.setIdleTimeout(socketTimeout);
1380+
}
13831381
}
13841382
}
13851383

@@ -1614,43 +1612,21 @@ private void checkStreamTimeouts(final long nowNanos) throws IOException {
16141612
}
16151613

16161614
final Timeout idleTimeout = stream.getIdleTimeout();
1617-
final Timeout lifetimeTimeout = stream.getLifetimeTimeout();
1618-
if ((idleTimeout == null || !idleTimeout.isEnabled())
1619-
&& (lifetimeTimeout == null || !lifetimeTimeout.isEnabled())) {
1615+
if (idleTimeout == null || !idleTimeout.isEnabled()) {
16201616
continue;
16211617
}
16221618

1623-
final long created = stream.getCreatedNanos();
16241619
final long last = stream.getLastActivityNanos();
1625-
1626-
if (idleTimeout != null && idleTimeout.isEnabled()) {
1627-
final long idleNanos = idleTimeout.toNanoseconds();
1628-
if (idleNanos > 0 && nowNanos - last > idleNanos) {
1629-
final int streamId = stream.getId();
1630-
final H2StreamTimeoutException ex = new H2StreamTimeoutException(
1631-
"HTTP/2 stream idle timeout (" + idleTimeout + ")",
1632-
streamId,
1633-
idleTimeout,
1634-
true);
1635-
stream.localReset(ex, H2Error.CANCEL);
1636-
// Once reset due to idle timeout, we do not care about lifetime anymore
1637-
continue;
1638-
}
1639-
}
1640-
1641-
if (lifetimeTimeout != null && lifetimeTimeout.isEnabled()) {
1642-
final long lifeNanos = lifetimeTimeout.toNanoseconds();
1643-
if (lifeNanos > 0 && nowNanos - created > lifeNanos) {
1644-
final int streamId = stream.getId();
1645-
final H2StreamTimeoutException ex = new H2StreamTimeoutException(
1646-
"HTTP/2 stream lifetime timeout (" + lifetimeTimeout + ")",
1647-
streamId,
1648-
lifetimeTimeout,
1649-
false);
1650-
stream.localReset(ex, H2Error.CANCEL);
1651-
}
1620+
final long idleNanos = idleTimeout.toNanoseconds();
1621+
if (idleNanos > 0 && nowNanos - last > idleNanos) {
1622+
final int streamId = stream.getId();
1623+
final H2StreamTimeoutException ex = new H2StreamTimeoutException(
1624+
"HTTP/2 stream idle timeout (" + idleTimeout + ")",
1625+
streamId,
1626+
idleTimeout,
1627+
true);
1628+
stream.localReset(ex, H2Error.CANCEL);
16521629
}
16531630
}
16541631
}
1655-
16561632
}

httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/H2Stream.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,13 @@ boolean isOutputReady() {
218218

219219
void produceOutput() throws HttpException, IOException {
220220
try {
221+
if (channel.isLocalReset()) {
222+
return;
223+
}
224+
if (cancelled.get()) {
225+
localResetCancelled();
226+
return;
227+
}
221228
touch();
222229

223230
handler.produceOutput();
@@ -227,6 +234,13 @@ void produceOutput() throws HttpException, IOException {
227234
}
228235

229236
void produceInputCapacityUpdate() throws IOException {
237+
if (channel.isLocalReset()) {
238+
return;
239+
}
240+
if (cancelled.get()) {
241+
localResetCancelled();
242+
return;
243+
}
230244
touch();
231245
handler.updateInputCapacity();
232246
}

0 commit comments

Comments
 (0)