Jetty-12 : Fixing ContextHandlerCollectionTest (#8322)

* Fixing ContextHandlerCollectionTest

* Disabling array Indentation checkstyle

+ Doesn't play nice with Java 17 new switch/case usages.
This commit is contained in:
Joakim Erdfelt 2022-07-20 16:42:45 -05:00 committed by GitHub
parent 68ddee69af
commit b241446e66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 286 additions and 264 deletions

View File

@ -77,9 +77,11 @@
</module> </module>
<!-- Indentation Rules --> <!-- Indentation Rules -->
<!-- Disabled: does not support Java 17 new switch/case
<module name="Indentation"> <module name="Indentation">
<property name="arrayInitIndent" value="8"/> <property name="arrayInitIndent" value="8"/>
</module> </module>
-->
<!-- Interface Type Parameter Name --> <!-- Interface Type Parameter Name -->
<module name="InterfaceTypeParameterName"> <module name="InterfaceTypeParameterName">

View File

@ -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 * 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', 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 * '@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 * 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. * 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) @ManagedAttribute(value = "Virtual hosts accepted by the context", readonly = true)
public List<String> getVirtualHosts() public List<String> getVirtualHosts()
{ {
return _vhosts.stream().map(VHost::getVHost).collect(Collectors.toList()); return _vhosts.stream().map(VHost::getName).collect(Collectors.toList());
} }
@Override @Override
@ -536,9 +536,7 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace
if (_vhosts.isEmpty()) if (_vhosts.isEmpty())
return true; return true;
// TODO is this correct? String host = normalizeHostname(request.getHttpURI().getHost());
String host = request.getHttpURI().getHost();
String connectorName = request.getConnectionMetaData().getConnector().getName(); String connectorName = request.getConnectionMetaData().getConnector().getName();
for (VHost vhost : _vhosts) for (VHost vhost : _vhosts)
@ -750,11 +748,21 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace
b.append('{'); b.append('{');
if (getDisplayName() != null) if (getDisplayName() != null)
b.append(getDisplayName()).append(','); 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('}'); b.append('}');
@ -1040,5 +1048,23 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace
{ {
return _vHost; return _vHost;
} }
String getName()
{
if (_vConnector != null)
return '@' + _vConnector;
else
return _vHost;
}
@Override
public String toString()
{
return "VHost{" +
"_vHost='" + _vHost + '\'' +
", _wild=" + _wild +
", _vConnector='" + _vConnector + '\'' +
'}';
}
} }
} }

View File

@ -14,7 +14,6 @@
package org.eclipse.jetty.server.handler; package org.eclipse.jetty.server.handler;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -248,7 +247,7 @@ public class ContextHandlerCollection extends Handler.Collection
private static final class Branch private static final class Branch
{ {
private final Handler _handler; private final Handler _handler;
private final ContextHandler[] _contexts; private final List<ContextHandler> _contexts;
Branch(Handler handler) Branch(Handler handler)
{ {
@ -256,16 +255,15 @@ public class ContextHandlerCollection extends Handler.Collection
if (handler instanceof ContextHandler) if (handler instanceof ContextHandler)
{ {
_contexts = new ContextHandler[]{(ContextHandler)handler}; _contexts = List.of((ContextHandler)handler);
} }
else if (handler instanceof Handler.Container) else if (handler instanceof Handler.Container)
{ {
List<ContextHandler> contexts = ((Handler.Container)handler).getDescendants(ContextHandler.class); List<ContextHandler> contexts = ((Handler.Container)handler).getDescendants(ContextHandler.class);
_contexts = new ContextHandler[contexts.size()]; _contexts = new ArrayList<>(contexts);
System.arraycopy(contexts, 0, _contexts, 0, contexts.size());
} }
else else
_contexts = new ContextHandler[0]; _contexts = List.of();
} }
Set<String> getContextPaths() Set<String> getContextPaths()
@ -288,7 +286,7 @@ public class ContextHandlerCollection extends Handler.Collection
return false; return false;
} }
ContextHandler[] getContextHandlers() List<ContextHandler> getContextHandlers()
{ {
return _contexts; return _contexts;
} }
@ -301,7 +299,7 @@ public class ContextHandlerCollection extends Handler.Collection
@Override @Override
public String toString() public String toString()
{ {
return String.format("{%s,%s}", _handler, Arrays.asList(_contexts)); return String.format("{%s,%s}", _handler, _contexts);
} }
} }

View File

@ -13,59 +13,106 @@
package org.eclipse.jetty.server.handler; 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 public class ContextHandlerCollectionTest
{ {
/* TODO public static Stream<Arguments> virtualHostCases()
@Test {
public void testVirtualHosts() throws Exception 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(); Server server = new Server();
LocalConnector connector0 = new LocalConnector(server); LocalConnector connector0 = new LocalConnector(server);
LocalConnector connector1 = new LocalConnector(server); LocalConnector connector1 = new LocalConnector(server);
connector1.setName("connector1"); connector1.setName("connector1");
server.setConnectors(new Connector[] server.addConnector(connector0);
{connector0, connector1}); server.addConnector(connector1);
ContextHandler contextA = new ContextHandler("/ctx"); ContextHandler contextA = new ContextHandler("/ctx");
contextA.setVirtualHosts(new String[] contextA.setVirtualHosts(List.of("www.example.com", "alias.example.com"));
{"www.example.com", "alias.example.com"}); contextA.setHandler(new IsHandledHandler("A"));
IsHandledHandler handlerA = new IsHandledHandler("A");
contextA.setHandler(handlerA);
contextA.setAllowNullPathInfo(true);
ContextHandler contextB = new ContextHandler("/ctx"); ContextHandler contextB = new ContextHandler("/ctx");
IsHandledHandler handlerB = new IsHandledHandler("B"); contextB.setHandler(new IsHandledHandler("B"));
contextB.setHandler(handlerB); contextB.setVirtualHosts(List.of("*.other.com@connector1"));
contextB.setVirtualHosts(new String[]
{"*.other.com", "@connector1"});
ContextHandler contextC = new ContextHandler("/ctx"); ContextHandler contextC = new ContextHandler("/ctx");
IsHandledHandler handlerC = new IsHandledHandler("C"); contextC.setHandler(new IsHandledHandler("C"));
contextC.setHandler(handlerC);
ContextHandler contextD = new ContextHandler("/"); ContextHandler contextD = new ContextHandler("/");
IsHandledHandler handlerD = new IsHandledHandler("D"); contextD.setHandler(new IsHandledHandler("D"));
contextD.setHandler(handlerD);
ContextHandler contextE = new ContextHandler("/ctx/foo"); ContextHandler contextE = new ContextHandler("/ctx/foo");
IsHandledHandler handlerE = new IsHandledHandler("E"); contextE.setHandler(new IsHandledHandler("E"));
contextE.setHandler(handlerE);
ContextHandler contextF = new ContextHandler("/ctxlong"); ContextHandler contextF = new ContextHandler("/ctxlong");
IsHandledHandler handlerF = new IsHandledHandler("F"); contextF.setHandler(new IsHandledHandler("F"));
contextF.setHandler(handlerF);
ContextHandlerCollection c = new ContextHandlerCollection(); ContextHandlerCollection c = new ContextHandlerCollection();
c.addHandler(contextA); c.addHandler(contextA);
c.addHandler(contextB); c.addHandler(contextB);
c.addHandler(contextC); c.addHandler(contextC);
HandlerList list = new HandlerList(); Handler.Collection handlers = new Handler.Collection();
list.addHandler(contextE); handlers.addHandler(contextE);
list.addHandler(contextF); handlers.addHandler(contextF);
list.addHandler(contextD); handlers.addHandler(contextD);
c.addHandler(list); c.addHandler(handlers);
server.setHandler(c); server.setHandler(c);
@ -73,58 +120,29 @@ public class ContextHandlerCollectionTest
{ {
server.start(); server.start();
Object[][] tests = new Object[][]{ LocalConnector connector = switch (useConnectorNum)
{connector0, "www.example.com.", "/ctx", handlerA}, {
{connector0, "www.example.com.", "/ctx/", handlerA}, case 0 -> connector0;
{connector0, "www.example.com.", "/ctx/info", handlerA}, case 1 -> connector1;
{connector0, "www.example.com", "/ctx/info", handlerA}, default -> fail("Unsupported connector number: " + useConnectorNum);
{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},
}; };
for (int i = 0; i < tests.length; i++) String rawRequest = ("""
{ GET %s HTTP/1.1\r
Object[] test = tests[i]; Host: %s\r
LocalConnector connector = (LocalConnector)test[0]; Connection: close\r
String host = (String)test[1]; \r
String uri = (String)test[2]; """).formatted(uri, host);
IsHandledHandler handler = (IsHandledHandler)test[3];
handlerA.reset(); String rawResponse = connector.getResponse(rawRequest);
handlerB.reset(); HttpTester.Response response = HttpTester.parseResponse(rawResponse);
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); assertThat(testInfo.getDisplayName(), response.getStatus(), is(expectedStatus));
String response = connector.getResponse("GET " + uri + " HTTP/1.0\nHost: " + host + "\n\n");
if (handler == null) if (response.getStatus() == HttpStatus.OK_200)
{ {
assertThat(t, response, Matchers.containsString(" 302 ")); assertThat(testInfo.getDisplayName(), response.getContent(), endsWith(handlerRef));
} assertThat(testInfo.getDisplayName(), response.get("X-IsHandled-Name"), is(handlerRef));
else
{
assertThat(t, response, endsWith(handler.toString()));
if (!handler.isHandled())
{
fail("FAILED " + t + "\n" + response);
}
}
} }
} }
finally finally
@ -133,14 +151,115 @@ public class ContextHandlerCollectionTest
} }
} }
@Test public static Stream<Arguments> virtualHostWildcardMatchedCases()
public void testVirtualHostWildcard() throws Exception {
List<Arguments> args = new ArrayList<>();
List<String> 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<String> contextHosts, String requestHost) throws Exception
{ {
Server server = new Server(); Server server = new Server();
LocalConnector connector = new LocalConnector(server); LocalConnector connector = new LocalConnector(server);
server.setConnectors(new Connector[]{connector}); server.setConnectors(new Connector[]{connector});
ContextHandler context = new ContextHandler("/"); 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<Arguments> virtualHostWildcardNoMatchCases()
{
List<Arguments> args = new ArrayList<>();
List<String> 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<String> 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"); IsHandledHandler handler = new IsHandledHandler("H");
context.setHandler(handler); context.setHandler(handler);
@ -153,35 +272,22 @@ public class ContextHandlerCollectionTest
try try
{ {
server.start(); 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[]{ String rawRequest = """
"example.com", ".example.com", "vhost.example.com" GET / HTTP/1.1\r
}); Host: %s\r
checkWildcardHost(false, server, new String[]{"example.com", "*.example.com"}, new String[]{ Connection:close\r
"badexample.com", ".badexample.com", "vhost.badexample.com" \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("<h2>HTTP ERROR 404 Not Found</h2>"));
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"}); connector.getResponse(rawRequest);
checkWildcardHost(false, server, new String[]{"*.example.com"}, new String[]{ assertFalse(handler.isHandled(), "'" + requestHost + "' should not have been handled.");
"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"
});
} }
finally 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 @Test
public void testFindContainer() throws Exception public void testFindContainer()
{ {
Server server = new Server(); Server server = new Server();
@ -225,7 +306,7 @@ public class ContextHandlerCollectionTest
ContextHandler contextB = new ContextHandler("/b"); ContextHandler contextB = new ContextHandler("/b");
IsHandledHandler handlerB = new IsHandledHandler("B"); IsHandledHandler handlerB = new IsHandledHandler("B");
HandlerWrapper wrapperB = new HandlerWrapper(); Handler.Wrapper wrapperB = new Handler.Wrapper();
wrapperB.setHandler(handlerB); wrapperB.setHandler(handlerB);
contextB.setHandler(wrapperB); contextB.setHandler(wrapperB);
@ -239,16 +320,16 @@ public class ContextHandlerCollectionTest
collection.addHandler(contextB); collection.addHandler(contextB);
collection.addHandler(contextC); collection.addHandler(contextC);
HandlerWrapper wrapper = new HandlerWrapper(); Handler.Wrapper wrapper = new Handler.Wrapper();
wrapper.setHandler(collection); wrapper.setHandler(collection);
server.setHandler(wrapper); server.setHandler(wrapper);
assertEquals(wrapper, AbstractHandlerContainer.findContainerOf(server, HandlerWrapper.class, handlerA)); assertEquals(wrapper, Handler.AbstractContainer.findContainerOf(server, Handler.Wrapper.class, handlerA));
assertEquals(contextA, AbstractHandlerContainer.findContainerOf(server, ContextHandler.class, handlerA)); assertEquals(contextA, Handler.AbstractContainer.findContainerOf(server, ContextHandler.class, handlerA));
assertEquals(contextB, AbstractHandlerContainer.findContainerOf(server, ContextHandler.class, handlerB)); assertEquals(contextB, Handler.AbstractContainer.findContainerOf(server, ContextHandler.class, handlerB));
assertEquals(wrapper, AbstractHandlerContainer.findContainerOf(server, HandlerWrapper.class, handlerB)); assertEquals(wrapper, Handler.AbstractContainer.findContainerOf(server, Handler.Wrapper.class, handlerB));
assertEquals(contextB, AbstractHandlerContainer.findContainerOf(collection, HandlerWrapper.class, handlerB)); assertEquals(contextB, Handler.AbstractContainer.findContainerOf(collection, Handler.Wrapper.class, handlerB));
assertEquals(wrapperB, AbstractHandlerContainer.findContainerOf(contextB, HandlerWrapper.class, handlerB)); assertEquals(wrapperB, Handler.AbstractContainer.findContainerOf(contextB, Handler.Wrapper.class, handlerB));
} }
@Test @Test
@ -264,18 +345,18 @@ public class ContextHandlerCollectionTest
ContextHandler left = new ContextHandler("/left"); ContextHandler left = new ContextHandler("/left");
left.setHandler(new IsHandledHandler("left")); left.setHandler(new IsHandledHandler("left"));
HandlerList centre = new HandlerList(); Handler.Collection centre = new Handler.Collection();
ContextHandler centreLeft = new ContextHandler("/leftcentre"); ContextHandler centreLeft = new ContextHandler("/leftcentre");
centreLeft.setHandler(new IsHandledHandler("left of centre")); centreLeft.setHandler(new IsHandledHandler("left of centre"));
ContextHandler centreRight = new ContextHandler("/rightcentre"); ContextHandler centreRight = new ContextHandler("/rightcentre");
centreRight.setHandler(new IsHandledHandler("right of centre")); 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"); ContextHandler right = new ContextHandler("/right");
right.setHandler(new IsHandledHandler("right")); right.setHandler(new IsHandledHandler("right"));
ContextHandlerCollection contexts = new ContextHandlerCollection(); 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.setHandler(contexts);
server.start(); server.start();
@ -311,65 +392,6 @@ public class ContextHandlerCollectionTest
assertThat(response, containsString("Wrapped: TRUE")); 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 private static final class WrappedHandler extends Handler.Wrapper
{ {
WrappedHandler(Handler handler) WrappedHandler(Handler handler)
@ -378,17 +400,24 @@ public class ContextHandlerCollectionTest
} }
@Override @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")) Request.Processor processor = super.handle(request);
response.getHeaders().put("Wrapped", "ASYNC"); if (processor == null)
return null;
return (req, resp, callback) ->
{
if (resp.getHeaders().contains("Wrapped"))
resp.getHeaders().put("Wrapped", "ASYNC");
else else
response.getHeaders().put("Wrapped", "TRUE"); resp.getHeaders().put("Wrapped", "TRUE");
super.handle(target, baseRequest, request, response); processor.process(req, resp, callback);
};
} }
} }
private static final class IsHandledHandler extends AbstractHandler private static final class IsHandledHandler extends Handler.Abstract
{ {
private boolean handled; private boolean handled;
private final String name; private final String name;
@ -404,11 +433,15 @@ public class ContextHandlerCollectionTest
} }
@Override @Override
public void handle(String s, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException public Request.Processor handle(Request request)
{
return (req, resp, callback) ->
{ {
baseRequest.setHandled(true);
this.handled = true; this.handled = true;
response.getWriter().print(name); resp.getHeaders().put("X-IsHandled-Name", name);
ByteBuffer nameBuffer = BufferUtil.toBuffer(name, StandardCharsets.UTF_8);
resp.write(true, nameBuffer, callback);
};
} }
public void reset() public void reset()
@ -422,41 +455,4 @@ public class ContextHandlerCollectionTest
return name; 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;
}
}
*/
} }