diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextRequest.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextRequest.java index 8498ed36afee..1a4eb4b30196 100644 --- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextRequest.java +++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextRequest.java @@ -13,7 +13,9 @@ package org.eclipse.jetty.server.handler; +import java.util.concurrent.TimeoutException; import java.util.function.Consumer; +import java.util.function.Predicate; import org.eclipse.jetty.server.Context; import org.eclipse.jetty.server.Request; @@ -39,6 +41,12 @@ public void demand(Runnable demandCallback) super.demand(new OnContextDemand(demandCallback)); } + @Override + public void addIdleTimeoutListener(Predicate onIdleTimeout) + { + super.addIdleTimeoutListener(t -> _context.test(onIdleTimeout, t, ContextRequest.this)); + } + @Override public void addFailureListener(Consumer onFailure) { diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ServerTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ServerTest.java index ca79b2e15267..b2cf089d6d23 100644 --- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ServerTest.java +++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ServerTest.java @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; @@ -30,6 +31,7 @@ import org.eclipse.jetty.io.Content; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.QuietException; +import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.internal.HttpChannelState; import org.eclipse.jetty.server.internal.HttpConnection; import org.eclipse.jetty.util.Blocker; @@ -48,11 +50,14 @@ import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.sameInstance; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ServerTest { private static final long IDLE_TIMEOUT = 1000L; private Server _server; + private ContextHandler _context; private LocalConnector _connector; private final AtomicReference _afterHandle = new AtomicReference<>(); @@ -60,6 +65,8 @@ public class ServerTest public void prepare() throws Exception { _server = new Server(); + _context = new ContextHandler("/"); + _server.setHandler(_context); _connector = new LocalConnector(_server, new HttpConnectionFactory() { @Override @@ -116,7 +123,7 @@ public void dispose() throws Exception @Test public void testSimpleGET() throws Exception { - _server.setHandler(new Handler.Abstract() + _context.setHandler(new Handler.Abstract() { @Override public boolean handle(Request request, Response response, Callback callback) @@ -161,7 +168,7 @@ public static Stream completionScenarios() @MethodSource("completionScenarios") public void testCompletion(boolean succeeded, boolean handling, boolean written, boolean last) throws Exception { - _server.setHandler(new Handler.Abstract(Invocable.InvocationType.BLOCKING) + _context.setHandler(new Handler.Abstract(Invocable.InvocationType.BLOCKING) { @Override public boolean handle(Request request, Response response, Callback callback) throws Exception @@ -222,7 +229,7 @@ public boolean handle(Request request, Response response, Callback callback) thr public void testIdleTimeoutNoListener() throws Exception { // See ServerTimeoutsTest for more complete idle timeout testing. - _server.setHandler(new Handler.Abstract() + _context.setHandler(new Handler.Abstract() { @Override public boolean handle(Request request, Response response, Callback callback) @@ -249,7 +256,7 @@ public void testIdleTimeoutNoListenerHttpConfigurationOnly() throws Exception { // See ServerTimeoutsTest for more complete idle timeout testing. - _server.setHandler(new Handler.Abstract() + _context.setHandler(new Handler.Abstract() { @Override public boolean handle(Request request, Response response, Callback callback) @@ -280,7 +287,7 @@ public void testIdleTimeoutFalseListener() throws Exception { // See ServerTimeoutsTest for more complete idle timeout testing. CompletableFuture callbackOnTimeout = new CompletableFuture<>(); - _server.setHandler(new Handler.Abstract() + _context.setHandler(new Handler.Abstract() { @Override public boolean handle(Request request, Response response, Callback callback) @@ -311,7 +318,7 @@ public void testIdleTimeoutWriteCallback() throws Exception { CompletableFuture onTimeout = new CompletableFuture<>(); CompletableFuture writeFail = new CompletableFuture<>(); - _server.setHandler(new Handler.Abstract() + _context.setHandler(new Handler.Abstract() { @Override public boolean handle(Request request, Response response, Callback callback) @@ -355,4 +362,49 @@ public void run() assertThat(x, instanceOf(TimeoutException.class)); } } + + @Test + public void testListenersInContext() throws Exception + { + CountDownLatch latch = new CountDownLatch(3); + _context.setHandler(new Handler.Abstract() + { + @Override + public boolean handle(Request request, Response response, Callback callback) + { + assertThat(ContextHandler.getCurrentContext(), sameInstance(_context.getContext())); + latch.countDown(); + + request.addIdleTimeoutListener(t -> + { + assertThat(ContextHandler.getCurrentContext(), sameInstance(_context.getContext())); + latch.countDown(); + return true; + }); + + request.addFailureListener(t -> + { + assertThat(ContextHandler.getCurrentContext(), sameInstance(_context.getContext())); + latch.countDown(); + }); + return true; + } + }); + _server.start(); + + String request = """ + GET /path HTTP/1.0\r + Host: hostname\r + \r + """; + + try (LocalConnector.LocalEndPoint localEndPoint = _connector.executeRequest(request)) + { + assertTrue(latch.await(3 * IDLE_TIMEOUT, TimeUnit.MILLISECONDS)); + String rawResponse = localEndPoint.getResponse(); + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + assertThat(response.getStatus(), is(HttpStatus.INTERNAL_SERVER_ERROR_500)); + } + } + }