diff --git a/build/build-resources/src/main/resources/jetty-checkstyle.xml b/build/build-resources/src/main/resources/jetty-checkstyle.xml index ea03ac5e994..55f68602436 100644 --- a/build/build-resources/src/main/resources/jetty-checkstyle.xml +++ b/build/build-resources/src/main/resources/jetty-checkstyle.xml @@ -77,9 +77,11 @@ + diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index d8fbcf68674..7cc99329e3d 100644 --- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -253,14 +253,14 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace * representation of IP addresses. Host names may start with '*.' to wildcard one level of names. Hosts and wildcard hosts may be followed with * '@connectorname', in which case they will match only if the the {@link Connector#getName()} for the request also matches. If an entry is just * '@connectorname' it will match any host if that connector was used. Note - In previous versions if one or more connectorname only entries existed - * and non of the connectors matched the handler would not match regardless of any hostname entries. If there is one or more connectorname only + * and none of the connectors matched the handler would not match regardless of any hostname entries. If there is one or more connectorname only * entries and one or more host only entries but no hostname and connector entries we assume the old behavior and will log a warning. The warning * can be removed by removing the host entries that were previously being ignored, or modifying to include a hostname and connectorname entry. */ @ManagedAttribute(value = "Virtual hosts accepted by the context", readonly = true) public List getVirtualHosts() { - return _vhosts.stream().map(VHost::getVHost).collect(Collectors.toList()); + return _vhosts.stream().map(VHost::getName).collect(Collectors.toList()); } @Override @@ -536,9 +536,7 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace if (_vhosts.isEmpty()) return true; - // TODO is this correct? - String host = request.getHttpURI().getHost(); - + String host = normalizeHostname(request.getHttpURI().getHost()); String connectorName = request.getConnectionMetaData().getConnector().getName(); for (VHost vhost : _vhosts) @@ -750,11 +748,21 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace b.append('{'); if (getDisplayName() != null) b.append(getDisplayName()).append(','); - b.append(getContextPath()).append(',').append(getResourceBase()).append(',').append(isAvailable()); + b.append(getContextPath()); + b.append(",b=").append(getResourceBase()); + b.append(",a=").append(_availability.get()); - for (String vh : vhosts) + if (!vhosts.isEmpty()) { - b.append(',').append(vh); + b.append(",vh=["); + b.append(String.join(",", vhosts)); + b.append(']'); + } + Handler nestedHandler = getHandler(); + if (nestedHandler != null) + { + b.append(",h="); + b.append(nestedHandler); } b.append('}'); @@ -1040,5 +1048,23 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace { return _vHost; } + + String getName() + { + if (_vConnector != null) + return '@' + _vConnector; + else + return _vHost; + } + + @Override + public String toString() + { + return "VHost{" + + "_vHost='" + _vHost + '\'' + + ", _wild=" + _wild + + ", _vConnector='" + _vConnector + '\'' + + '}'; + } } } diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java index 6780d9c11c7..e7ac1496cf0 100644 --- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java +++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java @@ -14,7 +14,6 @@ package org.eclipse.jetty.server.handler; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -248,7 +247,7 @@ public class ContextHandlerCollection extends Handler.Collection private static final class Branch { private final Handler _handler; - private final ContextHandler[] _contexts; + private final List _contexts; Branch(Handler handler) { @@ -256,16 +255,15 @@ public class ContextHandlerCollection extends Handler.Collection if (handler instanceof ContextHandler) { - _contexts = new ContextHandler[]{(ContextHandler)handler}; + _contexts = List.of((ContextHandler)handler); } else if (handler instanceof Handler.Container) { List contexts = ((Handler.Container)handler).getDescendants(ContextHandler.class); - _contexts = new ContextHandler[contexts.size()]; - System.arraycopy(contexts, 0, _contexts, 0, contexts.size()); + _contexts = new ArrayList<>(contexts); } else - _contexts = new ContextHandler[0]; + _contexts = List.of(); } Set getContextPaths() @@ -288,7 +286,7 @@ public class ContextHandlerCollection extends Handler.Collection return false; } - ContextHandler[] getContextHandlers() + List getContextHandlers() { return _contexts; } @@ -301,7 +299,7 @@ public class ContextHandlerCollection extends Handler.Collection @Override public String toString() { - return String.format("{%s,%s}", _handler, Arrays.asList(_contexts)); + return String.format("{%s,%s}", _handler, _contexts); } } diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java index 12b3b8f1585..0c8c2de0352 100644 --- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java +++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java @@ -13,59 +13,106 @@ package org.eclipse.jetty.server.handler; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpTester; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.LocalConnector; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.util.BufferUtil; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.fail; + public class ContextHandlerCollectionTest { - /* TODO - @Test - public void testVirtualHosts() throws Exception + public static Stream virtualHostCases() + { + return Stream.of( + Arguments.of(0, "www.example.com.", "/ctx", "-", HttpStatus.MOVED_PERMANENTLY_301), + Arguments.of(0, "www.example.com.", "/ctx/", "A", HttpStatus.OK_200), + Arguments.of(0, "www.example.com.", "/ctx/info", "A", HttpStatus.OK_200), + Arguments.of(0, "www.example.com", "/ctx/info", "A", HttpStatus.OK_200), + Arguments.of(0, "alias.example.com", "/ctx/info", "A", HttpStatus.OK_200), + Arguments.of(1, "www.example.com.", "/ctx/info", "A", HttpStatus.OK_200), + Arguments.of(1, "www.example.com", "/ctx/info", "A", HttpStatus.OK_200), + Arguments.of(1, "alias.example.com", "/ctx/info", "A", HttpStatus.OK_200), + + Arguments.of(1, "www.other.com", "/ctx", "-", HttpStatus.MOVED_PERMANENTLY_301), + Arguments.of(1, "www.other.com", "/ctx/", "B", HttpStatus.OK_200), + Arguments.of(1, "www.other.com", "/ctx/info", "B", HttpStatus.OK_200), + Arguments.of(0, "www.other.com", "/ctx/info", "C", HttpStatus.OK_200), + + Arguments.of(0, "www.example.com", "/ctxinfo", "D", HttpStatus.OK_200), + Arguments.of(1, "unknown.com", "/unknown", "D", HttpStatus.OK_200), + + Arguments.of(0, "alias.example.com", "/ctx/foo/info", "E", HttpStatus.OK_200), + Arguments.of(0, "alias.example.com", "/ctxlong/info", "F", HttpStatus.OK_200) + ); + } + + @ParameterizedTest + @MethodSource("virtualHostCases") + public void testVirtualHosts(int useConnectorNum, String host, String uri, String handlerRef, int expectedStatus, TestInfo testInfo) throws Exception { Server server = new Server(); LocalConnector connector0 = new LocalConnector(server); LocalConnector connector1 = new LocalConnector(server); connector1.setName("connector1"); - server.setConnectors(new Connector[] - {connector0, connector1}); + server.addConnector(connector0); + server.addConnector(connector1); ContextHandler contextA = new ContextHandler("/ctx"); - contextA.setVirtualHosts(new String[] - {"www.example.com", "alias.example.com"}); - IsHandledHandler handlerA = new IsHandledHandler("A"); - contextA.setHandler(handlerA); - contextA.setAllowNullPathInfo(true); + contextA.setVirtualHosts(List.of("www.example.com", "alias.example.com")); + contextA.setHandler(new IsHandledHandler("A")); ContextHandler contextB = new ContextHandler("/ctx"); - IsHandledHandler handlerB = new IsHandledHandler("B"); - contextB.setHandler(handlerB); - contextB.setVirtualHosts(new String[] - {"*.other.com", "@connector1"}); + contextB.setHandler(new IsHandledHandler("B")); + contextB.setVirtualHosts(List.of("*.other.com@connector1")); ContextHandler contextC = new ContextHandler("/ctx"); - IsHandledHandler handlerC = new IsHandledHandler("C"); - contextC.setHandler(handlerC); + contextC.setHandler(new IsHandledHandler("C")); ContextHandler contextD = new ContextHandler("/"); - IsHandledHandler handlerD = new IsHandledHandler("D"); - contextD.setHandler(handlerD); + contextD.setHandler(new IsHandledHandler("D")); ContextHandler contextE = new ContextHandler("/ctx/foo"); - IsHandledHandler handlerE = new IsHandledHandler("E"); - contextE.setHandler(handlerE); + contextE.setHandler(new IsHandledHandler("E")); ContextHandler contextF = new ContextHandler("/ctxlong"); - IsHandledHandler handlerF = new IsHandledHandler("F"); - contextF.setHandler(handlerF); + contextF.setHandler(new IsHandledHandler("F")); ContextHandlerCollection c = new ContextHandlerCollection(); c.addHandler(contextA); c.addHandler(contextB); c.addHandler(contextC); - HandlerList list = new HandlerList(); - list.addHandler(contextE); - list.addHandler(contextF); - list.addHandler(contextD); - c.addHandler(list); + Handler.Collection handlers = new Handler.Collection(); + handlers.addHandler(contextE); + handlers.addHandler(contextF); + handlers.addHandler(contextD); + c.addHandler(handlers); server.setHandler(c); @@ -73,58 +120,29 @@ public class ContextHandlerCollectionTest { server.start(); - Object[][] tests = new Object[][]{ - {connector0, "www.example.com.", "/ctx", handlerA}, - {connector0, "www.example.com.", "/ctx/", handlerA}, - {connector0, "www.example.com.", "/ctx/info", handlerA}, - {connector0, "www.example.com", "/ctx/info", handlerA}, - {connector0, "alias.example.com", "/ctx/info", handlerA}, - {connector1, "www.example.com.", "/ctx/info", handlerA}, - {connector1, "www.example.com", "/ctx/info", handlerA}, - {connector1, "alias.example.com", "/ctx/info", handlerA}, - - {connector1, "www.other.com", "/ctx", null}, - {connector1, "www.other.com", "/ctx/", handlerB}, - {connector1, "www.other.com", "/ctx/info", handlerB}, - {connector0, "www.other.com", "/ctx/info", handlerC}, - - {connector0, "www.example.com", "/ctxinfo", handlerD}, - {connector1, "unknown.com", "/unknown", handlerD}, - - {connector0, "alias.example.com", "/ctx/foo/info", handlerE}, - {connector0, "alias.example.com", "/ctxlong/info", handlerF}, + LocalConnector connector = switch (useConnectorNum) + { + case 0 -> connector0; + case 1 -> connector1; + default -> fail("Unsupported connector number: " + useConnectorNum); }; - for (int i = 0; i < tests.length; i++) + String rawRequest = (""" + GET %s HTTP/1.1\r + Host: %s\r + Connection: close\r + \r + """).formatted(uri, host); + + String rawResponse = connector.getResponse(rawRequest); + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat(testInfo.getDisplayName(), response.getStatus(), is(expectedStatus)); + + if (response.getStatus() == HttpStatus.OK_200) { - Object[] test = tests[i]; - LocalConnector connector = (LocalConnector)test[0]; - String host = (String)test[1]; - String uri = (String)test[2]; - IsHandledHandler handler = (IsHandledHandler)test[3]; - - handlerA.reset(); - handlerB.reset(); - handlerC.reset(); - handlerD.reset(); - handlerE.reset(); - handlerF.reset(); - - String t = String.format("test %d %s@%s --> %s | %s%n", i, uri, host, connector.getName(), handler); - String response = connector.getResponse("GET " + uri + " HTTP/1.0\nHost: " + host + "\n\n"); - - if (handler == null) - { - assertThat(t, response, Matchers.containsString(" 302 ")); - } - else - { - assertThat(t, response, endsWith(handler.toString())); - if (!handler.isHandled()) - { - fail("FAILED " + t + "\n" + response); - } - } + assertThat(testInfo.getDisplayName(), response.getContent(), endsWith(handlerRef)); + assertThat(testInfo.getDisplayName(), response.get("X-IsHandled-Name"), is(handlerRef)); } } finally @@ -133,14 +151,115 @@ public class ContextHandlerCollectionTest } } - @Test - public void testVirtualHostWildcard() throws Exception + public static Stream virtualHostWildcardMatchedCases() + { + List args = new ArrayList<>(); + + List contextHosts; + + contextHosts = List.of(); + args.add(Arguments.of(contextHosts, "example.com")); + args.add(Arguments.of(contextHosts, ".example.com")); + args.add(Arguments.of(contextHosts, "vhost.example.com")); + + contextHosts = List.of("example.com", "*.example.com"); + args.add(Arguments.of(contextHosts, "example.com")); + args.add(Arguments.of(contextHosts, ".example.com")); + args.add(Arguments.of(contextHosts, "vhost.example.com")); + + contextHosts = List.of("*.example.com"); + args.add(Arguments.of(contextHosts, "vhost.example.com")); + args.add(Arguments.of(contextHosts, ".example.com")); + + contextHosts = List.of("*.sub.example.com"); + args.add(Arguments.of(contextHosts, "vhost.sub.example.com")); + args.add(Arguments.of(contextHosts, ".sub.example.com")); + + return args.stream(); + } + + @ParameterizedTest + @MethodSource("virtualHostWildcardMatchedCases") + public void testVirtualHostWildcardMatched(List contextHosts, String requestHost) throws Exception { Server server = new Server(); LocalConnector connector = new LocalConnector(server); server.setConnectors(new Connector[]{connector}); ContextHandler context = new ContextHandler("/"); + context.setVirtualHosts(contextHosts); + context.setHandler(new IsHandledHandler("H")); + + ContextHandlerCollection c = new ContextHandlerCollection(); + c.addHandler(context); + + server.setHandler(c); + + try + { + server.start(); + + String rawRequest = """ + GET / HTTP/1.1\r + Host: %s\r + Connection:close\r + \r + """.formatted(requestHost); + + String rawResponse = connector.getResponse(rawRequest); + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + assertThat("Response status for [GET " + requestHost + "]", response.getStatus(), is(HttpStatus.OK_200)); + assertThat("Response body for [GET " + requestHost + "]", response.getContent(), is("H")); + assertThat("Response Header for [GET " + requestHost + "]", response.get("X-IsHandled-Name"), is("H")); + } + finally + { + server.stop(); + } + } + + public static Stream virtualHostWildcardNoMatchCases() + { + List args = new ArrayList<>(); + + List contextHosts; + + contextHosts = List.of("example.com", "*.example.com"); + args.add(Arguments.of(contextHosts, "badexample.com")); + args.add(Arguments.of(contextHosts, ".badexample.com")); + args.add(Arguments.of(contextHosts, "vhost.badexample.com")); + + contextHosts = List.of("*."); + args.add(Arguments.of(contextHosts, "anything.anything")); + + contextHosts = List.of("*.example.com"); + args.add(Arguments.of(contextHosts, "vhost.www.example.com")); + args.add(Arguments.of(contextHosts, "example.com")); + args.add(Arguments.of(contextHosts, "www.vhost.example.com")); + + contextHosts = List.of("*.sub.example.com"); + args.add(Arguments.of(contextHosts, ".example.com")); + args.add(Arguments.of(contextHosts, "sub.example.com")); + args.add(Arguments.of(contextHosts, "vhost.example.com")); + + contextHosts = List.of("example.*.com", "example.com.*"); + args.add(Arguments.of(contextHosts, "example.vhost.com")); + args.add(Arguments.of(contextHosts, "example.com.vhost")); + args.add(Arguments.of(contextHosts, "example.com")); + + return args.stream(); + } + + @ParameterizedTest + @MethodSource("virtualHostWildcardNoMatchCases") + public void testVirtualHostWildcardNoMatch(List contextHosts, String requestHost) throws Exception + { + Server server = new Server(); + LocalConnector connector = new LocalConnector(server); + server.setConnectors(new Connector[]{connector}); + + ContextHandler context = new ContextHandler("/"); + context.setVirtualHosts(contextHosts); IsHandledHandler handler = new IsHandledHandler("H"); context.setHandler(handler); @@ -153,35 +272,22 @@ public class ContextHandlerCollectionTest try { server.start(); - checkWildcardHost(true, server, null, new String[]{"example.com", ".example.com", "vhost.example.com"}); - checkWildcardHost(false, server, new String[]{null}, new String[]{ - "example.com", ".example.com", "vhost.example.com" - }); - checkWildcardHost(true, server, new String[]{"example.com", "*.example.com"}, new String[]{ - "example.com", ".example.com", "vhost.example.com" - }); - checkWildcardHost(false, server, new String[]{"example.com", "*.example.com"}, new String[]{ - "badexample.com", ".badexample.com", "vhost.badexample.com" - }); + String rawRequest = """ + GET / HTTP/1.1\r + Host: %s\r + Connection:close\r + \r + """.formatted(requestHost); - checkWildcardHost(false, server, new String[]{"*."}, new String[]{"anything.anything"}); + String rawResponse = connector.getResponse(rawRequest); + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + assertThat("Response status for [GET " + requestHost + "]", response.getStatus(), is(HttpStatus.NOT_FOUND_404)); + assertThat("Response body for [GET " + requestHost + "]", response.getContent(), containsString("

HTTP ERROR 404 Not Found

")); + assertThat("Response Header for [GET " + requestHost + "]", response.get("X-IsHandled-Name"), nullValue()); - checkWildcardHost(true, server, new String[]{"*.example.com"}, new String[]{"vhost.example.com", ".example.com"}); - checkWildcardHost(false, server, new String[]{"*.example.com"}, new String[]{ - "vhost.www.example.com", "example.com", "www.vhost.example.com" - }); - - checkWildcardHost(true, server, new String[]{"*.sub.example.com"}, new String[]{ - "vhost.sub.example.com", ".sub.example.com" - }); - checkWildcardHost(false, server, new String[]{"*.sub.example.com"}, new String[]{ - ".example.com", "sub.example.com", "vhost.example.com" - }); - - checkWildcardHost(false, server, new String[]{"example.*.com", "example.com.*"}, new String[]{ - "example.vhost.com", "example.com.vhost", "example.com" - }); + connector.getResponse(rawRequest); + assertFalse(handler.isHandled(), "'" + requestHost + "' should not have been handled."); } finally { @@ -189,33 +295,8 @@ public class ContextHandlerCollectionTest } } - private void checkWildcardHost(boolean succeed, Server server, String[] contextHosts, String[] requestHosts) throws Exception - { - LocalConnector connector = (LocalConnector)server.getConnectors()[0]; - ContextHandlerCollection handlerCollection = (ContextHandlerCollection)server.getHandler(); - ContextHandler context = (ContextHandler)handlerCollection.getHandlers()[0]; - IsHandledHandler handler = (IsHandledHandler)context.getHandler(); - - context.setVirtualHosts(contextHosts); - // trigger this manually - handlerCollection.mapContexts(); - - for (String host : requestHosts) - { - // System.err.printf("host=%s in %s%n",host,contextHosts==null?Collections.emptyList():Arrays.asList(contextHosts)); - - String response = connector.getResponse("GET / HTTP/1.0\n" + "Host: " + host + "\nConnection:close\n\n"); - // System.err.println(response); - if (succeed) - assertTrue(handler.isHandled(), "'" + host + "' should have been handled."); - else - assertFalse(handler.isHandled(), "'" + host + "' should not have been handled."); - handler.reset(); - } - } - @Test - public void testFindContainer() throws Exception + public void testFindContainer() { Server server = new Server(); @@ -225,7 +306,7 @@ public class ContextHandlerCollectionTest ContextHandler contextB = new ContextHandler("/b"); IsHandledHandler handlerB = new IsHandledHandler("B"); - HandlerWrapper wrapperB = new HandlerWrapper(); + Handler.Wrapper wrapperB = new Handler.Wrapper(); wrapperB.setHandler(handlerB); contextB.setHandler(wrapperB); @@ -239,16 +320,16 @@ public class ContextHandlerCollectionTest collection.addHandler(contextB); collection.addHandler(contextC); - HandlerWrapper wrapper = new HandlerWrapper(); + Handler.Wrapper wrapper = new Handler.Wrapper(); wrapper.setHandler(collection); server.setHandler(wrapper); - assertEquals(wrapper, AbstractHandlerContainer.findContainerOf(server, HandlerWrapper.class, handlerA)); - assertEquals(contextA, AbstractHandlerContainer.findContainerOf(server, ContextHandler.class, handlerA)); - assertEquals(contextB, AbstractHandlerContainer.findContainerOf(server, ContextHandler.class, handlerB)); - assertEquals(wrapper, AbstractHandlerContainer.findContainerOf(server, HandlerWrapper.class, handlerB)); - assertEquals(contextB, AbstractHandlerContainer.findContainerOf(collection, HandlerWrapper.class, handlerB)); - assertEquals(wrapperB, AbstractHandlerContainer.findContainerOf(contextB, HandlerWrapper.class, handlerB)); + assertEquals(wrapper, Handler.AbstractContainer.findContainerOf(server, Handler.Wrapper.class, handlerA)); + assertEquals(contextA, Handler.AbstractContainer.findContainerOf(server, ContextHandler.class, handlerA)); + assertEquals(contextB, Handler.AbstractContainer.findContainerOf(server, ContextHandler.class, handlerB)); + assertEquals(wrapper, Handler.AbstractContainer.findContainerOf(server, Handler.Wrapper.class, handlerB)); + assertEquals(contextB, Handler.AbstractContainer.findContainerOf(collection, Handler.Wrapper.class, handlerB)); + assertEquals(wrapperB, Handler.AbstractContainer.findContainerOf(contextB, Handler.Wrapper.class, handlerB)); } @Test @@ -264,18 +345,18 @@ public class ContextHandlerCollectionTest ContextHandler left = new ContextHandler("/left"); left.setHandler(new IsHandledHandler("left")); - HandlerList centre = new HandlerList(); + Handler.Collection centre = new Handler.Collection(); ContextHandler centreLeft = new ContextHandler("/leftcentre"); centreLeft.setHandler(new IsHandledHandler("left of centre")); ContextHandler centreRight = new ContextHandler("/rightcentre"); centreRight.setHandler(new IsHandledHandler("right of centre")); - centre.setHandlers(new Handler[]{centreLeft, new WrappedHandler(centreRight)}); + centre.setHandlers(List.of(centreLeft, new WrappedHandler(centreRight))); ContextHandler right = new ContextHandler("/right"); right.setHandler(new IsHandledHandler("right")); ContextHandlerCollection contexts = new ContextHandlerCollection(); - contexts.setHandlers(new Handler[]{root, left, centre, new WrappedHandler(right)}); + contexts.setHandlers(List.of(root, left, centre, new WrappedHandler(right))); server.setHandler(contexts); server.start(); @@ -311,65 +392,6 @@ public class ContextHandlerCollectionTest assertThat(response, containsString("Wrapped: TRUE")); } - @Test - public void testAsyncWrappedContext() throws Exception - { - Server server = new Server(); - LocalConnector connector = new LocalConnector(server); - server.setConnectors(new Connector[]{connector}); - - ContextHandler root = new ContextHandler("/"); - root.setHandler(new AsyncHandler("root")); - - ContextHandler left = new ContextHandler("/left"); - left.setHandler(new AsyncHandler("left")); - - ContextHandler centreLeft = new ContextHandler("/leftcentre"); - centreLeft.setHandler(new AsyncHandler("left of centre")); - ContextHandler centreRight = new ContextHandler("/rightcentre"); - centreRight.setHandler(new AsyncHandler("right of centre")); - HandlerList centre = new HandlerList(centreLeft, new WrappedHandler(centreRight)); - - ContextHandler right = new ContextHandler("/right"); - right.setHandler(new AsyncHandler("right")); - - ContextHandlerCollection contexts = new ContextHandlerCollection(); - contexts.setHandlers(new Handler[]{root, left, centre, new WrappedHandler(right)}); - - server.setHandler(contexts); - server.start(); - - String response = connector.getResponse("GET / HTTP/1.0\r\n\r\n"); - assertThat(response, startsWith("HTTP/1.1 200 OK")); - assertThat(response, endsWith("root")); - assertThat(response, not(containsString("Wrapped: TRUE"))); - - response = connector.getResponse("GET /foobar/info HTTP/1.0\r\n\r\n"); - assertThat(response, startsWith("HTTP/1.1 200 OK")); - assertThat(response, endsWith("root")); - assertThat(response, not(containsString("Wrapped: TRUE"))); - - response = connector.getResponse("GET /left/info HTTP/1.0\r\n\r\n"); - assertThat(response, startsWith("HTTP/1.1 200 OK")); - assertThat(response, endsWith("left")); - assertThat(response, not(containsString("Wrapped: TRUE"))); - - response = connector.getResponse("GET /leftcentre/info HTTP/1.0\r\n\r\n"); - assertThat(response, startsWith("HTTP/1.1 200 OK")); - assertThat(response, endsWith("left of centre")); - assertThat(response, not(containsString("Wrapped: TRUE"))); - - response = connector.getResponse("GET /rightcentre/info HTTP/1.0\r\n\r\n"); - assertThat(response, startsWith("HTTP/1.1 200 OK")); - assertThat(response, endsWith("right of centre")); - assertThat(response, containsString("Wrapped: ASYNC")); - - response = connector.getResponse("GET /right/info HTTP/1.0\r\n\r\n"); - assertThat(response, startsWith("HTTP/1.1 200 OK")); - assertThat(response, endsWith("right")); - assertThat(response, containsString("Wrapped: ASYNC")); - } - private static final class WrappedHandler extends Handler.Wrapper { WrappedHandler(Handler handler) @@ -378,17 +400,24 @@ public class ContextHandlerCollectionTest } @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public Request.Processor handle(Request request) throws Exception { - if (response.containsHeader("Wrapped")) - response.getHeaders().put("Wrapped", "ASYNC"); - else - response.getHeaders().put("Wrapped", "TRUE"); - super.handle(target, baseRequest, request, response); + Request.Processor processor = super.handle(request); + if (processor == null) + return null; + + return (req, resp, callback) -> + { + if (resp.getHeaders().contains("Wrapped")) + resp.getHeaders().put("Wrapped", "ASYNC"); + else + resp.getHeaders().put("Wrapped", "TRUE"); + processor.process(req, resp, callback); + }; } } - private static final class IsHandledHandler extends AbstractHandler + private static final class IsHandledHandler extends Handler.Abstract { private boolean handled; private final String name; @@ -404,11 +433,15 @@ public class ContextHandlerCollectionTest } @Override - public void handle(String s, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public Request.Processor handle(Request request) { - baseRequest.setHandled(true); - this.handled = true; - response.getWriter().print(name); + return (req, resp, callback) -> + { + this.handled = true; + resp.getHeaders().put("X-IsHandled-Name", name); + ByteBuffer nameBuffer = BufferUtil.toBuffer(name, StandardCharsets.UTF_8); + resp.write(true, nameBuffer, callback); + }; } public void reset() @@ -422,41 +455,4 @@ public class ContextHandlerCollectionTest return name; } } - - private static final class AsyncHandler extends AbstractHandler - { - private final String name; - - public AsyncHandler(String string) - { - name = string; - } - - @Override - public void handle(String s, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - - String n = (String)baseRequest.getAttribute("async"); - if (n == null) - { - AsyncContext async = baseRequest.startAsync(); - async.setTimeout(1000); - baseRequest.setAttribute("async", name); - async.dispatch(); - } - else - { - response.getWriter().print(n); - } - } - - @Override - public String toString() - { - return name; - } - } - - */ }