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:
commit
ecb3ab7e5b
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
@ -286,19 +301,22 @@ public class JspcMojo extends AbstractMojo
|
|||
if (i+1<webAppUrls.size())
|
||||
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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -358,21 +358,8 @@ public class HttpChannel implements Runnable
|
|||
}
|
||||
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();
|
||||
}
|
||||
// Complete generating the response
|
||||
_response.closeOutput();
|
||||
}
|
||||
}
|
||||
catch(EofException|ClosedChannelException 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -450,6 +450,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
_sendCallback.iterate();
|
||||
}
|
||||
|
||||
super.abort();
|
||||
private class SendCallback extends IteratingCallback
|
||||
{
|
||||
private ResponseInfo _info;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -541,10 +541,7 @@ public class Response implements HttpServletResponse
|
|||
@Override
|
||||
public void sendError(int sc) throws IOException
|
||||
{
|
||||
if (sc == 102)
|
||||
sendProcessing();
|
||||
else
|
||||
sendError(sc, null);
|
||||
sendError(sc, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
if (!trie.put(entry.getKey().substring(1),entry))
|
||||
{
|
||||
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)))
|
||||
{
|
||||
capacity+=512;
|
||||
continue loop;
|
||||
}
|
||||
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,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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -252,6 +252,8 @@ public class DecoderReaderTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
// TODO analyse and fix
|
||||
@Ignore
|
||||
@Test
|
||||
public void testSingleQuotes() throws Exception
|
||||
{
|
||||
|
@ -268,7 +270,9 @@ public class DecoderReaderTest
|
|||
Assert.assertThat("Quotes Author",quotes.author,is("Benjamin Franklin"));
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue