diff options
Diffstat (limited to 'jetty-server')
50 files changed, 986 insertions, 436 deletions
diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml index 3a3f5ee4fb..d2a4d712db 100644 --- a/jetty-server/pom.xml +++ b/jetty-server/pom.xml @@ -2,7 +2,7 @@ <parent> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-project</artifactId> - <version>9.2.2-SNAPSHOT</version> + <version>9.2.3-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jetty-server</artifactId> diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index 7d3402fbfa..3106eec257 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -19,8 +19,6 @@ package org.eclipse.jetty.server; import java.io.IOException; -import java.net.Socket; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -37,9 +35,7 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jetty.io.ArrayByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.ssl.SslConnection; import org.eclipse.jetty.util.FutureCallback; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -47,7 +43,6 @@ import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; import org.eclipse.jetty.util.thread.Scheduler; @@ -145,7 +140,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co private final Scheduler _scheduler; private final ByteBufferPool _byteBufferPool; private final Thread[] _acceptors; - private final Set<EndPoint> _endpoints = Collections.newSetFromMap(new ConcurrentHashMap()); + private final Set<EndPoint> _endpoints = Collections.newSetFromMap(new ConcurrentHashMap<EndPoint, Boolean>()); private final Set<EndPoint> _immutableEndPoints = Collections.unmodifiableSet(_endpoints); private volatile CountDownLatch _stopping; private long _idleTimeout = 30000; @@ -191,9 +186,9 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co int cores = Runtime.getRuntime().availableProcessors(); if (acceptors < 0) - acceptors = 1 + cores / 16; - if (acceptors > 2 * cores) - LOG.warn("Acceptors should be <= 2*availableProcessors: " + this); + acceptors=Math.max(1, Math.min(4,cores/8)); + if (acceptors > cores) + LOG.warn("Acceptors should be <= availableProcessors: " + this); _acceptors = new Thread[acceptors]; } @@ -261,7 +256,11 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co _stopping=new CountDownLatch(_acceptors.length); for (int i = 0; i < _acceptors.length; i++) - getExecutor().execute(new Acceptor(i)); + { + Acceptor a = new Acceptor(i); + addBean(a); + getExecutor().execute(a); + } LOG.info("Started {}", this); } @@ -299,6 +298,9 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co _stopping=null; super.doStop(); + + for (Acceptor a : getBeans(Acceptor.class)) + removeBean(a); LOG.info("Stopped {}", this); } @@ -440,6 +442,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co private class Acceptor implements Runnable { private final int _acceptor; + private String _name; private Acceptor(int id) { @@ -450,8 +453,9 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co public void run() { Thread current = Thread.currentThread(); - String name = current.getName(); - current.setName(name + "-acceptor-" + _acceptor + "-" + AbstractConnector.this); + String name=current.getName(); + _name=String.format("%s-acceptor-%d@%x-%s",name,_acceptor,hashCode(),AbstractConnector.this.toString()); + current.setName(_name); synchronized (AbstractConnector.this) { @@ -488,6 +492,16 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co stopping.countDown(); } } + + @Override + public String toString() + { + String name=_name; + if (name==null) + return String.format("acceptor-%d@%x", _acceptor, hashCode()); + return name; + } + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java index dcaecbe50f..2a16bdd550 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java @@ -25,7 +25,6 @@ import javax.servlet.http.Cookie; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.PathMap; -import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.util.DateCache; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.component.AbstractLifeCycle; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Connector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Connector.java index ce4544c900..0ea12cc734 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Connector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Connector.java @@ -24,7 +24,6 @@ import java.util.concurrent.Executor; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.component.Graceful; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java index 891e8ee1cf..ff8f14763d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java @@ -20,8 +20,6 @@ package org.eclipse.jetty.server; import java.net.InetSocketAddress; -import javax.servlet.ServletRequest; - import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpScheme; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Handler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Handler.java index cfe7b9a200..6b7f11fb1b 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Handler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Handler.java @@ -24,8 +24,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedOperation; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HostHeaderCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HostHeaderCustomizer.java index b39b25dcf4..7911351ef0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HostHeaderCustomizer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HostHeaderCustomizer.java @@ -20,8 +20,6 @@ package org.eclipse.jetty.server; import java.util.Objects; -import javax.servlet.http.HttpServletRequest; - /** * Customizes requests that lack the {@code Host} header (for example, HTTP 1.0 requests). * <p /> diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index e86001ed54..9248d9f874 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -397,10 +397,14 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H _state.completed(); if (!_response.isCommitted() && !_request.isHandled()) + { _response.sendError(404); + } else + { // Complete generating the response _response.closeOutput(); + } } catch(EofException|ClosedChannelException e) { @@ -795,10 +799,11 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H /** * 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 diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java index 352af25c75..f9c5054714 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java @@ -54,6 +54,23 @@ public class HttpConfiguration private boolean _sendXPoweredBy = false; //send X-Powered-By: header private boolean _sendDateHeader = true; //send Date: header + + /* ------------------------------------------------------------ */ + /** + * <p>An interface that allows a request object to be customized + * for a particular HTTP connector configuration. Unlike Filters, customizer are + * applied before the request is submitted for processing and can be specific to the + * connector on which the request was received. + * + * <p>Typically Customizers perform tasks such as: <ul> + * <li>process header fields that may be injected by a proxy or load balancer. + * <li>setup attributes that may come from the connection/connector such as SSL Session IDs + * <li>Allow a request to be marked as secure or authenticated if those have been offloaded + * and communicated by header, cookie or other out-of-band mechanism + * <li>Set request attributes/fields that are determined by the connector on which the + * request was received + * </ul> + */ public interface Customizer { public void customize(Connector connector, HttpConfiguration channelConfig, Request request); @@ -103,7 +120,8 @@ public class HttpConfiguration { return _customizers; } - + + /* ------------------------------------------------------------ */ public <T> T getCustomizer(Class<T> type) { for (Customizer c : _customizers) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 4d41cce3ab..cec4058cf6 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -426,11 +426,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http @Override public void onClose() { - if (_sendCallback.isInUse()) - { - LOG.warn("Closed with pending write:"+this); - _sendCallback.failed(new EofException("Connection closed")); - } + _sendCallback.close(); super.onClose(); } @@ -541,11 +537,11 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http } @Override - public void failed() + public void abort() { - getEndPoint().shutdownOutput(); + super.abort(); + _generator.setPersistent(false); } - @Override public boolean messageComplete() @@ -580,6 +576,10 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http _header = null; _shutdownOut = false; } + else if (isClosed()) + { + callback.failed(new EofException()); + } else { callback.failed(new WritePendingException()); @@ -705,7 +705,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http @Override public String toString() { - return String.format("SendCB@%x{s=%s,i=%s,cb=%s}",hashCode(),getState(),_info,_callback); + return String.format("%s[i=%s,cb=%s]",super.toString(),_info,_callback); } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java index d638984a39..12a23d5fb3 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java @@ -24,10 +24,7 @@ import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritePendingException; import java.util.concurrent.atomic.AtomicReference; -import javax.servlet.RequestDispatcher; import javax.servlet.ServletOutputStream; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; import javax.servlet.WriteListener; import org.eclipse.jetty.http.HttpContent; @@ -160,7 +157,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable catch(IOException e) { LOG.debug(e); - _channel.failed(); + _channel.abort(); } releaseBuffer(); return; @@ -195,7 +192,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable catch(IOException e) { LOG.debug(e); - _channel.failed(); + _channel.abort(); } releaseBuffer(); return; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java b/jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java index cb81d3c95e..95e894afc2 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java @@ -81,7 +81,7 @@ public class InclusiveByteRange * @param size Size of the resource. * @return LazyList of satisfiable ranges */ - public static List<InclusiveByteRange> satisfiableRanges(Enumeration headers, long size) + public static List<InclusiveByteRange> satisfiableRanges(Enumeration<String> headers, long size) { Object satRanges=null; @@ -89,7 +89,7 @@ public class InclusiveByteRange headers: while (headers.hasMoreElements()) { - String header = (String) headers.nextElement(); + String header = headers.nextElement(); StringTokenizer tok = new StringTokenizer(header,"=,",false); String t=null; try 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 1f05003a3d..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 @@ -138,7 +138,8 @@ public class LocalConnector extends AbstractConnector LocalEndPoint endp = executeRequest(requestsBuffer); endp.waitUntilClosedOrIdleFor(idleFor,units); ByteBuffer responses = endp.takeOutput(); - endp.getConnection().close(); + if (endp.isOutputShutdown()) + endp.close(); if (LOG.isDebugEnabled()) LOG.debug("responses {}", BufferUtil.toUTF8String(responses)); return responses; @@ -157,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/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 8dbb07792f..330bb40cd9 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -1247,7 +1247,7 @@ public class Request implements HttpServletRequest _port=0; return _serverName; } - _serverName = hostPort.substring(1,len-1); + _serverName = hostPort.substring(0,len); } else if (len==hostPort.length()) _serverName=hostPort; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java index e39c4a60fb..dc686260cd 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java @@ -33,7 +33,6 @@ import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.http.DateGenerator; import org.eclipse.jetty.http.HttpContent; -import org.eclipse.jetty.http.HttpContent.ResourceAsHttpContent; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.log.Log; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index eb95e20401..79f4e4989c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -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); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java index b017461310..dd26b04b14 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java @@ -20,8 +20,10 @@ package org.eclipse.jetty.server; import java.security.cert.X509Certificate; +import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSession; +import javax.servlet.ServletRequest; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.io.ssl.SslConnection; @@ -31,6 +33,12 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.ssl.SslContextFactory; + +/* ------------------------------------------------------------ */ +/** Customizer that extracts the attribute from an {@link SSLContext} + * and sets them on the request with {@link ServletRequest#setAttribute(String, Object)} + * according to Servlet Specification Requirements. + */ public class SecureRequestCustomizer implements HttpConfiguration.Customizer { private static final Logger LOG = Log.getLogger(SecureRequestCustomizer.class); @@ -40,7 +48,6 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer */ public static final String CACHED_INFO_ATTR = CachedInfo.class.getName(); - @Override public void customize(Connector connector, HttpConfiguration channelConfig, Request request) { @@ -53,14 +60,11 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer SSLEngine sslEngine=sslConnection.getSSLEngine(); customize(sslEngine,request); } - } /* ------------------------------------------------------------ */ /* - * Allow the Listener a chance to customise the request. before the server - * does its stuff. <br> - * This allows the required attributes to be set for SSL requests. <br> + * Customise the request attributes to be set for SSL requests. <br> * The requirements of the Servlet specs are: * <ul> * <li> an attribute named "javax.servlet.request.ssl_session_id" of type diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java index 66919f42a7..ce4bdd9097 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.server; +import java.awt.geom.PathIterator; import java.io.IOException; import java.lang.management.ManagementFactory; import java.net.InetAddress; @@ -32,6 +33,7 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; + import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -46,11 +48,13 @@ import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.HandlerWrapper; +import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.URIUtil; +import org.eclipse.jetty.util.UrlEncoded; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.Name; @@ -143,6 +147,25 @@ public class Server extends HandlerWrapper implements Attributes } /* ------------------------------------------------------------ */ + /** + * Set a graceful stop time. + * The {@link StatisticsHandler} must be configured so that open connections can + * be tracked for a graceful shutdown. + * @see org.eclipse.jetty.util.component.ContainerLifeCycle#setStopTimeout(long) + */ + @Override + public void setStopTimeout(long stopTimeout) + { + super.setStopTimeout(stopTimeout); + } + + /* ------------------------------------------------------------ */ + /** Set stop server at shutdown behaviour. + * @param stop If true, this server instance will be explicitly stopped when the + * JVM is shutdown. Otherwise the JVM is stopped with the server running. + * @see Runtime#addShutdownHook(Thread) + * @see ShutdownThread + */ public void setStopAtShutdown(boolean stop) { //if we now want to stop @@ -397,7 +420,7 @@ public class Server extends HandlerWrapper implements Attributes } catch (Exception e) { - mex.add(e.getCause()); + mex.add(e); } } } @@ -474,7 +497,6 @@ public class Server extends HandlerWrapper implements Attributes response.sendError(HttpStatus.BAD_REQUEST_400); request.setHandled(true); response.setStatus(200); - response.getHttpFields().put(HttpHeader.ALLOW,"GET,POST,HEAD,OPTIONS"); response.setContentLength(0); response.closeOutput(); } @@ -492,15 +514,15 @@ public class Server extends HandlerWrapper implements Attributes final Request baseRequest=connection.getRequest(); final String path=event.getPath(); - + if (path!=null) { // this is a dispatch with a path ServletContext context=event.getServletContext(); - HttpURI uri = new HttpURI(context==null?path:URIUtil.addPaths(context.getContextPath(),path)); + HttpURI uri = new HttpURI(URIUtil.addPaths(context==null?null:context.getContextPath(), path)); baseRequest.setUri(uri); baseRequest.setRequestURI(null); - baseRequest.setPathInfo(baseRequest.getRequestURI()); + baseRequest.setPathInfo(uri.getDecodedPath()); if (uri.getQuery()!=null) baseRequest.mergeQueryParameters(uri.getQuery(), true); //we have to assume dispatch path and query are UTF8 } @@ -606,6 +628,7 @@ public class Server extends HandlerWrapper implements Attributes /** * @return The URI of the first {@link NetworkConnector} and first {@link ContextHandler}, or null */ + @SuppressWarnings("resource") public URI getURI() { NetworkConnector connector=null; @@ -652,6 +675,7 @@ public class Server extends HandlerWrapper implements Attributes return this.getClass().getName()+"@"+Integer.toHexString(hashCode()); } + /* ------------------------------------------------------------ */ @Override public void dump(Appendable out,String indent) throws IOException { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java index a7d5fe0f2d..f4da30c004 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java @@ -20,12 +20,10 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.net.InetSocketAddress; -import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.nio.channels.Channel; import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.concurrent.Executor; @@ -37,7 +35,6 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.SelectChannelEndPoint; import org.eclipse.jetty.io.SelectorManager; import org.eclipse.jetty.io.SelectorManager.ManagedSelector; -import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.Name; @@ -208,7 +205,8 @@ public class ServerConnector extends AbstractNetworkConnector @Name("factories") ConnectionFactory... factories) { super(server,executor,scheduler,bufferPool,acceptors,factories); - _manager = new ServerConnectorManager(getExecutor(), getScheduler(), selectors > 0 ? selectors : Runtime.getRuntime().availableProcessors()); + _manager = new ServerConnectorManager(getExecutor(), getScheduler(), + selectors>0?selectors:Math.max(1,Math.min(4,Runtime.getRuntime().availableProcessors()/2))); addBean(_manager, true); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java index 11f249e139..8ac5a48207 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java @@ -48,126 +48,151 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements super(request); } + @Override public String getAuthType() { return null; } + @Override public Cookie[] getCookies() { return null; } + @Override public long getDateHeader(String name) { return 0; } + @Override public String getHeader(String name) { return null; } - public Enumeration getHeaders(String name) + @Override + public Enumeration<String> getHeaders(String name) { return null; } - public Enumeration getHeaderNames() + @Override + public Enumeration<String> getHeaderNames() { return null; } + @Override public int getIntHeader(String name) { return 0; } + @Override public String getMethod() { return null; } + @Override public String getPathInfo() { return null; } + @Override public String getPathTranslated() { return null; } + @Override public String getContextPath() { return null; } + @Override public String getQueryString() { return null; } + @Override public String getRemoteUser() { return null; } + @Override public boolean isUserInRole(String role) { return false; } + @Override public Principal getUserPrincipal() { return null; } + @Override public String getRequestedSessionId() { return null; } + @Override public String getRequestURI() { return null; } + @Override public StringBuffer getRequestURL() { return null; } + @Override public String getServletPath() { return null; } + @Override public HttpSession getSession(boolean create) { return null; } + @Override public HttpSession getSession() { return null; } + @Override public boolean isRequestedSessionIdValid() { return false; } + @Override public boolean isRequestedSessionIdFromCookie() { return false; } + @Override public boolean isRequestedSessionIdFromURL() { return false; } + @Override public boolean isRequestedSessionIdFromUrl() { return false; @@ -176,6 +201,7 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements /** * @see javax.servlet.http.HttpServletRequest#authenticate(javax.servlet.http.HttpServletResponse) */ + @Override public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { return false; @@ -184,6 +210,7 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements /** * @see javax.servlet.http.HttpServletRequest#getPart(java.lang.String) */ + @Override public Part getPart(String name) throws IOException, ServletException { return null; @@ -192,6 +219,7 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements /** * @see javax.servlet.http.HttpServletRequest#getParts() */ + @Override public Collection<Part> getParts() throws IOException, ServletException { return null; @@ -200,6 +228,7 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements /** * @see javax.servlet.http.HttpServletRequest#login(java.lang.String, java.lang.String) */ + @Override public void login(String username, String password) throws ServletException { @@ -208,6 +237,7 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements /** * @see javax.servlet.http.HttpServletRequest#logout() */ + @Override public void logout() throws ServletException { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java index 267391b56d..d6ca22d61e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java @@ -23,7 +23,6 @@ import java.util.Set; import javax.servlet.SessionCookieConfig; import javax.servlet.SessionTrackingMode; -import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java index abc6d61ef8..38b866574d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java @@ -54,20 +54,18 @@ public class ShutdownMonitor } /** - * ShutdownMonitorThread + * ShutdownMonitorRunnable * * Thread for listening to STOP.PORT for command to stop Jetty. * If ShowndownMonitor.exitVm is true, then Sytem.exit will also be * called after the stop. * */ - public class ShutdownMonitorThread extends Thread + private class ShutdownMonitorRunnable implements Runnable { - - public ShutdownMonitorThread () + public ShutdownMonitorRunnable() { - setDaemon(true); - setName("ShutdownMonitor"); + startListenSocket(); } @Override @@ -102,7 +100,7 @@ public class ShutdownMonitor // Graceful Shutdown debug("Issuing graceful shutdown.."); ShutdownThread.getInstance().run(); - + //Stop accepting any more close(serverSocket); serverSocket = null; @@ -148,28 +146,7 @@ public class ShutdownMonitor } } - public void start() - { - if (isAlive()) - { - // TODO why are we reentrant here? - if (DEBUG) - System.err.printf("ShutdownMonitorThread already started"); - return; // cannot start it again - } - - startListenSocket(); - - if (serverSocket == null) - { - return; - } - if (DEBUG) - System.err.println("Starting ShutdownMonitorThread"); - super.start(); - } - - private void startListenSocket() + public void startListenSocket() { if (port < 0) { @@ -217,9 +194,7 @@ public class ShutdownMonitor private String key; private boolean exitVm; private ServerSocket serverSocket; - private ShutdownMonitorThread thread; - - + private Thread thread; /** * Create a ShutdownMonitor using configuration from the System properties. @@ -372,18 +347,20 @@ public class ShutdownMonitor protected void start() throws Exception { - ShutdownMonitorThread t = null; + Thread t = null; + synchronized (this) { if (thread != null && thread.isAlive()) { - // TODO why are we reentrant here? if (DEBUG) System.err.printf("ShutdownMonitorThread already started"); return; // cannot start it again } - thread = new ShutdownMonitorThread(); + thread = new Thread(new ShutdownMonitorRunnable()); + thread.setDaemon(true); + thread.setName("ShutdownMonitor"); t = thread; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java index 0d54e536fb..16a09aca5f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java @@ -58,6 +58,7 @@ public abstract class AbstractHandlerContainer extends AbstractHandler implement } /* ------------------------------------------------------------ */ + @SuppressWarnings("unchecked") @Override public <T extends Handler> T getChildHandlerByClass(Class<T> byclass) { @@ -103,6 +104,7 @@ public abstract class AbstractHandlerContainer extends AbstractHandler implement { for (Handler h:branches) { + @SuppressWarnings("unchecked") T container = (T)h; Handler[] candidates = container.getChildHandlersByClass(handler.getClass()); if (candidates!=null) 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 f01f73a4ab..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 @@ -36,7 +36,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.ListIterator; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -67,7 +66,6 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.server.ClassLoaderDump; -import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Dispatcher; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HandlerContainer; @@ -108,7 +106,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu { public final static int SERVLET_MAJOR_VERSION=3; public final static int SERVLET_MINOR_VERSION=0; - public static final Class[] SERVLET_LISTENER_TYPES = new Class[] {ServletContextListener.class, + public static final Class<?>[] SERVLET_LISTENER_TYPES = new Class[] {ServletContextListener.class, ServletContextAttributeListener.class, ServletRequestListener.class, ServletRequestAttributeListener.class}; @@ -510,8 +508,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu /* * @see javax.servlet.ServletContext#getInitParameterNames() */ - @SuppressWarnings("rawtypes") - public Enumeration getInitParameterNames() + public Enumeration<String> getInitParameterNames() { return Collections.enumeration(_initParams.keySet()); } @@ -873,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()); @@ -929,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; @@ -1129,7 +1141,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu if (!_requestAttributeListeners.isEmpty()) { - ListIterator<ServletRequestAttributeListener> iter = _requestAttributeListeners.listIterator(_requestAttributeListeners.size()); for (int i=_requestAttributeListeners.size();i-->0;) baseRequest.removeEventListener(_requestAttributeListeners.get(i)); } @@ -1648,10 +1659,15 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu } /* ------------------------------------------------------------ */ + /** + * @param path + * @param resource + * @return True if the alias is OK + */ public boolean checkAlias(String path, Resource resource) { // Is the resource aliased? - if (resource.getAlias() != null) + if (resource.getAlias() != null) { if (LOG.isDebugEnabled()) LOG.debug("Aliased resource: " + resource + "~=" + resource.getAlias()); @@ -1880,7 +1896,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu matched_path = context_path; } - if (matched_path.equals(context_path)) + if (matched_path != null && matched_path.equals(context_path)) contexts.add(ch); } } @@ -2058,7 +2074,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu /* * @see javax.servlet.ServletContext#getInitParameterNames() */ - @SuppressWarnings("unchecked") @Override public Enumeration<String> getInitParameterNames() { @@ -2195,6 +2210,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu try { + @SuppressWarnings("unchecked") Class<? extends EventListener> clazz = _classLoader==null?Loader.loadClass(ContextHandler.class,className):_classLoader.loadClass(className); addListener(clazz); } @@ -2289,9 +2305,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu //classloader, or a parent of it try { - Class reflect = Loader.loadClass(getClass(), "sun.reflect.Reflection"); + Class<?> reflect = Loader.loadClass(getClass(), "sun.reflect.Reflection"); Method getCallerClass = reflect.getMethod("getCallerClass", Integer.TYPE); - Class caller = (Class)getCallerClass.invoke(null, 2); + Class<?> caller = (Class<?>)getCallerClass.invoke(null, 2); boolean ok = false; ClassLoader callerLoader = caller.getClassLoader(); 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..2d77d1c2af 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) + 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; + 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[]) @@ -164,60 +173,66 @@ public class ContextHandlerCollection extends HandlerCollection { Handler[] handlers = getHandlers(); if (handlers==null || handlers.length==0) - return; + return; - HttpChannelState async = baseRequest.getHttpChannelState(); - if (async.isAsync()) - { - ContextHandler context=async.getContextHandler(); - if (context!=null) - { - context.handle(target,baseRequest,request, response); - return; - } - } - - // data structure which maps a request to a context; first-best match wins - // { context path => [ context ] } - // } - if (target.startsWith("/")) - { - int limit = target.length()-1; - - while (limit>=0) - { - // Get best match - ContextHandler[] contexts = _contexts.getBest(target,1,limit); - if (contexts==null) - break; + HttpChannelState async = baseRequest.getHttpChannelState(); + if (async.isAsync()) + { + 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; + } + } + + // data structure which maps a request to a context; first-best match wins + // { context path => [ context ] } + // } + if (target.startsWith("/")) + { + int limit = target.length()-1; - int l=contexts[0].getContextPath().length(); - if (l==1 || target.length()==l || target.charAt(l)=='/') - { - for (ContextHandler handler : contexts) - { - handler.handle(target,baseRequest, request, response); - if (baseRequest.isHandled()) - return; - } - } - - limit=l-2; - } - } - else - { + while (limit>=0) + { + // Get best match + Map.Entry<String,Branch[]> branches = _pathBranches.getBest(target,1,limit); + + + if (branches==null) + break; + + int l=branches.getKey().length(); + if (l==1 || target.length()==l || target.charAt(l)=='/') + { + for (Branch branch : branches.getValue()) + { + branch.getHandler().handle(target,baseRequest, request, response); + if (baseRequest.isHandled()) + return; + } + } + + limit=l-2; + } + } + else + { // This may not work in all circumstances... but then I think it should never be called - for (int i=0;i<handlers.length;i++) - { - handlers[i].handle(target,baseRequest, request, response); - if ( baseRequest.isHandled()) - return; - } - } + for (int i=0;i<handlers.length;i++) + { + handlers[i].handle(target,baseRequest, request, response); + if ( baseRequest.isHandled()) + return; + } + } } - /* ------------------------------------------------------------ */ /** 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/DefaultHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java index f71720af41..cf92003c0e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java @@ -117,62 +117,63 @@ public class DefaultHandler extends AbstractHandler response.setStatus(HttpServletResponse.SC_NOT_FOUND); response.setContentType(MimeTypes.Type.TEXT_HTML.toString()); - ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(1500); - - writer.write("<HTML>\n<HEAD>\n<TITLE>Error 404 - Not Found"); - writer.write("</TITLE>\n<BODY>\n<H2>Error 404 - Not Found.</H2>\n"); - writer.write("No context on this server matched or handled this request.<BR>"); - writer.write("Contexts known to this server are: <ul>"); + try (ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(1500);) + { + writer.write("<HTML>\n<HEAD>\n<TITLE>Error 404 - Not Found"); + writer.write("</TITLE>\n<BODY>\n<H2>Error 404 - Not Found.</H2>\n"); + writer.write("No context on this server matched or handled this request.<BR>"); + writer.write("Contexts known to this server are: <ul>"); - Server server = getServer(); - Handler[] handlers = server==null?null:server.getChildHandlersByClass(ContextHandler.class); + Server server = getServer(); + Handler[] handlers = server==null?null:server.getChildHandlersByClass(ContextHandler.class); - for (int i=0;handlers!=null && i<handlers.length;i++) - { - ContextHandler context = (ContextHandler)handlers[i]; - if (context.isRunning()) - { - writer.write("<li><a href=\""); - if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0) - writer.write("http://"+context.getVirtualHosts()[0]+":"+request.getLocalPort()); - writer.write(context.getContextPath()); - if (context.getContextPath().length()>1 && context.getContextPath().endsWith("/")) - writer.write("/"); - writer.write("\">"); - writer.write(context.getContextPath()); - if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0) - writer.write(" @ "+context.getVirtualHosts()[0]+":"+request.getLocalPort()); - writer.write(" ---> "); - writer.write(context.toString()); - writer.write("</a></li>\n"); - } - else + for (int i=0;handlers!=null && i<handlers.length;i++) { - writer.write("<li>"); - writer.write(context.getContextPath()); - if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0) - writer.write(" @ "+context.getVirtualHosts()[0]+":"+request.getLocalPort()); - writer.write(" ---> "); - writer.write(context.toString()); - if (context.isFailed()) - writer.write(" [failed]"); - if (context.isStopped()) - writer.write(" [stopped]"); - writer.write("</li>\n"); + ContextHandler context = (ContextHandler)handlers[i]; + if (context.isRunning()) + { + writer.write("<li><a href=\""); + if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0) + writer.write("http://"+context.getVirtualHosts()[0]+":"+request.getLocalPort()); + writer.write(context.getContextPath()); + if (context.getContextPath().length()>1 && context.getContextPath().endsWith("/")) + writer.write("/"); + writer.write("\">"); + writer.write(context.getContextPath()); + if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0) + writer.write(" @ "+context.getVirtualHosts()[0]+":"+request.getLocalPort()); + writer.write(" ---> "); + writer.write(context.toString()); + writer.write("</a></li>\n"); + } + else + { + writer.write("<li>"); + writer.write(context.getContextPath()); + if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0) + writer.write(" @ "+context.getVirtualHosts()[0]+":"+request.getLocalPort()); + writer.write(" ---> "); + writer.write(context.toString()); + if (context.isFailed()) + writer.write(" [failed]"); + if (context.isStopped()) + writer.write(" [stopped]"); + writer.write("</li>\n"); + } } - } - writer.write("</ul><hr>"); - writer.write("<a href=\"http://eclipse.org/jetty\"><img border=0 src=\"/favicon.ico\"/></a> "); - writer.write("<a href=\"http://eclipse.org/jetty\">Powered by Jetty:// Java Web Server</a><hr/>\n"); + writer.write("</ul><hr>"); + writer.write("<a href=\"http://eclipse.org/jetty\"><img border=0 src=\"/favicon.ico\"/></a> "); + writer.write("<a href=\"http://eclipse.org/jetty\">Powered by Jetty:// Java Web Server</a><hr/>\n"); - writer.write("\n</BODY>\n</HTML>\n"); - writer.flush(); - response.setContentLength(writer.size()); - try (OutputStream out=response.getOutputStream()) - { - writer.writeTo(out); - } + writer.write("\n</BODY>\n</HTML>\n"); + writer.flush(); + response.setContentLength(writer.size()); + try (OutputStream out=response.getOutputStream()) + { + writer.writeTo(out); + } + } } /* ------------------------------------------------------------ */ 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/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java index dcbf6ff5d5..88226c951e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java @@ -30,7 +30,6 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.component.LifeCycle; /* ------------------------------------------------------------ */ /** A <code>HandlerWrapper</code> acts as a {@link Handler} but delegates the {@link Handler#handle handle} method and diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java index 1db4283bc6..7c3f2a3886 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java @@ -308,15 +308,16 @@ public class ResourceHandler extends HandlerWrapper { if (_context==null) return null; - base=_context.getBaseResource(); - if (base==null) - return null; + return _context.getResource(path); } try { path=URIUtil.canonicalPath(path); - return base.addPath(path); + Resource r = base.addPath(path); + if (r!=null && r.getAlias()!=null && !_context.checkAlias(path, r)) + return null; + return r; } catch(Exception e) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java index 93c9f86a57..9c948ae0e7 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java @@ -133,6 +133,7 @@ public class ShutdownHandler extends HandlerWrapper } } + @SuppressWarnings("resource") private String getServerUrl() { NetworkConnector connector=null; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSession.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSession.java index ec586ac09c..3bed6cda0c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSession.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSession.java @@ -397,7 +397,6 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI } /* ------------------------------------------------------------ */ - @SuppressWarnings({ "unchecked" }) @Override public Enumeration<String> getAttributeNames() { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java index 1f966c5957..aa039081e6 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java @@ -227,10 +227,10 @@ public abstract class AbstractSessionManager extends ContainerLifeCycle implemen _context=ContextHandler.getCurrentContext(); _loader=Thread.currentThread().getContextClassLoader(); - if (_sessionIdManager==null) + final Server server=getSessionHandler().getServer(); + synchronized (server) { - final Server server=getSessionHandler().getServer(); - synchronized (server) + if (_sessionIdManager==null) { _sessionIdManager=server.getSessionIdManager(); if (_sessionIdManager==null) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionIdManager.java index a17bc06f76..382b633b5c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionIdManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionIdManager.java @@ -32,8 +32,6 @@ import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.server.SessionIdManager; - /* ------------------------------------------------------------ */ /** * HashSessionIdManager. An in-memory implementation of the session ID manager. diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java index 1effd32f94..53ccd6398e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java @@ -19,7 +19,6 @@ package org.eclipse.jetty.server.session; import java.io.DataInputStream; -import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -34,10 +33,8 @@ import java.util.concurrent.TimeUnit; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; -import org.eclipse.jetty.server.SessionIdManager; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.ClassLoadingObjectInputStream; -import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; import org.eclipse.jetty.util.thread.Scheduler; @@ -308,9 +305,9 @@ public class HashSessionManager extends AbstractSessionManager _scavengePeriodMs=period; - if (_timer!=null && (period!=old_period || _task==null)) + synchronized (this) { - synchronized (this) + if (_timer!=null && (period!=old_period || _task==null)) { if (_task!=null) { @@ -569,18 +566,22 @@ public class HashSessionManager extends AbstractSessionManager { File file = new File(_storeDir,idInCuster); - FileInputStream in = null; Exception error = null; - try + if (!file.exists()) { - if (file.exists()) + if (LOG.isDebugEnabled()) { - in = new FileInputStream(file); - HashedSession session = restoreSession(in, null); - addSession(session, false); - session.didActivate(); - return session; + LOG.debug("Not loading: {}",file); } + return null; + } + + try (FileInputStream in = new FileInputStream(file)) + { + HashedSession session = restoreSession(in,null); + addSession(session,false); + session.didActivate(); + return session; } catch (Exception e) { @@ -588,8 +589,6 @@ public class HashSessionManager extends AbstractSessionManager } finally { - if (in != null) IO.close(in); - if (error != null) { if (isDeleteUnrestorableSessions() && file.exists() && file.getParentFile().equals(_storeDir) ) @@ -603,7 +602,10 @@ public class HashSessionManager extends AbstractSessionManager } } else - file.delete(); //delete successfully restored file + { + // delete successfully restored file + file.delete(); + } } return null; } @@ -641,8 +643,10 @@ public class HashSessionManager extends AbstractSessionManager if (session == null) session = (HashedSession)newSession(created, accessed, clusterId); + session.setRequests(requests); + // Attributes int size = di.readInt(); restoreSessionAttributes(di, size, session); @@ -652,7 +656,7 @@ public class HashSessionManager extends AbstractSessionManager int maxIdle = di.readInt(); session.setMaxInactiveInterval(maxIdle); } - catch (EOFException e) + catch (IOException e) { LOG.debug("No maxInactiveInterval persisted for session "+clusterId); LOG.ignore(e); @@ -661,12 +665,14 @@ public class HashSessionManager extends AbstractSessionManager return session; } - + + @SuppressWarnings("resource") private void restoreSessionAttributes (InputStream is, int size, HashedSession session) throws Exception { if (size>0) { + // input stream should not be closed here ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is); for (int i=0; i<size;i++) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashedSession.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashedSession.java index d36e4277e4..9bfa84d989 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashedSession.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashedSession.java @@ -145,24 +145,23 @@ public class HashedSession extends MemSession throws Exception { File file = null; - FileOutputStream fos = null; if (!_saveFailed && _hashSessionManager._storeDir != null) { - try + file = new File(_hashSessionManager._storeDir, super.getId()); + if (file.exists()) + { + file.delete(); + } + + try(FileOutputStream fos = new FileOutputStream(file,false)) { - file = new File(_hashSessionManager._storeDir, super.getId()); - if (file.exists()) - file.delete(); - file.createNewFile(); - fos = new FileOutputStream(file); save(fos); - IO.close(fos); } catch (Exception e) { saveFailed(); // We won't try again for this session - if (fos != null) IO.close(fos); - if (file != null) file.delete(); // No point keeping the file if we didn't save the whole session + if (file != null) + file.delete(); // No point keeping the file if we didn't save the whole session throw e; } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java index a70d48ecfe..535dc5f02e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java @@ -778,10 +778,10 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager if (LOG.isDebugEnabled()) LOG.debug("Scavenging every "+_scavengeIntervalMs+" ms"); - //if (_timer!=null && (period!=old_period || _task==null)) - if (_scheduler != null && (period!=old_period || _task==null)) + synchronized (this) { - synchronized (this) + //if (_timer!=null && (period!=old_period || _task==null)) + if (_scheduler != null && (period!=old_period || _task==null)) { if (_task!=null) _task.cancel(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java index fb4d7468c5..a84376b02a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java @@ -37,10 +37,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSessionEvent; -import javax.servlet.http.HttpSessionListener; - -import org.eclipse.jetty.server.SessionIdManager; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.session.JDBCSessionIdManager.SessionTableSchema; import org.eclipse.jetty.util.ClassLoadingObjectInputStream; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java index e85cc9e2ed..fc86f3de5f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java @@ -49,10 +49,12 @@ public class SessionHandler extends ScopedHandler final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); public final static EnumSet<SessionTrackingMode> DEFAULT_TRACKING = EnumSet.of(SessionTrackingMode.COOKIE,SessionTrackingMode.URL); - - public static final Class[] SESSION_LISTENER_TYPES = new Class[] {HttpSessionAttributeListener.class, - HttpSessionIdListener.class, - HttpSessionListener.class}; + + @SuppressWarnings("unchecked") + public static final Class<? extends EventListener>[] SESSION_LISTENER_TYPES = + new Class[] {HttpSessionAttributeListener.class, + HttpSessionIdListener.class, + HttpSessionListener.class}; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/CheckReverseProxyHeadersTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/CheckReverseProxyHeadersTest.java index 506ff9e2ea..cb60e0627d 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/CheckReverseProxyHeadersTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/CheckReverseProxyHeadersTest.java @@ -66,7 +66,7 @@ public class CheckReverseProxyHeadersTest @Override public void validate(HttpServletRequest request) { - assertEquals("::1", request.getServerName()); + assertEquals("[::1]", request.getServerName()); assertEquals(80, request.getServerPort()); assertEquals("10.20.30.40", request.getRemoteAddr()); assertEquals("10.20.30.40", request.getRemoteHost()); @@ -84,7 +84,7 @@ public class CheckReverseProxyHeadersTest @Override public void validate(HttpServletRequest request) { - assertEquals("::1", request.getServerName()); + assertEquals("[::1]", request.getServerName()); assertEquals(8888, request.getServerPort()); assertEquals("10.20.30.40", request.getRemoteAddr()); assertEquals("10.20.30.40", request.getRemoteHost()); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/GracefulStopTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/GracefulStopTest.java index 2794cfb1f9..6943f768ce 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/GracefulStopTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/GracefulStopTest.java @@ -30,6 +30,8 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.StdErrLog; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Before; @@ -79,6 +81,35 @@ public class GracefulStopTest Assert.assertThat(out,Matchers.containsString("200 OK")); } } + + @Test + public void testGracefulTimout() throws Exception + { + server.setStopTimeout(100); + new Thread() + { + @Override + public void run() + { + try + { + TimeUnit.SECONDS.sleep(1); + server.stop(); + } + catch (Exception e) + { + //e.printStackTrace(); + } + } + }.start(); + + try(Socket socket = new Socket("localhost",server.getBean(NetworkConnector.class).getLocalPort());) + { + socket.getOutputStream().write("GET / HTTP/1.0\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1)); + String out = IO.toString(socket.getInputStream()); + Assert.assertEquals("",out); + } + } private static class TestHandler extends AbstractHandler { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java index 96056fda5f..d582e578ce 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java @@ -723,7 +723,6 @@ public class HttpConnectionTest "12345\015\012"+ "0;\015\012\015\012"); offset = checkContains(response,offset,"HTTP/1.1 200"); - offset = checkContains(response,offset,"Allow: GET,POST,HEAD"); offset=0; response=connector.getResponses("GET * HTTP/1.1\n"+ diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java index e2b4f213d3..58497def1b 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java @@ -136,11 +136,11 @@ public class HttpURITest /*33*/ {"/?abc=test",null, null, null,null,"/", null,"abc=test",null}, /*34*/ {"/#fragment",null, null, null,null,"/", null,null,"fragment"}, /*35*/ {"http://192.0.0.1:8080/","http","//192.0.0.1:8080","192.0.0.1","8080","/",null,null,null}, - /*36*/ {"http://[2001:db8::1]:8080/","http","//[2001:db8::1]:8080","2001:db8::1","8080","/",null,null,null}, - /*37*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","2001:db8::1","8080","/",null,null,null}, - /*38*/ {"http://[2001:db8::1]/","http","//[2001:db8::1]","2001:db8::1",null,"/",null,null,null}, + /*36*/ {"http://[2001:db8::1]:8080/","http","//[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null}, + /*37*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null}, + /*38*/ {"http://[2001:db8::1]/","http","//[2001:db8::1]","[2001:db8::1]",null,"/",null,null,null}, /*39*/ {"//[2001:db8::1]:8080/",null,null,null,null,"//[2001:db8::1]:8080/",null,null,null}, - /*40*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","2001:db8::1","8080","/",null,null,null}, + /*40*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null}, /*41*/ {"*",null,null,null,null,"*",null, null,null} }; @@ -353,7 +353,7 @@ public class HttpURITest { /* 0*/ {" localhost:8080 ","localhost","8080"}, /* 1*/ {" 127.0.0.1:8080 ","127.0.0.1","8080"}, - /* 2*/ {" [127::0::0::1]:8080 ","127::0::0::1","8080"}, + /* 2*/ {" [127::0::0::1]:8080 ","[127::0::0::1]","8080"}, /* 3*/ {" error ",null,null}, /* 4*/ {" http://localhost:8080/ ",null,null}, }; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/NetworkTrafficListenerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/NetworkTrafficListenerTest.java index ca9d7999cb..21589a4442 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/NetworkTrafficListenerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/NetworkTrafficListenerTest.java @@ -41,7 +41,6 @@ import org.eclipse.jetty.io.NetworkTrafficListener; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.BufferUtil; import org.junit.After; -import org.junit.Ignore; import org.junit.Test; public class NetworkTrafficListenerTest diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java index 1643bab762..bfb52afab0 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java @@ -495,7 +495,6 @@ public class PartialRFC2616Test "Host: localhost\n"+ "\n"); offset=checkContains(response,offset, "HTTP/1.1 200","200")+1; - offset=checkContains(response,offset, "Allow: GET,POST,HEAD,OPTIONS","Allow")+1; offset=0; response=connector.getResponses("GET * HTTP/1.1\n"+ diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index e9ed6d78d6..ef8025c70e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -65,7 +65,6 @@ import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.StdErrLog; import org.hamcrest.Matchers; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -486,7 +485,7 @@ public class RequestTest assertThat(response,Matchers.containsString("200 OK")); assertEquals("http://[::1]/",results.get(i++)); assertEquals("0.0.0.0",results.get(i++)); - assertEquals("::1",results.get(i++)); + assertEquals("[::1]",results.get(i++)); assertEquals("80",results.get(i++)); @@ -500,7 +499,7 @@ public class RequestTest assertThat(response,Matchers.containsString("200 OK")); assertEquals("http://[::1]:8888/",results.get(i++)); assertEquals("0.0.0.0",results.get(i++)); - assertEquals("::1",results.get(i++)); + assertEquals("[::1]",results.get(i++)); assertEquals("8888",results.get(i++)); @@ -516,7 +515,7 @@ public class RequestTest assertThat(response,Matchers.containsString("200 OK")); assertEquals("https://[::1]/",results.get(i++)); assertEquals("remote",results.get(i++)); - assertEquals("::1",results.get(i++)); + assertEquals("[::1]",results.get(i++)); assertEquals("443",results.get(i++)); @@ -532,7 +531,7 @@ public class RequestTest assertThat(response,Matchers.containsString("200 OK")); assertEquals("https://[::1]:8888/",results.get(i++)); assertEquals("remote",results.get(i++)); - assertEquals("::1",results.get(i++)); + assertEquals("[::1]",results.get(i++)); assertEquals("8888",results.get(i++)); } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTest.java new file mode 100644 index 0000000000..03ee046aa8 --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTest.java @@ -0,0 +1,197 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.lang.reflect.Field; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.io.ChannelEndPoint; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.DefaultHandler; +import org.eclipse.jetty.server.handler.HandlerList; +import org.eclipse.jetty.util.IO; +import org.junit.Test; + +public class ServerConnectorTest +{ + public static class ReuseInfoHandler extends AbstractHandler + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + response.setContentType("text/plain"); + + EndPoint endPoint = baseRequest.getHttpChannel().getEndPoint(); + assertThat("Endpoint",endPoint,instanceOf(ChannelEndPoint.class)); + ChannelEndPoint channelEndPoint = (ChannelEndPoint)endPoint; + Socket socket = channelEndPoint.getSocket(); + ServerConnector connector = (ServerConnector)baseRequest.getHttpChannel().getConnector(); + + PrintWriter out = response.getWriter(); + out.printf("connector.getReuseAddress() = %b%n",connector.getReuseAddress()); + + try + { + Field fld = connector.getClass().getDeclaredField("_reuseAddress"); + assertThat("Field[_reuseAddress]",fld,notNullValue()); + fld.setAccessible(true); + Object val = fld.get(connector); + out.printf("connector._reuseAddress() = %b%n",val); + } + catch (Throwable t) + { + t.printStackTrace(out); + } + + out.printf("socket.getReuseAddress() = %b%n",socket.getReuseAddress()); + + baseRequest.setHandled(true); + } + } + + private URI toServerURI(ServerConnector connector) throws URISyntaxException + { + String host = connector.getHost(); + if (host == null) + { + host = "localhost"; + } + int port = connector.getLocalPort(); + return new URI(String.format("http://%s:%d/",host,port)); + } + + private String getResponse(URI uri) throws MalformedURLException, IOException + { + HttpURLConnection http = (HttpURLConnection)uri.toURL().openConnection(); + assertThat("Valid Response Code",http.getResponseCode(),anyOf(is(200),is(404))); + + try (InputStream in = http.getInputStream()) + { + return IO.toString(in,StandardCharsets.UTF_8); + } + } + + @Test + public void testReuseAddress_Default() throws Exception + { + Server server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(0); + server.addConnector(connector); + + HandlerList handlers = new HandlerList(); + handlers.addHandler(new ReuseInfoHandler()); + handlers.addHandler(new DefaultHandler()); + + server.setHandler(handlers); + + try + { + server.start(); + + URI uri = toServerURI(connector); + String response = getResponse(uri); + assertThat("Response",response,containsString("connector.getReuseAddress() = true")); + assertThat("Response",response,containsString("connector._reuseAddress() = true")); + assertThat("Response",response,containsString("socket.getReuseAddress() = true")); + } + finally + { + server.stop(); + } + } + + @Test + public void testReuseAddress_True() throws Exception + { + Server server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(0); + connector.setReuseAddress(true); + server.addConnector(connector); + + HandlerList handlers = new HandlerList(); + handlers.addHandler(new ReuseInfoHandler()); + handlers.addHandler(new DefaultHandler()); + + server.setHandler(handlers); + + try + { + server.start(); + + URI uri = toServerURI(connector); + String response = getResponse(uri); + assertThat("Response",response,containsString("connector.getReuseAddress() = true")); + assertThat("Response",response,containsString("connector._reuseAddress() = true")); + assertThat("Response",response,containsString("socket.getReuseAddress() = true")); + } + finally + { + server.stop(); + } + } + + @Test + public void testReuseAddress_False() throws Exception + { + Server server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(0); + connector.setReuseAddress(false); + server.addConnector(connector); + + HandlerList handlers = new HandlerList(); + handlers.addHandler(new ReuseInfoHandler()); + handlers.addHandler(new DefaultHandler()); + + server.setHandler(handlers); + + try + { + server.start(); + + URI uri = toServerURI(connector); + String response = getResponse(uri); + assertThat("Response",response,containsString("connector.getReuseAddress() = false")); + assertThat("Response",response,containsString("connector._reuseAddress() = false")); + assertThat("Response",response,containsString("socket.getReuseAddress() = false")); + } + finally + { + server.stop(); + } + } +} diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java index bd02b034d8..0b02ee1b8a 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java @@ -26,43 +26,36 @@ import java.io.LineNumberReader; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; +import java.util.concurrent.TimeUnit; import org.junit.Test; /** * ShutdownMonitorTest - * - * - * */ public class ShutdownMonitorTest { - - @Test - public void testShutdown () - throws Exception + public void testShutdown() throws Exception { - - //test port and key assignment + // test port and key assignment ShutdownMonitor.getInstance().setPort(0); ShutdownMonitor.getInstance().setExitVm(false); ShutdownMonitor.getInstance().start(); String key = ShutdownMonitor.getInstance().getKey(); int port = ShutdownMonitor.getInstance().getPort(); - - //try starting a 2nd time (should be ignored) - ShutdownMonitor.getInstance().start(); - - + + // try starting a 2nd time (should be ignored) + ShutdownMonitor.getInstance().start(); + stop(port,key,true); assertTrue(!ShutdownMonitor.getInstance().isAlive()); - - //should be able to change port and key because it is stopped + + // should be able to change port and key because it is stopped ShutdownMonitor.getInstance().setPort(0); - ShutdownMonitor.getInstance().setKey("foo"); + ShutdownMonitor.getInstance().setKey("foo"); ShutdownMonitor.getInstance().start(); - + key = ShutdownMonitor.getInstance().getKey(); port = ShutdownMonitor.getInstance().getPort(); assertTrue(ShutdownMonitor.getInstance().isAlive()); @@ -71,41 +64,34 @@ public class ShutdownMonitorTest assertTrue(!ShutdownMonitor.getInstance().isAlive()); } - - public void stop (int port, String key, boolean check) - throws Exception + public void stop(int port, String key, boolean check) throws Exception { - Socket s = null; - - try + System.out.printf("Attempting stop to localhost:%d (%b)%n",port,check); + try (Socket s = new Socket(InetAddress.getByName("127.0.0.1"),port)) { - //send stop command - s = new Socket(InetAddress.getByName("127.0.0.1"),port); - - OutputStream out = s.getOutputStream(); - out.write((key + "\r\nstop\r\n").getBytes()); - out.flush(); - - if (check) + // send stop command + try (OutputStream out = s.getOutputStream()) { - //wait a little - Thread.currentThread().sleep(600); + out.write((key + "\r\nstop\r\n").getBytes()); + out.flush(); - //check for stop confirmation - LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream())); - String response; - if ((response = lin.readLine()) != null) + if (check) { - assertEquals("Stopped", response); + // wait a little + TimeUnit.MILLISECONDS.sleep(600); + + // check for stop confirmation + LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream())); + String response; + if ((response = lin.readLine()) != null) + { + assertEquals("Stopped",response); + } + else + throw new IllegalStateException("No stop confirmation"); } - else - throw new IllegalStateException("No stop confirmation"); } } - finally - { - if (s != null) s.close(); - } } } 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; + } + } + } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java index ebd686d53d..a562c09591 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java @@ -22,6 +22,7 @@ import java.io.File; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.Log; @@ -33,24 +34,6 @@ import org.junit.Test; public class HashSessionManagerTest { - @After - public void enableStacks() - { - enableStacks(true); - } - - @Before - public void quietStacks() - { - enableStacks(false); - } - - protected void enableStacks(boolean enabled) - { - StdErrLog log = (StdErrLog)Log.getLogger("org.eclipse.jetty.server.session"); - log.setHideStacks(!enabled); - } - @Test public void testDangerousSessionIdRemoval() throws Exception { @@ -78,7 +61,8 @@ public class HashSessionManagerTest manager.setDeleteUnrestorableSessions(true); manager.setLazyLoad(true); File testDir = MavenTestingUtils.getTargetTestingDir("hashes"); - testDir.mkdirs(); + FS.ensureEmpty(testDir); + manager.setStoreDirectory(testDir); Assert.assertTrue(new File(testDir, "validFile.session").createNewFile()); @@ -88,7 +72,6 @@ public class HashSessionManagerTest manager.getSession("validFile.session"); Assert.assertTrue("File shouldn't exist!", !new File(testDir,"validFile.session").exists()); - } @Test @@ -116,7 +99,6 @@ public class HashSessionManagerTest server.start(); manager.start(); - HashedSession session = (HashedSession)manager.newHttpSession(new Request(null, null)); String sessionId = session.getId(); @@ -124,7 +106,7 @@ public class HashSessionManagerTest session.setAttribute("two", new Integer(2)); //stop will persist sessions - manager.setMaxInactiveInterval(30); //change max inactive interval for *new* sessions + manager.setMaxInactiveInterval(30); // change max inactive interval for *new* sessions manager.stop(); Assert.assertTrue("File should exist!", new File(testDir, session.getId()).exists()); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java index 6cc241a9b0..6c5addb60d 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java @@ -63,9 +63,9 @@ public class SelectChannelServerSslTest extends HttpServerTestBase @Override public void testFullMethod() throws Exception { - // Don't run on Windows (buggy JVM) - Assume.assumeTrue(!OS.IS_WINDOWS); - + // Don't run on Windows (buggy JVM) + Assume.assumeTrue(!OS.IS_WINDOWS); + try { super.testFullMethod(); @@ -79,8 +79,8 @@ public class SelectChannelServerSslTest extends HttpServerTestBase @Override public void testFullURI() throws Exception { - // Don't run on Windows (buggy JVM) - Assume.assumeTrue(!OS.IS_WINDOWS); + // Don't run on Windows (buggy JVM) + Assume.assumeTrue(!OS.IS_WINDOWS); try { super.testFullURI(); |