From 4c22ae9e1bff44b90cc7d2abf93fc813a14916a8 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 2 Nov 2021 22:46:35 +0100 Subject: [PATCH] Issue #6728 - QUIC and HTTP/3 - Fixed idle timeout handling. Signed-off-by: Simone Bordet --- .../server/internal/HttpChannelOverHTTP3.java | 50 ++++++++++++------- .../jetty/http/client/ServerTimeoutsTest.java | 4 +- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/jetty-http3/http3-server/src/main/java/org/eclipse/jetty/http3/server/internal/HttpChannelOverHTTP3.java b/jetty-http3/http3-server/src/main/java/org/eclipse/jetty/http3/server/internal/HttpChannelOverHTTP3.java index 6fb073bcc74..106f7199899 100644 --- a/jetty-http3/http3-server/src/main/java/org/eclipse/jetty/http3/server/internal/HttpChannelOverHTTP3.java +++ b/jetty-http3/http3-server/src/main/java/org/eclipse/jetty/http3/server/internal/HttpChannelOverHTTP3.java @@ -64,6 +64,12 @@ public class HttpChannelOverHTTP3 extends HttpChannel return (HttpTransportOverHTTP3)super.getHttpTransport(); } + @Override + public void setIdleTimeout(long timeoutMs) + { + stream.setIdleTimeout(timeoutMs); + } + void consumeInput() { getRequest().getHttpInput().consumeAll(); @@ -226,36 +232,44 @@ public class HttpChannelOverHTTP3 extends HttpChannel public boolean onIdleTimeout(Throwable failure, Consumer consumer) { - try (AutoLock l = lock.lock()) - { - if (content == null) - content = new HttpInput.ErrorContent(failure); - else - return false; - } - boolean wasDelayed = delayedUntilContent; delayedUntilContent = false; if (wasDelayed) connection.setApplicationMode(true); - boolean reset = getState().isIdle(); - if (reset) - consumeInput(); - getHttpTransport().onIdleTimeout(failure); - failure.addSuppressed(new Throwable("idle timeout")); + boolean neverDispatched = getState().isIdle(); + boolean hasDemand = stream.hasDemand(); - boolean needed = getRequest().getHttpInput().onContentProducible(); - if (needed || wasDelayed) + if (LOG.isDebugEnabled()) { - consumer.accept(this::handleWithContext); - reset = false; + LOG.debug("HTTP3 request idle timeout #{}/{}, dispatched={} demand={}", + stream.getId(), + Integer.toHexString(stream.getSession().hashCode()), + !neverDispatched, + hasDemand); } - return reset; + if (neverDispatched) + { + try (AutoLock l = lock.lock()) + { + content = new HttpInput.ErrorContent(failure); + } + consumer.accept(this::handleWithContext); + } + else if (hasDemand) + { + try (AutoLock l = lock.lock()) + { + content = new HttpInput.ErrorContent(failure); + } + if (getRequest().getHttpInput().onContentProducible()) + consumer.accept(this::handleWithContext); + } + return false; } private void handleWithContext() diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/ServerTimeoutsTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/ServerTimeoutsTest.java index 8b153bd10de..002512f73cb 100644 --- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/ServerTimeoutsTest.java +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/ServerTimeoutsTest.java @@ -52,6 +52,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; import static org.eclipse.jetty.http.client.Transport.FCGI; +import static org.eclipse.jetty.http.client.Transport.H2; +import static org.eclipse.jetty.http.client.Transport.H2C; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.instanceOf; @@ -599,7 +601,7 @@ public class ServerTimeoutsTest extends AbstractTest // In HTTP/2, we force the flow control window to be small, so that the server // stalls almost immediately without having written many bytes, so that the test // completes quickly. - Assumptions.assumeTrue(transport.isMultiplexed()); + Assumptions.assumeTrue(transport == H2C || transport == H2); init(transport);