Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Wilkins2014-07-23 05:22:20 +0000
committerGreg Wilkins2014-07-23 05:23:35 +0000
commit564ffca5dceb9bd54388770533a0f6065a5583ca (patch)
treecbe116230e425b27bc3d7a56e988e7a231d0719d
parent31359b1775eac5dd0f0cd6155f7da754ee80023b (diff)
downloadorg.eclipse.jetty.project-564ffca5dceb9bd54388770533a0f6065a5583ca.tar.gz
org.eclipse.jetty.project-564ffca5dceb9bd54388770533a0f6065a5583ca.tar.xz
org.eclipse.jetty.project-564ffca5dceb9bd54388770533a0f6065a5583ca.zip
440114 ContextHandlerCollection does not skip context wrappers
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java2
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java79
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java194
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java9
-rw-r--r--jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java201
5 files changed, 386 insertions, 99 deletions
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java
index 4047f871d3..26ff80fb5b 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java
@@ -158,6 +158,8 @@ public class LocalConnector extends AbstractConnector
private LocalEndPoint executeRequest(ByteBuffer rawRequest)
{
+ if (!isStarted())
+ throw new IllegalStateException("!STARTED");
LocalEndPoint endp = new LocalEndPoint();
endp.setInput(rawRequest);
_connects.add(endp);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
index 49c40f5b1f..ed6efd1b65 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
@@ -870,27 +870,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
_scontext.clearAttributes();
}
- /* ------------------------------------------------------------ */
- /*
- * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
- */
- public boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response) throws IOException
+ public boolean checkVirtualHost(final Request baseRequest)
{
- DispatcherType dispatch = baseRequest.getDispatcherType();
-
- switch (_availability)
- {
- case SHUTDOWN:
- case UNAVAILABLE:
- baseRequest.setHandled(true);
- response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
- return false;
- default:
- if ((DispatcherType.REQUEST.equals(dispatch) && baseRequest.isHandled()))
- return false;
- }
-
- // Check the vhosts
if (_vhosts != null && _vhosts.length > 0)
{
String vhost = normalizeHostname(baseRequest.getServerName());
@@ -926,27 +907,61 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
if (!match || connectorName && !connectorMatch)
return false;
}
-
+ return true;
+ }
+
+ public boolean checkContextPath(String uri)
+ {
// Are we not the root context?
if (_contextPath.length() > 1)
{
// reject requests that are not for us
- if (!target.startsWith(_contextPath))
+ if (!uri.startsWith(_contextPath))
return false;
- if (target.length() > _contextPath.length() && target.charAt(_contextPath.length()) != '/')
+ if (uri.length() > _contextPath.length() && uri.charAt(_contextPath.length()) != '/')
return false;
+ }
+ return true;
+ }
+
+ /* ------------------------------------------------------------ */
+ /*
+ * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ public boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response) throws IOException
+ {
+ DispatcherType dispatch = baseRequest.getDispatcherType();
- // redirect null path infos
- if (!_allowNullPathInfo && _contextPath.length() == target.length())
- {
- // context request must end with /
+ // Check the vhosts
+ if (!checkVirtualHost(baseRequest))
+ return false;
+
+ if (!checkContextPath(target))
+ return false;
+
+ // Are we not the root context?
+ // redirect null path infos
+ if (!_allowNullPathInfo && _contextPath.length() == target.length() && _contextPath.length()>1)
+ {
+ // context request must end with /
+ baseRequest.setHandled(true);
+ if (baseRequest.getQueryString() != null)
+ response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH) + "?" + baseRequest.getQueryString());
+ else
+ response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH));
+ return false;
+ }
+
+ switch (_availability)
+ {
+ case SHUTDOWN:
+ case UNAVAILABLE:
baseRequest.setHandled(true);
- if (baseRequest.getQueryString() != null)
- response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH) + "?" + baseRequest.getQueryString());
- else
- response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH));
+ response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
return false;
- }
+ default:
+ if ((DispatcherType.REQUEST.equals(dispatch) && baseRequest.isHandled()))
+ return false;
}
return true;
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java
index 4ade364903..19396d49ea 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java
@@ -19,6 +19,15 @@
package org.eclipse.jetty.server.handler;
import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -52,7 +61,8 @@ public class ContextHandlerCollection extends HandlerCollection
{
private static final Logger LOG = Log.getLogger(ContextHandlerCollection.class);
- private volatile Trie<ContextHandler[]> _contexts;
+ private final ConcurrentMap<ContextHandler,Handler> _contextBranches = new ConcurrentHashMap<>();
+ private volatile Trie<Map.Entry<String,Branch[]>> _pathBranches;
private Class<? extends ContextHandler> _contextClass = ContextHandler.class;
/* ------------------------------------------------------------ */
@@ -69,71 +79,70 @@ public class ContextHandlerCollection extends HandlerCollection
@ManagedOperation("update the mapping of context path to context")
public void mapContexts()
{
- int capacity=512;
+ _contextBranches.clear();
+
+ if (getHandlers()==null)
+ {
+ _pathBranches=new ArrayTernaryTrie<>(false,16);
+ return;
+ }
+
+ // Create map of contextPath to handler Branch
+ Map<String,Branch[]> map = new HashMap<>();
+ for (Handler handler:getHandlers())
+ {
+ Branch branch=new Branch(handler);
+ for (String contextPath : branch.getContextPaths())
+ {
+ Branch[] branches=map.get(contextPath);
+ map.put(contextPath, ArrayUtil.addToArray(branches, branch, Branch.class));
+ }
+
+ for (ContextHandler context : branch.getContextHandlers())
+ _contextBranches.putIfAbsent(context, branch.getHandler());
+ }
+
+ // Sort the branches so those with virtual hosts are considered before those without
+ for (Map.Entry<String,Branch[]> entry: map.entrySet())
+ {
+ Branch[] branches=entry.getValue();
+ Branch[] sorted=new Branch[branches.length];
+ int i=0;
+ for (Branch branch:branches)
+ if (branch.hasVirtualHost())
+ sorted[i++]=branch;
+ for (Branch branch:branches)
+ if (!branch.hasVirtualHost())
+ sorted[i++]=branch;
+ entry.setValue(sorted);
+ }
// Loop until we have a big enough trie to hold all the context paths
- Trie<ContextHandler[]> trie;
+ int capacity=512;
+ Trie<Map.Entry<String,Branch[]>> trie;
loop: while(true)
{
trie=new ArrayTernaryTrie<>(false,capacity);
-
- Handler[] branches = getHandlers();
-
- // loop over each group of contexts
- for (int b=0;branches!=null && b<branches.length;b++)
+ for (Map.Entry<String,Branch[]> entry: map.entrySet())
{
- Handler[] handlers=null;
-
- if (branches[b] instanceof ContextHandler)
- {
- handlers = new Handler[]{ branches[b] };
- }
- else if (branches[b] instanceof HandlerContainer)
+ if (!trie.put(entry.getKey().substring(1),entry))
{
- handlers = ((HandlerContainer)branches[b]).getChildHandlersByClass(ContextHandler.class);
- }
- else
- continue;
-
- // for each context handler in a group
- for (int i=0;handlers!=null && i<handlers.length;i++)
- {
- ContextHandler handler=(ContextHandler)handlers[i];
- String contextPath=handler.getContextPath().substring(1);
- ContextHandler[] contexts=trie.get(contextPath);
-
- if (!trie.put(contextPath,ArrayUtil.addToArray(contexts,handler,ContextHandler.class)))
- {
- capacity+=512;
- continue loop;
- }
+ capacity+=512;
+ continue loop;
}
}
-
- break;
+ break loop;
}
+
- // Sort the contexts so those with virtual hosts are considered before those without
- for (String ctx : trie.keySet())
+ if (LOG.isDebugEnabled())
{
- ContextHandler[] contexts=trie.get(ctx);
- ContextHandler[] sorted=new ContextHandler[contexts.length];
- int i=0;
- for (ContextHandler handler:contexts)
- if (handler.getVirtualHosts()!=null && handler.getVirtualHosts().length>0)
- sorted[i++]=handler;
- for (ContextHandler handler:contexts)
- if (handler.getVirtualHosts()==null || handler.getVirtualHosts().length==0)
- sorted[i++]=handler;
- trie.put(ctx,sorted);
+ for (String ctx : trie.keySet())
+ LOG.debug("{}->{}",ctx,Arrays.asList(trie.get(ctx).getValue()));
}
-
- //for (String ctx : trie.keySet())
- // System.err.printf("'%s'->%s%n",ctx,Arrays.asList(trie.get(ctx)));
- _contexts=trie;
+ _pathBranches=trie;
}
-
/* ------------------------------------------------------------ */
/*
* @see org.eclipse.jetty.server.server.handler.HandlerCollection#setHandlers(org.eclipse.jetty.server.server.Handler[])
@@ -172,11 +181,16 @@ public class ContextHandlerCollection extends HandlerCollection
ContextHandler context=async.getContextHandler();
if (context!=null)
{
- context.handle(target,baseRequest,request, response);
+ Handler branch = _contextBranches.get(context);
+
+ if (branch==null)
+ context.handle(target,baseRequest,request, response);
+ else
+ branch.handle(target, baseRequest, request, response);
return;
}
}
-
+
// data structure which maps a request to a context; first-best match wins
// { context path => [ context ] }
// }
@@ -187,16 +201,18 @@ public class ContextHandlerCollection extends HandlerCollection
while (limit>=0)
{
// Get best match
- ContextHandler[] contexts = _contexts.getBest(target,1,limit);
- if (contexts==null)
+ Map.Entry<String,Branch[]> branches = _pathBranches.getBest(target,1,limit);
+
+
+ if (branches==null)
break;
-
- int l=contexts[0].getContextPath().length();
+
+ int l=branches.getKey().length();
if (l==1 || target.length()==l || target.charAt(l)=='/')
{
- for (ContextHandler handler : contexts)
+ for (Branch branch : branches.getValue())
{
- handler.handle(target,baseRequest, request, response);
+ branch.getHandler().handle(target,baseRequest, request, response);
if (baseRequest.isHandled())
return;
}
@@ -217,7 +233,6 @@ public class ContextHandlerCollection extends HandlerCollection
}
}
-
/* ------------------------------------------------------------ */
/** Add a context handler.
* @param contextPath The context path to add
@@ -263,5 +278,64 @@ public class ContextHandlerCollection extends HandlerCollection
_contextClass = contextClass;
}
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
+ private final static class Branch
+ {
+ private final Handler _handler;
+ private final ContextHandler[] _contexts;
+
+ Branch(Handler handler)
+ {
+ _handler=handler;
+
+ if (handler instanceof ContextHandler)
+ {
+ _contexts = new ContextHandler[]{(ContextHandler)handler};
+ }
+ else if (handler instanceof HandlerContainer)
+ {
+ Handler[] contexts=((HandlerContainer)handler).getChildHandlersByClass(ContextHandler.class);
+ _contexts = new ContextHandler[contexts.length];
+ System.arraycopy(contexts, 0, _contexts, 0, contexts.length);
+ }
+ else
+ _contexts = new ContextHandler[0];
+ }
+
+ Set<String> getContextPaths()
+ {
+ Set<String> set = new HashSet<String>();
+ for (ContextHandler context:_contexts)
+ set.add(context.getContextPath());
+ return set;
+ }
+
+ boolean hasVirtualHost()
+ {
+ for (ContextHandler context:_contexts)
+ if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
+ return true;
+ return false;
+ }
+
+ ContextHandler[] getContextHandlers()
+ {
+ return _contexts;
+ }
+
+ Handler getHandler()
+ {
+ return _handler;
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("{%s,%s}",_handler,Arrays.asList(_contexts));
+ }
+ }
+
}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java
index c118c7ec1d..b79b75dc23 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java
@@ -19,6 +19,7 @@
package org.eclipse.jetty.server.handler;
import java.io.IOException;
+import java.util.Arrays;
import java.util.List;
import javax.servlet.ServletException;
@@ -185,4 +186,12 @@ public class HandlerCollection extends AbstractHandlerContainer
child.destroy();
super.destroy();
}
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public String toString()
+ {
+ Handler[] handlers=getHandlers();
+ return super.toString()+(handlers==null?"[]":Arrays.asList(getHandlers()).toString());
+ }
}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java
index 5e2adf2a2f..3c13fea0ae 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java
@@ -18,17 +18,24 @@
package org.eclipse.jetty.server.handler;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.endsWith;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
+import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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;
@@ -84,9 +91,9 @@ public class ContextHandlerCollectionTest
c.addHandler(contextC);
HandlerList list = new HandlerList();
- list.addHandler(contextD);
list.addHandler(contextE);
list.addHandler(contextF);
+ list.addHandler(contextD);
c.addHandler(list);
server.setHandler(c);
@@ -132,18 +139,22 @@ public class ContextHandlerCollectionTest
handlerE.reset();
handlerF.reset();
- // System.err.printf("test %d %s@%s --> %s | %s%n",i,uri,host,connector.getName(),handler);
+ String t = String.format("test %d %s@%s --> %s | %s%n",i,uri,host,connector.getName(),handler);
String response = connector.getResponses("GET "+uri+" HTTP/1.0\nHost: "+host+"\n\n");
if (handler==null)
{
- Assert.assertThat(response,Matchers.containsString(" 302 "));
+ Assert.assertThat(t,response,Matchers.containsString(" 302 "));
}
- else if (!handler.isHandled())
+ else
{
- System.err.printf("FAILED %d %s@%s --> %s | %s%n",i,uri,host,connector.getName(),handler);
- System.err.println(response);
- Assert.fail();
+ assertThat(t,response,endsWith(handler.toString()));
+ if (!handler.isHandled())
+ {
+ System.err.printf("FAILED %s",t);
+ System.err.println(response);
+ Assert.fail();
+ }
}
}
@@ -260,8 +271,148 @@ public class ContextHandlerCollectionTest
assertEquals(wrapperB,AbstractHandlerContainer.findContainerOf(contextB,HandlerWrapper.class,handlerB));
}
+
+ @Test
+ public void testWrappedContext() throws Exception
+ {
+ Server server = new Server();
+ LocalConnector connector = new LocalConnector(server);
+ server.setConnectors(new Connector[] { connector });
+
+ ContextHandler root = new ContextHandler("/");
+ root.setHandler(new IsHandledHandler("root"));
+
+ ContextHandler left = new ContextHandler("/left");
+ left.setHandler(new IsHandledHandler("left"));
+
+ HandlerList centre = new HandlerList();
+ 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)});
+
+ ContextHandler right = new ContextHandler("/right");
+ right.setHandler(new IsHandledHandler("right"));
+
+ ContextHandlerCollection contexts = new ContextHandlerCollection();
+ contexts.setHandlers(new Handler[]{root,left,centre,new WrappedHandler(right)});
+
+ server.setHandler(contexts);
+ server.start();
+
+ String response=connector.getResponses("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.getResponses("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.getResponses("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.getResponses("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.getResponses("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: TRUE"));
+
+ response=connector.getResponses("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: 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"));
+
+ HandlerList centre = new HandlerList();
+ ContextHandler centreLeft = new ContextHandler("/leftcentre");
+ centreLeft.setHandler(new AsyncHandler("left of centre"));
+ ContextHandler centreRight = new ContextHandler("/rightcentre");
+ centreRight.setHandler(new AsyncHandler("right of centre"));
+ centre.setHandlers(new Handler[]{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.getResponses("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.getResponses("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.getResponses("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.getResponses("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.getResponses("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.getResponses("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 HandlerWrapper
+ {
+ WrappedHandler(Handler handler)
+ {
+ setHandler(handler);
+ }
+
+ @Override
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ if (response.containsHeader("Wrapped"))
+ response.setHeader("Wrapped", "ASYNC");
+ else
+ response.setHeader("Wrapped", "TRUE");
+ super.handle(target, baseRequest, request, response);
+ }
+ }
+
+
private static final class IsHandledHandler extends AbstractHandler
{
private boolean handled;
@@ -298,5 +449,41 @@ public class ContextHandlerCollectionTest
}
+
+ 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;
+ }
+ }
+
}

Back to the top