Merge remote-tracking branch 'origin/master' into jetty-http2

Conflicts:
	jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java
This commit is contained in:
Greg Wilkins 2014-07-23 16:38:15 +10:00
commit ecb3ab7e5b
13 changed files with 449 additions and 133 deletions

View File

@ -82,6 +82,21 @@ public class JspcMojo extends AbstractMojo
public static final String PRECOMPILED_FLAG = "org.eclipse.jetty.jsp.precompiled";
/**
* JettyJspC
*
* Add some extra setters to standard JspC class to help configure it
* for running in maven.
*/
public static class JettyJspC extends JspC
{
public void setClassLoader (ClassLoader loader)
{
this.loader = loader;
}
}
/**
* Whether or not to include dependencies on the plugin's classpath with <scope>provided</scope>
* Use WITH CAUTION as you may wind up with duplicate jars/classes.
@ -219,7 +234,7 @@ public class JspcMojo extends AbstractMojo
*
* @parameter
*/
private JspC jspc;
private JettyJspC jspc;
@ -287,18 +302,21 @@ public class JspcMojo extends AbstractMojo
webAppClassPath.append(System.getProperty("path.separator"));
}
Thread.currentThread().setContextClassLoader(webAppClassLoader);
//Interpose a fake classloader as the webapp class loader. This is because the Apache JspC class
//uses a TldScanner which ignores jars outside of the WEB-INF/lib path on the webapp classloader.
//It will, however, look at all jars on the parents of the webapp classloader.
URLClassLoader fakeWebAppClassLoader = new URLClassLoader(new URL[0], webAppClassLoader);
Thread.currentThread().setContextClassLoader(fakeWebAppClassLoader);
if (jspc == null)
jspc = new JspC();
jspc = new JettyJspC();
jspc.setWebXmlFragment(webXmlFragment);
jspc.setUriroot(webAppSourceDirectory);
jspc.setOutputDir(generatedClasses);
jspc.setClassPath(sysClassPath+System.getProperty("path.separator")+webAppClassPath.toString());
jspc.setClassLoader(fakeWebAppClassLoader);
jspc.setCompile(true);
//jspc.setSystemClassPath(sysClassPath);
// JspC#setExtensions() does not exist, so
// always set concrete list of files that will be processed.

View File

@ -32,6 +32,7 @@ import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.servlet.AsyncContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
@ -51,6 +52,7 @@ import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.HttpCookieStore;
import org.eclipse.jetty.util.log.Log;
@ -558,7 +560,15 @@ public class ProxyServlet extends HttpServlet
_log.debug(getRequestId(request) + " proxying failed", failure);
if (response.isCommitted())
{
request.setAttribute("org.eclipse.jetty.server.Response.failure", failure);
// Use Jetty specific behavior to close connection
try
{
response.sendError(-1);
}
catch (IOException e)
{
getServletContext().log("close failed", e);
}
AsyncContext asyncContext = request.getAsyncContext();
asyncContext.complete();
}

View File

@ -357,24 +357,11 @@ public class HttpChannel implements Runnable
_response.sendError(404);
}
else
{
// There is no way in the Servlet API to directly close a connection,
// so we rely on applications to pass this attribute to signal they
// want to hard close the connection, without even closing the output.
Object failure = _request.getAttribute("org.eclipse.jetty.server.Response.failure");
if (failure != null)
{
if (LOG.isDebugEnabled())
LOG.debug("Explicit response failure", failure);
failed();
}
else
{
// Complete generating the response
_response.closeOutput();
}
}
}
catch(EofException|ClosedChannelException e)
{
LOG.debug(e);
@ -604,10 +591,11 @@ public class HttpChannel implements Runnable
/**
* If a write or similar to this channel fails this method should be called. The standard implementation
* of {@link #failed()} is a noop. But the different implementations of HttpChannel might want to take actions.
* is to call {@link HttpTransport#abort()}
*/
public void failed()
public void abort()
{
_transport.abort();
}
private class CommitCallback implements Callback

View File

@ -347,10 +347,10 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl
}
@Override
public void failed()
public void abort()
{
_httpConnection._generator.setPersistent(false);
getEndPoint().shutdownOutput();
super.abort();
_generator.setPersistent(false);
}
@Override

View File

@ -450,6 +450,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
_sendCallback.iterate();
}
super.abort();
private class SendCallback extends IteratingCallback
{
private ResponseInfo _info;

View File

@ -157,7 +157,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
catch(IOException e)
{
LOG.debug(e);
_channel.failed();
_channel.abort();
}
releaseBuffer();
return;
@ -192,7 +192,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
catch(IOException e)
{
LOG.debug(e);
_channel.failed();
_channel.abort();
}
releaseBuffer();
return;

View File

@ -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);

View File

@ -541,9 +541,6 @@ public class Response implements HttpServletResponse
@Override
public void sendError(int sc) throws IOException
{
if (sc == 102)
sendProcessing();
else
sendError(sc, null);
}
@ -553,6 +550,17 @@ public class Response implements HttpServletResponse
if (isIncluding())
return;
switch(code)
{
case -1:
_channel.abort();
return;
case 102:
sendProcessing();
return;
default:
}
if (isCommitted())
LOG.warn("Committed before "+code+" "+message);

View File

@ -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,18 +907,41 @@ 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();
// 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())
if (!_allowNullPathInfo && _contextPath.length() == target.length() && _contextPath.length()>1)
{
// context request must end with /
baseRequest.setHandled(true);
@ -947,6 +951,17 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH));
return false;
}
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;
}
return true;

View File

@ -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)
{
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)))
if (!trie.put(entry.getKey().substring(1),entry))
{
capacity+=512;
continue loop;
}
}
break loop;
}
break;
}
// 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,7 +181,12 @@ public class ContextHandlerCollection extends HandlerCollection
ContextHandler context=async.getContextHandler();
if (context!=null)
{
Handler branch = _contextBranches.get(context);
if (branch==null)
context.handle(target,baseRequest,request, response);
else
branch.handle(target, baseRequest, request, response);
return;
}
}
@ -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));
}
}
}

View File

@ -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());
}
}

View File

@ -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,20 +139,24 @@ 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);
assertThat(t,response,endsWith(handler.toString()));
if (!handler.isHandled())
{
System.err.printf("FAILED %s",t);
System.err.println(response);
Assert.fail();
}
}
}
}
finally
@ -261,6 +272,146 @@ public class ContextHandlerCollectionTest
}
@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
{
@ -299,4 +450,40 @@ 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;
}
}
}

View File

@ -252,6 +252,8 @@ public class DecoderReaderTest
server.stop();
}
// TODO analyse and fix
@Ignore
@Test
public void testSingleQuotes() throws Exception
{
@ -269,6 +271,8 @@ public class DecoderReaderTest
Assert.assertThat("Quotes Count",quotes.quotes.size(),is(3));
}
// TODO analyse and fix
@Ignore
@Test
@Ignore ("Quotes appear to be able to arrive in any order?")
public void testTwoQuotes() throws Exception