diff options
author | Jan Bartel | 2010-06-16 11:02:05 +0000 |
---|---|---|
committer | Jan Bartel | 2010-06-16 11:02:05 +0000 |
commit | 1991632fdfe0b797cabc8b0b4b26faddb9de659a (patch) | |
tree | fd0f2f310970b8832da4e2e95e375832c6870046 | |
parent | 884b98091c31a5db010414373d1b29a0011c04b7 (diff) | |
download | org.eclipse.jetty.project-1991632fdfe0b797cabc8b0b4b26faddb9de659a.tar.gz org.eclipse.jetty.project-1991632fdfe0b797cabc8b0b4b26faddb9de659a.tar.xz org.eclipse.jetty.project-1991632fdfe0b797cabc8b0b4b26faddb9de659a.zip |
Update to jetty-7-base-for-jetty-8-20100616
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/branches/jetty-8@2012 7e9141cc-0065-0410-87d8-b60c137991c4
195 files changed, 5351 insertions, 2351 deletions
diff --git a/README.txt b/README.txt index 640c7e9b43..436e95e588 100644 --- a/README.txt +++ b/README.txt @@ -1,62 +1,11 @@ -JETTY -===== +This is a source checkout of the Jetty webserver. -The Jetty project is a 100% Java HTTP Server, HTTP Client -and Servlet Container. - - -The Jetty @ eclipse project is based on the Jetty project at codehaus - - http://jetty.codehaus.org - -Ongoing development is now at the eclipse foundation - - http://www.eclipse.org/jetty/ - - -Jetty @ eclipse is open source and is dual licensed using the apache 2.0 and -eclipse public license 1.0. You may choose either license when distributing -jetty. - - - -BUILDING JETTY -============== - -Jetty uses maven 2 as its build system. Maven will fetch -the dependancies, build the server and assemble a runnable -version: +To build, use: mvn install +The jetty distribution will be built in - -RUNNING JETTY -============= - -The run directory is either the top-level of a binary release -or jetty-distribution/target/assembly-prep directory when built from -source. - -To run with the default options: - - java -jar start.jar - -To run with specific configuration file(s) - - java -jar start.jar etc/jetty.xml - -To see the available options - - java -jar start.jar --help - -To run with JSP support - - java -jar start.jar OPTIONS=Server,jsp - -To run with JMX support - - java -jar start.jar OPTIONS=Server,jmx etc/jetty-jmx.xml etc/jetty.xml - + jetty-distribution/target/distribution diff --git a/VERSION.txt b/VERSION.txt index b0acab8f5c..6b47f18cf5 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1,11 +1,66 @@ -jetty-8.0.0.M1 8 April 2010 +jetty-8.0.0.M1-SNAPSHOT + 306350 Ensure jars excluded by ordering are not scanned for annotations + Ensure <absolute-ordering> in web.xml overrides relative <ordering> in fragments + Ensure empty <absolute-ordering> implies exclusion of all fragments + Ensure servlet-api jar class inheritance hierarchy is scanned - + 306349 ProxyServlet does not work unless deployed at / -jetty-7.1.1-SNAPSHOT +jetty-7.1.5-SNAPSHOT + + 311550 The WebAppProvider should allow setTempDirectory + + 316449 Websocket disconnect fix + + 316584 Exception on startup if temp path has spaces and extractWAR=false + + 316597 Removed null check and fixed name in Resource#hrefEncodeURI + + JETTY-1237 Save local/remote address to be available after close + +jetty-7.1.4.v20100610 + + 298551 SslSocketConnector does not need keystore stream + + 295715 AbstractSessionManager decoupled from Context + + 292326 Stop continuations if server is stopped. + + 292814 Make QoSFilter and DoSFilter JMX manageable + + 293222 Improve request log to handle/show asynchronous latency + + 294212 Can not customize session cookie path + + 301608 Deregister shutdown hooks + + 302350 org.eclipse.jetty.server.NCSARequestLog is missing JavaDoc + + 303661 jetty.sh failes if JETTY_HOME is not writeable + + 304100 Better document JMX setup in jetty-jmx.xml + + 305300 AsyncContext.start dispatches runnable + + 314299 Create test harness for JDBCLoginService + + 314581 Implement the Sec-Websocket handshake + + 315190 CrossOriginFilter avoid headers not understood by WebSocket + + 315687 included init script fails to test for JETTY_HOME as empty + + 315715 Improved Cookie version handling. Server.setMaxCookieVersion + + 315744 Fixed STOP.PORT and STOP.KEY in start.jar + + 315748 Removed --fromDaemon from start.jar (replaced with --daemon) + + 315925 Improved context xml configuration handling + + 315995 Incorrect package name in system classes list + + 316119 Fixed maxIdleTime for SocketEndPoint + + 316254 Implement @DeclareRoles + + 316334 Breaking change on org.eclipse.jetty.client.HttpExchange + + 316399 Debug output in MultiPartFilter + + 316413 Restarting webapp for packed war fails + + 316557 OSGi HttpService failure due to undeployed context handlers + + JETTY-547 Delay close after shutdown until request read + + JETTY-1231 Support context request log handler + +jetty-7.1.3.v20100526 + + 296567 HttpClient RedirectListener handles new HttpDestination + + 297598 JDBCLoginService uses hardcoded credential class + + 305898 Websocket handles query string in URI + + 307457 Exchanges are left unhandled when connection is lost + + 313205 Unable to run test-jdbc-sessions tests + + 314177 JSTL support is broken + + 314009 jetty.xml configuration file on command line + + 314459 support maven3 for builds + +jetty-7.1.2.v20100523 + + 308866 Update test suite to JUnit4 - Module jetty-util + + 312948 Recycle SSL crypto buffers + + 313196 randomly allocate ports for session test. + + 313278 Implement octet ranges in IPAccessHandler + + 313336 secure websockets + + 314009 updated README.txt + + Update links to jetty website and wiki on test webapp + +jetty-7.1.1.v20100517 + 302344 Make the list of available contexts if root context is not configured optional + 304803 Remove TypeUtil Integer and Long caches + 306226 HttpClient should allow changing the keystore and truststore type diff --git a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java index 53d67062da..27f9d30bac 100644 --- a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java +++ b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java @@ -31,7 +31,6 @@ import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; -import org.eclipse.jetty.server.ssl.SslSocketConnector; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.QueuedThreadPool; @@ -66,7 +65,7 @@ public class LikeJettyXml server.setConnectors(new Connector[] { connector }); - SslSocketConnector ssl_connector = new SslSocketConnector(); + SslSelectChannelConnector ssl_connector = new SslSelectChannelConnector(); ssl_connector.setPort(8443); ssl_connector.setKeystore(jetty_home + "/etc/keystore"); ssl_connector.setPassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); diff --git a/jetty-aggregate/pom.xml b/jetty-aggregate/pom.xml index 73e187d778..5af67d04b4 100644 --- a/jetty-aggregate/pom.xml +++ b/jetty-aggregate/pom.xml @@ -11,6 +11,24 @@ <name>Jetty :: Aggregate Project</name> <packaging>pom</packaging> <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-pmd-plugin</artifactId> + <configuration> + <!-- No Point running PMD on aggregate projects --> + <skip>true</skip> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <!-- No Point running Findbugs on aggregate projects --> + <skip>true</skip> + </configuration> + </plugin> + </plugins> </build> <modules> <module>jetty-server</module> diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index d2bef18158..6e610bf228 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -35,6 +35,7 @@ import org.eclipse.jetty.webapp.WebAppContext; public class AnnotationConfiguration extends AbstractConfiguration { public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap"; + public static final String DISCOVERED_ANNOTATIONS = "org.eclipse.jetty.discoveredAnnotations"; public void preConfigure(final WebAppContext context) throws Exception @@ -61,13 +62,17 @@ public class AnnotationConfiguration extends AbstractConfiguration //Only scan jars and classes if metadata is not complete and the web app is version 3.0, or //a 2.5 version webapp that has specifically asked to discover annotations if (Log.isDebugEnabled()) Log.debug("parsing annotations"); - + + List<ClassAnnotation> discoveredAnnotations = new ArrayList<ClassAnnotation>(); + context.setAttribute(DISCOVERED_ANNOTATIONS, discoveredAnnotations); + AnnotationParser parser = new AnnotationParser(); //Discoverable annotations - those that you have to look for without loading a class parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", new WebServletAnnotationHandler(context)); parser.registerAnnotationHandler("javax.servlet.annotation.WebFilter", new WebFilterAnnotationHandler(context)); parser.registerAnnotationHandler("javax.servlet.annotation.WebListener", new WebListenerAnnotationHandler(context)); + ClassInheritanceHandler classHandler = new ClassInheritanceHandler(); parser.registerClassHandler(classHandler); registerServletContainerInitializerAnnotationHandlers(context, parser); @@ -92,6 +97,15 @@ public class AnnotationConfiguration extends AbstractConfiguration //save the type inheritance map created by the parser for later reference context.setAttribute(CLASS_INHERITANCE_MAP, classHandler.getMap()); + + //TODO change the time at which the discovered annotations are applied. According to the + //servlet spec p.81, the annotations associated with a fragment have to be applied directly + //after those of the fragment's descriptor. For now, to make progress, we just process them + //as we have been doing, ie after all the descriptors have been processed. + for (ClassAnnotation annotation:discoveredAnnotations) + { + annotation.apply(); + } } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java index 35efeadcbb..07073649cc 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java @@ -38,7 +38,7 @@ public class WebFilterAnnotationHandler implements DiscoverableAnnotationHandler List<Value> values) { WebFilterAnnotation wfAnnotation = new WebFilterAnnotation(_context, className); - //TODO add to list + ((List<ClassAnnotation>)_context.getAttribute(AnnotationConfiguration.DISCOVERED_ANNOTATIONS)).add(wfAnnotation); } public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java index e9a708c92e..6663ba7ae0 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java @@ -33,7 +33,7 @@ public class WebListenerAnnotationHandler implements DiscoverableAnnotationHandl List<Value> values) { WebListenerAnnotation wlAnnotation = new WebListenerAnnotation(_context, className); - //TODO put in list + ((List<ClassAnnotation>)_context.getAttribute(AnnotationConfiguration.DISCOVERED_ANNOTATIONS)).add(wlAnnotation); } public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java index f6c7526e1c..c5ae644e51 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java @@ -17,6 +17,7 @@ import java.util.List; import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; import org.eclipse.jetty.annotations.AnnotationParser.Value; +import org.eclipse.jetty.annotations.ClassAnnotation; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.webapp.WebAppContext; @@ -50,7 +51,7 @@ public class WebServletAnnotationHandler implements DiscoverableAnnotationHandle return; WebServletAnnotation annotation = new WebServletAnnotation (_context, className); - //TODO keep list of these + ((List<ClassAnnotation>)_context.getAttribute(AnnotationConfiguration.DISCOVERED_ANNOTATIONS)).add(annotation); } public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java index f0c56d58b4..8b51c8812b 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java @@ -13,15 +13,16 @@ package org.eclipse.jetty.annotations; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import java.util.ArrayList; -import java.util.List; import java.util.Arrays; import java.util.HashSet; +import java.util.List; -import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; -import org.eclipse.jetty.annotations.AnnotationParser.Value; -import org.eclipse.jetty.annotations.AnnotationParser.ListValue; -import org.eclipse.jetty.annotations.AnnotationParser.SimpleValue; import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection; import org.eclipse.jetty.plus.annotation.RunAsCollection; import org.eclipse.jetty.security.ConstraintSecurityHandler; @@ -30,12 +31,6 @@ import org.eclipse.jetty.servlet.ServletMapping; import org.eclipse.jetty.webapp.WebAppContext; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.fail; - /** * TestServletAnnotations * @@ -55,6 +50,8 @@ public class TestServletAnnotations wac.setAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION, collection); RunAsCollection runAsCollection = new RunAsCollection(); wac.setAttribute(RunAsCollection.RUNAS_COLLECTION, runAsCollection); + List<ClassAnnotation> discoveredAnnotations = new ArrayList<ClassAnnotation>(); + wac.setAttribute(AnnotationConfiguration.DISCOVERED_ANNOTATIONS, discoveredAnnotations); parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", new WebServletAnnotationHandler(wac)); parser.parse(classes, new ClassNameResolver () @@ -69,6 +66,11 @@ public class TestServletAnnotations return false; } }); + + assertEquals(1, discoveredAnnotations.size()); + assertTrue(discoveredAnnotations.get(0) instanceof WebServletAnnotation); + + discoveredAnnotations.get(0).apply(); ServletHolder[] holders = wac.getServletHandler().getServlets(); assertNotNull(holders); diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml index c4e2ab5924..bcd2905c76 100644 --- a/jetty-client/pom.xml +++ b/jetty-client/pom.xml @@ -38,7 +38,7 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> - <archive> + <archive> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> @@ -56,16 +56,17 @@ <artifactId>jetty-server</artifactId> <version>${project.version}</version> <scope>test</scope> - </dependency> + </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-security</artifactId> <version>${project.version}</version> <scope>test</scope> - </dependency> + </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java index 5c81aa2a0e..be20cc49c6 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java @@ -296,7 +296,7 @@ public class HttpClient extends HttpBuffers implements Attributes /** * Registers a listener that can listen to the stream of execution between the client and the - * server and influence events. Sequential calls to the method wrapper sequentially wrap the preceeding + * server and influence events. Sequential calls to the method wrapper sequentially wrap the preceding * listener in a delegation model. * <p/> * NOTE: the SecurityListener is a special listener which doesn't need to be added via this @@ -313,7 +313,8 @@ public class HttpClient extends HttpBuffers implements Attributes } _registeredListeners.add(listenerClass); } - + + /* ------------------------------------------------------------ */ public LinkedList<String> getRegisteredListeners() { return _registeredListeners; diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java index 021756a79d..0c5f2a56fa 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java @@ -28,7 +28,6 @@ import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersions; -import org.eclipse.jetty.http.ssl.SslSelectChannelEndPoint; import org.eclipse.jetty.io.AsyncEndPoint; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.Buffers; @@ -37,6 +36,7 @@ import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.View; import org.eclipse.jetty.io.nio.SelectChannelEndPoint; +import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.Timeout; diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java index 09ab59e94d..b885828022 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java @@ -219,7 +219,7 @@ public class HttpDestination if (connection!=null) { _connections.remove(connection); - connection.getEndPoint().close(); + connection.close(); connection=null; } if (_idle.size() > 0) @@ -229,9 +229,10 @@ public class HttpDestination if (connection==null) return null; - if (connection.cancelIdleTimeout() ) + // Check if the connection was idle, + // but it expired just a moment ago + if (connection.cancelIdleTimeout()) return connection; - } } @@ -271,6 +272,11 @@ public class HttpDestination HttpExchange ex = _queue.removeFirst(); ex.setStatus(HttpExchange.STATUS_EXCEPTED); ex.getEventListener().onConnectionFailed(throwable); + + // Since an existing connection had failed, we need to create a + // connection if the queue is not empty and client is running. + if (!_queue.isEmpty() && _client.isStarted()) + startNewConnection(); } } @@ -323,7 +329,7 @@ public class HttpDestination else { HttpExchange ex = _queue.removeFirst(); - connection.send(ex); + send(connection, ex); } } @@ -372,7 +378,7 @@ public class HttpDestination else { HttpExchange ex = _queue.removeFirst(); - connection.send(ex); + send(connection, ex); } this.notifyAll(); } @@ -388,7 +394,7 @@ public class HttpDestination } } - public void returnIdleConnection(HttpConnection connection) throws IOException + public void returnIdleConnection(HttpConnection connection) { try { @@ -403,10 +409,10 @@ public class HttpDestination { _idle.remove(connection); _connections.remove(connection); + if (!_queue.isEmpty() && _client.isStarted()) startNewConnection(); } - } public void send(HttpExchange ex) throws IOException @@ -483,11 +489,9 @@ public class HttpDestination HttpConnection connection = getIdleConnection(); if (connection != null) { - boolean sent = connection.send(ex); - if (!sent) connection = null; + send(connection, ex); } - - if (connection == null) + else { synchronized (this) { @@ -500,6 +504,20 @@ public class HttpDestination } } + protected void send(HttpConnection connection, HttpExchange exchange) throws IOException + { + synchronized (this) + { + // If server closes the connection, put the exchange back + // to the exchange queue and recycle the connection + if(!connection.send(exchange)) + { + _queue.addFirst(exchange); + returnIdleConnection(connection); + } + } + } + @Override public synchronized String toString() { diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java index 2a1039d7d5..e9faf18e09 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java @@ -325,6 +325,15 @@ public class HttpExchange } } + /** + * @deprecated + */ + @Deprecated + public boolean isDone (int status) + { + return isDone(); + } + public HttpEventListener getEventListener() { return _listener; diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectListener.java index 6e0d47d0a2..d3de1e680a 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectListener.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectListener.java @@ -16,6 +16,7 @@ package org.eclipse.jetty.client; import java.io.IOException; import org.eclipse.jetty.http.HttpHeaders; +import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.io.Buffer; @@ -26,8 +27,8 @@ import org.eclipse.jetty.io.Buffer; */ public class RedirectListener extends HttpEventListenerWrapper { + private final HttpExchange _exchange; private HttpDestination _destination; - private HttpExchange _exchange; private String _location; private int _attempts; private boolean _requestComplete; @@ -44,6 +45,7 @@ public class RedirectListener extends HttpEventListenerWrapper _exchange = ex; } + @Override public void onResponseStatus( Buffer version, int status, Buffer reason ) throws IOException { @@ -61,6 +63,7 @@ public class RedirectListener extends HttpEventListenerWrapper } + @Override public void onResponseHeader( Buffer name, Buffer value ) throws IOException { @@ -77,6 +80,7 @@ public class RedirectListener extends HttpEventListenerWrapper super.onResponseHeader(name,value); } + @Override public void onRequestComplete() throws IOException { _requestComplete = true; @@ -87,6 +91,7 @@ public class RedirectListener extends HttpEventListenerWrapper } } + @Override public void onResponseComplete() throws IOException { _responseComplete = true; @@ -109,7 +114,23 @@ public class RedirectListener extends HttpEventListenerWrapper else _exchange.setURI(_location); - _destination.resend(_exchange); + // destination may have changed + HttpDestination destination=_destination.getHttpClient().getDestination(_exchange.getAddress(),HttpSchemes.HTTPS.equals(String.valueOf(_exchange.getScheme()))); + + if (_destination==destination) + _destination.resend(_exchange); + else + { + // unwrap to find ultimate listener. + HttpEventListener listener=this; + while(listener instanceof HttpEventListenerWrapper) + listener=((HttpEventListenerWrapper)listener).getEventListener(); + //reset the listener + _exchange.getEventListener().onRetry(); + _exchange.reset(); + _exchange.setEventListener(listener); + destination.send(_exchange); + } return false; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java b/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java index aba10d0615..730a53a01a 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/SelectConnector.java @@ -25,7 +25,6 @@ import javax.net.ssl.SSLSession; import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.http.HttpVersions; -import org.eclipse.jetty.http.ssl.SslSelectChannelEndPoint; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.Buffers; import org.eclipse.jetty.io.ConnectedEndPoint; @@ -35,6 +34,7 @@ import org.eclipse.jetty.io.nio.DirectNIOBuffer; import org.eclipse.jetty.io.nio.IndirectNIOBuffer; import org.eclipse.jetty.io.nio.SelectChannelEndPoint; import org.eclipse.jetty.io.nio.SelectorManager; +import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.Timeout; diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionTest.java index f282b82285..beed5f51b4 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionTest.java @@ -14,49 +14,161 @@ package org.eclipse.jetty.client; +import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import junit.framework.TestCase; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * @version $Revision$ $Date$ */ -public class ConnectionTest extends TestCase +public class ConnectionTest { + @Test + public void testServerClosedConnection() throws Exception + { + ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(null); + int port=serverSocket.getLocalPort(); + + HttpClient httpClient = new HttpClient(); + httpClient.setMaxConnectionsPerAddress(1); + httpClient.start(); + try + { + CountDownLatch latch = new CountDownLatch(1); + HttpExchange exchange = new ConnectionExchange(latch); + exchange.setAddress(new Address("localhost", port)); + exchange.setURI("/"); + httpClient.send(exchange); + + Socket remote = serverSocket.accept(); + OutputStream output = remote.getOutputStream(); + output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8")); + output.write("Content-Length: 0\r\n".getBytes("UTF-8")); + output.write("\r\n".getBytes("UTF-8")); + output.flush(); + + assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone()); + + remote.close(); + + // Need to wait a bit to allow the client to detect + // that the server has closed the connection + Thread.sleep(500); + + // The server has closed the connection and another attempt to send + // with the same connection would fail because the connection has been + // closed by the client as well. + // The client must open a new connection in this case, and we check + // that the new request completes correctly + exchange.reset(); + httpClient.send(exchange); + + remote = serverSocket.accept(); + output = remote.getOutputStream(); + output.write("HTTP/1.1 200 OK\r\n".getBytes("UTF-8")); + output.write("Content-Length: 0\r\n".getBytes("UTF-8")); + output.write("\r\n".getBytes("UTF-8")); + output.flush(); + + assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone()); + } + finally + { + httpClient.stop(); + } + } + + @Test public void testConnectionFailed() throws Exception { - ServerSocket socket = new ServerSocket(); - socket.bind(null); - int port=socket.getLocalPort(); - socket.close(); + ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(null); + int port=serverSocket.getLocalPort(); + serverSocket.close(); HttpClient httpClient = new HttpClient(); httpClient.start(); + try + { + CountDownLatch latch = new CountDownLatch(1); + HttpExchange exchange = new ConnectionExchange(latch); + exchange.setAddress(new Address("localhost", port)); + exchange.setURI("/"); + httpClient.send(exchange); - CountDownLatch latch = new CountDownLatch(1); - HttpExchange exchange = new ConnectionExchange(latch); - exchange.setAddress(new Address("localhost", port)); - exchange.setURI("/"); - httpClient.send(exchange); + boolean passed = latch.await(4000, TimeUnit.MILLISECONDS); + assertTrue(passed); - boolean passed = latch.await(4000, TimeUnit.MILLISECONDS); - assertTrue(passed); + long wait = 100; + long maxWait = 10 * wait; + long curWait = wait; + while (curWait < maxWait && !exchange.isDone()) + { + Thread.sleep(wait); + curWait += wait; + } - long wait = 100; - long maxWait = 10 * wait; - long curWait = wait; - while (curWait < maxWait && !exchange.isDone()) + assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.getStatus()); + } + finally { - Thread.sleep(wait); - curWait += wait; + httpClient.stop(); } + } + + @Test + public void testMultipleConnectionsFailed() throws Exception + { + ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(null); + int port=serverSocket.getLocalPort(); + serverSocket.close(); - assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.getStatus()); + HttpClient httpClient = new HttpClient(); + httpClient.setMaxConnectionsPerAddress(1); + httpClient.start(); + try + { + HttpExchange[] exchanges = new HttpExchange[20]; + final CountDownLatch latch = new CountDownLatch(exchanges.length); + for (int i = 0; i < exchanges.length; ++i) + { + HttpExchange exchange = new HttpExchange() + { + @Override + protected void onConnectionFailed(Throwable x) + { + latch.countDown(); + } + }; + exchange.setAddress(new Address("localhost", port)); + exchange.setURI("/"); + exchanges[i] = exchange; + } + + for (HttpExchange exchange : exchanges) + httpClient.send(exchange); + + for (HttpExchange exchange : exchanges) + assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone()); + + assertTrue(latch.await(1000, TimeUnit.MILLISECONDS)); + } + finally + { + httpClient.stop(); + } } + @Test public void testConnectionTimeoutWithSocketConnector() throws Exception { HttpClient httpClient = new HttpClient(); @@ -64,7 +176,6 @@ public class ConnectionTest extends TestCase int connectTimeout = 5000; httpClient.setConnectTimeout(connectTimeout); httpClient.start(); - try { CountDownLatch latch = new CountDownLatch(1); @@ -86,6 +197,7 @@ public class ConnectionTest extends TestCase } } + @Test public void testConnectionTimeoutWithSelectConnector() throws Exception { HttpClient httpClient = new HttpClient(); @@ -93,7 +205,6 @@ public class ConnectionTest extends TestCase int connectTimeout = 5000; httpClient.setConnectTimeout(connectTimeout); httpClient.start(); - try { CountDownLatch latch = new CountDownLatch(1); @@ -115,56 +226,62 @@ public class ConnectionTest extends TestCase } } + @Test public void testIdleConnection() throws Exception { - ServerSocket socket = new ServerSocket(); - socket.bind(null); - int port=socket.getLocalPort(); + ServerSocket serverSocket = new ServerSocket(); + serverSocket.bind(null); + int port=serverSocket.getLocalPort(); HttpClient httpClient = new HttpClient(); httpClient.setIdleTimeout(700); httpClient.start(); + try + { + HttpExchange exchange = new ConnectionExchange(); + exchange.setAddress(new Address("localhost", port)); + exchange.setURI("/"); + HttpDestination dest = httpClient.getDestination(new Address("localhost", port),false); - HttpExchange exchange = new ConnectionExchange(); - exchange.setAddress(new Address("localhost", port)); - exchange.setURI("/"); - HttpDestination dest = httpClient.getDestination(new Address("localhost", port),false); - - httpClient.send(exchange); - Socket s = socket.accept(); - byte[] buf = new byte[4096]; - s.getInputStream().read(buf); - assertEquals(1,dest.getConnections()); - assertEquals(0,dest.getIdleConnections()); - - s.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes()); + httpClient.send(exchange); + Socket s = serverSocket.accept(); + byte[] buf = new byte[4096]; + s.getInputStream().read(buf); + assertEquals(1,dest.getConnections()); + assertEquals(0,dest.getIdleConnections()); - Thread.sleep(300); - assertEquals(1,dest.getConnections()); - assertEquals(1,dest.getIdleConnections()); + s.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes()); - exchange = new ConnectionExchange(); - exchange.setAddress(new Address("localhost", port)); - exchange.setURI("/"); + Thread.sleep(300); + assertEquals(1,dest.getConnections()); + assertEquals(1,dest.getIdleConnections()); - httpClient.send(exchange); - s.getInputStream().read(buf); - assertEquals(1,dest.getConnections()); - assertEquals(0,dest.getIdleConnections()); - s.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes()); + exchange = new ConnectionExchange(); + exchange.setAddress(new Address("localhost", port)); + exchange.setURI("/"); - Thread.sleep(500); + httpClient.send(exchange); + s.getInputStream().read(buf); + assertEquals(1,dest.getConnections()); + assertEquals(0,dest.getIdleConnections()); + s.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes()); - assertEquals(1,dest.getConnections()); - assertEquals(1,dest.getIdleConnections()); + Thread.sleep(500); - Thread.sleep(500); + assertEquals(1,dest.getConnections()); + assertEquals(1,dest.getIdleConnections()); - assertEquals(0,dest.getConnections()); - assertEquals(0,dest.getIdleConnections()); + Thread.sleep(500); - socket.close(); + assertEquals(0,dest.getConnections()); + assertEquals(0,dest.getIdleConnections()); + serverSocket.close(); + } + finally + { + httpClient.stop(); + } } private class ConnectionExchange extends HttpExchange @@ -187,7 +304,7 @@ public class ConnectionTest extends TestCase if (latch!=null) latch.countDown(); } - + @Override protected void onException(Throwable x) { diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java index 71692727d8..e2daf2b485 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java @@ -6,157 +6,108 @@ package org.eclipse.jetty.client; // 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 +// 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. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== import java.io.IOException; -import java.util.concurrent.atomic.AtomicInteger; - +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - -import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.util.log.Log; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; -/* Test expiring connections - * +/** * Test contributed by: Michiel Thuys for JETTY-806 */ -public class ExpireTest extends TestCase +public class ExpireTest { - HttpClient client; - - Server server; - - AtomicInteger expireCount = new AtomicInteger(); + private Server server; + private HttpClient client; + private int port; - final String host = "localhost"; - - int _port; - - @Override - protected void setUp() throws Exception + @Before + public void init() throws Exception { - client = new HttpClient(); - client.setConnectorType( HttpClient.CONNECTOR_SELECT_CHANNEL ); - client.setTimeout( 200 ); - client.setMaxRetries( 0 ); - client.setMaxConnectionsPerAddress(100); - try - { - client.start(); - } - catch ( Exception e ) - { - throw new Error( "Cannot start HTTP client: " + e ); - } - - // Create server server = new Server(); SelectChannelConnector connector = new SelectChannelConnector(); - connector.setHost( host ); - connector.setPort( 0 ); - server.setConnectors( new Connector[] { connector } ); - server.setHandler( new AbstractHandler() + connector.setHost("localhost"); + connector.setPort(0); + server.addConnector(connector); + server.setHandler(new AbstractHandler() { - public void handle( String target, Request baseRequest, HttpServletRequest servletRequest, HttpServletResponse response ) throws IOException, - ServletException + public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) + throws IOException, ServletException { - Request request = (Request) servletRequest; + request.setHandled(true); try { - Thread.sleep( 2000 ); + Thread.sleep(2000); } - catch ( InterruptedException e ) + catch (InterruptedException x) { - // TODO Auto-generated catch block - e.printStackTrace(); + throw new ServletException(x); } - request.setHandled( true ); } - } ); - try - { - server.start(); - _port = connector.getLocalPort(); - } - catch ( Exception e ) - { - Log.warn( "Cannot create server: " + e ); - } + }); + server.start(); + port = connector.getLocalPort(); + + client = new HttpClient(); + client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); + client.setTimeout(200); + client.setMaxRetries(0); + client.setMaxConnectionsPerAddress(100); + client.start(); } - @Override - protected void tearDown() throws Exception + @After + public void destroy() throws Exception { client.stop(); server.stop(); + server.join(); } - public void testExpire() throws IOException + @Test + public void testExpire() throws Exception { - String baseUrl = "http://" + host + ":" + _port + "/"; + String baseUrl = "http://" + "localhost" + ":" + port + "/"; int count = 200; - expireCount.set( 0 ); - Log.info( "Starting test on " + baseUrl ); + final CountDownLatch expires = new CountDownLatch(count); for (int i=0;i<count;i++) { - if (i%10==0) - System.err.print('.'); - expireCount.incrementAndGet(); - final ContentExchange ex = new ContentExchange() + final ContentExchange exchange = new ContentExchange() { @Override protected void onExpire() { - expireCount.decrementAndGet(); + expires.countDown(); } }; - ex.setMethod( "GET" ); - ex.setURL( baseUrl ); + exchange.setMethod("GET"); + exchange.setURL(baseUrl); - client.send( ex ); - try - { - Thread.sleep( 50 ); - } - catch ( InterruptedException e ) - { - break; - } + client.send(exchange); + Thread.sleep(50); } - // Log.info("Test done"); - // Wait to be sure that all exchanges have expired - try - { - Thread.sleep( 2000 ); - int loops = 0; - while ( expireCount.get()>0 && loops < 10 ) // max out at 30 seconds - { - Log.info( "waiting for test to complete: "+expireCount.get()+" of "+count ); - ++loops; - Thread.sleep( 2000 ); - } - Thread.sleep( 2000 ); - } - catch ( InterruptedException e ) - { - } - System.err.println('!'); - assertEquals( 0, expireCount.get() ); + // Wait to be sure that all exchanges have expired + assertTrue(expires.await(5, TimeUnit.SECONDS)); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpGetRedirectTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpGetRedirectTest.java index af29296bdb..cb4b6738ed 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpGetRedirectTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpGetRedirectTest.java @@ -35,6 +35,7 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ @@ -63,6 +64,8 @@ public class HttpGetRedirectTest private Realm _realm; private String _protocol; private String _requestUrl; + private String _requestUrl2; + private RedirectHandler _handler; public void setUp() throws Exception @@ -73,10 +76,14 @@ public class HttpGetRedirectTest _server = new Server(); configureServer(_server); + org.eclipse.jetty.server.bio.SocketConnector connector = new org.eclipse.jetty.server.bio.SocketConnector(); + _server.addConnector(connector); _server.start(); int port = _server.getConnectors()[0].getLocalPort(); _requestUrl = _protocol+"://localhost:"+port+ "/content.txt"; + + _handler._toURL=_protocol+"://localhost:"+connector.getLocalPort()+ "/moved.txt"; } public void tearDown() @@ -92,7 +99,7 @@ public class HttpGetRedirectTest public void testGet() throws Exception { startClient(_realm); - + ContentExchange getExchange = new ContentExchange(); getExchange.setURL(_requestUrl); getExchange.setMethod(HttpMethods.GET); @@ -107,10 +114,10 @@ public class HttpGetRedirectTest content = getExchange.getResponseContent(); } - stopClient(); - assertEquals(HttpStatus.OK_200,responseStatus); assertEquals(_content,content); + + stopClient(); } protected void configureServer(Server server) @@ -121,8 +128,8 @@ public class HttpGetRedirectTest SelectChannelConnector connector = new SelectChannelConnector(); server.addConnector(connector); - Handler handler = new RedirectHandler(HttpStatus.MOVED_PERMANENTLY_301, "/content.txt", "/moved.txt", 1); - server.setHandler( handler ); + _handler = new RedirectHandler(HttpStatus.MOVED_PERMANENTLY_301, "/content.txt", "WAIT FOR IT", 2); + server.setHandler( _handler ); } @@ -162,46 +169,26 @@ public class HttpGetRedirectTest _realm = realm; } - public static void copyStream(InputStream in, OutputStream out) - { - try - { - byte[] buffer=new byte[1024]; - int len; - while ((len=in.read(buffer))>=0) - { - out.write(buffer,0,len); - } - } - catch (EofException e) - { - System.err.println(e); - } - catch (IOException e) - { - e.printStackTrace(); - } - } private static class RedirectHandler extends AbstractHandler { - private final String origUrl; - - private final int code; + private final String _fromURI; + private final int _code; + private final int _maxRedirects; + private int _redirectCount = 0; + private String _toURL; - private final int maxRedirects; - - private int redirectCount = 0; - - private final String currUrl; - - public RedirectHandler( final int code, final String currUrl, final String origUrl, final int maxRedirects ) + public RedirectHandler( final int code, final String fromURI, final String toURL, final int maxRedirects ) { - this.code = code; - this.currUrl = currUrl; - this.origUrl = origUrl; - this.maxRedirects = maxRedirects; + this._code = code; + this._fromURI = fromURI; + this._toURL = toURL; + this._maxRedirects = maxRedirects; + + if (_fromURI==null || _toURL==null) + throw new IllegalArgumentException(); + } public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) @@ -212,23 +199,18 @@ public class HttpGetRedirectTest return; } - if (request.getRequestURI().equals(currUrl)) + if (request.getRequestURI().equals(_fromURI)) { - redirectCount++; - - if ( maxRedirects < 0 || redirectCount <= maxRedirects ) - { - response.setStatus( code ); - response.setHeader( "Location", currUrl ); - } - else - { - response.setStatus( code ); - response.setHeader( "Location", origUrl ); - } + _redirectCount++; + + String location = ( _redirectCount <= _maxRedirects )?_fromURI:_toURL; + + response.setStatus( _code ); + response.setHeader( "Location", location ); + ( (Request) request ).setHandled( true ); } - else if (request.getRequestURI().equals(origUrl)) + else { PrintWriter out = response.getWriter(); out.write(_content); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpHeadersTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpHeadersTest.java index 0737c01f64..60ae2f9e43 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpHeadersTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpHeadersTest.java @@ -4,11 +4,11 @@ // 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 +// 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. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.client; @@ -18,13 +18,10 @@ import java.io.IOException; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import junit.framework.TestCase; - import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.server.Connector; @@ -32,10 +29,16 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -public class HttpHeadersTest extends TestCase +public class HttpHeadersTest { - private static String _content = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. " + private static final String CONTENT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. " + "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque " + "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. " + "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam " @@ -48,75 +51,67 @@ public class HttpHeadersTest extends TestCase + "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse " + "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque."; - private File _docRoot; private Server _server; - private Connector _connector; private TestHeaderHandler _handler; private int _port; - public void setUp() throws Exception + @Before + public void init() throws Exception { - _docRoot = new File("target/test-output/docroot/"); - _docRoot.mkdirs(); - _docRoot.deleteOnExit(); + File docRoot = new File("target/test-output/docroot/"); + if (!docRoot.exists()) + assertTrue(docRoot.mkdirs()); + docRoot.deleteOnExit(); + + _server = new Server(); + Connector connector = new SelectChannelConnector(); + _server.addConnector(connector); + + _handler = new TestHeaderHandler(); + _server.setHandler(_handler); + + _server.start(); - startServer(); + _port = connector.getLocalPort(); } - public void tearDown() throws Exception + @After + public void destroy() throws Exception { - stopServer(); + _server.stop(); + _server.join(); } + @Test public void testHttpHeaders() throws Exception { - HttpClient client = new HttpClient(); - client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - client.start(); - - String requestUrl = "http://localhost:" + _port + "/header"; - - ContentExchange exchange = new ContentExchange(); - exchange.setURL(requestUrl); - exchange.setMethod(HttpMethods.GET); - exchange.addRequestHeader("User-Agent","Jetty-Client/7.0"); - - client.send(exchange); - int state = exchange.waitForDone(); - - String content = ""; - int responseStatus = exchange.getResponseStatus(); - if (responseStatus == HttpStatus.OK_200) + HttpClient httpClient = new HttpClient(); + httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); + httpClient.start(); + try { - content = exchange.getResponseContent(); - } - - assertEquals(HttpStatus.OK_200,responseStatus); - assertEquals(_content,content); - assertEquals("Jetty-Client/7.0",_handler.headers.get("User-Agent")); - } - - protected void startServer() throws Exception - { - _server = new Server(0); + String requestUrl = "http://localhost:" + _port + "/header"; - _connector = new SelectChannelConnector(); - _server.addConnector(_connector); + ContentExchange exchange = new ContentExchange(); + exchange.setURL(requestUrl); + exchange.setMethod(HttpMethods.GET); + exchange.addRequestHeader("User-Agent","Jetty-Client/7.0"); - _handler = new TestHeaderHandler(); - _server.setHandler(_handler); + httpClient.send(exchange); - _server.start(); + int state = exchange.waitForDone(); + assertEquals(HttpExchange.STATUS_COMPLETED, state); + int responseStatus = exchange.getResponseStatus(); + assertEquals(HttpStatus.OK_200,responseStatus); - _port = _connector.getLocalPort(); - } + String content = exchange.getResponseContent(); - protected void stopServer() throws Exception - { - if (_server != null) + assertEquals(HttpHeadersTest.CONTENT,content); + assertEquals("Jetty-Client/7.0",_handler.headers.get("User-Agent")); + } + finally { - _server.stop(); - _server = null; + httpClient.stop(); } } @@ -138,7 +133,7 @@ public class HttpHeadersTest extends TestCase response.setContentType("text/plain"); response.setStatus(HttpServletResponse.SC_OK); - response.getWriter().print(_content); + response.getWriter().print(CONTENT); baseRequest.setHandled(true); } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/security/SecurityResolverTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/security/SecurityResolverTest.java index 7c3386093b..9c70665e33 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/security/SecurityResolverTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/security/SecurityResolverTest.java @@ -4,35 +4,36 @@ // 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 +// 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. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.client.security; -import junit.framework.TestCase; +import org.junit.Test; -public class SecurityResolverTest extends TestCase +public class SecurityResolverTest { + @Test public void testNothing() { - } + /* TODO public void testCredentialParsing() throws Exception { SecurityListener resolver = new SecurityListener(); Buffer value = new ByteArrayBuffer("basic a=b".getBytes()); - + assertEquals( "basic", resolver.scrapeAuthenticationType( value.toString() ) ); assertEquals( 1, resolver.scrapeAuthenticationDetails( value.toString() ).size() ); value = new ByteArrayBuffer("digest a=boo, c=\"doo\" , egg=foo".getBytes()); - + assertEquals( "digest", resolver.scrapeAuthenticationType( value.toString() ) ); Map<String,String> testMap = resolver.scrapeAuthenticationDetails( value.toString() ); assertEquals( 3, testMap.size() ); @@ -40,6 +41,6 @@ public class SecurityResolverTest extends TestCase assertEquals( "doo", testMap.get("c") ); assertEquals( "foo", testMap.get("egg") ); } - + */ } diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java index 250bcdc5cf..6a90a5ad3c 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java @@ -97,7 +97,7 @@ public class ContinuationSupport * deployed. It may be an implementation native to the container (eg * org.eclipse.jetty.server.AsyncContinuation) or one of the utility * implementations provided such as an internal <code>FauxContinuation</code> - * or a real implementation like {@link Servlet3Continuation}. + * or a real implementation like {@link org.eclipse.jetty.continuation.Servlet3Continuation}. * @param request The request * @return a Continuation instance */ diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java index 6b37f79bdf..4dc1f5a370 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java @@ -96,7 +96,15 @@ public class App if (_context == null) { _context = getAppProvider().createContextHandler(this); - this._context.setAttributes(new AttributesMap(_manager.getContextAttributes())); + + AttributesMap attributes = _manager.getContextAttributes(); + if (attributes!=null && attributes.size()>0) + { + // Merge the manager attributes under the existing attributes + attributes = new AttributesMap(attributes); + attributes.addAll(_context.getAttributes()); + _context.setAttributes(attributes); + } } return _context; } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java index 2ae8f7af63..7738cecb32 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java @@ -54,8 +54,6 @@ public class AppLifeCycle extends Graph * the node being processed * @param app * the app being processed - * @param deploymentManager - * the {@link DeploymentManager} tracking the {@link AppLifeCycle} and {@link App} * @throws Exception * if any problem severe enough to halt the AppLifeCycle processing */ diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ContextDeployer.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ContextDeployer.java index 74b905c8c4..0a7c6c29de 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ContextDeployer.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ContextDeployer.java @@ -448,7 +448,14 @@ public class ContextDeployer extends AbstractLifeCycle xmlConfiguration.setProperties(properties); ContextHandler context=(ContextHandler)xmlConfiguration.configure(); - context.setAttributes(new AttributesMap(_contextAttributes)); + + // merge attributes + if (_contextAttributes!=null && _contextAttributes.size()>0) + { + AttributesMap attributes = new AttributesMap(_contextAttributes); + attributes.addAll(context.getAttributes()); + context.setAttributes(attributes); + } return context; } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java index 7a1d20404c..417ff6cc33 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java @@ -12,6 +12,7 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.WebInfConfiguration; /* ------------------------------------------------------------ */ @@ -27,6 +28,7 @@ public class WebAppProvider extends ScanningAppProvider private boolean _parentLoaderPriority = false; private String _defaultsDescriptor; private Filter _filter; + private File _tempDirectory; private String[] _configurationClasses; private static class Filter implements FilenameFilter @@ -36,13 +38,17 @@ public class WebAppProvider extends ScanningAppProvider public boolean accept(File dir, String name) { if (!dir.exists()) + { return false; + } String lowername = name.toLowerCase(); File file = new File(dir,name); // is it not a directory and not a war ? if (!file.isDirectory() && !lowername.endsWith(".war")) + { return false; + } // is it a directory for an existing war file? if (file.isDirectory() && @@ -57,7 +63,9 @@ public class WebAppProvider extends ScanningAppProvider { String context=name; if (!file.isDirectory()) + { context=context.substring(0,context.length()-4); + } if (new File(_contexts,context+".xml").exists() || new File(_contexts,context+".XML").exists() ) { @@ -112,7 +120,7 @@ public class WebAppProvider extends ScanningAppProvider { _parentLoaderPriority = parentLoaderPriority; } - + /* ------------------------------------------------------------ */ /** Get the defaultsDescriptor. * @return the defaultsDescriptor @@ -156,7 +164,7 @@ public class WebAppProvider extends ScanningAppProvider } catch (MalformedURLException e) { - e.printStackTrace(); + throw new RuntimeException(e); } catch (IOException e) { @@ -183,6 +191,27 @@ public class WebAppProvider extends ScanningAppProvider return _configurationClasses; } + /** + * Set the Work directory where unpacked WAR files are managed from. + * <p> + * Default is the same as the <code>java.io.tmpdir</code> System Property. + * + * @param directory the new work directory + */ + public void setTempDir(File directory) + { + _tempDirectory = directory; + } + + /** + * Get the user supplied Work Directory. + * + * @return the user supplied work directory (null if user has not set Temp Directory yet) + */ + public File getTempDir() + { + return _tempDirectory; + } /* ------------------------------------------------------------ */ public ContextHandler createContextHandler(final App app) throws Exception @@ -203,31 +232,54 @@ public class WebAppProvider extends ScanningAppProvider // Context Path is the same as the archive. context = context.substring(0,context.length() - 4); } - else + else + { throw new IllegalStateException("unable to create ContextHandler for "+app); + } // special case of archive (or dir) named "root" is / context - if (context.equalsIgnoreCase("root") || context.equalsIgnoreCase("root/")) + if (context.equalsIgnoreCase("root") || context.equalsIgnoreCase("root/")) + { context = URIUtil.SLASH; + } // Ensure "/" is Prepended to all context paths. - if (context.charAt(0) != '/') + if (context.charAt(0) != '/') + { context = "/" + context; + } // Ensure "/" is Not Trailing in context paths. - if (context.endsWith("/") && context.length() > 0) + if (context.endsWith("/") && context.length() > 0) + { context = context.substring(0,context.length() - 1); + } WebAppContext wah = new WebAppContext(); wah.setContextPath(context); wah.setWar(file.getAbsolutePath()); - if (_defaultsDescriptor != null) + if (_defaultsDescriptor != null) + { wah.setDefaultsDescriptor(_defaultsDescriptor); + } wah.setExtractWAR(_extractWars); wah.setParentLoaderPriority(_parentLoaderPriority); - if (_configurationClasses != null) + if (_configurationClasses != null) + { wah.setConfigurationClasses(_configurationClasses); + } + if (_tempDirectory != null) + { + /* Since the Temp Dir is really a context base temp directory, + * Lets set the Temp Directory in a way similar to how WebInfConfiguration does it, + * instead of setting the + * WebAppContext.setTempDirectory(File). + * If we used .setTempDirectory(File) all webapps will wind up in the + * same temp / work directory, overwriting each others work. + */ + wah.setAttribute(WebAppContext.BASETEMPDIR,_tempDirectory); + } return wah; } diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java new file mode 100644 index 0000000000..8fc7cb5930 --- /dev/null +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java @@ -0,0 +1,76 @@ +package org.eclipse.jetty.deploy.providers; + +import java.io.File; + +import org.eclipse.jetty.deploy.test.XmlConfiguredJetty; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class WebAppProviderTest +{ + private static XmlConfiguredJetty jetty; + + @BeforeClass + public static void setupEnvironment() throws Exception + { + jetty = new XmlConfiguredJetty(); + jetty.addConfiguration("jetty.xml"); + jetty.addConfiguration("jetty-deploy-wars.xml"); + + // Setup initial context + jetty.copyContext("foo.xml","foo.xml"); + jetty.copyWebapp("foo-webapp-1.war","foo.war"); + + // Should not throw an Exception + jetty.load(); + + // Start it + jetty.start(); + } + + @AfterClass + public static void teardownEnvironment() throws Exception + { + // Stop jetty. + jetty.stop(); + } + + @Test + public void testStartupContext() + { + // Check Server for Handlers + jetty.printHandlers(System.out); + jetty.assertWebAppContextsExists("/foo"); + + File workDir = jetty.getJettyDir("workish"); + + // Test for regressions + assertDirNotExists("root of work directory",workDir,"webinf"); + assertDirNotExists("root of work directory",workDir,"jsp"); + + // Test for correct behavior + Assert.assertTrue("Should have generated directory in work directory: " + workDir,hasJettyGeneratedPath(workDir,"foo.war")); + } + + private static boolean hasJettyGeneratedPath(File basedir, String expectedWarFilename) + { + for (File path : basedir.listFiles()) + { + if (path.exists() && path.isDirectory() && path.getName().startsWith("Jetty_") && path.getName().contains(expectedWarFilename)) + { + System.out.println("Found expected generated directory: " + path); + return true; + } + } + + return false; + } + + public static void assertDirNotExists(String msg, File workDir, String subdir) + { + File dir = new File(workDir,subdir); + Assert.assertFalse("Should not have " + subdir + " in " + msg + " - " + workDir,dir.exists()); + } +} diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java index 954c776397..89e03dd26f 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/test/XmlConfiguredJetty.java @@ -59,7 +59,7 @@ public class XmlConfiguredJetty { this(MavenTestingUtils.getTestID()); } - + public XmlConfiguredJetty(String testname) throws IOException { xmlConfigurations = new ArrayList<URL>(); @@ -69,9 +69,10 @@ public class XmlConfiguredJetty // Ensure we have a new (pristene) directory to work with. int idx = 0; jettyHome = new File(jettyHomeBase + "#" + idx); - while(jettyHome.exists()) { - idx++; - jettyHome = new File(jettyHomeBase + "#" + idx); + while (jettyHome.exists()) + { + idx++; + jettyHome = new File(jettyHomeBase + "#" + idx); } deleteContents(jettyHome); // Prepare Jetty.Home (Test) dir @@ -91,15 +92,28 @@ public class XmlConfiguredJetty deleteContents(contextsDir); } contextsDir.mkdirs(); + File webappsDir = new File(jettyHome,"webapps"); if (webappsDir.exists()) { deleteContents(webappsDir); } webappsDir.mkdirs(); + File tmpDir = new File(jettyHome,"tmp"); + if (tmpDir.exists()) + { + deleteContents(tmpDir); + } tmpDir.mkdirs(); + File workishDir = new File(jettyHome,"workish"); + if (workishDir.exists()) + { + deleteContents(workishDir); + } + workishDir.mkdirs(); + // Setup properties System.setProperty("java.io.tmpdir",tmpDir.getAbsolutePath()); properties.setProperty("jetty.home",jettyHome.getAbsolutePath()); @@ -108,6 +122,7 @@ public class XmlConfiguredJetty properties.setProperty("test.resourcesdir",MavenTestingUtils.getTestResourcesDir().getAbsolutePath()); properties.setProperty("test.webapps",webappsDir.getAbsolutePath()); properties.setProperty("test.targetdir",MavenTestingUtils.getTargetDir().getAbsolutePath()); + properties.setProperty("test.workdir",workishDir.getAbsolutePath()); // Write out configuration for use by ConfigurationManager. File testConfig = MavenTestingUtils.getTargetFile("xml-configured-jetty.properties"); @@ -238,11 +253,11 @@ public class XmlConfiguredJetty private void deleteContents(File dir) { System.out.printf("Delete (dir) %s/%n",dir); - if(!dir.exists()) + if (!dir.exists()) { - return; + return; } - + for (File file : dir.listFiles()) { // Safety measure. only recursively delete within target directory. diff --git a/jetty-deploy/src/test/resources/jetty-deploy-wars.xml b/jetty-deploy/src/test/resources/jetty-deploy-wars.xml new file mode 100644 index 0000000000..f336584c66 --- /dev/null +++ b/jetty-deploy/src/test/resources/jetty-deploy-wars.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> + +<Configure id="Server" class="org.eclipse.jetty.server.Server"> + + <Call name="addLifeCycle"> + <Arg> + <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager"> + <Set name="contexts"> + <Ref id="Contexts" /> + </Set> + + <!-- Providers of Apps --> + <Set name="appProviders"> + <Array type="org.eclipse.jetty.deploy.AppProvider"> + <Item> + <New class="org.eclipse.jetty.deploy.providers.WebAppProvider"> + <Set name="monitoredDir"><SystemProperty name="jetty.home" />/webapps</Set> + <Set name="scanInterval">1</Set> + <Set name="tempDir"><Property name="jetty.home" default="target" />/workish</Set> + </New> + </Item> + </Array> + </Set> + </New> + </Arg> + </Call> + +</Configure> diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index e2114fc740..08c4bf85d9 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -10,12 +10,13 @@ <packaging>pom</packaging> <properties> <eclipse-mirror>http://mirror.cc.vt.edu/pub/eclipse/eclipse/downloads/drops</eclipse-mirror> - <orbit-url>http://download.eclipse.org/tools/orbit/downloads/drops/S20100423142122/bundles</orbit-url> + <orbit-url>http://download.eclipse.org/tools/orbit/downloads/drops/R20100519200754/bundles</orbit-url> <assembly-directory>target/distribution</assembly-directory> - <eclipse-drop>S-3.6M7-201004291549</eclipse-drop> - <orbit-javax-activation-version>${javax-activation-version}.0.v200906290531</orbit-javax-activation-version> + <eclipse-drop>S-3.6RC4-201006031500</eclipse-drop> + <eclipse-ecj-version>3.6RC4</eclipse-ecj-version> + <orbit-javax-activation-version>${javax-activation-version}.0.v201005080500</orbit-javax-activation-version> <orbit-javax-el-version>2.1.0.v201004190952</orbit-javax-el-version> - <orbit-javax-mail-glassfish-version>${javax-mail-version}.v200808130215</orbit-javax-mail-glassfish-version> + <orbit-javax-mail-glassfish-version>${javax-mail-version}.v201005082020</orbit-javax-mail-glassfish-version> </properties> <build> <sourceDirectory>${project.build.directory}/sources</sourceDirectory> @@ -38,6 +39,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> + <version>1.4</version> <executions> <execution> <phase>generate-resources</phase> @@ -46,14 +48,36 @@ </goals> <configuration> <tasks> + <!-- This is the Orbit Downloads Process --> + + <!-- Step 1: download orbit artifact into orbit-cache (if not present) --> + <property name="orbit-cache" value="${user.home}/.m2/eclipse-orbit" /> + + <mkdir dir="${orbit-cache}" /> + <get dest="${orbit-cache}" verbose="true" skipexisting="true"> + <url url="${orbit-url}/javax.activation_${orbit-javax-activation-version}.jar" /> + <url url="${orbit-url}/javax.mail.glassfish_${orbit-javax-mail-glassfish-version}.jar" /> + </get> + + <mkdir dir="${orbit-cache}/${eclipse-drop}" /> + <get dest="${orbit-cache}/${eclipse-drop}" verbose="true" skipexisting="true"> + <url url="${eclipse-mirror}/${eclipse-drop}/ecj-${eclipse-ecj-version}.jar" /> + </get> + + <!-- Step 2: copy the orbit artifact from orbit-cache to the appropriate lib directory --> + + <!-- ${jetty.home}/lib/ --> <mkdir dir="${assembly-directory}/lib" /> -<!-- - <get src="${orbit-url}/javax.servlet_${orbit-javax-servlet-version}.jar" dest="${assembly-directory}/lib/servlet-api-2.5.jar" usetimestamp="true" verbose="true" /> ---> + <!-- ${jetty.home}/lib/jndi/ --> <mkdir dir="${assembly-directory}/lib/jndi" /> - <get src="${orbit-url}/javax.activation_${orbit-javax-activation-version}.jar" dest="${assembly-directory}/lib/jndi/javax.activation_${orbit-javax-activation-version}.jar" usetimestamp="true" verbose="true" /> - <get src="${orbit-url}/javax.mail.glassfish_${orbit-javax-mail-glassfish-version}.jar" dest="${assembly-directory}/lib/jndi/javax.mail.glassfish_${orbit-javax-mail-glassfish-version}.jar" usetimestamp="true" verbose="true" /> + <copy todir="${assembly-directory}/lib/jndi"> + <fileset dir="${orbit-cache}"> + <include name="javax.activation_${orbit-javax-activation-version}.jar" /> + <include name="javax.mail.glassfish_${orbit-javax-mail-glassfish-version}.jar" /> + </fileset> + </copy> + <copy file="../VERSION.txt" todir="${assembly-directory}" /> <chmod dir="${assembly-directory}/bin" perm="755" includes="**/*.sh" /> </tasks> diff --git a/jetty-distribution/src/main/resources/README.txt b/jetty-distribution/src/main/resources/README.txt index 5d41b2c813..2a094bd58e 100644 --- a/jetty-distribution/src/main/resources/README.txt +++ b/jetty-distribution/src/main/resources/README.txt @@ -3,88 +3,64 @@ JETTY ===== The Jetty project is a 100% Java HTTP Server, HTTP Client -and Servlet Container. The core project is hosted by -the Eclipse Foundation at +and Servlet Container. - http://www.eclipse.org/jetty/ -The jetty integrations with 3rd party modules are hosted -by the Codehaus at +The Jetty @ eclipse project is based on the Jetty project at codehaus http://jetty.codehaus.org +Ongoing development is now at the eclipse foundation -JETTY DISTRIBUTION -================== - -This is the jetty-distribution module from Jetty @ eclipse -project and is based on the Jetty modules from eclipse plus -dependencies that have been through the eclipse IP -process and conditioning. + http://www.eclipse.org/jetty/ -This distribution and its dependencies are provided under -the terms and conditions of the Eclipse Foundation Software -User Agreement unless otherwise specified. -This distribution contains only the core functionality -of a servlet server and the HTTP client. +Jetty @ eclipse is open source and is dual licensed using the apache 2.0 and +eclipse public license 1.0. You may choose either license when distributing +jetty. -Some modules (eg annotations) are missing dependencies -which may be discovered by using the command - mvn dependency:tree -within the source module and placing them in the -lib/ext directory. Alternately we recommend the jetty-hightide -distribution for users that desire more third party integrations. -JETTY HIGHTIDE +BUILDING JETTY ============== -The Jetty-hightide distribution is available for -download via http://jetty.codehaus.org and contains -the core jetty modules, plus the 3rd party dependencies -and integrations needed to create a full featured -application server. - +Jetty uses maven 2 as its build system. Maven will fetch +the dependancies, build the server and assemble a runnable +version: -MAVEN -===== -All Jetty artifacts are available as maven dependencies -under the org.eclipse.jetty and org.mortbay.hightide group IDs + mvn install - http://repo1.maven.org/maven2/org/eclipse/jetty/ - http://repo2.maven.org/maven2/org/mortbay/jetty/ RUNNING JETTY ============= -The run directory is either the top-level of a distribution -or jetty-distribution/target/distribution directory when built from +The run directory is either the top-level of a binary release +or jetty-distribution/target/assembly-prep directory when built from source. To run with the default options: java -jar start.jar -To run with specific configuration file(s) - - java -jar start.jar etc/jetty.xml - -To see the available options +To see the available options and the default arguments +provided by the start.ini file: java -jar start.jar --help -To run with JSP support (if available) +To run with extra configuration file(s) appended, eg SSL + + java -jar start.jar etc/jetty-ssl.xml - java -jar start.jar OPTIONS=Server,jsp +To run with extra configuration file(s) prepended, eg logging & jmx -To run with JMX support + java -jar start.jar --pre=etc/jetty-logging.xml --pre=etc/jetty-jmx.xml - java -jar start.jar OPTIONS=Server,jmx etc/jetty-jmx.xml etc/jetty.xml +To run without the args from start.ini -To run with JSP & JMX support + java -jar start.jar --ini OPTIONS=Server,websocket etc/jetty.xml etc/jetty-deploy.xml etc/jetty-ssl.xml - java -jar start.jar OPTIONS=Server,jsp,jmx etc/jetty-jmx.xml etc/jetty.xml +to list the know OPTIONS: + java -jar start.jar --list-options diff --git a/jetty-distribution/src/main/resources/bin/jetty.sh b/jetty-distribution/src/main/resources/bin/jetty.sh index a4dd871d84..5b237a5ec6 100755 --- a/jetty-distribution/src/main/resources/bin/jetty.sh +++ b/jetty-distribution/src/main/resources/bin/jetty.sh @@ -121,9 +121,6 @@ readConfig() - - - ################################################## # Get the action & configs ################################################## @@ -218,9 +215,8 @@ if [ -z "$JETTY_HOME" ] ; then then JETTY_HOME= fi + [ "$JETTY_HOME" ] && break done - - [ "$JETTY_HOME" ] && break done fi @@ -247,38 +243,6 @@ then exit 1 fi - -########################################################### -# Get the list of config.xml files from the command line. -########################################################### -for ARG -do - if [ -f "$ARG" ] - then - CONF="$ARG" - elif [ -f "$JETTY_HOME/etc/$ARG" ] - then - CONF="$JETTY_HOME/etc/$ARG" - elif [ -f "$ARG.xml" ] - then - CONF="$ARG.xml" - elif [ -f "$JETTY_HOME/etc/$ARG.xml" ] - then - CONF="$JETTY_HOME/etc/$ARG.xml" - else - echo "** ERROR: Cannot find configuration '$ARG' specified in the command line." - exit 1 - fi - if [ ! -r "$CONF" ] - then - echo "** ERROR: Cannot read configuration '$ARG' specified in the command line." - exit 1 - fi - - CONFIGS+=("$CONF") -done - - ################################################## # Try to find this script's configuration file, # but only if no configurations were given on the @@ -302,14 +266,11 @@ if [ -z "$CONFIGS" ] && [ -f "$JETTY_CONF" ] && [ -r "$JETTY_CONF" ] then while read -r CONF do - if [ ! -r "$CONF" ] - then - echo "** WARNING: Cannot read '$CONF' specified in '$JETTY_CONF'" - elif [ -f "$CONF" ] - then - # assume it's a configure.xml file - CONFIGS+=("$CONF") - elif [ -d "$CONF" ] + if expr "$CONF" : '#' >/dev/null ; then + continue + fi + + if [ -d "$CONF" ] then # assume it's a directory with configure.xml files # for example: /etc/jetty.d/ @@ -324,21 +285,13 @@ then fi done else - echo "** WARNING: Don''t know what to do with '$CONF' specified in '$JETTY_CONF'" + # assume it's a command line parameter (let start.jar deal with its validity) + CONFIGS+=("$CONF") fi done < "$JETTY_CONF" fi ##################################################### -# Run the standard server if there's nothing else to run -##################################################### -if [ "${#CONFIGS[@]}" -eq 0 ] -then - CONFIGS=("$JETTY_HOME/etc/jetty-logging.xml" "$JETTY_HOME/etc/jetty.xml") -fi - - -##################################################### # Find a location for the pid file ##################################################### if [ -z "$JETTY_RUN" ] @@ -412,7 +365,7 @@ fi ################################################## -# Determine which JVM of version >1.2 +# Determine which JVM of version >1.5 # Try to use JAVA_HOME ################################################## if [ -z "$JAVA" ] && [ "$JAVA_HOME" ] @@ -428,7 +381,7 @@ fi if [ -z "$JAVA" ] then - echo "Cannot find a JRE or JDK. Please set JAVA_HOME to a >=1.2 JRE" 2>&2 + echo "Cannot find a JRE or JDK. Please set JAVA_HOME to a >=1.5 JRE" 2>&2 exit 1 fi @@ -474,7 +427,10 @@ JAVA_OPTIONS+=("-Djetty.home=$JETTY_HOME" "-Djava.io.tmpdir=$TMPDIR") JETTY_START=$JETTY_HOME/start.jar [ ! -f "$JETTY_START" ] && JETTY_START=$JETTY_HOME/lib/start.jar -RUN_ARGS=("${JAVA_OPTIONS[@]}" -jar "$JETTY_START" --fromDaemon $JETTY_ARGS "${CONFIGS[@]}") +START_INI=$(dirname $JETTY_START)/start.ini +[ -r "$START_INI" ] || START_INI="" + +RUN_ARGS=("${JAVA_OPTIONS[@]}" -jar "$JETTY_START" $JETTY_ARGS "${CONFIGS[@]}") RUN_CMD=("$JAVA" "${RUN_ARGS[@]}") ##################################################### @@ -508,9 +464,12 @@ case "$ACTION" in if type start-stop-daemon > /dev/null 2>&1 then - [ -z "$JETTY_USER" ] && JETTY_USER=$USER - (( UID == 0 )) && CH_USER=-c$JETTY_USER - if start-stop-daemon -S -p"$JETTY_PID" "$CH_USER" -d"$JETTY_HOME" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" + unset CH_USER + if [ -n "$JETTY_USER" ] + then + CH_USER="-c$JETTY_USER" + fi + if start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_HOME" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" --daemon then sleep 1 if running "$JETTY_PID" @@ -541,7 +500,7 @@ case "$ACTION" in chown "$JETTY_USER" "$JETTY_PID" # FIXME: Broken solution: wordsplitting, pathname expansion, arbitrary command execution, etc. su - "$JETTY_USER" -c " - ${RUN_CMD[*]} & + ${RUN_CMD[*]} --daemon & disown \$! echo \$! > '$JETTY_PID'" else @@ -641,6 +600,7 @@ case "$ACTION" in echo "JETTY_PID = $JETTY_PID" echo "JETTY_PORT = $JETTY_PORT" echo "JETTY_LOGS = $JETTY_LOGS" + echo "START_INI = $START_INI" echo "CONFIGS = ${CONFIGS[*]}" echo "JAVA_OPTIONS = ${JAVA_OPTIONS[*]}" echo "JAVA = $JAVA" diff --git a/jetty-distribution/src/main/resources/etc/jetty.conf b/jetty-distribution/src/main/resources/etc/jetty.conf new file mode 100644 index 0000000000..b79f3169fb --- /dev/null +++ b/jetty-distribution/src/main/resources/etc/jetty.conf @@ -0,0 +1,13 @@ +# ======================================================== +# jetty.conf Configuration for jetty.sh script +# -------------------------------------------------------- +# This file is used by the jetty.sh script to provide +# extra configuration arguments for the start.jar command +# created by that script. +# +# Each line in this file becomes an arguement to start.jar +# unless this file contains an --ini option, then these +# arguments will be in addition to those found in the +# start.ini file +# ======================================================= +--pre=etc/jetty-logging.xml diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java index 7f7000b760..db0db7902f 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/AbstractGenerator.java @@ -434,24 +434,30 @@ public abstract class AbstractGenerator implements Generator /* ------------------------------------------------------------ */ /** * Utility method to send an error response. If the builder is not committed, this call is - * equivalent to a setResponse, addcontent and complete call. + * equivalent to a setResponse, addContent and complete call. * - * @param code - * @param reason - * @param content - * @param close - * @throws IOException + * @param code The error code + * @param reason The error reason + * @param content Contents of the error page + * @param close True if the connection should be closed + * @throws IOException if there is a problem flushing the response */ public void sendError(int code, String reason, String content, boolean close) throws IOException { + if (close) + _persistent=false; if (!isCommitted()) { setResponse(code, reason); - if (close) - _persistent=false; - completeHeader(null, false); if (content != null) + { + completeHeader(null, false); addContent(new View(new ByteArrayBuffer(content)), Generator.LAST); + } + else + { + completeHeader(null, true); + } complete(); } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index 486b863814..e98db730ac 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -285,17 +285,15 @@ public class HttpFields }; - - - - public final static String __01Jan1970=formatCookieDate(0); public final static Buffer __01Jan1970_BUFFER=new ByteArrayBuffer(__01Jan1970); /* -------------------------------------------------------------- */ - protected final ArrayList<Field> _fields = new ArrayList<Field>(20); - protected final HashMap<Buffer,Field> _bufferMap = new HashMap<Buffer,Field>(32); - protected int _revision; + private final ArrayList<Field> _fields = new ArrayList<Field>(20); + private final HashMap<Buffer,Field> _bufferMap = new HashMap<Buffer,Field>(32); + private final int _maxCookieVersion; + private int _revision; + @@ -305,8 +303,18 @@ public class HttpFields */ public HttpFields() { + _maxCookieVersion=1; } + /* ------------------------------------------------------------ */ + /** + * Constructor. + */ + public HttpFields(int maxCookieVersion) + { + _maxCookieVersion=maxCookieVersion; + } + /* -------------------------------------------------------------- */ /** * Get Collection of header names. @@ -1018,20 +1026,29 @@ public class HttpFields final String comment, final boolean isSecure, final boolean isHttpOnly, - final int version) + int version) { + String delim=_maxCookieVersion==0?"":"\"\\\n\r\t\f\b%+ ;="; + // Check arguments if (name == null || name.length() == 0) throw new IllegalArgumentException("Bad cookie name"); // Format value and params StringBuilder buf = new StringBuilder(128); String name_value_params; - QuotedStringTokenizer.quoteIfNeeded(buf, name); + boolean quoted = QuotedStringTokenizer.quoteIfNeeded(buf, name, delim); buf.append('='); String start=buf.toString(); if (value != null && value.length() > 0) - QuotedStringTokenizer.quoteIfNeeded(buf, value); + quoted|=QuotedStringTokenizer.quoteIfNeeded(buf, value, delim); + + // upgrade to version 1 cookies if quoted. + if (quoted&&version==0 && _maxCookieVersion>=1) + version=1; + if (version>_maxCookieVersion) + version=_maxCookieVersion; + if (version > 0) { buf.append(";Version="); @@ -1039,7 +1056,7 @@ public class HttpFields if (comment != null && comment.length() > 0) { buf.append(";Comment="); - QuotedStringTokenizer.quoteIfNeeded(buf, comment); + QuotedStringTokenizer.quoteIfNeeded(buf, comment, delim); } } if (path != null && path.length() > 0) @@ -1048,25 +1065,24 @@ public class HttpFields if (path.trim().startsWith("\"")) buf.append(path); else - QuotedStringTokenizer.quoteIfNeeded(buf,path); + QuotedStringTokenizer.quoteIfNeeded(buf,path,delim); } if (domain != null && domain.length() > 0) { buf.append(";Domain="); - QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase()); + QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase(),delim); } if (maxAge >= 0) { - if (version == 0) - { - buf.append(";Expires="); - if (maxAge == 0) - buf.append(__01Jan1970); - else - formatCookieDate(buf, System.currentTimeMillis() + 1000L * maxAge); - } - else + // Always add the expires param as some browsers still don't handle max-age + buf.append(";Expires="); + if (maxAge == 0) + buf.append(__01Jan1970); + else + formatCookieDate(buf, System.currentTimeMillis() + 1000L * maxAge); + + if (version >0) { buf.append(";Max-Age="); buf.append(maxAge); @@ -1084,7 +1100,6 @@ public class HttpFields // TODO - straight to Buffer? name_value_params = buf.toString(); - put(HttpHeaders.EXPIRES_BUFFER, __01Jan1970_BUFFER); // look for existing cookie Field field = getField(HttpHeaders.SET_COOKIE_BUFFER); @@ -1104,6 +1119,9 @@ public class HttpFields } add(HttpHeaders.SET_COOKIE_BUFFER, new ByteArrayBuffer(name_value_params)); + + // Expire responses with set-cookie headers so they do not get cached. + put(HttpHeaders.EXPIRES_BUFFER, __01Jan1970_BUFFER); } /* -------------------------------------------------------------- */ diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java index d3de39800d..9350aa1cd0 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java @@ -885,8 +885,8 @@ public class HttpGenerator extends AbstractGenerator { if (_state == STATE_FLUSHING) _state = STATE_END; - if (_state==STATE_END && !_persistent && _status!=100) - _endp.close(); + if (_state==STATE_END && !_persistent && _status!=100 && _method==null) + _endp.shutdownOutput(); } else // Try to prepare more to write. diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 006e3fc1fa..b3ccf79002 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -226,7 +226,7 @@ public class HttpParser implements Parser /* ------------------------------------------------------------------------------- */ /** * Parse until next Event. - * @returns number of bytes filled from endpoint or -1 if fill never called. + * @return number of bytes filled from endpoint or -1 if fill never called. */ public long parseNext() throws IOException { diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java index 79c36c725f..8086084198 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.http; +import java.net.CookieHandler; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; @@ -367,9 +368,20 @@ public class HttpFieldsTest fields.clear(); fields.addSetCookie("ev erything","va lue","do main","pa th",1,"co mment",true,true,2); - assertEquals("\"ev erything\"=\"va lue\";Version=2;Comment=\"co mment\";Path=\"pa th\";Domain=\"do main\";Max-Age=1;Secure;HttpOnly",fields.getStringField("Set-Cookie")); + String setCookie=fields.getStringField("Set-Cookie"); + assertTrue(setCookie.startsWith("\"ev erything\"=\"va lue\";Version=1;Comment=\"co mment\";Path=\"pa th\";Domain=\"do main\";Expires=")); + assertTrue(setCookie.endsWith("GMT;Max-Age=1;Secure;HttpOnly")); fields.clear(); + fields.addSetCookie("name","value",null,null,-1,null,false,false,0); + setCookie=fields.getStringField("Set-Cookie"); + assertEquals(-1,setCookie.indexOf("Version=")); + fields.clear(); + fields.addSetCookie("name","v a l u e",null,null,-1,null,false,false,0); + setCookie=fields.getStringField("Set-Cookie"); + assertEquals(17,setCookie.indexOf("Version=1")); + + fields.clear(); fields.addSetCookie("json","{\"services\":[\"cwa\", \"aa\"]}",null,null,-1,null,false,false,-1); assertEquals("json=\"{\\\"services\\\":[\\\"cwa\\\", \\\"aa\\\"]}\"",fields.getStringField("Set-Cookie")); @@ -386,6 +398,12 @@ public class HttpFieldsTest Enumeration e=fields.getValues("Set-Cookie"); assertEquals("name=more;Domain=domain",e.nextElement()); assertEquals("foo=bob;Domain=domain",e.nextElement()); + + fields=new HttpFields(0); + fields.addSetCookie("name","value==",null,null,-1,null,false,false,0); + setCookie=fields.getStringField("Set-Cookie"); + assertEquals("name=value==",setCookie); + } private Set<String> enum2set(Enumeration<String> e) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java index befe4f7be0..1c89fb0059 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java @@ -153,6 +153,14 @@ public class ByteArrayEndPoint implements ConnectedEndPoint /* ------------------------------------------------------------ */ /* + * @see org.eclipse.io.EndPoint#shutdownOutput() + */ + public void shutdownOutput() throws IOException + { + } + + /* ------------------------------------------------------------ */ + /* * @see org.eclipse.io.EndPoint#close() */ public void close() throws IOException diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java index 4a329da7ba..95a33e242c 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java @@ -23,7 +23,12 @@ import java.io.IOException; public interface EndPoint { /** - * Close any backing stream associated with the buffer + * Shutdown any backing output stream associated with the endpoint + */ + void shutdownOutput() throws IOException; + + /** + * Close any backing stream associated with the endpoint */ void close() throws IOException; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/SocketEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/SocketEndPoint.java index b53ddb50f5..9f45293647 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/SocketEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/SocketEndPoint.java @@ -1,5 +1,5 @@ // ======================================================================== -// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 2004-2010 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 @@ -29,9 +29,9 @@ import org.eclipse.jetty.util.log.Log; */ public class SocketEndPoint extends StreamEndPoint { - Socket _socket; - InetSocketAddress _local; - InetSocketAddress _remote; + final Socket _socket; + final InetSocketAddress _local; + final InetSocketAddress _remote; /** * @@ -41,6 +41,8 @@ public class SocketEndPoint extends StreamEndPoint { super(socket.getInputStream(),socket.getOutputStream()); _socket=socket; + _local=(InetSocketAddress)_socket.getLocalSocketAddress(); + _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); super.setMaxIdleTime(_socket.getSoTimeout()); } @@ -52,6 +54,9 @@ public class SocketEndPoint extends StreamEndPoint { super(socket.getInputStream(),socket.getOutputStream()); _socket=socket; + _local=(InetSocketAddress)_socket.getLocalSocketAddress(); + _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); + _socket.setSoTimeout(maxIdleTime>0?maxIdleTime:0); super.setMaxIdleTime(maxIdleTime); } @@ -64,27 +69,25 @@ public class SocketEndPoint extends StreamEndPoint return super.isOpen() && _socket!=null && !_socket.isClosed() && !_socket.isInputShutdown() && !_socket.isOutputShutdown(); } + + + /* ------------------------------------------------------------ */ + /* + * @see org.eclipse.jetty.io.bio.StreamEndPoint#shutdownOutput() + */ + @Override + public void shutdownOutput() throws IOException + { + if (!_socket.isClosed() && !_socket.isOutputShutdown()) + _socket.shutdownOutput(); + } + /* (non-Javadoc) * @see org.eclipse.io.BufferIO#close() */ @Override public void close() throws IOException { - if (!_socket.isClosed() && !_socket.isOutputShutdown()) - { - try - { - _socket.shutdownOutput(); - } - catch(IOException e) - { - Log.ignore(e); - } - catch(UnsupportedOperationException e) - { - Log.ignore(e); - } - } _socket.close(); _in=null; _out=null; @@ -98,9 +101,6 @@ public class SocketEndPoint extends StreamEndPoint @Override public String getLocalAddr() { - if (_local==null) - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); - if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress()) return StringUtil.ALL_INTERFACES; @@ -114,9 +114,6 @@ public class SocketEndPoint extends StreamEndPoint @Override public String getLocalHost() { - if (_local==null) - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); - if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress()) return StringUtil.ALL_INTERFACES; @@ -131,8 +128,6 @@ public class SocketEndPoint extends StreamEndPoint public int getLocalPort() { if (_local==null) - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); - if (_local==null) return -1; return _local.getPort(); } @@ -145,8 +140,6 @@ public class SocketEndPoint extends StreamEndPoint public String getRemoteAddr() { if (_remote==null) - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); - if (_remote==null) return null; InetAddress addr = _remote.getAddress(); return ( addr == null ? null : addr.getHostAddress() ); @@ -160,8 +153,6 @@ public class SocketEndPoint extends StreamEndPoint public String getRemoteHost() { if (_remote==null) - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); - if (_remote==null) return null; return _remote.getAddress().getCanonicalHostName(); } @@ -174,8 +165,6 @@ public class SocketEndPoint extends StreamEndPoint public int getRemotePort() { if (_remote==null) - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); - if (_remote==null) return -1; return _remote.getPort(); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java index eee564a06b..24e1b9e0ab 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java @@ -73,6 +73,10 @@ public class StreamEndPoint implements EndPoint return !isOpen(); } + public void shutdownOutput() throws IOException + { + } + /* * @see org.eclipse.io.BufferIO#close() */ diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java index d89161cd05..c9628b86ab 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java @@ -29,18 +29,17 @@ import org.eclipse.jetty.util.log.Log; /** + * Channel End Point. + * <p>Holds the channel and socket for an NIO endpoint. * - * - * To change the template for this generated type comment go to - * Window - Preferences - Java - Code Generation - Code and Comments */ public class ChannelEndPoint implements EndPoint { protected final ByteChannel _channel; protected final ByteBuffer[] _gather2=new ByteBuffer[2]; protected final Socket _socket; - protected InetSocketAddress _local; - protected InetSocketAddress _remote; + protected final InetSocketAddress _local; + protected final InetSocketAddress _remote; protected int _maxIdleTime; /** @@ -52,7 +51,15 @@ public class ChannelEndPoint implements EndPoint this._channel = channel; _socket=(channel instanceof SocketChannel)?((SocketChannel)channel).socket():null; if (_socket!=null) + { + _local=(InetSocketAddress)_socket.getLocalSocketAddress(); + _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); _maxIdleTime=_socket.getSoTimeout(); + } + else + { + _local=_remote=null; + } } /** @@ -64,7 +71,16 @@ public class ChannelEndPoint implements EndPoint _maxIdleTime=maxIdleTime; _socket=(channel instanceof SocketChannel)?((SocketChannel)channel).socket():null; if (_socket!=null) + { + _local=(InetSocketAddress)_socket.getLocalSocketAddress(); + _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); _socket.setSoTimeout(_maxIdleTime); + } + else + { + _local=_remote=null; + } + } public boolean isBlocking() @@ -93,34 +109,23 @@ public class ChannelEndPoint implements EndPoint /* (non-Javadoc) * @see org.eclipse.io.EndPoint#close() */ - public void close() throws IOException + public void shutdownOutput() throws IOException { - if (_channel.isOpen()) + if (_channel.isOpen() && _channel instanceof SocketChannel) { - try - { - if (_channel instanceof SocketChannel) - { - // TODO - is this really required? - Socket socket= ((SocketChannel)_channel).socket(); - if (!socket.isClosed()&&!socket.isOutputShutdown()) - socket.shutdownOutput(); - } - } - catch(IOException e) - { - Log.ignore(e); - } - catch(UnsupportedOperationException e) - { - Log.ignore(e); - } - finally - { - _channel.close(); - } + Socket socket= ((SocketChannel)_channel).socket(); + if (!socket.isClosed()&&!socket.isOutputShutdown()) + socket.shutdownOutput(); } } + + /* (non-Javadoc) + * @see org.eclipse.io.EndPoint#close() + */ + public void close() throws IOException + { + _channel.close(); + } /* (non-Javadoc) * @see org.eclipse.io.EndPoint#fill(org.eclipse.io.Buffer) @@ -332,13 +337,8 @@ public class ChannelEndPoint implements EndPoint { if (_socket==null) return null; - - if (_local==null) - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); - if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress()) return StringUtil.ALL_INTERFACES; - return _local.getAddress().getHostAddress(); } @@ -350,13 +350,8 @@ public class ChannelEndPoint implements EndPoint { if (_socket==null) return null; - - if (_local==null) - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); - if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress()) return StringUtil.ALL_INTERFACES; - return _local.getAddress().getCanonicalHostName(); } @@ -368,9 +363,6 @@ public class ChannelEndPoint implements EndPoint { if (_socket==null) return 0; - - if (_local==null) - _local=(InetSocketAddress)_socket.getLocalSocketAddress(); if (_local==null) return -1; return _local.getPort(); @@ -384,10 +376,6 @@ public class ChannelEndPoint implements EndPoint { if (_socket==null) return null; - - if (_remote==null) - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); - if (_remote==null) return null; return _remote.getAddress().getHostAddress(); @@ -401,10 +389,6 @@ public class ChannelEndPoint implements EndPoint { if (_socket==null) return null; - - if (_remote==null) - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); - if (_remote==null) return null; return _remote.getAddress().getCanonicalHostName(); @@ -418,10 +402,6 @@ public class ChannelEndPoint implements EndPoint { if (_socket==null) return 0; - - if (_remote==null) - _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); - return _remote==null?-1:_remote.getPort(); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java index bb94c9e620..6ab56c4fe2 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectChannelEndPoint.java @@ -212,7 +212,6 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable, { if (_idleTimestamp!=0 && _maxIdleTime!=0 && now>(_idleTimestamp+_maxIdleTime)) { - System.err.println("EXPIRED "+now+">("+_idleTimestamp+"+"+_maxIdleTime+")"); idleExpired(); } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java index 497d605c3f..52d47e0d1e 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SelectorManager.java @@ -49,14 +49,14 @@ public abstract class SelectorManager extends AbstractLifeCycle // TODO Tune these by approx system speed. private static final int __JVMBUG_THRESHHOLD=Integer.getInteger("org.mortbay.io.nio.JVMBUG_THRESHHOLD",512).intValue(); private static final int __MONITOR_PERIOD=Integer.getInteger("org.mortbay.io.nio.MONITOR_PERIOD",1000).intValue(); - private static final int __MAX_SELECTS=Integer.getInteger("org.mortbay.io.nio.MAX_SELECTS",15000).intValue(); + private static final int __MAX_SELECTS=Integer.getInteger("org.mortbay.io.nio.MAX_SELECTS",25000).intValue(); private static final int __BUSY_PAUSE=Integer.getInteger("org.mortbay.io.nio.BUSY_PAUSE",50).intValue(); private static final int __BUSY_KEY=Integer.getInteger("org.mortbay.io.nio.BUSY_KEY",-1).intValue(); private int _maxIdleTime; private int _lowResourcesMaxIdleTime; private long _lowResourcesConnections; - private transient SelectSet[] _selectSet; + private SelectSet[] _selectSet; private int _selectSets=1; private volatile int _set; @@ -98,7 +98,16 @@ public abstract class SelectorManager extends AbstractLifeCycle { return _selectSets; } - + + /* ------------------------------------------------------------ */ + /** + * @param i + * @return The select set + */ + public SelectSet getSelectSet(int i) + { + return _selectSet[i]; + } /* ------------------------------------------------------------ */ /** Register a channel * @param channel @@ -494,16 +503,16 @@ public abstract class SelectorManager extends AbstractLifeCycle if (now>_log) { if (_paused>0) - Log.info(this+" Busy selector - injecting delay "+_paused+" times"); + Log.debug(this+" Busy selector - injecting delay "+_paused+" times"); if (_jvmFix2>0) - Log.info(this+" JVM BUG(s) - injecting delay"+_jvmFix2+" times"); + Log.debug(this+" JVM BUG(s) - injecting delay"+_jvmFix2+" times"); if (_jvmFix1>0) - Log.info(this+" JVM BUG(s) - recreating selector "+_jvmFix1+" times, cancelled keys "+_jvmFix0+" times"); + Log.debug(this+" JVM BUG(s) - recreating selector "+_jvmFix1+" times, cancelled keys "+_jvmFix0+" times"); else if(Log.isDebugEnabled() && _jvmFix0>0) - Log.info(this+" JVM BUG(s) - cancelled keys "+_jvmFix0+" times"); + Log.debug(this+" JVM BUG(s) - cancelled keys "+_jvmFix0+" times"); _paused=0; _jvmFix2=0; _jvmFix1=0; diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/ssl/SslSelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SslSelectChannelEndPoint.java index 12af314109..0133c62920 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/ssl/SslSelectChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/SslSelectChannelEndPoint.java @@ -11,7 +11,7 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== -package org.eclipse.jetty.http.ssl; +package org.eclipse.jetty.io.nio; import java.io.IOException; import java.nio.ByteBuffer; @@ -24,13 +24,9 @@ import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import org.eclipse.jetty.http.Parser; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.Buffers; import org.eclipse.jetty.io.EofException; -import org.eclipse.jetty.io.nio.NIOBuffer; -import org.eclipse.jetty.io.nio.SelectChannelEndPoint; -import org.eclipse.jetty.io.nio.SelectorManager; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -54,10 +50,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint private final SSLEngine _engine; private final SSLSession _session; - private final ByteBuffer _inBuffer; - private final NIOBuffer _inNIOBuffer; - private final ByteBuffer _outBuffer; - private final NIOBuffer _outNIOBuffer; + private volatile NIOBuffer _inNIOBuffer; + private volatile NIOBuffer _outNIOBuffer; private final ByteBuffer[] _gather=new ByteBuffer[2]; @@ -69,7 +63,6 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint private final boolean _debug = __log.isDebugEnabled(); // snapshot debug status for optimizer - /* ------------------------------------------------------------ */ public SslSelectChannelEndPoint(Buffers buffers,SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey key, SSLEngine engine) throws IOException @@ -81,15 +74,46 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint _engine=engine; _session=engine.getSession(); - // TODO pool buffers and use only when needed. - _outNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize()); - _outBuffer=_outNIOBuffer.getByteBuffer(); - _inNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize()); - _inBuffer=_inNIOBuffer.getByteBuffer(); - if (_debug) __log.debug(_session+" channel="+channel); } - + + /* ------------------------------------------------------------ */ + private void needOutBuffer() + { + if (_outNIOBuffer==null) + { + _outNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize()); + } + } + + /* ------------------------------------------------------------ */ + private void needInBuffer() + { + if (_inNIOBuffer==null) + { + _inNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize()); + } + } + + /* ------------------------------------------------------------ */ + private void freeOutBuffer() + { + if (_outNIOBuffer.length()==0) + { + _buffers.returnBuffer(_outNIOBuffer); + _outNIOBuffer=null; + } + } + + /* ------------------------------------------------------------ */ + private void freeInBuffer() + { + if (_inNIOBuffer.length()==0) + { + _buffers.returnBuffer(_inNIOBuffer); + _inNIOBuffer=null; + } + } /* ------------------------------------------------------------ */ /** @@ -119,14 +143,11 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint { Log.info(""+_result); } - /* ------------------------------------------------------------ */ @Override - public void close() throws IOException + public void shutdownOutput() throws IOException { // TODO - this really should not be done in a loop here - but with async callbacks. - - _closing=true; long end=System.currentTimeMillis()+((SocketChannel)_channel).socket().getSoTimeout(); try { @@ -194,19 +215,22 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint case NEED_WRAP: { + needOutBuffer(); + ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer(); try - { + { _outNIOBuffer.compact(); int put=_outNIOBuffer.putIndex(); - _outBuffer.position(put); + out_buffer.position(put); _result=null; - _result=_engine.wrap(__NO_BUFFERS,_outBuffer); + _result=_engine.wrap(__NO_BUFFERS,out_buffer); if (_debug) __log.debug(_session+" close wrap "+_result); _outNIOBuffer.setPutIndex(put+_result.bytesProduced()); } finally { - _outBuffer.position(0); + out_buffer.position(0); + freeOutBuffer(); } break; @@ -214,18 +238,29 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint } } } - catch(IOException e) + catch (InterruptedException e) { Log.ignore(e); } - catch (InterruptedException e) + } + + + /* ------------------------------------------------------------ */ + @Override + public void close() throws IOException + { + try + { + _closing=true; + shutdownOutput(); + } + catch(IOException e) { Log.ignore(e); } finally { super.close(); - if (_inNIOBuffer!=null) _buffers.returnBuffer(_inNIOBuffer); if (_outNIOBuffer!=null) @@ -237,7 +272,7 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint /* ------------------------------------------------------------ */ /** Fill the buffer with unencrypted bytes. - * Called by a {@link Parser} instance when more data is + * Called by a Http Parser when more data is * needed to continue parsing a request or a response. */ @Override @@ -339,7 +374,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint // The SSL needs to send some handshake data to the other side, // so let fill become a flush for a little bit. wraps++; - synchronized(_outBuffer) + needOutBuffer(); + ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer(); + synchronized(out_buffer) { try { @@ -347,9 +384,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint // generate required handshake messages into _outNIOBuffer _outNIOBuffer.compact(); int put=_outNIOBuffer.putIndex(); - _outBuffer.position(); + out_buffer.position(); _result=null; - _result=_engine.wrap(__NO_BUFFERS,_outBuffer); + _result=_engine.wrap(__NO_BUFFERS,out_buffer); if (_debug) __log.debug(_session+" fill wrap "+_result); switch(_result.getStatus()) { @@ -364,13 +401,14 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint } finally { - _outBuffer.position(0); + out_buffer.position(0); } } // flush the encrypted outNIOBuffer flush(); - + freeOutBuffer(); + break; } } @@ -416,7 +454,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint if (buffer!=null) available+=buffer.length(); - int tries=0; + needOutBuffer(); + ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer(); loop: while (true) { if (_outNIOBuffer.length()>0) @@ -495,15 +534,15 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint case NEED_WRAP: { checkRenegotiate(); - synchronized(_outBuffer) + synchronized(out_buffer) { try { _outNIOBuffer.compact(); int put=_outNIOBuffer.putIndex(); - _outBuffer.position(); + out_buffer.position(); _result=null; - _result=_engine.wrap(__NO_BUFFERS,_outBuffer); + _result=_engine.wrap(__NO_BUFFERS,out_buffer); if (_debug) __log.debug(_session+" flush wrap "+_result); switch(_result.getStatus()) { @@ -517,7 +556,7 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint } finally { - _outBuffer.position(0); + out_buffer.position(0); } } @@ -529,7 +568,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint } } } - + + freeOutBuffer(); return consumed; } @@ -537,6 +577,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint @Override public void flush() throws IOException { + if (_outNIOBuffer==null) + return; + int len=_outNIOBuffer.length(); if (isBufferingOutput()) { @@ -578,6 +621,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint */ private boolean unwrap(ByteBuffer buffer) throws IOException { + needInBuffer(); + ByteBuffer in_buffer=_inNIOBuffer.getByteBuffer(); + if (_inNIOBuffer.hasContent()) _inNIOBuffer.compact(); else @@ -602,7 +648,11 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint { if (_inNIOBuffer.length()==0) { - _outNIOBuffer.clear(); + if (_outNIOBuffer!=null) + { + _outNIOBuffer.clear(); + freeOutBuffer(); + } throw e; } break; @@ -614,7 +664,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint { if(!isOpen()) { - _outNIOBuffer.clear(); + if (_outNIOBuffer!=null) + _outNIOBuffer.clear(); throw new EofException(); } return false; @@ -625,12 +676,12 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint { // inBuffer is the NIO buffer inside the _inNIOBuffer, // so update its position and limit from the inNIOBuffer. - _inBuffer.position(_inNIOBuffer.getIndex()); - _inBuffer.limit(_inNIOBuffer.putIndex()); + in_buffer.position(_inNIOBuffer.getIndex()); + in_buffer.limit(_inNIOBuffer.putIndex()); _result=null; // Do the unwrap - _result=_engine.unwrap(_inBuffer,buffer); + _result=_engine.unwrap(in_buffer,buffer); if (_debug) __log.debug(_session+" unwrap unwrap "+_result); // skip the bytes consumed @@ -639,8 +690,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint finally { // reset the buffer so it can be managed by the _inNIOBuffer again. - _inBuffer.position(0); - _inBuffer.limit(_inBuffer.capacity()); + in_buffer.position(0); + in_buffer.limit(in_buffer.capacity()); + freeInBuffer(); } // handle the unwrap results @@ -658,7 +710,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint if(!isOpen()) { _inNIOBuffer.clear(); - _outNIOBuffer.clear(); + if (_outNIOBuffer!=null) + _outNIOBuffer.clear(); throw new EofException(); } return (total_filled > 0); @@ -703,17 +756,19 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint _gather[1].position(buffer.getIndex()); _gather[1].limit(buffer.putIndex()); - synchronized(_outBuffer) + needOutBuffer(); + ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer(); + synchronized(out_buffer) { int consumed=0; try { _outNIOBuffer.clear(); - _outBuffer.position(0); - _outBuffer.limit(_outBuffer.capacity()); + out_buffer.position(0); + out_buffer.limit(out_buffer.capacity()); _result=null; - _result=_engine.wrap(_gather,_outBuffer); + _result=_engine.wrap(_gather,out_buffer); if (_debug) __log.debug(_session+" wrap wrap "+_result); _outNIOBuffer.setGetIndex(0); _outNIOBuffer.setPutIndex(_result.bytesProduced()); @@ -721,7 +776,7 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint } finally { - _outBuffer.position(0); + out_buffer.position(0); if (consumed>0) { @@ -740,6 +795,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint _gather[1].limit(_gather[1].capacity()); } assert consumed==0; + + freeOutBuffer(); } } } @@ -776,15 +833,17 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint _gather[0].limit(buffer.putIndex()); int consumed=0; - synchronized(_outBuffer) + needOutBuffer(); + ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer(); + synchronized(out_buffer) { try { _outNIOBuffer.clear(); - _outBuffer.position(0); - _outBuffer.limit(_outBuffer.capacity()); + out_buffer.position(0); + out_buffer.limit(out_buffer.capacity()); _result=null; - _result=_engine.wrap(_gather[0],_outBuffer); + _result=_engine.wrap(_gather[0],out_buffer); if (_debug) __log.debug(_session+" wrap wrap "+_result); _outNIOBuffer.setGetIndex(0); _outNIOBuffer.setPutIndex(_result.bytesProduced()); @@ -792,7 +851,7 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint } finally { - _outBuffer.position(0); + out_buffer.position(0); if (consumed>0) { @@ -803,6 +862,8 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint _gather[0].limit(_gather[0].capacity()); } assert consumed==0; + + freeOutBuffer(); } } } @@ -828,14 +889,16 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint @Override public boolean isBufferingInput() { - return _inNIOBuffer.hasContent(); + final Buffer in = _inNIOBuffer; + return in==null?false:_inNIOBuffer.hasContent(); } /* ------------------------------------------------------------ */ @Override public boolean isBufferingOutput() { - return _outNIOBuffer.hasContent(); + final NIOBuffer b=_outNIOBuffer; + return b==null?false:b.hasContent(); } /* ------------------------------------------------------------ */ @@ -855,6 +918,9 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint @Override public String toString() { - return super.toString()+","+_engine.getHandshakeStatus()+", in/out="+_inNIOBuffer.length()+"/"+_outNIOBuffer.length()+" "+_result; + final NIOBuffer i=_inNIOBuffer; + final NIOBuffer o=_outNIOBuffer; + return super.toString()+","+_engine.getHandshakeStatus()+", in/out="+ + (i==null?0:_inNIOBuffer.length())+"/"+(o==null?0:o.length())+" "+_result; } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java new file mode 100644 index 0000000000..c0a7d1a9dd --- /dev/null +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/EndPointTest.java @@ -0,0 +1,75 @@ +package org.eclipse.jetty.io; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.channels.SelectionKey; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.rmi.server.ServerCloneException; +import java.util.concurrent.Exchanger; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import javax.net.ServerSocketFactory; + +import org.eclipse.jetty.io.bio.SocketEndPoint; +import org.eclipse.jetty.io.nio.IndirectNIOBuffer; +import org.eclipse.jetty.io.nio.SelectChannelEndPoint; +import org.eclipse.jetty.io.nio.SelectorManager; +import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint; +import org.eclipse.jetty.io.nio.SelectorManager.SelectSet; +import org.junit.Assert; +import org.junit.Test; + +public class EndPointTest +{ + @Test + public void testSocketEndPoints() throws Exception + { + final ServerSocket server = new ServerSocket(); + server.bind(null); + + final Exchanger<Socket> accepted = new Exchanger<Socket>(); + new Thread(){ + public void run() + { + try + { + accepted.exchange(server.accept()); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + }.start(); + + Socket s0 = new Socket(server.getInetAddress(),server.getLocalPort()); + Socket s1 = accepted.exchange(null,5,TimeUnit.SECONDS); + + SocketEndPoint in = new SocketEndPoint(s0); + SocketEndPoint out = new SocketEndPoint(s1); + + check(in,out); + } + + + private void check(EndPoint in, EndPoint out) throws Exception + { + String data="Now is the time for all good men to come to the aid of the party"; + Buffer send = new ByteArrayBuffer(data); + Buffer receive = new IndirectNIOBuffer(4096); + + int lo=out.flush(send); + int li=in.fill(receive); + + Assert.assertEquals(data.length(),lo); + Assert.assertEquals(data.length(),li); + Assert.assertEquals(data,receive.toString()); + + in.close(); + out.close(); + } +} diff --git a/jetty-jmx/src/main/config/etc/jetty-jmx.xml b/jetty-jmx/src/main/config/etc/jetty-jmx.xml index 4df07109f3..bdce9d4298 100644 --- a/jetty-jmx/src/main/config/etc/jetty-jmx.xml +++ b/jetty-jmx/src/main/config/etc/jetty-jmx.xml @@ -1,12 +1,12 @@ <?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> -<!-- =============================================================== --> -<!-- Configure the JVM JMX Server --> -<!-- this configuration file should be used in combination with --> -<!-- other configuration files. e.g. --> -<!-- java -DOPTIONS=jmx -jar start.jar etc/jetty-jmx.xml etc/jetty.xml --> -<!-- =============================================================== --> +<!-- ============================================================================ --> +<!-- To correctly start Jetty with JMX module enabled, this configuration --> +<!-- file must appear first in the list of the configuration files. --> +<!-- The simplest way to achieve this is to add etc/jetty-jmx.xml as the --> +<!-- first file in configuration file list at the end of start.ini file. --> +<!-- ============================================================================ --> <Configure id="Server" class="org.eclipse.jetty.server.Server"> <!-- =========================================================== --> @@ -50,8 +50,37 @@ </Arg> </Call> </Ref> + + <!-- In order to connect to the JMX server remotely from a different + process, possibly running on a different host, Jetty JMX module + can create a remote JMX connector. It requires RMI registry to + be started prior to creating the connector server because the + JMX specification uses RMI to facilitate connections. + --> - <!-- optionally add a remote JMX connector + <!-- Optionally start the RMI registry. Normally RMI registry runs on + port 1099. The argument below can be changed in order to comply + with the firewall requirements. + --> + <!-- + <Call name="createRegistry" class="java.rmi.registry.LocateRegistry"> + <Arg type="java.lang.Integer">1099</Arg> + <Call name="sleep" class="java.lang.Thread"> + <Arg type="java.lang.Integer">1000</Arg> + </Call> + </Call> + --> + + <!-- Optionally add a remote JMX connector. The parameters of the constructor + below specify the JMX service URL, and the object name string for the + connector server bean. The parameters of the JMXServiceURL constructor + specify the protocol that clients will use to connect to the remote JMX + connector (RMI), the hostname of the server (local hostname), port number + (automatically assigned), and the URL path. Note that URL path contains + the RMI registry hostname and port number, that may need to be modified + in order to comply with the firewall requirements. + --> + <!-- <New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer"> <Arg> <New class="javax.management.remote.JMXServiceURL"> @@ -65,6 +94,5 @@ <Call name="start" /> </New> --> - </Configure> diff --git a/jetty-jmx/src/main/resources/org/eclipse/jetty/server/jmx/AbstractConnector-mbean.properties b/jetty-jmx/src/main/resources/org/eclipse/jetty/server/jmx/AbstractConnector-mbean.properties index e2d97a4860..fd7667217d 100644 --- a/jetty-jmx/src/main/resources/org/eclipse/jetty/server/jmx/AbstractConnector-mbean.properties +++ b/jetty-jmx/src/main/resources/org/eclipse/jetty/server/jmx/AbstractConnector-mbean.properties @@ -16,5 +16,4 @@ confidentialPort: Port to use for confidential redirections. confidentialScheme: Scheme to use for confidential redirections. integralPort: Port to use for integral redirections. integralScheme: Scheme to use for integral redirections. -lowResourcesConnections: The number of connections, which if exceeded represents low resources lowResourcesMaxIdleTime: The period in ms that a connection may be idle when the connector has low resources, before it is closed. diff --git a/jetty-jmx/src/main/resources/org/eclipse/jetty/server/nio/jmx/SelectChannelConnector-mbean.properties b/jetty-jmx/src/main/resources/org/eclipse/jetty/server/nio/jmx/SelectChannelConnector-mbean.properties index 096a4b4aad..dbe718d5b0 100644 --- a/jetty-jmx/src/main/resources/org/eclipse/jetty/server/nio/jmx/SelectChannelConnector-mbean.properties +++ b/jetty-jmx/src/main/resources/org/eclipse/jetty/server/nio/jmx/SelectChannelConnector-mbean.properties @@ -1 +1,2 @@ SelectChannelConnector: HTTP connector using NIO ByteChannels and Selectors +lowResourcesConnections: The number of connections, which if exceeded represents low resources diff --git a/jetty-jmx/src/main/resources/org/eclipse/jetty/server/session/jmx/AbstractSessionManager-mbean.properties b/jetty-jmx/src/main/resources/org/eclipse/jetty/server/session/jmx/AbstractSessionManager-mbean.properties index 2bc03eb42a..385f28a420 100644 --- a/jetty-jmx/src/main/resources/org/eclipse/jetty/server/session/jmx/AbstractSessionManager-mbean.properties +++ b/jetty-jmx/src/main/resources/org/eclipse/jetty/server/session/jmx/AbstractSessionManager-mbean.properties @@ -9,15 +9,10 @@ sessionCookie: The set session cookie sessionDomain: The domain of the session cookie or null for the default sessionPath: The path of the session cookie or null for the default sessionsTotal: The total number of sessions -sessionsMax: The maximum number of simultaneous sessions -sessionTimeMax: The maximum session lifetime in seconds -sessionTimeMean: The mean session lifetime in seconds -sessionTimeStdDev: The standard deviation of session lifetime in seconds sessionIdPathParameterName: The name to use for URL session tracking statsReset(): Reset statistics sessions: Current instantaneous number of sessions sessionsMax: Maximum number of simultaneous sessions since statsReset() was called -sessionsMin: Minimum number of simultaneous sessions since statsReset() was called sessionTimeMax: Maximum amount of time in seconds session remained valid since statsReset() was called sessionTimeTotal: Total amount of time in seconds sessions remained valid since statsReset() was called sessionTimeMean: Mean amount of time in seconds a session remained valid since statsReset() was called diff --git a/jetty-jmx/src/main/resources/org/eclipse/jetty/servlets/jmx/DoSFilter-mbean.properties b/jetty-jmx/src/main/resources/org/eclipse/jetty/servlets/jmx/DoSFilter-mbean.properties new file mode 100644 index 0000000000..6a1f31aa49 --- /dev/null +++ b/jetty-jmx/src/main/resources/org/eclipse/jetty/servlets/jmx/DoSFilter-mbean.properties @@ -0,0 +1,12 @@ +DoSFilter: Limit exposure to abuse from request flooding, whether malicious, or as a result of a misconfigured client. +maxRequestsPerSec: maximum number of requests from a connection per second. Requests in excess of this are first delayed, then throttled. +delayMs: delay (in milliseconds) that is applied to all requests over the rate limit, before they are considered at all, 0 - no delay, -1 - reject request. +maxWaitMs: maximum amount of time (in milliseconds) the filter will blocking wait for the throttle semaphore. +throttledRequests: number of requests over the rate limit able to be considered at once. +throttleMs: amount of time (in milliseconds) to async wait for semaphore. +maxRequestMs: maximum amount of time (in milliseconds) to allow the request to process. +maxIdleTrackerMs: maximum amount of time (in milliseconds) to keep track of request rates for a connection, before deciding that the user has gone away, and discarding it. +insertHeaders: insert the DoSFilter headers into the response. +trackSessions: usage rate is tracked by session if a session exists. +remotePort: usage rate is tracked by IP+port (effectively connection) if session tracking is not used. +ipWhitelist: list of IP addresses that will not be rate limited.
\ No newline at end of file diff --git a/jetty-jmx/src/main/resources/org/eclipse/jetty/servlets/jmx/QoSFilter-mbean.properties b/jetty-jmx/src/main/resources/org/eclipse/jetty/servlets/jmx/QoSFilter-mbean.properties new file mode 100644 index 0000000000..c781d638aa --- /dev/null +++ b/jetty-jmx/src/main/resources/org/eclipse/jetty/servlets/jmx/QoSFilter-mbean.properties @@ -0,0 +1,4 @@ +QoSFilter: Quality of Service Filter. +maxRequests: maximum number of requests allowed to be processedat the same time. +waitMs: (short) amount of time (in milliseconds) that the filter would wait for the semaphore to become available before suspending a request. +suspendMs: amount of time (in milliseconds) that the filter would suspend a request for while waiting for the semaphore to become available. diff --git a/jetty-jsp-2.1/pom.xml b/jetty-jsp-2.1/pom.xml index 28da0acae2..e1dccc7c97 100644 --- a/jetty-jsp-2.1/pom.xml +++ b/jetty-jsp-2.1/pom.xml @@ -2,7 +2,7 @@ <parent> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-project</artifactId> - <version>7.1.1-SNAPSHOT</version> + <version>7.1.5-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jetty-jsp-2.1</artifactId> diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java index 084fac8b49..40b56be20b 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java +++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java @@ -118,7 +118,7 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto * Support only 2 types of packaging for the bundle: - the bundle is a jar (recommended for runtime.) - the bundle is a folder and contain jars in the root * and/or in the lib folder (nice for PDE developement situations) Unsupported: the bundle is a jar that embeds more jars. * - * @return + * @return array of URLs * @throws Exception */ public URL[] getJarsWithTlds(OSGiAppProvider provider, BundleFileLocatorHelper locatorHelper) throws Exception diff --git a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarURLConnection.java b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarURLConnection.java index ec31f3c24a..744a43c2ec 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarURLConnection.java +++ b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarURLConnection.java @@ -99,7 +99,7 @@ public class WarURLConnection extends URLConnection /** * @param url The file url (for example) - * @param The manifest to use as a replacement to the jar file inside + * @param mf The manifest to use as a replacement to the jar file inside * the file url. */ public WarURLConnection(URL url, Manifest mf) throws IOException diff --git a/jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF b/jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF index 861d73ad82..44efed3f2b 100644 --- a/jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF +++ b/jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF @@ -2,59 +2,9 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Jetty OSGi bootstrap Bundle-SymbolicName: org.eclipse.jetty.osgi.boot;singleton:=true +Bundle-Vendor: Mort Bay Consulting Bundle-Version: 8.0.0.qualifier Bundle-Activator: org.eclipse.jetty.osgi.boot.JettyBootstrapActivator -Bundle-Vendor: Mort Bay Consulting -Export-Package: org, - org.eclipse, - org.eclipse.jetty, - org.eclipse.jetty.osgi, - org.eclipse.jetty.osgi.boot, - org.eclipse.jetty.osgi.boot.internal, - org.eclipse.jetty.osgi.boot.internal.jsp, - org.eclipse.jetty.osgi.boot.internal.serverfactory, - org.eclipse.jetty.osgi.boot.internal.webapp, - org.eclipse.jetty.osgi.boot.utils, - org.eclipse.jetty.osgi.boot.utils.internal -Require-Bundle: org.eclipse.jetty.ajp;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.annotations;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.client;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.continuation;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.deploy;bundle-version="[8.0, - 9)", - org.eclipse.jetty.http;bundle-version="[8.0, - 9)", - org.eclipse.jetty.io;bundle-version="[8.0, - 9)", - org.eclipse.jetty.jmx;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.jndi;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.plus;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.rewrite;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.security;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.server;bundle-version="[8.0, - 9)", - org.eclipse.jetty.servlet;bundle-version="[8.0, - 9)", - org.eclipse.jetty.servlets;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.util;bundle-version="[8.0, - 9)", - org.eclipse.jetty.webapp;bundle-version="[8.0, - 9)", - org.eclipse.jetty.websocket;bundle-version="[8.0, - 9)";resolution:=optional, - org.eclipse.jetty.xml;bundle-version="[8.0, - 9)" -Bundle-RequiredExecutionEnvironment: J2SE-1.6 Import-Package: javax.mail;version="1.4.0";resolution:=optional, javax.mail.event;version="1.4.0";resolution:=optional, javax.mail.internet;version="1.4.0";resolution:=optional, @@ -73,4 +23,29 @@ Import-Package: javax.mail;version="1.4.0";resolution:=optional, org.slf4j;resolution:=optional, org.slf4j.spi;resolution:=optional, org.slf4j.helpers;resolution:=optional + org.xml.sax, + org.xml.sax.helpers +Bundle-RequiredExecutionEnvironment: J2SE-1.6 +Bundle-Classpath: . +Require-Bundle: org.eclipse.jetty.ajp;bundle-version="[8.0,8)";resolution:=optional, + org.eclipse.jetty.annotations;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.client;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.continuation;bundle-version="[7.0,9)";resolution:=optional, + org.eclipse.jetty.deploy;bundle-version="[8.0,9)", + org.eclipse.jetty.http;bundle-version="[8.0,9)", + org.eclipse.jetty.io;bundle-version="[8.0,9)", + org.eclipse.jetty.jmx;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.jndi;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.plus;bundle-version="[8.0,9.0)";resolution:=optional, + org.eclipse.jetty.rewrite;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.security;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.server;bundle-version="[8.0,9)", + org.eclipse.jetty.servlet;bundle-version="[8.0,9)", + org.eclipse.jetty.servlets;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.util;bundle-version="[8.0,9)", + org.eclipse.jetty.webapp;bundle-version="[8.0,9)", + org.eclipse.jetty.websocket;bundle-version="[8.0,9)";resolution:=optional, + org.eclipse.jetty.xml;bundle-version="[8.0,9)" +Export-Package: org.eclipse.jetty.osgi.boot, + org.eclipse.jetty.osgi.boot.utils Bundle-ActivationPolicy: lazy diff --git a/jetty-osgi/jetty-osgi-boot/build.properties b/jetty-osgi/jetty-osgi-boot/build.properties index d9a9ce1f7f..ba1366d090 100644 --- a/jetty-osgi/jetty-osgi-boot/build.properties +++ b/jetty-osgi/jetty-osgi-boot/build.properties @@ -3,13 +3,6 @@ output.. = target/classes/ bin.includes = META-INF/,\ .,\ jettyhome/ -bin.excludes = jettyhome/logs/2009_09_21.request.log,\ - jettyhome/lib/atomikos-util-3.5.8.jar,\ - jettyhome/lib/transactions-3.5.8.jar,\ - jettyhome/lib/transactions-api-3.5.8.jar,\ - jettyhome/lib/transactions-jdbc-3.5.8.jar,\ - jettyhome/lib/transactions-jta-3.5.8.jar,\ - jettyhome/lib/ext/derby-10.4.1.3.jar,\ - jettyhome/lib/ext/derbytools-10.4.1.3.jar -src.includes = META-INF/,\ - jettyhome/ +bin.excludes = jettyhome/logs/*.log,\ + jettyhome/lib/* +src.includes = jettyhome/ diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java index 1c7250fcef..c76a71c0ff 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java @@ -148,8 +148,8 @@ public class JettyBootstrapActivator implements BundleActivator * registers it as an OSGi service. The tracker * {@link JettyContextHandlerServiceTracker} will do the actual deployment. * - * @param context - * The current bundle context + * @param contributor + * The bundle * @param webappFolderPath * The path to the root of the webapp. Must be a path relative to * bundle; either an absolute path. @@ -171,18 +171,15 @@ public class JettyBootstrapActivator implements BundleActivator * registers it as an OSGi service. The tracker * {@link JettyContextHandlerServiceTracker} will do the actual deployment. * - * @param context - * The current bundle context + * @param contributor + * The bundle * @param webappFolderPath * The path to the root of the webapp. Must be a path relative to * bundle; either an absolute path. * @param contextPath * The context path. Must start with "/" - * @param thisBundleInstallationOverride - * The location to a folder where the context file is located - * This overrides the default behavior that consists of using the - * location where the bundle is installed. Useful when in fact - * the webapp contributed is not inside a bundle. + * @param dic + * TODO: parameter description * @throws Exception */ public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath, Dictionary<String, String> dic) throws Exception @@ -220,11 +217,8 @@ public class JettyBootstrapActivator implements BundleActivator * @param contextFilePath * The path to the file inside the bundle that defines the * context. - * @param thisBundleInstallationOverride - * The location to a folder where the context file is located - * This overrides the default behavior that consists of using the - * location where the bundle is installed. Useful when in fact - * the webapp contributed is not inside a bundle. + * @param dic + * TODO: parameter description * @throws Exception */ public static void registerContext(Bundle contributor, String contextFilePath, Dictionary<String, String> dic) throws Exception diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiAppProvider.java index 9ddc27bc74..c48c52fb9d 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiAppProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiAppProvider.java @@ -91,8 +91,6 @@ public class OSGiAppProvider extends ScanningAppProvider implements AppProvider /** * Default OSGiAppProvider consutructed when none are defined in the * jetty.xml configuration. - * - * @param contextsDir */ public OSGiAppProvider() { diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloaderWithInsertedJettyClassloader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloaderWithInsertedJettyClassloader.java index 67104b7173..9c989c7f7e 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloaderWithInsertedJettyClassloader.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloaderWithInsertedJettyClassloader.java @@ -30,7 +30,7 @@ public class TldLocatableURLClassloaderWithInsertedJettyClassloader extends TldL /** * - * @param osgiClassLoader + * @param osgiClassLoaderParent * The parent classloader * @param internalClassLoader * The classloader that will be at the same level than the diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebappRegistrationHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebappRegistrationHelper.java index 447893d315..e55a03aea5 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebappRegistrationHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebappRegistrationHelper.java @@ -396,17 +396,19 @@ public class WebappRegistrationHelper /** * Deploy a new web application on the jetty server. * - * @param context - * The current bundle context + * @param bundle + * The bundle * @param webappFolderPath * The path to the root of the webapp. Must be a path relative to * bundle; either an absolute path. * @param contextPath * The context path. Must start with "/" - * @param classInBundle - * A class that belongs to the current bundle to inherit from the - * osgi classloader. Null to not have access to the OSGI - * classloader. + * @param extraClasspath + * @param overrideBundleInstallLocation + * @param webXmlPath + * @param defaultWebXmlPath + * TODO: parameter description + * @return The contexthandler created and started * @throws Exception */ public ContextHandler registerWebapplication(Bundle bundle, String webappFolderPath, String contextPath, String extraClasspath, @@ -439,12 +441,16 @@ public class WebappRegistrationHelper } /** - * @See {@link WebAppDeployer#scan()} - * TODO: refacotr this into the createContext method of OSGiAppProvider. - * + * TODO: refactor this into the createContext method of OSGiAppProvider. + * @see WebAppDeployer#scan() + + * @param contributor * @param webapp * @param contextPath - * @param classInBundle + * @param extraClasspath + * @param bundleInstall + * @param webXmlPath + * @param defaultWebXmlPath * @return The contexthandler created and started * @throws Exception */ @@ -537,7 +543,7 @@ public class WebappRegistrationHelper /** * Stop a ContextHandler and remove it from the collection. * - * @See ContextDeployer#undeploy + * @see ContextDeployer#undeploy * @param contextHandler * @throws Exception */ @@ -579,9 +585,11 @@ public class WebappRegistrationHelper * Context encompasses jndi and all other things. This makes the definition * of the webapp a lot more self-contained. * - * @param webapp - * @param contextPath - * @param classInBundle + * @param contributor + * @param contextFileRelativePath + * @param extraClasspath + * @param overrideBundleInstallLocation + * @return The contexthandler created and started * @throws Exception */ public ContextHandler registerContext(Bundle contributor, String contextFileRelativePath, String extraClasspath, String overrideBundleInstallLocation) @@ -725,7 +733,7 @@ public class WebappRegistrationHelper webAppContext.setServerClasses(null); } - context.start(); + _provider.addContext(context); return context; } finally diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java index 8aef238472..d0a75c5b2c 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java @@ -53,7 +53,7 @@ public interface BundleFileLocatorHelper * * @param bundle * @param path - * @return + * @return file object * @throws Exception */ public File getFileInBundle(Bundle bundle, String path) throws Exception; diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/WebappRegistrationCustomizer.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/WebappRegistrationCustomizer.java index 5db0a2f4de..1a37a046c6 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/WebappRegistrationCustomizer.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/WebappRegistrationCustomizer.java @@ -46,7 +46,7 @@ public interface WebappRegistrationCustomizer * the root and/or in the lib folder (nice for PDE developement situations) * Unsupported: the bundle is a jar that embeds more jars. * - * @return + * @return array of URLs * @throws Exception */ URL[] getJarsWithTlds(OSGiAppProvider provider, BundleFileLocatorHelper fileLocator) throws Exception; diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java index 10d1698ae3..a918cd7706 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java @@ -61,7 +61,7 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper * Assuming the bundle is started. * * @param bundle - * @return + * @return classloader object */ public ClassLoader getBundleClassLoader(Bundle bundle) { diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java index cd2732825a..7f6d5f25e7 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java @@ -145,7 +145,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper * * @param bundle * @param path - * @return + * @return file object * @throws Exception */ public File getFileInBundle(Bundle bundle, String path) throws Exception diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java index ca0659a7ba..0852bf5f9b 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java @@ -53,10 +53,10 @@ public interface Authenticator * @param request The request * @param response The response * @param mandatory True if authentication is mandatory. - * @return An Authentication. If Authentication is successful, this will be a {@link Authentication.User}. If a response has + * @return An Authentication. If Authentication is successful, this will be a {@link org.eclipse.jetty.server.Authentication.User}. If a response has * been sent by the Authenticator (which can be done for both successful and unsuccessful authentications), then the result will - * implement {@link Authentication.ResponseSent}. If Authentication is not manditory, then a {@link Authentication.Deferred} - * may be returned. + * implement {@link org.eclipse.jetty.server.Authentication.ResponseSent}. If Authentication is not manditory, then a + * {@link org.eclipse.jetty.server.Authentication.Deferred} may be returned. * * @throws ServerAuthException */ diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java index 65ec7fc991..2b2b746276 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/DefaultIdentityService.java @@ -24,9 +24,10 @@ import org.eclipse.jetty.server.UserIdentity; /** * Default Identity Service implementation. * This service handles only role reference maps passed in an - * associated {@link UserIdentity.Scope}. If there are roles + * associated {@link org.eclipse.jetty.server.UserIdentity.Scope}. If there are roles * refs present, then associate will wrap the UserIdentity with one - * that uses the role references in the {@link UserIdentity#isUserInRole(String, org.eclipse.jetty.server.UserIdentity.Scope)} + * that uses the role references in the + * {@link org.eclipse.jetty.server.UserIdentity#isUserInRole(String, org.eclipse.jetty.server.UserIdentity.Scope)} * implementation. All other operations are effectively noops. * */ diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java index c5d1138cf6..c95c226c61 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; +import org.eclipse.jetty.http.security.Credential; import org.eclipse.jetty.http.security.Password; import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.util.Loader; @@ -248,7 +249,7 @@ public class JDBCLoginService extends MappedLoginService roles.add(rs.getString(_roleTableRoleField)); stat.close(); - return putUser(username, new Password(credentials),roles.toArray(new String[roles.size()])); + return putUser(username, Credential.getCredential(credentials),roles.toArray(new String[roles.size()])); } } catch (SQLException e) 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 cc8877dcac..7fed43a9a1 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 @@ -68,15 +68,10 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector private boolean _useDNS; private boolean _forwarded; private String _hostHeader; - private String _forwardedHostHeader = "X-Forwarded-Host"; // default to - // mod_proxy_http - // header - private String _forwardedServerHeader = "X-Forwarded-Server"; // default to - // mod_proxy_http - // header - private String _forwardedForHeader = "X-Forwarded-For"; // default to - // mod_proxy_http - // header + + private String _forwardedHostHeader = "X-Forwarded-Host"; + private String _forwardedServerHeader = "X-Forwarded-Server"; + private String _forwardedForHeader = "X-Forwarded-For"; private boolean _reuseAddress = true; protected int _maxIdleTime = 200000; @@ -87,101 +82,70 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector private final AtomicLong _statsStartedAt = new AtomicLong(-1L); - private final CounterStatistic _connectionStats = new CounterStatistic(); // connections - // to - // server - private final SampleStatistic _requestStats = new SampleStatistic(); // requests - // per - // connection - private final SampleStatistic _connectionDurationStats = new SampleStatistic(); // duration - // of - // a - // connection + /** connections to server */ + private final CounterStatistic _connectionStats = new CounterStatistic(); + /** requests per connection */ + private final SampleStatistic _requestStats = new SampleStatistic(); + /** duration of a connection */ + private final SampleStatistic _connectionDurationStats = new SampleStatistic(); - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /** */ public AbstractConnector() { } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ public final Buffer newBuffer(int size) { // TODO remove once no overrides established return null; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ @Override public Buffer newRequestBuffer(int size) { return new ByteArrayBuffer(size); } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ @Override public Buffer newRequestHeader(int size) { return new ByteArrayBuffer(size); } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ @Override public Buffer newResponseBuffer(int size) { return new ByteArrayBuffer(size); } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ @Override public Buffer newResponseHeader(int size) { return new ByteArrayBuffer(size); } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ @Override protected boolean isRequestHeader(Buffer buffer) { return true; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ @Override protected boolean isResponseHeader(Buffer buffer) { return true; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /* */ public Server getServer() @@ -189,19 +153,13 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector return _server; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ public void setServer(Server server) { _server = server; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /* * @see org.eclipse.jetty.http.HttpListener#getHttpServer() */ @@ -210,19 +168,13 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector return _threadPool; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ public void setThreadPool(ThreadPool pool) { _threadPool = pool; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /** */ public void setHost(String host) @@ -230,10 +182,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector _host = host; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /* */ public String getHost() @@ -241,10 +190,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector return _host; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /* * @see org.eclipse.jetty.server.server.HttpListener#setPort(int) */ @@ -253,10 +199,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector _port = port; } - /* - * -------------------------------------------------------------------------- - * ----- - */ + /* ------------------------------------------------------------ */ /* * @see org.eclipse.jetty.server.server.HttpListener#getPort() */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java index ae413e0964..cfc9a3ce75 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java @@ -673,7 +673,7 @@ public class AsyncContinuation implements AsyncContext, Continuation { _expireAt = System.currentTimeMillis()+_timeoutMs; long wait=_timeoutMs; - while (_expireAt>0 && wait>0) + while (_expireAt>0 && wait>0 && _connection.getServer().isRunning()) { try { @@ -686,7 +686,7 @@ public class AsyncContinuation implements AsyncContext, Continuation wait=_expireAt-System.currentTimeMillis(); } - if (_expireAt>0 && wait<=0) + if (_expireAt>0 && wait<=0 && _connection.getServer().isRunning()) { expired(); } @@ -824,11 +824,19 @@ public class AsyncContinuation implements AsyncContext, Continuation } /* ------------------------------------------------------------ */ - public void start(Runnable run) + public void start(final Runnable run) { final AsyncEventState event=_event; if (event!=null) - ((Context)event.getServletContext()).getContextHandler().handle(run); + { + _connection.getServer().getThreadPool().dispatch(new Runnable() + { + public void run() + { + ((Context)event.getServletContext()).getContextHandler().handle(run); + } + }); + } } /* ------------------------------------------------------------ */ 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 de9e4e764a..8230561120 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 @@ -148,7 +148,7 @@ public class HttpConnection implements Connection HttpBuffers ab = (HttpBuffers)_connector; _parser = new HttpParser(ab.getRequestBuffers(), endpoint, new RequestHandler()); _requestFields = new HttpFields(); - _responseFields = new HttpFields(); + _responseFields = new HttpFields(server.getMaxCookieVersion()); _request = new Request(this); _response = new Response(this); _generator = new HttpGenerator(ab.getResponseBuffers(), _endp); @@ -165,7 +165,7 @@ public class HttpConnection implements Connection _endp = endpoint; _parser = parser; _requestFields = new HttpFields(); - _responseFields = new HttpFields(); + _responseFields = new HttpFields(server.getMaxCookieVersion()); _request = request; _response = new Response(this); _generator = generator; @@ -190,7 +190,13 @@ public class HttpConnection implements Connection { return _requests; } - + + /* ------------------------------------------------------------ */ + public Server getServer() + { + return _server; + } + /* ------------------------------------------------------------ */ /** * @return The time this connection was established. @@ -484,6 +490,7 @@ public class HttpConnection implements Connection { _parser.reset(true); more_in_buffer=false; + _endp.close(); } if (more_in_buffer) @@ -632,7 +639,6 @@ public class HttpConnection implements Connection Log.debug(e); _request.setHandled(true); _generator.sendError(info==null?400:500, null, null, true); - } finally { @@ -1020,7 +1026,10 @@ public class HttpConnection implements Connection if (_expect) { - _generator.sendError(HttpStatus.EXPECTATION_FAILED_417, null, null, true); + _generator.setResponse(HttpStatus.EXPECTATION_FAILED_417, null); + _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER); + _generator.completeHeader(_responseFields, true); + _generator.complete(); return; } @@ -1176,13 +1185,13 @@ public class HttpConnection implements Connection else { _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER, - contentType+";charset="+QuotedStringTokenizer.quote(enc,";= ")); + contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= ")); } } else { _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER, - contentType+";charset="+QuotedStringTokenizer.quote(enc,";= ")); + contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= ")); } } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java index 2ee82a28f2..f90e7818fc 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java @@ -41,6 +41,10 @@ import org.eclipse.jetty.util.log.Log; * * @org.apache.xbean.XBean element="ncsaLog" */ + +/* ------------------------------------------------------------ */ +/** + */ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog { private String _filename; @@ -57,6 +61,7 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog private boolean _logLatency = false; private boolean _logCookies = false; private boolean _logServer = false; + private boolean _logDispatch = false; private transient OutputStream _out; private transient OutputStream _fileOut; @@ -66,6 +71,10 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog private transient ArrayList _buffers; private transient char[] _copy; + /* ------------------------------------------------------------ */ + /** + * Create request log object with default settings. + */ public NCSARequestLog() { _extended = true; @@ -75,9 +84,11 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog /* ------------------------------------------------------------ */ /** - * @param filename - * The filename for the request log. This may be in the - * format expected by {@link RolloverFileOutputStream} + * Create request log object with specified output file name. + * + * @param filename the file name for the request log. + * This may be in the format expected + * by {@link RolloverFileOutputStream} */ public NCSARequestLog(String filename) { @@ -89,9 +100,12 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog /* ------------------------------------------------------------ */ /** - * @param filename - * The filename for the request log. This may be in the - * format expected by {@link RolloverFileOutputStream} + * Set the output file name of the request log. + * The file name may be in the format expected by + * {@link RolloverFileOutputStream}. + * + * @param filename file name of the request log + * */ public void setFilename(String filename) { @@ -104,11 +118,25 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog _filename = filename; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the output file name of the request log. + * + * @return file name of the request log + */ public String getFilename() { return _filename; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the file name of the request log with the expanded + * date wildcard if the output is written to the disk using + * {@link RolloverFileOutputStream}. + * + * @return file name of the request log, or null if not applicable + */ public String getDatedFilename() { if (_fileOut instanceof RolloverFileOutputStream) @@ -118,116 +146,306 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog /* ------------------------------------------------------------ */ /** - * @param format - * Format for the timestamps in the log file. If not set, the - * pre-formated request timestamp is used. + * Set the timestamp format for request log entries in the file. + * If this is not set, the pre-formated request timestamp is used. + * + * @param format timestamp format string */ public void setLogDateFormat(String format) { _logDateFormat = format; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the timestamp format string for request log entries. + * + * @return timestamp format string. + */ public String getLogDateFormat() { return _logDateFormat; } + /* ------------------------------------------------------------ */ + /** + * Set the locale of the request log. + * + * @param logLocale locale object + */ public void setLogLocale(Locale logLocale) { _logLocale = logLocale; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the locale of the request log. + * + * @return locale object + */ public Locale getLogLocale() { return _logLocale; } + /* ------------------------------------------------------------ */ + /** + * Set the timezone of the request log. + * + * @param tz timezone string + */ public void setLogTimeZone(String tz) { _logTimeZone = tz; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the timezone of the request log. + * + * @return timezone string + */ public String getLogTimeZone() { return _logTimeZone; } + /* ------------------------------------------------------------ */ + /** + * Set the number of days before rotated log files are deleted. + * + * @param retainDays number of days to keep a log file + */ public void setRetainDays(int retainDays) { _retainDays = retainDays; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the number of days before rotated log files are deleted. + * + * @return number of days to keep a log file + */ public int getRetainDays() { return _retainDays; } + /* ------------------------------------------------------------ */ + /** + * Set the extended request log format flag. + * + * @param extended true - log the extended request information, + * false - do not log the extended request information + */ public void setExtended(boolean extended) { _extended = extended; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the extended request log format flag. + * + * @return value of the flag + */ public boolean isExtended() { return _extended; } + /* ------------------------------------------------------------ */ + /** + * Set append to log flag. + * + * @param append true - request log file will be appended after restart, + * false - request log file will be overwritten after restart + */ public void setAppend(boolean append) { _append = append; } + /* ------------------------------------------------------------ */ + /** + * Retrieve append to log flag. + * + * @return value of the flag + */ public boolean isAppend() { return _append; } + /* ------------------------------------------------------------ */ + /** + * Set request paths that will not be logged. + * + * @param ignorePaths array of request paths + */ public void setIgnorePaths(String[] ignorePaths) { _ignorePaths = ignorePaths; } + /* ------------------------------------------------------------ */ + /** + * Retrieve the request paths that will not be logged. + * + * @return array of request paths + */ public String[] getIgnorePaths() { return _ignorePaths; } + /* ------------------------------------------------------------ */ + /** + * Controls logging of the request cookies. + * + * @param logCookies true - values of request cookies will be logged, + * false - values of request cookies will not be logged + */ public void setLogCookies(boolean logCookies) { _logCookies = logCookies; } + /* ------------------------------------------------------------ */ + /** + * Retrieve log cookies flag + * + * @return value of the flag + */ public boolean getLogCookies() { return _logCookies; } - public boolean getLogServer() + /* ------------------------------------------------------------ */ + /** + * Controls logging of the request hostname. + * + * @param logServer true - request hostname will be logged, + * false - request hostname will not be logged + */ + public void setLogServer(boolean logServer) { - return _logServer; + _logServer = logServer; } - public void setLogServer(boolean logServer) + /* ------------------------------------------------------------ */ + /** + * Retrieve log hostname flag. + * + * @return value of the flag + */ + public boolean getLogServer() { - _logServer = logServer; + return _logServer; } + /* ------------------------------------------------------------ */ + /** + * Controls logging of request processing time. + * + * @param logLatency true - request processing time will be logged + * false - request processing time will not be logged + */ public void setLogLatency(boolean logLatency) { _logLatency = logLatency; } + /* ------------------------------------------------------------ */ + /** + * Retrieve log request processing time flag. + * + * @return value of the flag + */ public boolean getLogLatency() { return _logLatency; } + /* ------------------------------------------------------------ */ + /** + * Controls whether the actual IP address of the connection or + * the IP address from the X-Forwarded-For header will be logged. + * + * @param preferProxiedForAddress true - IP address from header will be logged, + * false - IP address from the connection will be logged + */ public void setPreferProxiedForAddress(boolean preferProxiedForAddress) { _preferProxiedForAddress = preferProxiedForAddress; } + + /* ------------------------------------------------------------ */ + /** + * Retrieved log X-Forwarded-For IP address flag. + * + * @return value of the flag + */ + public boolean getPreferProxiedForAddress() + { + return _preferProxiedForAddress; + } + + /* ------------------------------------------------------------ */ + /** + * Set the log file name date format. + * @see RolloverFileOutputStream#RolloverFileOutputStream(String, boolean, int, TimeZone, String, String) + * + * @param logFileDateFormat format string that is passed to {@link RolloverFileOutputStream} + */ + public void setFilenameDateFormat(String logFileDateFormat) + { + _filenameDateFormat = logFileDateFormat; + } + + /* ------------------------------------------------------------ */ + /** + * Retrieve the file name date format string. + * + * @return the log File Date Format + */ + public String getFilenameDateFormat() + { + return _filenameDateFormat; + } + + /* ------------------------------------------------------------ */ + /** + * Controls logging of the request dispatch time + * + * @param value true - request dispatch time will be logged + * false - request dispatch time will not be logged + */ + public void setLogDispatch(boolean value) + { + _logDispatch = value; + } /* ------------------------------------------------------------ */ + /** + * Retrieve request dispatch time logging flag + * + * @return value of the flag + */ + public boolean isLogDispatch() + { + return _logDispatch; + } + + /* ------------------------------------------------------------ */ + /** + * Writes the request and response information to the output stream. + * + * @see org.eclipse.jetty.server.RequestLog#log(org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response) + */ public void log(Request request, Response response) { if (!isStarted()) @@ -374,11 +592,20 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog _writer.write('\"'); } } + + final long now = System.currentTimeMillis(); + final long start = request.getTimeStamp(); + final long dispatch = request.getDispatchTime(); + if (_logDispatch) + { + _writer.write(' '); + _writer.write(Long.toString(now - (dispatch==0 ? start:dispatch))); + } if (_logLatency) { _writer.write(' '); - _writer.write(Long.toString(System.currentTimeMillis() - request.getTimeStamp())); + _writer.write(Long.toString(now - start)); } _writer.write(StringUtil.__LINE_SEPARATOR); @@ -394,6 +621,14 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog } /* ------------------------------------------------------------ */ + /** + * Writes extended request and response information to the output stream. + * + * @param request request object + * @param response response object + * @param writer log file writer + * @throws IOException + */ protected void logExtended(Request request, Response response, Writer writer) throws IOException @@ -420,6 +655,11 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog } /* ------------------------------------------------------------ */ + /** + * Set up request logging and open log file. + * + * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart() + */ @Override protected void doStart() throws Exception { @@ -456,6 +696,11 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog } /* ------------------------------------------------------------ */ + /** + * Close the log file and perform cleanup. + * + * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop() + */ @Override protected void doStop() throws Exception { @@ -487,28 +732,4 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog _buffers = null; _copy = null; } - - /* ------------------------------------------------------------ */ - /** - * @return the log File Date Format - */ - public String getFilenameDateFormat() - { - return _filenameDateFormat; - } - - /* ------------------------------------------------------------ */ - /** - * Set the log file date format. - * - * @see RolloverFileOutputStream#RolloverFileOutputStream(String, boolean, int, TimeZone, String, String) - * @param logFileDateFormat - * the logFileDateFormat to pass to - * {@link RolloverFileOutputStream} - */ - public void setFilenameDateFormat(String logFileDateFormat) - { - _filenameDateFormat = logFileDateFormat; - } - } 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 3805a423b5..a1c5599fc6 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 @@ -166,7 +166,8 @@ public class Request implements HttpServletRequest private HttpSession _session; private SessionManager _sessionManager; private long _timeStamp; - + private long _dispatchTime; + private Buffer _timeStampBuffer; private HttpURI _uri; @@ -1225,6 +1226,16 @@ public class Request implements HttpServletRequest } /* ------------------------------------------------------------ */ + /** Get timestamp of the request dispatch + * + * @return timestamp + */ + public long getDispatchTime() + { + return _dispatchTime; + } + + /* ------------------------------------------------------------ */ public boolean isAsyncStarted() { return _async.isAsyncStarted(); @@ -1565,7 +1576,9 @@ public class Request implements HttpServletRequest /* ------------------------------------------------------------ */ /** - * @param context + * Set request context + * + * @param context context object */ public void setContext(Context context) { @@ -1575,7 +1588,8 @@ public class Request implements HttpServletRequest /* ------------------------------------------------------------ */ /** - * @return True if this is the first call of {@link #takeNewContext()} since the last {@link #setContext(Context)} call. + * @return True if this is the first call of {@link #takeNewContext()} + * since the last {@link #setContext(org.eclipse.jetty.server.handler.ContextHandler.Context)} call. */ public boolean takeNewContext() { @@ -1801,6 +1815,16 @@ public class Request implements HttpServletRequest } /* ------------------------------------------------------------ */ + /** Set timetstamp of request dispatch + * + * @param value timestamp + */ + public void setDispatchTime(long value) + { + _dispatchTime = value; + } + + /* ------------------------------------------------------------ */ public AsyncContext startAsync() throws IllegalStateException { if (!_asyncSupported) 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 4610476cb9..37ed17efca 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 @@ -721,7 +721,7 @@ public class Response implements HttpServletResponse if (_contentType==null) { - _contentType = _mimeType+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType = _mimeType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } } @@ -730,16 +730,16 @@ public class Response implements HttpServletResponse int i1=_contentType.indexOf("charset=",i0); if (i1<0) { - _contentType = _contentType+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType = _contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); } else { int i8=i1+8; int i2=_contentType.indexOf(" ",i8); if (i2<0) - _contentType=_contentType.substring(0,i8)+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType=_contentType.substring(0,i8)+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); else - _contentType=_contentType.substring(0,i8)+QuotedStringTokenizer.quote(_characterEncoding,";= ")+_contentType.substring(i2); + _contentType=_contentType.substring(0,i8)+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ")+_contentType.substring(i2); } _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } @@ -867,12 +867,12 @@ public class Response implements HttpServletResponse } else if (i2<0) { - _contentType=contentType.substring(0,i1)+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType=contentType.substring(0,i1)+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } else { - _contentType=contentType.substring(0,i1)+contentType.substring(i2)+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType=contentType.substring(0,i1)+contentType.substring(i2)+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } } @@ -918,7 +918,7 @@ public class Response implements HttpServletResponse else // No encoding in the params. { _cachedMimeType=null; - _contentType=_characterEncoding==null?contentType:contentType+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType=_characterEncoding==null?contentType:contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } } @@ -939,13 +939,13 @@ public class Response implements HttpServletResponse } else { - _contentType=_mimeType+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType=_mimeType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } } else { - _contentType=contentType+";charset="+QuotedStringTokenizer.quote(_characterEncoding,";= "); + _contentType=contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= "); _connection.getResponseFields().put(HttpHeaders.CONTENT_TYPE_BUFFER,_contentType); } } 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 0e7e3bb987..5afa7a23e1 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 @@ -70,7 +70,9 @@ public class Server extends HandlerWrapper implements Attributes private boolean _sendDateHeader = false; //send Date: header private int _graceful=0; private boolean _stopAtShutdown; + private int _maxCookieVersion=1; + /* ------------------------------------------------------------ */ public Server() { @@ -434,7 +436,24 @@ public class Server extends HandlerWrapper implements Attributes { return _sendDateHeader; } - + + /* ------------------------------------------------------------ */ + /** Get the maximum cookie version. + * @return the maximum set-cookie version sent by this server + */ + public int getMaxCookieVersion() + { + return _maxCookieVersion; + } + + /* ------------------------------------------------------------ */ + /** Set the maximum cookie version. + * @param maxCookieVersion the maximum set-cookie version sent by this server + */ + public void setMaxCookieVersion(int maxCookieVersion) + { + _maxCookieVersion = maxCookieVersion; + } /* ------------------------------------------------------------ */ /** 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 0b5d6ecd6b..114a5076b3 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 @@ -88,6 +88,13 @@ import org.eclipse.jetty.util.resource.Resource; public class ContextHandler extends ScopedHandler implements Attributes, Server.Graceful { private static final ThreadLocal<Context> __context=new ThreadLocal<Context>(); + + /** + * If a context attribute with this name is set, it is interpreted as a + * comma separated list of attribute name. Any other context attributes that + * are set with a name from this list will result in a call to {@link #setManagedAttribute(String, Object)}, + * which typically initiates the creation of a JMX MBean for the attribute value. + */ public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.context.ManagedAttributes"; /* ------------------------------------------------------------ */ @@ -104,11 +111,11 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. protected Context _scontext; - private AttributesMap _attributes; - private AttributesMap _contextAttributes; + private final AttributesMap _attributes; + private final AttributesMap _contextAttributes; + private final Map<String,String> _initParams; private ClassLoader _classLoader; private String _contextPath="/"; - private Map<String,String> _initParams; private String _displayName; private Resource _baseResource; private MimeTypes _mimeTypes; @@ -146,6 +153,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. super(); _scontext=new Context(); _attributes=new AttributesMap(); + _contextAttributes=new AttributesMap(); _initParams=new HashMap<String,String>(); } @@ -158,6 +166,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. super(); _scontext=context; _attributes=new AttributesMap(); + _contextAttributes=new AttributesMap(); _initParams=new HashMap<String,String>(); } @@ -578,7 +587,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. Thread current_thread=null; Context old_context=null; - _contextAttributes=new AttributesMap(); + _contextAttributes.clearAttributes(); try { @@ -640,7 +649,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { String name = (String)e.nextElement(); Object value = _scontext.getAttribute(name); - setManagedAttribute(name,value); + checkManagedAttribute(name,value); } } @@ -717,7 +726,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. while(e.hasMoreElements()) { String name = (String)e.nextElement(); - setManagedAttribute(name,null); + checkManagedAttribute(name,null); } } finally @@ -728,9 +737,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. current_thread.setContextClassLoader(old_classloader); } - if (_contextAttributes!=null) - _contextAttributes.clearAttributes(); - _contextAttributes=null; + _contextAttributes.clearAttributes(); } /* ------------------------------------------------------------ */ @@ -888,8 +895,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } // start manual inline of nextScope(target,baseRequest,request,response); - //noinspection ConstantIfStatement - if (false) + if (never()) nextScope(target,baseRequest,request,response); else if (_nextScope!=null) _nextScope.doScope(target,baseRequest,request, response); @@ -953,7 +959,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. // start manual inline of nextHandle(target,baseRequest,request,response); //noinspection ConstantIfStatement - if (false) + if (never()) nextHandle(target,baseRequest,request,response); else if (_nextScope!=null && _nextScope==_handler) _nextScope.doHandle(target,baseRequest,request, response); @@ -1034,7 +1040,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. */ public void removeAttribute(String name) { - setManagedAttribute(name,null); + checkManagedAttribute(name,null); _attributes.removeAttribute(name); } @@ -1047,7 +1053,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. */ public void setAttribute(String name, Object value) { - setManagedAttribute(name,value); + checkManagedAttribute(name,value); _attributes.setAttribute(name,value); } @@ -1057,27 +1063,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. */ public void setAttributes(Attributes attributes) { - if (attributes instanceof AttributesMap) - { - _attributes = (AttributesMap)attributes; - Enumeration e = _attributes.getAttributeNames(); - while (e.hasMoreElements()) - { - String name = (String)e.nextElement(); - setManagedAttribute(name,attributes.getAttribute(name)); - } - } - else + _attributes.clearAttributes(); + _attributes.addAll(attributes); + Enumeration e = _attributes.getAttributeNames(); + while (e.hasMoreElements()) { - _attributes=new AttributesMap(); - Enumeration e = attributes.getAttributeNames(); - while (e.hasMoreElements()) - { - String name = (String)e.nextElement(); - Object value=attributes.getAttribute(name); - setManagedAttribute(name,value); - _attributes.setAttribute(name,value); - } + String name = (String)e.nextElement(); + checkManagedAttribute(name,attributes.getAttribute(name)); } } @@ -1088,26 +1080,26 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. while (e.hasMoreElements()) { String name = (String)e.nextElement(); - setManagedAttribute(name,null); + checkManagedAttribute(name,null); } _attributes.clearAttributes(); } /* ------------------------------------------------------------ */ - private void setManagedAttribute(String name, Object value) + public void checkManagedAttribute(String name, Object value) { if (_managedAttributes!=null && _managedAttributes.containsKey(name)) { - Object old =_managedAttributes.put(name,value); - if (old!=null) - getServer().getContainer().removeBean(old); - if (value!=null) - { - if (_logger.isDebugEnabled()) _logger.debug("Managing "+name); - getServer().getContainer().addBean(value); - } + setManagedAttribute(name,value); } } + + /* ------------------------------------------------------------ */ + public void setManagedAttribute(String name, Object value) + { + Object old =_managedAttributes.put(name,value); + getServer().getContainer().update(this,old,value,name); + } /* ------------------------------------------------------------ */ /** @@ -1138,17 +1130,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* ------------------------------------------------------------ */ /** - * @param initParams The initParams to set. - */ - public void setInitParams(Map<String,String> initParams) - { - if (initParams == null) - return; - _initParams = new HashMap<String,String>(initParams); - } - - /* ------------------------------------------------------------ */ - /** * @param servletContextName The servletContextName to set. */ public void setDisplayName(String servletContextName) @@ -1820,15 +1801,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. @Override public synchronized void setAttribute(String name, Object value) { - - if (_contextAttributes==null) - { - // Set it on the handler - ContextHandler.this.setAttribute(name, value); - return; - } - - setManagedAttribute(name,value); + checkManagedAttribute(name,value); Object old_value=_contextAttributes.getAttribute(name); if (value==null) @@ -1862,7 +1835,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. @Override public synchronized void removeAttribute(String name) { - setManagedAttribute(name,null); + checkManagedAttribute(name,null); if (_contextAttributes==null) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java index 6ed3d15fdd..746666aa1d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java @@ -14,10 +14,9 @@ package org.eclipse.jetty.server.handler; import java.io.IOException; -import java.util.HashMap; +import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -28,78 +27,150 @@ import org.eclipse.jetty.http.PathMap; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.HttpConnection; import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.util.IPAddressMap; +import org.eclipse.jetty.util.log.Log; /** * IP Access Handler * <p> - * Control access to the wrapped handler by the real remote IP. - * The real IP of the connection is used (not the IP reported in the forwarded for headers), - * as this cannot be as easily forged. + * Controls access to the wrapped handler by the real remote IP. Control is provided + * by white/black lists that include both internet addresses and URIs. This handler + * uses the real internet address of the connection, not one reported in the forwarded + * for headers, as this cannot be as easily forged. * <p> - * Control is provided by white/black lists of both internet addresses and URIs. - * Internet addresses may be absolute (eg 10.1.2.3) or a prefix pattern (eg 10.1.3. ). - * URI patterns follow the servlet specification for simple prefix and suffix wild cards. + * Typically, the black/white lists will be used in one of three modes: + * <ul> + * <li>Blocking a few specific IPs/URLs by specifying several black list entries. + * <li>Allowing only some specific IPs/URLs by specifying several white lists entries. + * <li>Allowing a general range of IPs/URLs by specifying several general white list + * entries, that are then further refined by several specific black list exceptions + * </ul> + * <p> + * An empty white list is treated as match all. If there is at least one entry in + * the white list, then a request must match a white list entry. Black list entries + * are always applied, so that even if an entry matches the white list, a black list + * entry will override it. * <p> - * An empty white list is treated as match all. If there is at least one entry in the - * white list, then a request must match a white list entry. Black list entries are always - * appied, so that even if an entry matches the white list, a black list entry will override. + * Internet addresses may be specified as absolute address or as a combination of + * four octet wildcard specifications (a.b.c.d) that are defined as follows. * </p> + * <pre> + * nnn - an absolute value (0-255) + * mmm-nnn - an inclusive range of absolute values, + * with following shorthand notations: + * nnn- => nnn-255 + * -nnn => 0-nnn + * - => 0-255 + * a,b,... - a list of wildcard specifications + * </pre> + * <p> + * Internet address specification is separated from the URI pattern using the "|" (pipe) + * character. URI patterns follow the servlet specification for simple * prefix and + * suffix wild cards (e.g. /, /foo, /foo/bar, /foo/bar/*, *.baz). * <p> - * Examples of match specifications are: + * Earlier versions of the handler used internet address prefix wildcard specification + * to define a range of the internet addresses (e.g. 127., 10.10., 172.16.1.). + * They also used the first "/" character of the URI pattern to separate it from the + * internet address. Both of these features have been deprecated in the current version. + * <p> + * Examples of the entry specifications are: * <ul> - * <li>10.1.2.3 - all requests from IP 10.1.2.3 - * <li>10.1.2.3/foo/bar - all requests from IP 10.1.2.3 to URI /foo/bar - * <li>10.1.2.3/foo/* - all requests from IP 10.1.2.3 to URIs starting with /foo/ - * <li>10.1.2.3/*.html - all requests from IP 10.1.2.3 to URIs ending with .html - * <li>10.1. - all requests from IPs starting with 10.1. - * <li>10.1./foo/bar - all requests from IPs starting with 10.1. to URI /foo/bar - * <li>10.1./foo/* - all requests from IPs starting with 10.1. to URIs starting with /foo/ + * <li>10.10.1.2 - all requests from IP 10.10.1.2 + * <li>10.10.1.2|/foo/bar - all requests from IP 10.10.1.2 to URI /foo/bar + * <li>10.10.1.2|/foo/* - all requests from IP 10.10.1.2 to URIs starting with /foo/ + * <li>10.10.1.2|*.html - all requests from IP 10.10.1.2 to URIs ending with .html + * <li>10.10.0-255.0-255 - all requests from IPs within 10.10.0.0/16 subnet + * <li>10.10.0-.-255|/foo/bar - all requests from IPs within 10.10.0.0/16 subnet to URI /foo/bar + * <li>10.10.0-3,1,3,7,15|/foo/* - all requests from IPs addresses with last octet equal + * to 1,3,7,15 in subnet 10.10.0.0/22 to URIs starting with /foo/ * </ul> * <p> - * Typically, the black/white lists will be used in one of three modes: - * <nl> - * <li>Blocking a few specific IPs/URLs by specifying several black list entries. - * <li>Allowing only some specific IPs/URLs by specifying several white lists entries. - * <li>Allowing a general range of IPs/URLs by specifying serveral general white list - * entries, that are then further refined by several specific black list exceptions - * </ul> - * + * Earlier versions of the handler used internet address prefix wildcard specification + * to define a range of the internet addresses (e.g. 127., 10.10., 172.16.1.). + * They also used the first "/" character of the URI pattern to separate it from the + * internet address. Both of these features have been deprecated in the current version. */ public class IPAccessHandler extends HandlerWrapper { - Map<String,PathMap> _whiteAddr = new HashMap<String, PathMap>(); - List<String> _whitePattern = new CopyOnWriteArrayList<String>(); - Map<String,PathMap> _blackAddr = new HashMap<String, PathMap>(); - List<String> _blackPattern = new CopyOnWriteArrayList<String>(); - + IPAddressMap<PathMap> _white = new IPAddressMap<PathMap>(); + IPAddressMap<PathMap> _black = new IPAddressMap<PathMap>(); + + /* ------------------------------------------------------------ */ /** + * Creates new handler object */ public IPAccessHandler() { + super(); + } + + /* ------------------------------------------------------------ */ + /** + * Creates new handler object and initializes white- and black-list + * + * @param white array of whitelist entries + * @param black array of blacklist entries + */ + public IPAccessHandler(String[] white, String []black) + { + super(); + + if (white != null && white.length > 0) + setWhite(white); + if (black != null && black.length > 0) + setBlack(black); } - public void addBlack(String addrPath) + /* ------------------------------------------------------------ */ + /** + * Add a whitelist entry to an existing handler configuration + * + * @param entry new whitelist entry + */ + public void addWhite(String entry) { - add(addrPath, _blackAddr, _blackPattern); + add(entry, _white); } - public void addWhite(String addrPath) + /* ------------------------------------------------------------ */ + /** + * Add a blacklist entry to an existing handler configuration + * + * @param entry new blacklist entry + */ + public void addBlack(String entry) { - add(addrPath, _whiteAddr, _whitePattern); + add(entry, _black); } - public void setBlack(String[] addrPaths) + /* ------------------------------------------------------------ */ + /** + * Re-initialize the whitelist of existing handler object + * + * @param entries array of whitelist entries + */ + public void setWhite(String[] entries) { - set(addrPaths, _blackAddr, _blackPattern); + set(entries, _white); } - public void setWhite(String[] addrPaths) + /* ------------------------------------------------------------ */ + /** + * Re-initialize the blacklist of existing handler object + * + * @param entries array of blacklist entries + */ + public void setBlack(String[] entries) { - set(addrPaths, _whiteAddr, _whitePattern); + set(entries, _black); } + /* ------------------------------------------------------------ */ /** + * Checks the incoming request against the whitelist and blacklist + * + * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException @@ -123,78 +194,178 @@ public class IPAccessHandler extends HandlerWrapper getHandler().handle(target,baseRequest, request, response); } + - protected void add(String addrPath, Map<String,PathMap> addrMap, List<String> patternList) + /* ------------------------------------------------------------ */ + /** + * Helper method to parse the new entry and add it to + * the specified address pattern map. + * + * @param entry new entry + * @param patternMap target address pattern map + */ + protected void add(String entry, IPAddressMap<PathMap> patternMap) { - int idx = addrPath.indexOf('/'); - String addr = idx > 0 ? addrPath.substring(0,idx) : addrPath; - String path = idx > 0 ? addrPath.substring(idx) : null; - if (path!=null && path.length()>1 && path.charAt(1)=='*') - path=path.substring(1); - - PathMap map = addrMap.get(addr); - if (map==null) + if (entry != null && entry.length() > 0) { - map = new PathMap(true); - addrMap.put(addr,map); + boolean deprecated = false; + int idx; + if (entry.indexOf('|') > 0 ) + { + idx = entry.indexOf('|'); + } + else + { + idx = entry.indexOf('/'); + deprecated = (idx >= 0); + } + + String addr = idx > 0 ? entry.substring(0,idx) : entry; + String path = idx > 0 ? entry.substring(idx) : "/*"; + if (addr.endsWith(".")) - patternList.add(addr); + deprecated = true; + if (path!=null && (path.startsWith("|") || path.startsWith("/*."))) + path=path.substring(1); + + PathMap pathMap = patternMap.get(addr); + if (pathMap == null) + { + pathMap = new PathMap(true); + patternMap.put(addr,pathMap); + } + if (path != null) + pathMap.put(path,path); + + if (deprecated) + Log.debug(toString() +" - deprecated specification syntax: "+entry); } - - if (path != null) - map.put(path,path); } - protected void set(String[] addrPaths, Map<String,PathMap> addrMap, List<String> patternList) + /* ------------------------------------------------------------ */ + /** + * Helper method to process a list of new entries and replace + * the content of the specified address pattern map + * + * @param entries new entries + * @param patternMap target address pattern map + */ + protected void set(String[] entries, IPAddressMap<PathMap> patternMap) { - addrMap.clear(); - patternList.clear(); - for (String addrPath:addrPaths) - add(addrPath, addrMap, patternList); + patternMap.clear(); + + for (String addrPath:entries) + { + add(addrPath, patternMap); + } } + /* ------------------------------------------------------------ */ + /** + * Check if specified request is allowed by current IPAccess rules. + * + * @param addr internet address + * @param path context path + * @return true if request is allowed + * + */ protected boolean isAddrUriAllowed(String addr, String path) { - if (_whiteAddr.size()>0) + if (_white.size()>0) { - PathMap white=_whiteAddr.get(addr); + boolean match = false; - if (white==null || (white.size()>0 && white.match(path)==null)) + Object whiteObj = _white.getLazyMatches(addr); + if (whiteObj != null) { - boolean match=false; - for (String pattern:_whitePattern) + List whiteList = (whiteObj instanceof List) ? (List)whiteObj : Collections.singletonList(whiteObj); + + for (Object entry: whiteList) { - if (addr.startsWith(pattern)) - { - white=_whiteAddr.get(pattern); - if (white!=null && white.size()>0 && white.match(path)!=null) - { - match=true; - break; - } - } + PathMap pathMap = ((Map.Entry<String,PathMap>)entry).getValue(); + if (match = (pathMap!=null && (pathMap.size()==0 || pathMap.match(path)!=null))) + break; } - if (!match) - return false; } + + if (!match) + return false; } - PathMap black=_blackAddr.get(addr); - if (black!=null && (black.size()==0 || black.match(path)!=null)) - return false; - - for (String pattern:_blackPattern) + if (_black.size() > 0) { - if (addr.startsWith(pattern)) + Object blackObj = _black.getLazyMatches(addr); + if (blackObj != null) { - black=_blackAddr.get(pattern); - if (black!=null && black.match(path)!=null) - return false; - break; + List blackList = (blackObj instanceof List) ? (List)blackObj : Collections.singletonList(blackObj); + + for (Object entry: blackList) + { + PathMap pathMap = ((Map.Entry<String,PathMap>)entry).getValue(); + if (pathMap!=null && (pathMap.size()==0 || pathMap.match(path)!=null)) + return false; + } } } return true; } -} + /* ------------------------------------------------------------ */ + /** + * Dump the white- and black-list configurations when started + * + * @see org.eclipse.jetty.server.handler.HandlerWrapper#doStart() + */ + @Override + protected void doStart() + throws Exception + { + super.doStart(); + + if (Log.isDebugEnabled()) + { + System.err.println(dump()); + } + } + + /* ------------------------------------------------------------ */ + /** + * Dump the handler configuration + */ + public String dump() + { + StringBuilder buf = new StringBuilder(); + + buf.append(toString()); + buf.append(" WHITELIST:\n"); + dump(buf, _white); + buf.append(toString()); + buf.append(" BLACKLIST:\n"); + dump(buf, _black); + + return buf.toString(); + } + + /* ------------------------------------------------------------ */ + /** + * Dump a pattern map into a StringBuilder buffer + * + * @param buf buffer + * @param patternMap pattern map to dump + */ + protected void dump(StringBuilder buf, IPAddressMap<PathMap> patternMap) + { + for (String addr: patternMap.keySet()) + { + for (Object path: ((PathMap)patternMap.get(addr)).values()) + { + buf.append("# "); + buf.append(addr); + buf.append("|"); + buf.append(path); + buf.append("\n"); + } + } + } + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java index 61d949da32..76ee4391a0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java @@ -20,6 +20,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.server.AsyncContinuation; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.RequestLog; import org.eclipse.jetty.server.Response; @@ -47,9 +48,24 @@ public class RequestLogHandler extends HandlerWrapper public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - super.handle(target, baseRequest, request, response); - if (DispatcherType.REQUEST.equals(baseRequest.getDispatcherType()) && _requestLog!=null) - _requestLog.log((Request)request, (Response)response); + AsyncContinuation continuation = baseRequest.getAsyncContinuation(); + if (!continuation.isInitial()) + { + baseRequest.setDispatchTime(System.currentTimeMillis()); + } + + try + { + super.handle(target, baseRequest, request, response); + } + finally + { + if (_requestLog != null && DispatcherType.REQUEST.equals(baseRequest.getDispatcherType())) + { + _requestLog.log(baseRequest, (Response)response); + } + + } } /* ------------------------------------------------------------ */ @@ -131,6 +147,5 @@ public class RequestLogHandler extends HandlerWrapper if (_requestLog!=null) _requestLog.stop(); } - } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ScopedHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ScopedHandler.java index ae3154c3b7..d4ff318c7a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ScopedHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ScopedHandler.java @@ -134,7 +134,7 @@ public abstract class ScopedHandler extends HandlerWrapper throws IOException, ServletException { // this method has been manually inlined in several locations, but - // is called protected by an in(false), so your IDE can find those + // is called protected by an if(never()), so your IDE can find those // locations if this code is changed. if (_nextScope!=null) _nextScope.doScope(target,baseRequest,request, response); @@ -158,7 +158,7 @@ public abstract class ScopedHandler extends HandlerWrapper public final void nextHandle(String target, final Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // this method has been manually inlined in several locations, but - // is called protected by an in(false), so your IDE can find those + // is called protected by an if(never()), so your IDE can find those // locations if this code is changed. if (_nextScope!=null && _nextScope==_handler) _nextScope.doHandle(target,baseRequest,request, response); @@ -166,4 +166,10 @@ public abstract class ScopedHandler extends HandlerWrapper _handler.handle(target,baseRequest, request, response); } + /* ------------------------------------------------------------ */ + protected boolean never() + { + return false; + } + } 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 d529b5f835..63f512e749 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 @@ -125,7 +125,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement ) ) { - HttpCookie cookie=getSessionCookie(session,_context.getContextPath(),secure); + HttpCookie cookie=getSessionCookie(session,_context==null?"/":(_context.getContextPath()),secure); s.cookieSet(); s.setIdChanged(false); return cookie; @@ -328,12 +328,14 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement { if (isUsingCookies()) { + String sessionPath = (_sessionPath==null) ? contextPath : _sessionPath; + sessionPath = (sessionPath==null||sessionPath.length()==0) ? "/" : sessionPath; String id = getNodeId(session); HttpCookie cookie=new HttpCookie( _sessionCookie, id, _sessionDomain, - (contextPath==null||contextPath.length()==0)?"/":contextPath, + sessionPath, _cookieConfig.getMaxAge(), _cookieConfig.isHttpOnly(), requestIsSecure&&_cookieConfig.isSecure()); 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 8f6e176d02..0272e8c11f 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 @@ -221,8 +221,7 @@ public class SessionHandler extends ScopedHandler throws IOException, ServletException { // start manual inline of nextHandle(target,baseRequest,request,response); - //noinspection ConstantIfStatement - if (false) + if (never()) nextHandle(target,baseRequest,request,response); else if (_nextScope!=null && _nextScope==_handler) _nextScope.doHandle(target,baseRequest,request, response); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslCertificates.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslCertificates.java index 94803ab856..25b1ac7dda 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslCertificates.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslCertificates.java @@ -10,9 +10,9 @@ import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import org.eclipse.jetty.http.HttpSchemes; -import org.eclipse.jetty.http.ssl.SslSelectChannelEndPoint; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.bio.SocketEndPoint; +import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java index 101787f828..71bb96de93 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java @@ -13,14 +13,12 @@ package org.eclipse.jetty.server.ssl; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.security.KeyStore; import java.security.SecureRandom; -import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -29,7 +27,6 @@ import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; @@ -38,7 +35,6 @@ import javax.net.ssl.TrustManagerFactory; import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpSchemes; import org.eclipse.jetty.http.security.Password; -import org.eclipse.jetty.http.ssl.SslSelectChannelEndPoint; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.Buffers; import org.eclipse.jetty.io.Connection; @@ -47,11 +43,11 @@ import org.eclipse.jetty.io.ThreadLocalBuffers; import org.eclipse.jetty.io.bio.SocketEndPoint; import org.eclipse.jetty.io.nio.DirectNIOBuffer; import org.eclipse.jetty.io.nio.SelectChannelEndPoint; +import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint; import org.eclipse.jetty.io.nio.SelectorManager.SelectSet; import org.eclipse.jetty.server.HttpConnection; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSocketConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSocketConnector.java index 8fac62c8cf..ca99861cd9 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSocketConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSocketConnector.java @@ -137,7 +137,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector Socket socket = _serverSocket.accept(); configure(socket); - ConnectorEndPoint connection=new SslConnection(socket); + ConnectorEndPoint connection=new SslConnectorEndPoint(socket); connection.dispatch(); } @@ -205,14 +205,10 @@ public class SslSocketConnector extends SocketConnector implements SslConnector try { if (keystorePath!=null) - { keystoreInputStream = Resource.newResource(keystorePath).getInputStream(); - keystore=KeyStore.getInstance(keystoreType); - keystore.load(keystoreInputStream,keystorePassword==null?null:keystorePassword.toString().toCharArray()); - return keystore; - } - - return null; + keystore=KeyStore.getInstance(keystoreType); + keystore.load(keystoreInputStream,keystorePassword==null?null:keystorePassword.toString().toCharArray()); + return keystore; } finally { @@ -606,14 +602,19 @@ public class SslSocketConnector extends SocketConnector implements SslConnector } /* ------------------------------------------------------------ */ - public class SslConnection extends ConnectorEndPoint + public class SslConnectorEndPoint extends ConnectorEndPoint { - public SslConnection(Socket socket) throws IOException + public SslConnectorEndPoint(Socket socket) throws IOException { super(socket); } @Override + public void shutdownOutput() throws IOException + { + } + + @Override public void run() { try @@ -667,7 +668,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector /** * Unsupported. * - * @todo we should remove this as it is no longer an overridden method from SslConnector (like it was in the past) + * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past) */ public String getAlgorithm() { @@ -678,7 +679,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector /** * Unsupported. * - * @todo we should remove this as it is no longer an overridden method from SslConnector (like it was in the past) + * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past) */ public void setAlgorithm(String algorithm) { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java index c8d01d3418..059986f2de 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java @@ -156,7 +156,7 @@ public class ContextHandlerTest handler.setAttribute("aaa","111"); handler.getServletContext().setAttribute("bbb","222"); assertEquals("111",handler.getServletContext().getAttribute("aaa")); - assertEquals("222",handler.getAttribute("bbb")); + assertEquals(null,handler.getAttribute("bbb")); handler.start(); @@ -164,20 +164,20 @@ public class ContextHandlerTest handler.setAttribute("ccc","333"); handler.getServletContext().setAttribute("ddd","444"); assertEquals("111",handler.getServletContext().getAttribute("aaa")); - assertEquals("222",handler.getServletContext().getAttribute("bbb")); + assertEquals(null,handler.getServletContext().getAttribute("bbb")); + handler.getServletContext().setAttribute("bbb","222"); assertEquals("333",handler.getServletContext().getAttribute("ccc")); assertEquals("444",handler.getServletContext().getAttribute("ddd")); assertEquals("111",handler.getAttribute("aaa")); - assertEquals("222",handler.getAttribute("bbb")); + assertEquals(null,handler.getAttribute("bbb")); assertEquals("333",handler.getAttribute("ccc")); assertEquals(null,handler.getAttribute("ddd")); - handler.stop(); assertEquals("111",handler.getServletContext().getAttribute("aaa")); - assertEquals("222",handler.getServletContext().getAttribute("bbb")); + assertEquals(null,handler.getServletContext().getAttribute("bbb")); assertEquals("333",handler.getServletContext().getAttribute("ccc")); assertEquals(null,handler.getServletContext().getAttribute("ddd")); } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/IPAccessHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/IPAccessHandlerTest.java new file mode 100644 index 0000000000..6ac5e7969f --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/IPAccessHandlerTest.java @@ -0,0 +1,395 @@ +// ======================================================================== +// Copyright (c) 2010 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.handler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.Socket; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.bio.SocketConnector; +import org.eclipse.jetty.util.log.Log; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class IPAccessHandlerTest +{ + private static Server _server; + private static Connector _connector; + private static IPAccessHandler _handler; + + private String _white; + private String _black; + private String _host; + private String _uri; + private String _code; + + @BeforeClass + public static void setUp() + throws Exception + { + _server = new Server(); + _connector = new SocketConnector(); + _server.setConnectors(new Connector[] { _connector }); + + _handler = new IPAccessHandler(); + _handler.setHandler(new AbstractHandler() + { + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + response.setStatus(HttpStatus.OK_200); + } + }); + _server.setHandler(_handler); + _server.start(); + } + + /* ------------------------------------------------------------ */ + @AfterClass + public static void tearDown() + throws Exception + { + _server.stop(); + } + + /* ------------------------------------------------------------ */ + public IPAccessHandlerTest(String white, String black, String host, String uri, String code) + { + _white = white; + _black = black; + _host = host; + _uri = uri; + _code = code; + } + + /* ------------------------------------------------------------ */ + @Test + public void testHandler() + throws Exception + { + _handler.setWhite(_white.split(";",-1)); + _handler.setBlack(_black.split(";",-1)); + + String request = "GET " + _uri + " HTTP/1.1\n" + "Host: "+ _host + "\n\n"; + Socket socket = new Socket("localhost", _connector.getLocalPort()); + socket.setSoTimeout(5000); + try + { + OutputStream output = socket.getOutputStream(); + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + + output.write(request.getBytes("UTF-8")); + output.flush(); + + Response response = readResponse(input); + assertEquals(_code, response.getCode()); + } + finally + { + socket.close(); + } + } + + /* ------------------------------------------------------------ */ + protected Response readResponse(BufferedReader reader) + throws IOException + { + // Simplified parser for HTTP responses + String line = reader.readLine(); + if (line == null) + throw new EOFException(); + Matcher responseLine = Pattern.compile("HTTP/1\\.1\\s+(\\d+)").matcher(line); + assertTrue(responseLine.lookingAt()); + String code = responseLine.group(1); + + Map<String, String> headers = new LinkedHashMap<String, String>(); + while ((line = reader.readLine()) != null) + { + if (line.trim().length() == 0) + break; + + Matcher header = Pattern.compile("([^:]+):\\s*(.*)").matcher(line); + assertTrue(header.lookingAt()); + String headerName = header.group(1); + String headerValue = header.group(2); + headers.put(headerName.toLowerCase(), headerValue.toLowerCase()); + } + + StringBuilder body = new StringBuilder(); + if (headers.containsKey("content-length")) + { + int length = Integer.parseInt(headers.get("content-length")); + for (int i = 0; i < length; ++i) + { + char c = (char)reader.read(); + body.append(c); + } + } + else if ("chunked".equals(headers.get("transfer-encoding"))) + { + while ((line = reader.readLine()) != null) + { + if ("0".equals(line)) + { + line = reader.readLine(); + assertEquals("", line); + break; + } + + int length = Integer.parseInt(line, 16); + for (int i = 0; i < length; ++i) + { + char c = (char)reader.read(); + body.append(c); + } + line = reader.readLine(); + assertEquals("", line); + } + } + + return new Response(code, headers, body.toString().trim()); + } + + /* ------------------------------------------------------------ */ + protected class Response + { + private final String code; + private final Map<String, String> headers; + private final String body; + + /* ------------------------------------------------------------ */ + private Response(String code, Map<String, String> headers, String body) + { + this.code = code; + this.headers = headers; + this.body = body; + } + + /* ------------------------------------------------------------ */ + public String getCode() + { + return code; + } + + /* ------------------------------------------------------------ */ + public Map<String, String> getHeaders() + { + return headers; + } + + /* ------------------------------------------------------------ */ + public String getBody() + { + return body; + } + + /* ------------------------------------------------------------ */ + @Override + public String toString() + { + StringBuilder builder = new StringBuilder(); + builder.append(code).append("\r\n"); + for (Map.Entry<String, String> entry : headers.entrySet()) + builder.append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n"); + builder.append("\r\n"); + builder.append(body); + return builder.toString(); + } + } + + /* ------------------------------------------------------------ */ + @Parameters + public static Collection<Object[]> data() { + Object[][] data = new Object[][] { + // Empty lists + {"", "", "127.0.0.1", "/", "200"}, + {"", "", "127.0.0.1", "/dump/info", "200"}, + + // White list + {"127.0.0.1", "", "127.0.0.1", "/", "200"}, + {"127.0.0.1", "", "127.0.0.1", "/dispatch", "200"}, + {"127.0.0.1", "", "127.0.0.1", "/dump/info", "200"}, + + {"127.0.0.1|/", "", "127.0.0.1", "/", "200"}, + {"127.0.0.1|/", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.1|/", "", "127.0.0.1", "/dump/info", "403"}, + + {"127.0.0.1|/*", "", "127.0.0.1", "/", "200"}, + {"127.0.0.1|/*", "", "127.0.0.1", "/dispatch", "200"}, + {"127.0.0.1|/*", "", "127.0.0.1", "/dump/info", "200"}, + + {"127.0.0.1|/dump/*", "", "127.0.0.1", "/", "403"}, + {"127.0.0.1|/dump/*", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.1|/dump/*", "", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/*", "", "127.0.0.1", "/dump/test", "200"}, + + {"127.0.0.1|/dump/info", "", "127.0.0.1", "/", "403"}, + {"127.0.0.1|/dump/info", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.1|/dump/info", "", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/info", "", "127.0.0.1", "/dump/test", "403"}, + + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/", "403"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/dump/test", "200"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/dump/fail", "403"}, + + {"127.0.0.0-2|", "", "127.0.0.1", "/", "200"}, + {"127.0.0.0-2|", "", "127.0.0.1", "/dump/info", "200"}, + + {"127.0.0.0-2|/", "", "127.0.0.1", "/", "200"}, + {"127.0.0.0-2|/", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.0-2|/", "", "127.0.0.1", "/dump/info", "403"}, + + {"127.0.0.0-2|/dump/*", "", "127.0.0.1", "/", "403"}, + {"127.0.0.0-2|/dump/*", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.0-2|/dump/*", "", "127.0.0.1", "/dump/info", "200"}, + + {"127.0.0.0-2|/dump/info", "", "127.0.0.1", "/", "403"}, + {"127.0.0.0-2|/dump/info", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.0-2|/dump/info", "", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.0-2|/dump/info", "", "127.0.0.1", "/dump/test", "403"}, + + {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/", "403"}, + {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/dump/test", "200"}, + {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/dump/fail", "403"}, + + // Black list + {"", "127.0.0.1", "127.0.0.1", "/", "403"}, + {"", "127.0.0.1", "127.0.0.1", "/dispatch", "403"}, + {"", "127.0.0.1", "127.0.0.1", "/dump/info", "403"}, + + {"", "127.0.0.1|/", "127.0.0.1", "/", "403"}, + {"", "127.0.0.1|/", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.1|/", "127.0.0.1", "/dump/info", "200"}, + + {"", "127.0.0.1|/*", "127.0.0.1", "/", "403"}, + {"", "127.0.0.1|/*", "127.0.0.1", "/dispatch", "403"}, + {"", "127.0.0.1|/*", "127.0.0.1", "/dump/info", "403"}, + + {"", "127.0.0.1|/dump/*", "127.0.0.1", "/", "200"}, + {"", "127.0.0.1|/dump/*", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.1|/dump/*", "127.0.0.1", "/dump/info", "403"}, + {"", "127.0.0.1|/dump/*", "127.0.0.1", "/dump/test", "403"}, + + {"", "127.0.0.1|/dump/info", "127.0.0.1", "/", "200"}, + {"", "127.0.0.1|/dump/info", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.1|/dump/info", "127.0.0.1", "/dump/info", "403"}, + {"", "127.0.0.1|/dump/info", "127.0.0.1", "/dump/test", "200"}, + + {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/", "200"}, + {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/dump/info", "403"}, + {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/dump/test", "403"}, + {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/dump/fail", "200"}, + + {"", "127.0.0.0-2|", "127.0.0.1", "/", "403"}, + {"", "127.0.0.0-2|", "127.0.0.1", "/dump/info", "403"}, + + {"", "127.0.0.0-2|/", "127.0.0.1", "/", "403"}, + {"", "127.0.0.0-2|/", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.0-2|/", "127.0.0.1", "/dump/info", "200"}, + + {"", "127.0.0.0-2|/dump/*", "127.0.0.1", "/", "200"}, + {"", "127.0.0.0-2|/dump/*", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.0-2|/dump/*", "127.0.0.1", "/dump/info", "403"}, + + {"", "127.0.0.0-2|/dump/info", "127.0.0.1", "/", "200"}, + {"", "127.0.0.0-2|/dump/info", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.0-2|/dump/info", "127.0.0.1", "/dump/info", "403"}, + {"", "127.0.0.0-2|/dump/info", "127.0.0.1", "/dump/test", "200"}, + + {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/", "200"}, + {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/dispatch", "200"}, + {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/dump/info", "403"}, + {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/dump/test", "403"}, + {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/dump/fail", "200"}, + + // Both lists + {"127.0.0.1|/dump", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump", "200"}, + {"127.0.0.1|/dump", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump/info", "403"}, + {"127.0.0.1|/dump", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump/fail", "403"}, + + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump", "200"}, + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump/fail", "403"}, + + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/test;127.0.0.1|/dump/fail", "127.0.0.1", "/dump", "200"}, + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/test;127.0.0.1|/dump/fail", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/test;127.0.0.1|/dump/fail", "127.0.0.1", "/dump/test", "403"}, + {"127.0.0.1|/dump/*", "127.0.0.1|/dump/test;127.0.0.1|/dump/fail", "127.0.0.1", "/dump/fail", "403"}, + + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1|/dump/test", "127.0.0.1", "/dump", "403"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1|/dump/test", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1|/dump/test", "127.0.0.1", "/dump/test", "403"}, + {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1|/dump/test", "127.0.0.1", "/dump/fail", "403"}, + + {"127.0.0.1|/;127.0.0.0-2|/dump/*", "127.0.0.0,1|/dump/fail", "127.0.0.1", "/", "200"}, + {"127.0.0.1|/;127.0.0.0-2|/dump/*", "127.0.0.0,1|/dump/fail", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/;127.0.0.0-2|/dump/*", "127.0.0.0,1|/dump/fail", "127.0.0.1", "/dump/fail", "403"}, + + // Different address + {"127.0.0.2", "", "127.0.0.1", "/", "403"}, + {"127.0.0.2", "", "127.0.0.1", "/dump/info", "403"}, + + {"127.0.0.2|/dump/*", "", "127.0.0.1", "/", "403"}, + {"127.0.0.2|/dump/*", "", "127.0.0.1", "/dump/info", "403"}, + + {"127.0.0.2|/dump/info", "", "127.0.0.1", "/", "403"}, + {"127.0.0.2|/dump/info", "", "127.0.0.1", "/dump/info", "403"}, + {"127.0.0.2|/dump/info", "", "127.0.0.1", "/dump/test", "403"}, + + {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/", "403"}, + {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/dispatch", "403"}, + {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/dump/info", "200"}, + {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/dump/test", "403"}, + {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/dump/fail", "403"}, + + {"172.0.0.0-255", "", "127.0.0.1", "/", "403"}, + {"172.0.0.0-255", "", "127.0.0.1", "/dump/info", "403"}, + + {"172.0.0.0-255|/dump/*;127.0.0.0-255|/dump/*", "", "127.0.0.1", "/", "403"}, + {"172.0.0.0-255|/dump/*;127.0.0.0-255|/dump/*", "", "127.0.0.1", "/dispatch", "403"}, + {"172.0.0.0-255|/dump/*;127.0.0.0-255|/dump/*", "", "127.0.0.1", "/dump/info", "200"}, + }; + return Arrays.asList(data); + }; +} diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java index a5955f911d..f739b1dc3d 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java @@ -49,6 +49,7 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.HandlerWrapper; +import org.eclipse.jetty.server.handler.ScopedHandler; import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.Loader; @@ -247,7 +248,18 @@ public class ServletContextHandler extends ContextHandler handler=_sessionHandler; } - setHandler(handler); + // skip any wrapped handlers + HandlerWrapper wrapper=this; + while (wrapper!=handler && wrapper.getHandler() instanceof HandlerWrapper) + wrapper=(HandlerWrapper)wrapper.getHandler(); + + // if we are not already linked + if (wrapper!=handler) + { + if (wrapper.getHandler()!=null ) + throw new IllegalStateException("!ScopedHandler"); + wrapper.setHandler(handler); + } super.startContext(); diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index cfeff43bb7..a0871621ae 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -380,7 +380,7 @@ public class ServletHandler extends ScopedHandler baseRequest.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, ((ServletHolder.Registration)servlet_holder.getRegistration()).getMultipartConfig()); // start manual inline of nextScope(target,baseRequest,request,response); - if (false) + if (never()) nextScope(target,baseRequest,request,response); else if (_nextScope!=null) _nextScope.doScope(target,baseRequest,request, response); diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java index 7cf2859f75..694267d847 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java @@ -162,7 +162,7 @@ public class CrossOriginFilter implements Filter { String origin = request.getHeader(ORIGIN_HEADER); // Is it a cross origin request ? - if (origin != null) + if (origin != null && isEnabled(request)) { if (originMatches(origin)) { @@ -186,6 +186,18 @@ public class CrossOriginFilter implements Filter chain.doFilter(request, response); } + protected boolean isEnabled(HttpServletRequest request) + { + // WebSocket clients such as Chrome 5 implement a version of the WebSocket + // protocol that does not accept extra response headers on the upgrade response + if ("Upgrade".equalsIgnoreCase(request.getHeader("Connection")) && + "WebSocket".equalsIgnoreCase(request.getHeader("Upgrade"))) + { + return false; + } + return true; + } + private boolean originMatches(String origin) { if (anyOriginAllowed) return true; diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java index f18a5f1f54..a678441988 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java @@ -37,6 +37,7 @@ import javax.servlet.http.HttpSessionBindingListener; import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.continuation.ContinuationSupport; +import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.Timeout; @@ -60,35 +61,53 @@ import org.eclipse.jetty.util.thread.Timeout; * The {@link #extractUserId(ServletRequest request)} function should be * implemented, in order to uniquely identify authenticated users. * <p> - * The following init parameters control the behavior of the filter: + * The following init parameters control the behavior of the filter:<dl> * - * maxRequestsPerSec the maximum number of requests from a connection per + * <dt>maxRequestsPerSec</dt> + * <dd>the maximum number of requests from a connection per * second. Requests in excess of this are first delayed, - * then throttled. + * then throttled.</dd> * - * delayMs is the delay given to all requests over the rate limit, + * <dt>delayMs</dt> + * <dd>is the delay given to all requests over the rate limit, * before they are considered at all. -1 means just reject request, - * 0 means no delay, otherwise it is the delay. + * 0 means no delay, otherwise it is the delay.</dd> * - * maxWaitMs how long to blocking wait for the throttle semaphore. + * <dt>maxWaitMs</dt> + * <dd>how long to blocking wait for the throttle semaphore.</dd> * - * throttledRequests is the number of requests over the rate limit able to be - * considered at once. + * <dt>throttledRequests</dt> + * <dd>is the number of requests over the rate limit able to be + * considered at once.</dd> * - * throttleMs how long to async wait for semaphore. + * <dt>throttleMs</dt> + * <dd>how long to async wait for semaphore.</dd> * - * maxRequestMs how long to allow this request to run. + * <dt>maxRequestMs</dt> + * <dd>how long to allow this request to run.</dd> * - * maxIdleTrackerMs how long to keep track of request rates for a connection, - * before deciding that the user has gone away, and discarding it + * <dt>maxIdleTrackerMs</dt> + * <dd>how long to keep track of request rates for a connection, + * before deciding that the user has gone away, and discarding it</dd> * - * insertHeaders if true , insert the DoSFilter headers into the response. Defaults to true. + * <dt>insertHeaders</dt> + * <dd>if true , insert the DoSFilter headers into the response. Defaults to true.</dd> * - * trackSessions if true, usage rate is tracked by session if a session exists. Defaults to true. + * <dt>trackSessions</dt> + * <dd>if true, usage rate is tracked by session if a session exists. Defaults to true.</dd> * - * remotePort if true and session tracking is not used, then rate is tracked by IP+port (effectively connection). Defaults to false. + * <dt>remotePort</dt> + * <dd>if true and session tracking is not used, then rate is tracked by IP+port (effectively connection). Defaults to false.</dd> * - * ipWhitelist a comma-separated list of IP addresses that will not be rate limited + * <dt>ipWhitelist</dt> + * <dd>a comma-separated list of IP addresses that will not be rate limited</dd> + * + * <dt>managedAttr</dt> + * <dd>if set to true, then this servlet is set as a {@link ServletContext} attribute with the + * filter name as the attribute name. This allows context external mechanism (eg JMX via {@link ContextHandler#MANAGED_ATTRIBUTES}) to + * manage the configuration of the filter.</dd> + * </dl> + * </p> */ public class DoSFilter implements Filter @@ -104,6 +123,7 @@ public class DoSFilter implements Filter final static long __DEFAULT_MAX_REQUEST_MS_INIT_PARAM=30000L; final static long __DEFAULT_MAX_IDLE_TRACKER_MS_INIT_PARAM=30000L; + final static String MANAGED_ATTR_INIT_PARAM="managedAttr"; final static String MAX_REQUESTS_PER_S_INIT_PARAM = "maxRequestsPerSec"; final static String DELAY_MS_INIT_PARAM = "delayMs"; final static String THROTTLED_REQUESTS_INIT_PARAM = "throttledRequests"; @@ -123,20 +143,23 @@ public class DoSFilter implements Filter ServletContext _context; + protected String _name; protected long _delayMs; protected long _throttleMs; - protected long _waitMs; + protected long _maxWaitMs; protected long _maxRequestMs; protected long _maxIdleTrackerMs; protected boolean _insertHeaders; protected boolean _trackSessions; protected boolean _remotePort; + protected int _throttledRequests; protected Semaphore _passes; protected Queue<Continuation>[] _queue; protected ContinuationListener[] _listener; protected int _maxRequestsPerSec; protected final ConcurrentHashMap<String, RateTracker> _rateTrackers=new ConcurrentHashMap<String, RateTracker>(); + protected String _whitelistStr; private final HashSet<String> _whitelist = new HashSet<String>(); private final Timeout _requestTimeoutQ = new Timeout(); @@ -170,7 +193,6 @@ public class DoSFilter implements Filter } _rateTrackers.clear(); - _whitelist.clear(); int baseRateLimit = __DEFAULT_MAX_REQUESTS_PER_SEC; if (filterConfig.getInitParameter(MAX_REQUESTS_PER_S_INIT_PARAM) != null) @@ -182,15 +204,16 @@ public class DoSFilter implements Filter delay = Integer.parseInt(filterConfig.getInitParameter(DELAY_MS_INIT_PARAM)); _delayMs = delay; - int passes = __DEFAULT_THROTTLE; + int throttledRequests = __DEFAULT_THROTTLE; if (filterConfig.getInitParameter(THROTTLED_REQUESTS_INIT_PARAM) != null) - passes = Integer.parseInt(filterConfig.getInitParameter(THROTTLED_REQUESTS_INIT_PARAM)); - _passes = new Semaphore(passes,true); + throttledRequests = Integer.parseInt(filterConfig.getInitParameter(THROTTLED_REQUESTS_INIT_PARAM)); + _passes = new Semaphore(throttledRequests,true); + _throttledRequests = throttledRequests; long wait = __DEFAULT_WAIT_MS; if (filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM) != null) wait = Integer.parseInt(filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM)); - _waitMs = wait; + _maxWaitMs = wait; long suspend = __DEFAULT_THROTTLE_MS; if (filterConfig.getInitParameter(THROTTLE_MS_INIT_PARAM) != null) @@ -207,18 +230,10 @@ public class DoSFilter implements Filter maxIdleTrackerMs = Long.parseLong(filterConfig.getInitParameter(MAX_IDLE_TRACKER_MS_INIT_PARAM)); _maxIdleTrackerMs = maxIdleTrackerMs; - String whitelistString = ""; + _whitelistStr = ""; if (filterConfig.getInitParameter(IP_WHITELIST_INIT_PARAM) !=null ) - whitelistString = filterConfig.getInitParameter(IP_WHITELIST_INIT_PARAM); - - if (whitelistString.length() > 0) - { - StringTokenizer tokenizer = new StringTokenizer(whitelistString, ","); - while (tokenizer.hasMoreTokens()) - _whitelist.add(tokenizer.nextToken().trim()); - - Log.info("Whitelisted IP addresses: {}", _whitelist.toString()); - } + _whitelistStr = filterConfig.getInitParameter(IP_WHITELIST_INIT_PARAM); + initWhitelist(); String tmp = filterConfig.getInitParameter(INSERT_HEADERS_INIT_PARAM); _insertHeaders = tmp==null || Boolean.parseBoolean(tmp); @@ -272,6 +287,9 @@ public class DoSFilter implements Filter } }); _timerThread.start(); + + if (_context!=null && Boolean.parseBoolean(filterConfig.getInitParameter(MANAGED_ATTR_INIT_PARAM))) + _context.setAttribute(filterConfig.getFilterName(),this); } @@ -353,7 +371,7 @@ public class DoSFilter implements Filter try { // check if we can afford to accept another request at this time - accepted = _passes.tryAcquire(_waitMs,TimeUnit.MILLISECONDS); + accepted = _passes.tryAcquire(_maxWaitMs,TimeUnit.MILLISECONDS); if (!accepted) { @@ -622,6 +640,281 @@ public class DoSFilter implements Filter return null; } + /* ------------------------------------------------------------ */ + /** + * Initialize the IP address whitelist + */ + protected void initWhitelist() + { + _whitelist.clear(); + StringTokenizer tokenizer = new StringTokenizer(_whitelistStr, ","); + while (tokenizer.hasMoreTokens()) + _whitelist.add(tokenizer.nextToken().trim()); + + Log.info("Whitelisted IP addresses: {}", _whitelist.toString()); + } + + /* ------------------------------------------------------------ */ + /** + * Get maximum number of requests from a connection per + * second. Requests in excess of this are first delayed, + * then throttled. + * + * @return maximum number of requests + */ + public int getMaxRequestsPerSec() + { + return _maxRequestsPerSec; + } + + /* ------------------------------------------------------------ */ + /** + * Get maximum number of requests from a connection per + * second. Requests in excess of this are first delayed, + * then throttled. + * + * @param value maximum number of requests + */ + public void setMaxRequestsPerSec(int value) + { + _maxRequestsPerSec = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get delay (in milliseconds) that is applied to all requests + * over the rate limit, before they are considered at all. + */ + public long getDelayMs() + { + return _delayMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set delay (in milliseconds) that is applied to all requests + * over the rate limit, before they are considered at all. + * + * @param value delay (in milliseconds), 0 - no delay, -1 - reject request + */ + public void setDelayMs(long value) + { + _delayMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get maximum amount of time (in milliseconds) the filter will + * blocking wait for the throttle semaphore. + * + * @return maximum wait time + */ + public long getMaxWaitMs() + { + return _maxWaitMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set maximum amount of time (in milliseconds) the filter will + * blocking wait for the throttle semaphore. + * + * @param value maximum wait time + */ + public void setMaxWaitMs(long value) + { + _maxWaitMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get number of requests over the rate limit able to be + * considered at once. + * + * @return number of requests + */ + public long getThrottledRequests() + { + return _throttledRequests; + } + + /* ------------------------------------------------------------ */ + /** + * Set number of requests over the rate limit able to be + * considered at once. + * + * @param value number of requests + */ + public void setThrottledRequests(int value) + { + _passes = new Semaphore((value-_throttledRequests+_passes.availablePermits()), true); + _throttledRequests = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get amount of time (in milliseconds) to async wait for semaphore. + * + * @return wait time + */ + public long getThrottleMs() + { + return _throttleMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set amount of time (in milliseconds) to async wait for semaphore. + * + * @param value wait time + */ + public void setThrottleMs(long value) + { + _throttleMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get maximum amount of time (in milliseconds) to allow + * the request to process. + * + * @return maximum processing time + */ + public long getMaxRequestMs() + { + return _maxRequestMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set maximum amount of time (in milliseconds) to allow + * the request to process. + * + * @param value maximum processing time + */ + public void setMaxRequestMs(long value) + { + _maxRequestMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get maximum amount of time (in milliseconds) to keep track + * of request rates for a connection, before deciding that + * the user has gone away, and discarding it. + * + * @return maximum tracking time + */ + public long getMaxIdleTrackerMs() + { + return _maxIdleTrackerMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set maximum amount of time (in milliseconds) to keep track + * of request rates for a connection, before deciding that + * the user has gone away, and discarding it. + * + * @param value maximum tracking time + */ + public void setMaxIdleTrackerMs(long value) + { + _maxIdleTrackerMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Check flag to insert the DoSFilter headers into the response. + * + * @return value of the flag + */ + public boolean isInsertHeaders() + { + return _insertHeaders; + } + + /* ------------------------------------------------------------ */ + /** + * Set flag to insert the DoSFilter headers into the response. + * + * @param value value of the flag + */ + public void setInsertHeaders(boolean value) + { + _insertHeaders = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get flag to have usage rate tracked by session if a session exists. + * + * @return value of the flag + */ + public boolean isTrackSessions() + { + return _trackSessions; + } + + /* ------------------------------------------------------------ */ + /** + * Set flag to have usage rate tracked by session if a session exists. + * @param value value of the flag + */ + public void setTrackSessions(boolean value) + { + _trackSessions = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get flag to have usage rate tracked by IP+port (effectively connection) + * if session tracking is not used. + * + * @return value of the flag + */ + public boolean isRemotePort() + { + return _remotePort; + } + + + /* ------------------------------------------------------------ */ + /** + * Set flag to have usage rate tracked by IP+port (effectively connection) + * if session tracking is not used. + * + * @param value value of the flag + */ + public void setRemotePort(boolean value) + { + _remotePort = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get a list of IP addresses that will not be rate limited. + * + * @return comma-separated whitelist + */ + public String getWhitelist() + { + return _whitelistStr; + } + + + /* ------------------------------------------------------------ */ + /** + * Set a list of IP addresses that will not be rate limited. + * + * @param value comma-separated whitelist + */ + public void setWhitelist(String value) + { + _whitelistStr = value; + initWhitelist(); + } + /** * A RateTracker is associated with a connection, and stores request rate * data. diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java index 117ac00e9b..7de14cbc8e 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java @@ -60,9 +60,7 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; * the web application. * <p> * To facilitate JMX monitoring, the "HttpClient", it's "ThreadPool" and the "Logger" - * are set as context attributes prefixed with "org.eclipse.jetty.servlets."+name - * (unless otherwise set with attrPrefix). This attribute prefix is also used for the - * logger name. + * are set as context attributes prefixed with the servlet name. * <p> * The following init parameters may be used to configure the servlet: <ul> * <li>name - Name of Proxy servlet (default: "ProxyServlet" @@ -92,7 +90,6 @@ public class ProxyServlet implements Servlet protected ServletConfig _config; protected ServletContext _context; - protected String _name="ProxyServlet"; /* ------------------------------------------------------------ */ /* (non-Javadoc) @@ -111,17 +108,14 @@ public class ProxyServlet implements Servlet try { - String t = config.getInitParameter("attrPrefix"); - if (t!=null) - _name=t; - _log= Log.getLogger("org.eclipse.jetty.servlets."+_name); + _log= Log.getLogger("org.eclipse.jetty.servlets."+config.getServletName()); - t = config.getInitParameter("maxThreads"); + String t = config.getInitParameter("maxThreads"); if (t!=null) _client.setThreadPool(new QueuedThreadPool(Integer.parseInt(t))); else _client.setThreadPool(new QueuedThreadPool()); - ((QueuedThreadPool)_client.getThreadPool()).setName(_name.substring(_name.lastIndexOf('.')+1)); + ((QueuedThreadPool)_client.getThreadPool()).setName(config.getServletName()); t = config.getInitParameter("maxConnections"); if (t!=null) @@ -131,9 +125,9 @@ public class ProxyServlet implements Servlet if (_context!=null) { - _context.setAttribute("org.eclipse.jetty.servlets."+_name+".Logger",_log); - _context.setAttribute("org.eclipse.jetty.servlets."+_name+".ThreadPool",_client.getThreadPool()); - _context.setAttribute("org.eclipse.jetty.servlets."+_name+".HttpClient",_client); + _context.setAttribute(config.getServletName()+".Logger",_log); + _context.setAttribute(config.getServletName()+".ThreadPool",_client.getThreadPool()); + _context.setAttribute(config.getServletName()+".HttpClient",_client); } } catch (Exception e) @@ -513,7 +507,7 @@ public class ProxyServlet implements Servlet if (!_prefix.startsWith("/")) throw new UnavailableException("Prefix parameter must start with a '/'."); - _log.info(_name + " @ " + _prefix + " to " + _proxyTo); + _log.info(config.getServletName()+" @ " + _prefix + " to " + _proxyTo); } @Override diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java index 21b6843c2c..cf3a97dea5 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java @@ -33,21 +33,23 @@ import javax.servlet.http.HttpSession; import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.continuation.ContinuationSupport; +import org.eclipse.jetty.server.handler.ContextHandler; /** * Quality of Service Filter. + * * This filter limits the number of active requests to the number set by the "maxRequests" init parameter (default 10). * If more requests are received, they are suspended and placed on priority queues. Priorities are determined by * the {@link #getPriority(ServletRequest)} method and are a value between 0 and the value given by the "maxPriority" * init parameter (default 10), with higher values having higher priority. - * <p> + * </p><p> * This filter is ideal to prevent wasting threads waiting for slow/limited * resources such as a JDBC connection pool. It avoids the situation where all of a * containers thread pool may be consumed blocking on such a slow resource. * By limiting the number of active threads, a smaller thread pool may be used as * the threads are not wasted waiting. Thus more memory may be available for use by * the active threads. - * <p> + * </p><p> * Furthermore, this filter uses a priority when resuming waiting requests. So that if * a container is under load, and there are many requests waiting for resources, * the {@link #getPriority(ServletRequest)} method is used, so that more important @@ -55,12 +57,16 @@ import org.eclipse.jetty.continuation.ContinuationSupport; * maxRequest limit slightly smaller than the containers thread pool and a high priority * allocated to admin users. Thus regardless of load, admin users would always be * able to access the web application. - * <p> + * </p><p> * The maxRequest limit is policed by a {@link Semaphore} and the filter will wait a short while attempting to acquire * the semaphore. This wait is controlled by the "waitMs" init parameter and allows the expense of a suspend to be * avoided if the semaphore is shortly available. If the semaphore cannot be obtained, the request will be suspended * for the default suspend period of the container or the valued set as the "suspendMs" init parameter. - * + * </p><p> + * If the "managedAttr" init parameter is set to true, then this servlet is set as a {@link ServletContext} attribute with the + * filter name as the attribute name. This allows context external mechanism (eg JMX via {@link ContextHandler#MANAGED_ATTRIBUTES}) to + * manage the configuration of the filter. + * </p> * * */ @@ -71,23 +77,31 @@ public class QoSFilter implements Filter final static int __DEFAULT_WAIT_MS=50; final static long __DEFAULT_TIMEOUT_MS = -1; + final static String MANAGED_ATTR_INIT_PARAM="managedAttr"; final static String MAX_REQUESTS_INIT_PARAM="maxRequests"; final static String MAX_PRIORITY_INIT_PARAM="maxPriority"; final static String MAX_WAIT_INIT_PARAM="waitMs"; final static String SUSPEND_INIT_PARAM="suspendMs"; ServletContext _context; - long _waitMs; - long _suspendMs; - Semaphore _passes; - Queue<Continuation>[] _queue; - ContinuationListener[] _listener; - String _suspended="QoSFilter@"+this.hashCode(); + + protected long _waitMs; + protected long _suspendMs; + protected int _maxRequests; + private Semaphore _passes; + private Queue<Continuation>[] _queue; + private ContinuationListener[] _listener; + private String _suspended="QoSFilter@"+this.hashCode(); + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) + */ public void init(FilterConfig filterConfig) { _context=filterConfig.getServletContext(); - + int max_priority=__DEFAULT_MAX_PRIORITY; if (filterConfig.getInitParameter(MAX_PRIORITY_INIT_PARAM)!=null) max_priority=Integer.parseInt(filterConfig.getInitParameter(MAX_PRIORITY_INIT_PARAM)); @@ -110,10 +124,11 @@ public class QoSFilter implements Filter }; } - int passes=__DEFAULT_PASSES; + int maxRequests=__DEFAULT_PASSES; if (filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM)!=null) - passes=Integer.parseInt(filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM)); - _passes=new Semaphore(passes,true); + maxRequests=Integer.parseInt(filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM)); + _passes=new Semaphore(maxRequests,true); + _maxRequests = maxRequests; long wait = __DEFAULT_WAIT_MS; if (filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM)!=null) @@ -124,8 +139,15 @@ public class QoSFilter implements Filter if (filterConfig.getInitParameter(SUSPEND_INIT_PARAM)!=null) suspend=Integer.parseInt(filterConfig.getInitParameter(SUSPEND_INIT_PARAM)); _suspendMs=suspend; + + if (_context!=null && Boolean.parseBoolean(filterConfig.getInitParameter(MANAGED_ATTR_INIT_PARAM))) + _context.setAttribute(filterConfig.getFilterName(),this); } + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) + */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { @@ -238,6 +260,83 @@ public class QoSFilter implements Filter } + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.Filter#destroy() + */ public void destroy(){} + /* ------------------------------------------------------------ */ + /** + * Get the (short) amount of time (in milliseconds) that the filter would wait + * for the semaphore to become available before suspending a request. + * + * @return wait time (in milliseconds) + */ + public long getWaitMs() + { + return _waitMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set the (short) amount of time (in milliseconds) that the filter would wait + * for the semaphore to become available before suspending a request. + * + * @param value wait time (in milliseconds) + */ + public void setWaitMs(long value) + { + _waitMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get the amount of time (in milliseconds) that the filter would suspend + * a request for while waiting for the semaphore to become available. + * + * @return suspend time (in milliseconds) + */ + public long getSuspendMs() + { + return _suspendMs; + } + + /* ------------------------------------------------------------ */ + /** + * Set the amount of time (in milliseconds) that the filter would suspend + * a request for while waiting for the semaphore to become available. + * + * @param value suspend time (in milliseconds) + */ + public void setSuspendMs(long value) + { + _suspendMs = value; + } + + /* ------------------------------------------------------------ */ + /** + * Get the maximum number of requests allowed to be processed + * at the same time. + * + * @return maximum number of requests + */ + public int getMaxRequests() + { + return _maxRequests; + } + + /* ------------------------------------------------------------ */ + /** + * Set the maximum number of requests allowed to be processed + * at the same time. + * + * @param passes the _passes to set + */ + public void setMaxRequests(int value) + { + _passes = new Semaphore((value-_maxRequests+_passes.availablePermits()), true); + _maxRequests = value; + } + } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java index 534b0ea6f4..34651edb09 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java @@ -193,10 +193,10 @@ public abstract class AbstractDoSFilterTest String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; String responses = doRequests(request+request+request+request,1,0,0,last); //System.out.println("responses are " + responses); - assertEquals(5,count(responses,"HTTP/1.1 200 OK")); - assertEquals(1,count(responses,"DoSFilter: delayed")); - assertEquals(1,count(responses,"DoSFilter: throttled")); - assertEquals(0,count(responses,"DoSFilter: unavailable")); + assertEquals("200 OK responses", 5,count(responses,"HTTP/1.1 200 OK")); + assertEquals("delayed responses", 1,count(responses,"DoSFilter: delayed")); + assertEquals("throttled responses", 1,count(responses,"DoSFilter: throttled")); + assertEquals("unavailable responses", 0,count(responses,"DoSFilter: unavailable")); other.join(); } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java index e81ee2556a..a067dd5e44 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java @@ -13,17 +13,18 @@ package org.eclipse.jetty.start; import java.io.BufferedReader; +import java.io.Closeable; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; -import java.io.Reader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.ConnectException; @@ -33,12 +34,11 @@ import java.security.Policy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.TimeZone; -import org.eclipse.jetty.start.log.RedirectedStreamLogger; /*-------------------------------------------*/ /** @@ -54,6 +54,12 @@ import org.eclipse.jetty.start.log.RedirectedStreamLogger; */ public class Main { + private static final int EXIT_USAGE = 1; + private static final int ERR_LOGGING = -1; + private static final int ERR_INVOKE_MAIN = -2; + private static final int ERR_SECURITY = -3; + private static final int ERR_NOT_STOPPED = -4; + private static final int ERR_UNKNOWN = -5; private boolean _showUsage = false; private boolean _dumpVersions = false; private boolean _listConfig = false; @@ -61,7 +67,6 @@ public class Main private boolean _dryRun = false; private boolean _exec = false; private boolean _secure = false; - private boolean _fromDaemon = false; private final Config _config = new Config(); private Set<String> _sysProps = new HashSet<String>(); private List<String> _jvmArgs = new ArrayList<String>(); @@ -79,6 +84,7 @@ public class Main catch (Throwable t) { t.printStackTrace(System.err); + System.exit(ERR_UNKNOWN); } } @@ -92,7 +98,7 @@ public class Main boolean ini=false; for (String arg : args) { - if (arg.startsWith("--ini=")) + if (arg.startsWith("--ini=")||arg.equals("--ini")) { ini=true; if (arg.length()>6) @@ -106,20 +112,24 @@ public class Main _startConfig=arg.substring(9); } else + { arguments.add(arg); + } } // if no non-option inis, add the start.ini if (!ini) + { arguments.addAll(0,loadStartIni(null)); + } // The XML Configuration Files to initialize with List<String> xmls = new ArrayList<String>(); // Process the arguments + int startup=0; for (String arg : arguments) { - if ("--help".equals(arg) || "-?".equals(arg)) { _showUsage = true; @@ -128,8 +138,8 @@ public class Main if ("--stop".equals(arg)) { - int port = Integer.parseInt(_config.getProperty("STOP.KEY",System.getProperty("STOP.PORT","-1"))); - String key = _config.getProperty("STOP.KETY",System.getProperty("STOP.KEY",null)); + int port = Integer.parseInt(_config.getProperty("STOP.PORT",System.getProperty("STOP.PORT","-1"))); + String key = _config.getProperty("STOP.KEY",System.getProperty("STOP.KEY",null)); stop(port,key); return; } @@ -165,12 +175,31 @@ public class Main } // Special internal indicator that jetty was started by the jetty.sh Daemon - if ("--fromDaemon".equals(arg)) + if ("--daemon".equals(arg)) { - _fromDaemon = true; - PrintStream logger = new PrintStream(new RedirectedStreamLogger("daemon_yyyy_mm_dd.log",false,90,TimeZone.getTimeZone("GMT"))); + File startDir = new File(System.getProperty("jetty.logs","logs")); + if (!startDir.exists() || !startDir.canWrite() ) + startDir = new File("."); + File startLog = new File(startDir,"start.log"); + if (!startLog.exists() && !startLog.createNewFile()) + { + // Output about error is lost in majority of cases. + System.err.println("Unable to create: " + startLog.getAbsolutePath()); + // Toss a unique exit code indicating this failure. + System.exit(ERR_LOGGING); + } + + if (!startLog.canWrite()) + { + // Output about error is lost in majority of cases. + System.err.println("Unable to write to: " + startLog.getAbsolutePath()); + // Toss a unique exit code indicating this failure. + System.exit(ERR_LOGGING); + } + PrintStream logger = new PrintStream(new FileOutputStream(startLog,false)); System.setOut(logger); System.setErr(logger); + System.out.println("Establishing start.log on " + new Date()); continue; } @@ -179,6 +208,12 @@ public class Main _secure = true; continue; } + + if (arg.startsWith("--pre=")) + { + xmls.add(startup++,arg.substring(6)); + continue; + } if (arg.startsWith("-D")) { @@ -219,7 +254,9 @@ public class Main _config.addActiveOption(opt); } else + { this._config.setProperty(assign[0],assign[1]); + } break; case 1: this._config.setProperty(assign[0],null); @@ -230,7 +267,7 @@ public class Main continue; } - + // Anything else is considered an XML file. xmls.add(arg); } @@ -241,6 +278,7 @@ public class Main { t.printStackTrace(System.err); System.out.println("Use java -jar start.jar --help for usage information."); + System.exit(ERR_UNKNOWN); } } @@ -253,8 +291,10 @@ public class Main File startIniFile = ini==null?((jettyHome!=null)? new File(jettyHome,"start.ini"):new File("start.ini")):new File(ini); if (!startIniFile.exists() || !startIniFile.canRead()) { - if (ini!=null) - System.err.println("Warning - can't find ini file: "+ini); + if (ini != null) + { + System.err.println("Warning - can't find ini file: " + ini); + } // No start.ini found, skip load. return Collections.emptyList(); } @@ -271,15 +311,18 @@ public class Main String arg; while ((arg = buf.readLine()) != null) { - arg=arg.trim(); - if (arg.length()==0 || arg.startsWith("#")) + arg = arg.trim(); + if (arg.length() == 0 || arg.startsWith("#")) + { continue; + } args.add(arg); } } catch (IOException e) { - e.printStackTrace(); + e.printStackTrace(System.err); + System.exit(ERR_UNKNOWN); } finally { @@ -299,7 +342,7 @@ public class Main { System.err.println("Usage: java -jar start.jar [options] [properties] [configs]"); System.err.println("ERROR: detailed usage resource unavailable"); - System.exit(1); + System.exit(EXIT_USAGE); } BufferedReader buf = null; @@ -394,19 +437,9 @@ public class Main } finally { - if (buf != null) - { - try - { - buf.close(); - } - catch (IOException ignore) - { - /* ignore */ - } - } + close(buf); } - System.exit(1); + System.exit(EXIT_USAGE); } public void invokeMain(ClassLoader classloader, String classname, List<String> args) throws IllegalAccessException, InvocationTargetException, @@ -426,14 +459,19 @@ public class Main if (Config.isDebug() || invoked_class == null) { if (invoked_class == null) + { System.err.println("ClassNotFound: " + classname); + } else + { System.err.println(classname + " " + invoked_class.getPackage().getImplementationVersion()); + } if (invoked_class == null) { System.err.println("Usage: java -jar start.jar [options] [properties] [configs]"); System.err.println(" java -jar start.jar --help # for more information"); + System.exit(ERR_INVOKE_MAIN); return; } } @@ -448,36 +486,19 @@ public class Main } /* ------------------------------------------------------------ */ - public static void close(Reader reader) - { - if (reader == null) - { - return; - } - try - { - reader.close(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - /* ------------------------------------------------------------ */ - public static void close(InputStream stream) + public static void close(Closeable c) { - if (stream == null) + if (c == null) { return; } try { - stream.close(); + c.close(); } catch (IOException e) { - e.printStackTrace(); + e.printStackTrace(System.err); } } @@ -496,12 +517,6 @@ public class Main throw new FileNotFoundException("No XML configuration files specified in start.config or command line."); } - // Add required logging if executed via the daemon. - if (_fromDaemon) - { - configuredXmls.add("etc/jetty-logging.xml"); - } - // Add mandatory options for secure mode if (_secure) { @@ -575,8 +590,10 @@ public class Main return; } - if (_jvmArgs.size()>0 || _sysProps.size()>0) + if (_jvmArgs.size() > 0 || _sysProps.size() > 0) + { System.err.println("WARNING: System properties and/or JVM args set. Consider using --dry-run or --exec"); + } // Set current context class loader to what is selected. Thread.currentThread().setContextClassLoader(cl); @@ -593,12 +610,16 @@ public class Main // Check for override of start class (via "jetty.server" property) String mainClass = System.getProperty("jetty.server"); if (mainClass != null) + { classname = mainClass; + } // Check for override of start class (via "main.class" property) mainClass = System.getProperty("main.class"); if (mainClass != null) + { classname = mainClass; + } Config.debug("main.class=" + classname); @@ -606,7 +627,8 @@ public class Main } catch (Exception e) { - e.printStackTrace(); + e.printStackTrace(System.err); + System.exit(ERR_INVOKE_MAIN); } } @@ -844,28 +866,23 @@ public class Main } catch (SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + e.printStackTrace(System.err); } catch (NoSuchMethodException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + e.printStackTrace(System.err); } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + e.printStackTrace(System.err); } catch (IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + e.printStackTrace(System.err); } catch (InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + e.printStackTrace(System.err); } } } @@ -920,12 +937,15 @@ public class Main { Policy policy = Policy.getPolicy(); if (policy != null) + { policy.refresh(); + } } } catch (Exception e) { - e.printStackTrace(); + e.printStackTrace(System.err); + System.exit(ERR_SECURITY); } } @@ -959,8 +979,8 @@ public class Main } catch (Exception e) { - e.printStackTrace(); - System.exit(1); + e.printStackTrace(System.err); + System.exit(ERR_UNKNOWN); } finally { @@ -1015,8 +1035,8 @@ public class Main catch (Exception e) { e.printStackTrace(); - System.exit(1); - return null; // never executed (just to satisfy javac compiler) + System.exit(ERR_UNKNOWN); + return null; // never executed (just here to satisfy javac compiler) } finally { @@ -1027,8 +1047,10 @@ public class Main private InputStream getConfigStream() throws FileNotFoundException { String config=_startConfig; - if (config==null || config.length()==0) - config=System.getProperty("START","org/eclipse/jetty/start/start.config"); + if (config == null || config.length() == 0) + { + config = System.getProperty("START","org/eclipse/jetty/start/start.config"); + } Config.debug("config=" + config); @@ -1037,15 +1059,17 @@ public class Main // resource not found, try filesystem next if (cfgstream == null) + { cfgstream = new FileInputStream(config); + } return cfgstream; } private void startMonitor() { - int port = Integer.parseInt(System.getProperty("STOP.PORT","-1")); - String key = System.getProperty("STOP.KEY",null); + int port = Integer.parseInt(_config.getProperty("STOP.PORT",System.getProperty("STOP.PORT","-1"))); + String key = _config.getProperty("STOP.KEY",System.getProperty("STOP.KEY",null)); Monitor.monitor(port,key); } @@ -1061,7 +1085,9 @@ public class Main try { if (_port <= 0) + { System.err.println("STOP.PORT system property must be specified"); + } if (_key == null) { _key = ""; @@ -1070,18 +1096,26 @@ public class Main } Socket s = new Socket(InetAddress.getByName("127.0.0.1"),_port); - OutputStream out = s.getOutputStream(); - out.write((_key + "\r\nstop\r\n").getBytes()); - out.flush(); - s.close(); + try + { + OutputStream out = s.getOutputStream(); + out.write((_key + "\r\nstop\r\n").getBytes()); + out.flush(); + } + finally + { + s.close(); + } } catch (ConnectException e) { System.err.println("ERROR: Not running!"); + System.exit(ERR_NOT_STOPPED); } catch (Exception e) { - e.printStackTrace(); + e.printStackTrace(System.err); + System.exit(ERR_UNKNOWN); } } } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/log/RedirectedStreamLogger.java b/jetty-start/src/main/java/org/eclipse/jetty/start/log/RedirectedStreamLogger.java deleted file mode 100644 index 65ba90f2b1..0000000000 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/log/RedirectedStreamLogger.java +++ /dev/null @@ -1,299 +0,0 @@ -package org.eclipse.jetty.start.log; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.TimeZone; -import java.util.Timer; -import java.util.TimerTask; - -public class RedirectedStreamLogger extends FilterOutputStream -{ - private static Timer __rollover; - - final static String YYYY_MM_DD = "yyyy_mm_dd"; - final static String ROLLOVER_FILE_DATE_FORMAT = "yyyy_MM_dd"; - final static String ROLLOVER_FILE_BACKUP_FORMAT = "HHmmssSSS"; - final static int ROLLOVER_FILE_RETAIN_DAYS = 31; - - private RollTask _rollTask; - private SimpleDateFormat _fileBackupFormat; - private SimpleDateFormat _fileDateFormat; - - private String _filename; - private File _file; - private boolean _append; - private int _retainDays; - - /* ------------------------------------------------------------ */ - /** - * @param filename - * The filename must include the string "yyyy_mm_dd", which is replaced with the actual date when - * creating and rolling over the file. - * @throws IOException - */ - public RedirectedStreamLogger(String filename) throws IOException - { - this(filename,true,ROLLOVER_FILE_RETAIN_DAYS); - } - - /* ------------------------------------------------------------ */ - /** - * @param filename - * The filename must include the string "yyyy_mm_dd", which is replaced with the actual date when - * creating and rolling over the file. - * @param append - * If true, existing files will be appended to. - * @throws IOException - */ - public RedirectedStreamLogger(String filename, boolean append) throws IOException - { - this(filename,append,ROLLOVER_FILE_RETAIN_DAYS); - } - - /* ------------------------------------------------------------ */ - /** - * @param filename - * The filename must include the string "yyyy_mm_dd", which is replaced with the actual date when - * creating and rolling over the file. - * @param append - * If true, existing files will be appended to. - * @param retainDays - * The number of days to retain files before deleting them. 0 to retain forever. - * @throws IOException - */ - public RedirectedStreamLogger(String filename, boolean append, int retainDays) throws IOException - { - this(filename,append,retainDays,TimeZone.getDefault()); - } - - /* ------------------------------------------------------------ */ - /** - * @param filename - * The filename must include the string "yyyy_mm_dd", which is replaced with the actual date when - * creating and rolling over the file. - * @param append - * If true, existing files will be appended to. - * @param retainDays - * The number of days to retain files before deleting them. 0 to retain forever. - * @throws IOException - */ - public RedirectedStreamLogger(String filename, boolean append, int retainDays, TimeZone zone) throws IOException - { - this(filename,append,retainDays,zone,null,null); - } - - /* ------------------------------------------------------------ */ - /** - * @param filename - * The filename must include the string "yyyy_mm_dd", which is replaced with the actual date when - * creating and rolling over the file. - * @param append - * If true, existing files will be appended to. - * @param retainDays - * The number of days to retain files before deleting them. 0 to retain forever. - * @param dateFormat - * The format for the date file substitution. The default is "yyyy_MM_dd". - * @param backupFormat - * The format for the file extension of backup files. The default is "HHmmssSSS". - * @throws IOException - */ - public RedirectedStreamLogger(String filename, boolean append, int retainDays, TimeZone zone, String dateFormat, String backupFormat) throws IOException - { - super(null); - - if (dateFormat == null) - dateFormat = ROLLOVER_FILE_DATE_FORMAT; - _fileDateFormat = new SimpleDateFormat(dateFormat); - - if (backupFormat == null) - backupFormat = ROLLOVER_FILE_BACKUP_FORMAT; - _fileBackupFormat = new SimpleDateFormat(backupFormat); - - _fileBackupFormat.setTimeZone(zone); - _fileDateFormat.setTimeZone(zone); - - if (filename != null) - { - filename = filename.trim(); - if (filename.length() == 0) - filename = null; - } - if (filename == null) - throw new IllegalArgumentException("Invalid filename"); - - _filename = filename; - _append = append; - _retainDays = retainDays; - setFile(); - - synchronized (RedirectedStreamLogger.class) - { - if (__rollover == null) - __rollover = new Timer(RedirectedStreamLogger.class.getName(),true); - - _rollTask = new RollTask(); - - Calendar now = Calendar.getInstance(); - now.setTimeZone(zone); - - GregorianCalendar midnight = new GregorianCalendar(now.get(Calendar.YEAR),now.get(Calendar.MONTH),now.get(Calendar.DAY_OF_MONTH),23,0); - midnight.setTimeZone(zone); - midnight.add(Calendar.HOUR,1); - __rollover.scheduleAtFixedRate(_rollTask,midnight.getTime(),1000L * 60 * 60 * 24); - } - } - - /* ------------------------------------------------------------ */ - public String getFilename() - { - return _filename; - } - - /* ------------------------------------------------------------ */ - public String getDatedFilename() - { - if (_file == null) - return null; - return _file.toString(); - } - - /* ------------------------------------------------------------ */ - public int getRetainDays() - { - return _retainDays; - } - - /* ------------------------------------------------------------ */ - private synchronized void setFile() throws IOException - { - // Check directory - File file = new File(_filename); - _filename = file.getCanonicalPath(); - file = new File(_filename); - File dir = new File(file.getParent()); - if (!dir.isDirectory() || !dir.canWrite()) - throw new IOException("Cannot write log directory " + dir); - - Date now = new Date(); - - // Is this a rollover file? - String filename = file.getName(); - int i = filename.toLowerCase().indexOf(YYYY_MM_DD); - if (i >= 0) - { - file = new File(dir,filename.substring(0,i) + _fileDateFormat.format(now) + filename.substring(i + YYYY_MM_DD.length())); - } - - if (file.exists() && !file.canWrite()) - throw new IOException("Cannot write log file " + file); - - // Do we need to change the output stream? - if (out == null || !file.equals(_file)) - { - // Yep - _file = file; - if (!_append && file.exists()) - file.renameTo(new File(file.toString() + "." + _fileBackupFormat.format(now))); - OutputStream oldOut = out; - out = new FileOutputStream(file.toString(),_append); - if (oldOut != null) - oldOut.close(); - //if(log.isDebugEnabled())log.debug("Opened "+_file); - } - } - - /* ------------------------------------------------------------ */ - private void removeOldFiles() - { - if (_retainDays > 0) - { - long now = System.currentTimeMillis(); - - File file = new File(_filename); - File dir = new File(file.getParent()); - String fn = file.getName(); - int s = fn.toLowerCase().indexOf(YYYY_MM_DD); - if (s < 0) - return; - String prefix = fn.substring(0,s); - String suffix = fn.substring(s + YYYY_MM_DD.length()); - - String[] logList = dir.list(); - for (int i = 0; i < logList.length; i++) - { - fn = logList[i]; - if (fn.startsWith(prefix) && fn.indexOf(suffix,prefix.length()) >= 0) - { - File f = new File(dir,fn); - long date = f.lastModified(); - if (((now - date) / (1000 * 60 * 60 * 24)) > _retainDays) - f.delete(); - } - } - } - } - - /* ------------------------------------------------------------ */ - @Override - public void write(byte[] buf) throws IOException - { - out.write(buf); - } - - /* ------------------------------------------------------------ */ - @Override - public void write(byte[] buf, int off, int len) throws IOException - { - out.write(buf,off,len); - } - - /* ------------------------------------------------------------ */ - /** - */ - @Override - public void close() throws IOException - { - synchronized (RedirectedStreamLogger.class) - { - try - { - super.close(); - } - finally - { - out = null; - _file = null; - } - - _rollTask.cancel(); - } - } - - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - private class RollTask extends TimerTask - { - @Override - public void run() - { - try - { - RedirectedStreamLogger.this.setFile(); - RedirectedStreamLogger.this.removeOldFiles(); - - } - catch (IOException e) - { - e.printStackTrace(); - } - } - } -} diff --git a/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt b/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt index ba59db2335..16761c2c26 100644 --- a/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt +++ b/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt @@ -23,15 +23,12 @@ Command Line Options: a sub processes. This can be used when start.ini contains -X or -D arguments, but creates an extra JVM instance. - - --secure Enable Security: - * JVM Security Manager - * Security Policies - * Secure Logging - * Audit Logging --stop Stop the running Jetty instance. + --daemon Start in daemon mode with stderr and stdout + redirected to ${jetty.log}/start.log + --config=<file> Specify an alternate start.config file. The default is the start.config file inside the start.jar. The default can also be specified @@ -42,6 +39,9 @@ Command Line Options: start.ini file will be read if it exists. A --ini option with no file indicates that start.ini should not be read. + + --pre=<file> Specify a configuration file that is to be processed + before any configuration files listed in start.ini System Properties: These are set with a command line like "java -Dname=value ..." and are diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml index 849486cd41..6dd5db3172 100644 --- a/jetty-util/pom.xml +++ b/jetty-util/pom.xml @@ -66,6 +66,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> <dependency> diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java index d433996e7c..ce23e549c8 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java @@ -40,7 +40,8 @@ public class AttributesMap implements Attributes { _map=map; } - + + /* ------------------------------------------------------------ */ public AttributesMap(AttributesMap map) { _map=new HashMap<String,Object>(map._map); @@ -117,7 +118,13 @@ public class AttributesMap implements Attributes { _map.clear(); } - + + /* ------------------------------------------------------------ */ + public int size() + { + return _map.size(); + } + /* ------------------------------------------------------------ */ @Override public String toString() @@ -130,5 +137,16 @@ public class AttributesMap implements Attributes { return _map.keySet(); } + + /* ------------------------------------------------------------ */ + public void addAll(Attributes attributes) + { + Enumeration<String> e = attributes.getAttributeNames(); + while (e.hasMoreElements()) + { + String name=e.nextElement(); + setAttribute(name,attributes.getAttribute(name)); + } + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java new file mode 100644 index 0000000000..53345a1088 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java @@ -0,0 +1,362 @@ +// ======================================================================== +// Copyright (c) 2010 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.util; + +import java.util.BitSet; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; + + +/* ------------------------------------------------------------ */ +/** + * Internet address map to object + * <p> + * Internet addresses may be specified as absolute address or as a combination of + * four octet wildcard specifications (a.b.c.d) that are defined as follows. + * </p> + * <pre> + * nnn - an absolute value (0-255) + * mmm-nnn - an inclusive range of absolute values, + * with following shorthand notations: + * nnn- => nnn-255 + * -nnn => 0-nnn + * - => 0-255 + * a,b,... - a list of wildcard specifications + * </pre> + */ +public class IPAddressMap<TYPE> extends HashMap<String, TYPE> +{ + private final HashMap<String,IPAddrPattern> _patterns = new HashMap<String,IPAddrPattern>(); + + /* --------------------------------------------------------------- */ + /** Construct empty AddrPatternMap. + */ + public IPAddressMap() + { + super(11); + } + + /* --------------------------------------------------------------- */ + /** Construct empty AddrPatternMap. + * + * @param capacity initial capacity + */ + public IPAddressMap(int capacity) + { + super (capacity); + } + + /* ------------------------------------------------------------ */ + /** + * Insert a new internet address into map + * + * @see java.util.HashMap#put(java.lang.Object, java.lang.Object) + */ + @Override + public TYPE put(String addrSpec, TYPE object) + throws IllegalArgumentException + { + if (addrSpec == null || addrSpec.trim().length() == 0) + throw new IllegalArgumentException("Invalid IP address pattern: "+addrSpec); + + String spec = addrSpec.trim(); + if (_patterns.get(spec) == null) + _patterns.put(spec,new IPAddrPattern(spec)); + + return super.put(spec, object); + } + + /* ------------------------------------------------------------ */ + /** + * Retrieve the object mapped to the specified internet address literal + * + * @see java.util.HashMap#get(java.lang.Object) + */ + /* ------------------------------------------------------------ */ + /** + * @see java.util.HashMap#get(java.lang.Object) + */ + @Override + public TYPE get(Object key) + { + return super.get(key); + } + + /* ------------------------------------------------------------ */ + /** + * Retrieve the first object that is associated with the specified + * internet address by taking into account the wildcard specifications. + * + * @param addr internet address + * @return associated object + */ + public TYPE match(String addr) + { + Map.Entry<String, TYPE> entry = getMatch(addr); + return entry==null ? null : entry.getValue(); + } + + /* ------------------------------------------------------------ */ + /** + * Retrieve the first map entry that is associated with the specified + * internet address by taking into account the wildcard specifications. + * + * @param addr internet address + * @return map entry associated + */ + public Map.Entry<String, TYPE> getMatch(String addr) + { + if (addr != null) + { + for(Map.Entry<String, TYPE> entry: super.entrySet()) + { + if (_patterns.get(entry.getKey()).match(addr)) + { + return entry; + } + } + } + return null; + } + + /* ------------------------------------------------------------ */ + /** + * Retrieve a lazy list of map entries associated with specified + * internet address by taking into account the wildcard specifications. + * + * @param addr internet address + * @return lazy list of map entries + */ + public Object getLazyMatches(String addr) + { + if (addr == null) + return LazyList.getList(super.entrySet()); + + Object entries = null; + for(Map.Entry<String, TYPE> entry: super.entrySet()) + { + if (_patterns.get(entry.getKey()).match(addr)) + { + entries = LazyList.add(entries,entry); + } + } + return entries; + } + + /* ------------------------------------------------------------ */ + /** + * IPAddrPattern + * + * Represents internet address wildcard. + * Matches the wildcard to provided internet address. + */ + private static class IPAddrPattern + { + private final OctetPattern[] _octets = new OctetPattern[4]; + /* ------------------------------------------------------------ */ + /** + * Create new IPAddrPattern + * + * @param value internet address wildcard specification + * @throws IllegalArgumentException if wildcard specification is invalid + */ + public IPAddrPattern(String value) + throws IllegalArgumentException + { + if (value == null || value.trim().length() == 0) + throw new IllegalArgumentException("Invalid IP address pattern: "+value); + + try + { + StringTokenizer parts = new StringTokenizer(value, "."); + + String part; + for (int idx=0; idx<4; idx++) + { + part = parts.hasMoreTokens() ? parts.nextToken().trim() : "0-255"; + + int len = part.length(); + if (len == 0 && parts.hasMoreTokens()) + throw new IllegalArgumentException("Invalid IP address pattern: "+value); + + _octets[idx] = new OctetPattern(len==0 ? "0-255" : part); + } + } + catch (IllegalArgumentException ex) + { + throw new IllegalArgumentException("Invalid IP address pattern: "+value, ex); + } + } + + /* ------------------------------------------------------------ */ + /** + * Match the specified internet address against the wildcard + * + * @param value internet address + * @return true if specified internet address matches wildcard specification + * + * @throws IllegalArgumentException if specified internet address is invalid + */ + public boolean match(String value) + throws IllegalArgumentException + { + if (value == null || value.trim().length() == 0) + throw new IllegalArgumentException("Invalid IP address: "+value); + + try + { + StringTokenizer parts = new StringTokenizer(value, "."); + + boolean result = true; + for (int idx=0; idx<4; idx++) + { + if (!parts.hasMoreTokens()) + throw new IllegalArgumentException("Invalid IP address: "+value); + + if (!(result &= _octets[idx].match(parts.nextToken()))) + break; + } + return result; + } + catch (IllegalArgumentException ex) + { + throw new IllegalArgumentException("Invalid IP address: "+value, ex); + } + } + } + + /* ------------------------------------------------------------ */ + /** + * OctetPattern + * + * Represents a single octet wildcard. + * Matches the wildcard to the specified octet value. + */ + private static class OctetPattern extends BitSet + { + private final BitSet _mask = new BitSet(256); + + /* ------------------------------------------------------------ */ + /** + * Create new OctetPattern + * + * @param octetSpec octet wildcard specification + * @throws IllegalArgumentException if wildcard specification is invalid + */ + public OctetPattern(String octetSpec) + throws IllegalArgumentException + { + try + { + if (octetSpec != null) + { + String spec = octetSpec.trim(); + if(spec.length() == 0) + { + _mask.set(0,255); + } + else + { + StringTokenizer parts = new StringTokenizer(spec,","); + while (parts.hasMoreTokens()) + { + String part = parts.nextToken().trim(); + if (part.length() > 0) + { + if (part.indexOf('-') < 0) + { + Integer value = Integer.valueOf(part); + _mask.set(value); + } + else + { + int low = 0, high = 255; + + String[] bounds = part.split("-",-2); + if (bounds.length != 2) + { + throw new IllegalArgumentException("Invalid octet spec: "+octetSpec); + } + + if (bounds[0].length() > 0) + { + low = Integer.parseInt(bounds[0]); + } + if (bounds[1].length() > 0) + { + high = Integer.parseInt(bounds[1]); + } + + if (low > high) + { + throw new IllegalArgumentException("Invalid octet spec: "+octetSpec); + } + + _mask.set(low, high+1); + } + } + } + } + } + } + catch (NumberFormatException ex) + { + throw new IllegalArgumentException("Invalid octet spec: "+octetSpec, ex); + } + } + + /* ------------------------------------------------------------ */ + /** + * Match specified octet value against the wildcard + * + * @param value octet value + * @return true if specified octet value matches the wildcard + * @throws IllegalArgumentException if specified octet value is invalid + */ + public boolean match(String value) + throws IllegalArgumentException + { + if (value == null || value.trim().length() == 0) + throw new IllegalArgumentException("Invalid octet: "+value); + + try + { + int number = Integer.parseInt(value); + return match(number); + } + catch (NumberFormatException ex) + { + throw new IllegalArgumentException("Invalid octet: "+value); + } + } + + /* ------------------------------------------------------------ */ + /** + * Match specified octet value against the wildcard + * + * @param number octet value + * @return true if specified octet value matches the wildcard + * @throws IllegalArgumentException if specified octet value is invalid + */ + public boolean match(int number) + throws IllegalArgumentException + { + if (number < 0 || number > 255) + throw new IllegalArgumentException("Invalid octet: "+number); + + return _mask.get(number); + } + } +}
\ No newline at end of file diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/QuotedStringTokenizer.java b/jetty-util/src/main/java/org/eclipse/jetty/util/QuotedStringTokenizer.java index aaff8a5946..78689e2409 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/QuotedStringTokenizer.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/QuotedStringTokenizer.java @@ -267,7 +267,7 @@ public class QuotedStringTokenizer * @param s The string to quote. * @return quoted string */ - public static String quote(String s, String delim) + public static String quoteIfNeeded(String s, String delim) { if (s==null) return null; @@ -413,88 +413,30 @@ public class QuotedStringTokenizer /* ------------------------------------------------------------ */ - /** Quote a string into a StringBuffer. - * The characters ", \, \n, \r, \t, \f, \b are escaped. - * Quotes are forced if any escaped characters are present or there - * is a ", ', space, +, =, ; or % character. + /** Quote a string into a StringBuffer only if needed. + * Quotes are forced if any delim characters are present. * * @param buf The StringBuffer * @param s The String to quote. + * @param delim String of characters that must be quoted. + * @return true if quoted; */ - public static void quoteIfNeeded(Appendable buf, String s) + public static boolean quoteIfNeeded(Appendable buf, String s,String delim) { - try + for (int i=0;i<s.length();i++) { - int e=-1; - - search: for (int i=0;i<s.length();i++) - { - char c = s.charAt(i); - switch(c) - { - case '"': - case '\\': - case '\n': - case '\r': - case '\t': - case '\f': - case '\b': - case '%': - case '+': - case ' ': - case ';': - case '=': - e=i; - buf.append('"'); - // TODO when 1.4 support is dropped: buf.append(s,0,e); - for (int j=0;j<e;j++) - buf.append(s.charAt(j)); - break search; - - default: - continue; - } - } - - if (e<0) - { - buf.append(s); - return; - } - - for (int i=e;i<s.length();i++) + char c = s.charAt(i); + if (delim.indexOf(c)>=0) { - char c = s.charAt(i); - switch(c) - { - case '"': - buf.append("\\\""); - continue; - case '\\': - buf.append("\\\\"); - continue; - case '\n': - buf.append("\\n"); - continue; - case '\r': - buf.append("\\r"); - continue; - case '\t': - buf.append("\\t"); - continue; - case '\f': - buf.append("\\f"); - continue; - case '\b': - buf.append("\\b"); - continue; - - default: - buf.append(c); - continue; - } + quote(buf,s); + return true; } - buf.append('"'); + } + + try + { + buf.append(s); + return false; } catch(IOException e) { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java index 0eeab95c86..2adca11192 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java @@ -77,7 +77,7 @@ public class Log if (__log == null || !__log.getClass().equals(log_class)) { __log = (Logger)log_class.newInstance(); - __log.info("Logging to {} via {}", __log, log_class.getName()); + __log.debug("Logging to {} via {}", __log, log_class.getName()); } } catch(NoClassDefFoundError e) @@ -101,7 +101,7 @@ public class Log { log_class = StdErrLog.class; __log = new StdErrLog(); - __log.info("Logging to {} via {}", __log, log_class.getName()); + __log.debug("Logging to {} via {}", __log, log_class.getName()); } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java index 96b3d921b0..c4b2749562 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java @@ -303,6 +303,13 @@ public class StdErrLog implements Logger buffer.append("\n\tat "); format(buffer, elements[i].toString()); } + + Throwable cause = thrown.getCause(); + if (cause!=null && cause!=thrown) + { + buffer.append("\nCaused by: "); + format(buffer,cause); + } } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java index 16d66825b1..4d860a4fb9 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java @@ -489,7 +489,7 @@ public abstract class Resource implements Serializable buf.append("\">Parent Directory</A></TD><TD></TD><TD></TD></TR>\n"); } - String defangedBase = defangURI(base); + String encodedBase = hrefEncodeURI(base); DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); @@ -498,7 +498,7 @@ public abstract class Resource implements Serializable Resource item = addPath(ls[i]); buf.append("\n<TR><TD><A HREF=\""); - String path=URIUtil.addPaths(defangedBase,URIUtil.encodePath(ls[i])); + String path=URIUtil.addPaths(encodedBase,URIUtil.encodePath(ls[i])); buf.append(path); @@ -522,38 +522,35 @@ public abstract class Resource implements Serializable } /** - * Defang any characters that could break the URI string in an HREF. + * Encode any characters that could break the URI string in an HREF. * Such as <a href="/path/to;<script>Window.alert("XSS"+'%20'+"here");</script>">Link</a> * * The above example would parse incorrectly on various browsers as the "<" or '"' characters * would end the href attribute value string prematurely. * - * @param raw the raw text to defang. + * @param raw the raw text to encode. * @return the defanged text. */ - private static String defangURI(String raw) + private static String hrefEncodeURI(String raw) { StringBuffer buf = null; - - if (buf==null) + + for (int i=0;i<raw.length();i++) { - for (int i=0;i<raw.length();i++) + char c=raw.charAt(i); + switch(c) { - char c=raw.charAt(i); - switch(c) - { - case '\'': - case '"': - case '<': - case '>': - buf=new StringBuffer(raw.length()<<1); - break; - } + case '\'': + case '"': + case '<': + case '>': + buf=new StringBuffer(raw.length()<<1); + break; } - if (buf==null) - return raw; } - + if (buf==null) + return raw; + for (int i=0;i<raw.length();i++) { char c=raw.charAt(i); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceCollection.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceCollection.java index 7ff50cfe63..8d55ee2f3f 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceCollection.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceCollection.java @@ -114,6 +114,10 @@ public class ResourceCollection extends Resource throw new IllegalArgumentException(_resources[i] + " is not an existing directory."); } } + catch(IllegalArgumentException e) + { + throw e; + } catch(Exception e) { throw new RuntimeException(e); @@ -458,12 +462,9 @@ public class ResourceCollection extends Resource public String toString() { if(_resources==null) - return ""; + return "[]"; - StringBuilder buffer = new StringBuilder(); - for(Resource r : _resources) - buffer.append(r.toString()).append(';'); - return buffer.toString(); + return String.valueOf(Arrays.asList(_resources)); } /* ------------------------------------------------------------ */ diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ShutdownThread.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ShutdownThread.java index 58f363d515..ebf3096fff 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ShutdownThread.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ShutdownThread.java @@ -35,6 +35,7 @@ public class ShutdownThread extends Thread { private static final ShutdownThread _thread = new ShutdownThread(); + private boolean _hooked; private final List<LifeCycle> _lifeCycles = new CopyOnWriteArrayList<LifeCycle>(); /* ------------------------------------------------------------ */ @@ -45,17 +46,39 @@ public class ShutdownThread extends Thread */ private ShutdownThread() { + } + + /* ------------------------------------------------------------ */ + private synchronized void hook() + { try - { - Runtime.getRuntime().addShutdownHook(this); - } - catch(Exception e) - { - Log.ignore(e); - Log.info("shutdown already commenced"); - } + { + if (!_hooked) + Runtime.getRuntime().addShutdownHook(this); + _hooked=true; + } + catch(Exception e) + { + Log.ignore(e); + Log.info("shutdown already commenced"); + } } - + + /* ------------------------------------------------------------ */ + private synchronized void unhook() + { + try + { + _hooked=false; + Runtime.getRuntime().removeShutdownHook(this); + } + catch(Exception e) + { + Log.ignore(e); + Log.info("shutdown already commenced"); + } + } + /* ------------------------------------------------------------ */ /** * Returns the instance of the singleton @@ -71,18 +94,24 @@ public class ShutdownThread extends Thread public static synchronized void register(LifeCycle... lifeCycles) { _thread._lifeCycles.addAll(Arrays.asList(lifeCycles)); + if (_thread._lifeCycles.size()>0) + _thread.hook(); } /* ------------------------------------------------------------ */ public static synchronized void register(int index, LifeCycle... lifeCycles) { _thread._lifeCycles.addAll(index,Arrays.asList(lifeCycles)); + if (_thread._lifeCycles.size()>0) + _thread.hook(); } /* ------------------------------------------------------------ */ public static synchronized void deregister(LifeCycle lifeCycle) { _thread._lifeCycles.remove(lifeCycle); + if (_thread._lifeCycles.size()==0) + _thread.unhook(); } /* ------------------------------------------------------------ */ @@ -101,11 +130,4 @@ public class ShutdownThread extends Thread } } } - - /* ------------------------------------------------------------ */ - protected Object readResolve() - throws ObjectStreamException - { - return _thread; - } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ArrayQueueTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ArrayQueueTest.java index f79c618564..028208bd32 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ArrayQueueTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ArrayQueueTest.java @@ -13,11 +13,16 @@ package org.eclipse.jetty.util; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; -public class ArrayQueueTest extends TestCase +import org.junit.Test; + + +public class ArrayQueueTest { - + @Test public void testWrap() throws Exception { ArrayQueue<String> queue = new ArrayQueue<String>(3,3); @@ -63,6 +68,7 @@ public class ArrayQueueTest extends TestCase } + @Test public void testRemove() throws Exception { ArrayQueue<String> queue = new ArrayQueue<String>(3,3); @@ -82,6 +88,7 @@ public class ArrayQueueTest extends TestCase assertEquals(i+"!",queue.get(i)); } + @Test public void testGrow() throws Exception { ArrayQueue<String> queue = new ArrayQueue<String>(3,5); @@ -123,10 +130,9 @@ public class ArrayQueueTest extends TestCase for (int i=0;i<12;i++) queue.add(""+('a'+i)); assertEquals(13,queue.getCapacity()); - - } + @Test public void testFullEmpty() throws Exception { ArrayQueue<String> queue = new ArrayQueue<String>(2); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/BlockingArrayQueueTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/BlockingArrayQueueTest.java index a7ae482adc..7daee8f5c5 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/BlockingArrayQueueTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/BlockingArrayQueueTest.java @@ -13,17 +13,22 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.util.HashSet; import java.util.Random; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; -import junit.framework.TestCase; +import org.junit.Test; + -public class BlockingArrayQueueTest extends TestCase +public class BlockingArrayQueueTest { + @Test public void testWrap() throws Exception { BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(3); @@ -66,6 +71,7 @@ public class BlockingArrayQueueTest extends TestCase } + @Test public void testRemove() throws Exception { BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(3,3); @@ -85,6 +91,7 @@ public class BlockingArrayQueueTest extends TestCase assertEquals(i+"!",queue.get(i)); } + @Test public void testGrow() throws Exception { BlockingArrayQueue<String> queue = new BlockingArrayQueue<String>(3,2); @@ -128,11 +135,9 @@ public class BlockingArrayQueueTest extends TestCase s+=2; c+=2; } - - - } + @Test public void testTake() throws Exception { final String[] data=new String[4]; @@ -178,6 +183,7 @@ public class BlockingArrayQueueTest extends TestCase volatile boolean _running; + @Test public void testConcurrentAccess() throws Exception { final int THREADS=50; @@ -306,9 +312,5 @@ public class BlockingArrayQueueTest extends TestCase HashSet<Integer> consSet = new HashSet<Integer>(consumed); assertEquals(prodSet,consSet); - - - - } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/DateCacheTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/DateCacheTest.java index e49eff036e..15284fd249 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/DateCacheTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/DateCacheTest.java @@ -13,37 +13,23 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.util.Locale; import java.util.TimeZone; -import junit.framework.TestSuite; +import org.junit.Test; /* ------------------------------------------------------------ */ /** Util meta Tests. * */ -public class DateCacheTest extends junit.framework.TestCase +public class DateCacheTest { - public DateCacheTest(String name) - { - super(name); - } - - public static junit.framework.Test suite() { - TestSuite suite = new TestSuite(DateCacheTest.class); - return suite; - } - - /* ------------------------------------------------------------ */ - /** main. - */ - public static void main(String[] args) - { - junit.textui.TestRunner.run(suite()); - } - /* ------------------------------------------------------------ */ + @Test public void testDateCache() throws Exception { //@WAS: Test t = new Test("org.eclipse.jetty.util.DateCache"); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/IPAddressMapTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/IPAddressMapTest.java new file mode 100644 index 0000000000..f1ade99091 --- /dev/null +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/IPAddressMapTest.java @@ -0,0 +1,172 @@ +// ======================================================================== +// Copyright (c) 2010 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.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.junit.Test; + + +public class IPAddressMapTest +{ + @Test + public void testOneAddress() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("10.5.2.1","1"); + + assertNotNull(map.match("10.5.2.1")); + + assertNull(map.match("101.5.2.1")); + assertNull(map.match("10.15.2.1")); + assertNull(map.match("10.5.22.1")); + assertNull(map.match("10.5.2.0")); + } + + /* ------------------------------------------------------------ */ + @Test + public void testOneRange() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("1-15.16-31.32-63.64-127","1"); + + assertNotNull(map.match("7.23.39.71")); + assertNotNull(map.match("1.16.32.64")); + assertNotNull(map.match("15.31.63.127")); + + assertNull(map.match("16.32.64.128")); + assertNull(map.match("1.16.32.63")); + assertNull(map.match("1.16.31.64")); + assertNull(map.match("1.15.32.64")); + assertNull(map.match("0.16.32.64")); + } + + /* ------------------------------------------------------------ */ + @Test + public void testOneMissing() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("10.5.2.","1"); + + assertNotNull(map.match("10.5.2.0")); + assertNotNull(map.match("10.5.2.128")); + assertNotNull(map.match("10.5.2.255")); + } + + /* ------------------------------------------------------------ */ + @Test + public void testTwoMissing() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("10.5.","1"); + + assertNotNull(map.match("10.5.2.0")); + assertNotNull(map.match("10.5.2.128")); + assertNotNull(map.match("10.5.2.255")); + assertNotNull(map.match("10.5.0.1")); + assertNotNull(map.match("10.5.128.1")); + assertNotNull(map.match("10.5.255.1")); + } + + /* ------------------------------------------------------------ */ + @Test + public void testThreeMissing() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("10.","1"); + + assertNotNull(map.match("10.5.2.0")); + assertNotNull(map.match("10.5.2.128")); + assertNotNull(map.match("10.5.2.255")); + assertNotNull(map.match("10.5.0.1")); + assertNotNull(map.match("10.5.128.1")); + assertNotNull(map.match("10.5.255.1")); + assertNotNull(map.match("10.0.1.1")); + assertNotNull(map.match("10.128.1.1")); + assertNotNull(map.match("10.255.1.1")); + } + + /* ------------------------------------------------------------ */ + @Test + public void testOneMixed() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("0-15,21.10,16-31.0-15,32-63.-95,128-","1"); + + assertNotNull(map.match("7.23.39.46")); + assertNotNull(map.match("10.20.10.150")); + assertNotNull(map.match("21.10.32.255")); + assertNotNull(map.match("21.10.15.0")); + + assertNull(map.match("16.15.20.100")); + assertNull(map.match("15.10.63.100")); + assertNull(map.match("15.10.64.128")); + assertNull(map.match("15.11.32.95")); + assertNull(map.match("16.31.63.128")); + } + + /* ------------------------------------------------------------ */ + @Test + public void testManyMixed() + { + IPAddressMap<String> map = new IPAddressMap(); + + map.put("10.5.2.1","1"); + map.put("1-15.16-31.32-63.64-127","2"); + map.put("1-15,21.10,16-31.0-15,32-63.-55,195-","3"); + map.put("44.99.99.","4"); + map.put("55.99.","5"); + map.put("66.","6"); + + assertEquals("1", map.match("10.5.2.1")); + + assertEquals("2", map.match("7.23.39.71")); + assertEquals("2", map.match("1.16.32.64")); + assertEquals("2", map.match("15.31.63.127")); + + assertEquals("3", map.match("7.23.39.46")); + assertEquals("3", map.match("10.20.10.200")); + assertEquals("3", map.match("21.10.32.255")); + assertEquals("3", map.match("21.10.15.0")); + + assertEquals("4", map.match("44.99.99.0")); + assertEquals("5", map.match("55.99.128.1")); + assertEquals("6", map.match("66.255.1.1")); + + assertNull(map.match("101.5.2.1")); + assertNull(map.match("10.15.2.1")); + assertNull(map.match("10.5.22.1")); + assertNull(map.match("10.5.2.0")); + + assertNull(map.match("16.32.64.96")); + assertNull(map.match("1.16.32.194")); + assertNull(map.match("1.16.31.64")); + assertNull(map.match("1.15.32.64")); + assertNull(map.match("0.16.32.64")); + + assertNull(map.match("16.15.20.100")); + assertNull(map.match("15.10.63.100")); + assertNull(map.match("15.10.64.128")); + assertNull(map.match("15.11.32.95")); + assertNull(map.match("16.31.63.128")); + } +} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/LazyListTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/LazyListTest.java index 4f1613e6e4..93716a4a74 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/LazyListTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/LazyListTest.java @@ -13,32 +13,28 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; -import junit.framework.TestCase; +import org.junit.Test; + /** * * */ -public class LazyListTest extends TestCase +public class LazyListTest { - - /** - * Constructor for LazyListTest. - * @param arg0 - */ - public LazyListTest(String arg0) - { - super(arg0); - } - /* * Test for Object add(Object, Object) */ + @Test public void testAddObjectObject() { Object list=null; @@ -79,6 +75,7 @@ public class LazyListTest extends TestCase /* * Test for Object add(Object, int, Object) */ + @Test public void testAddObjectintObject() { Object list=null; @@ -100,7 +97,7 @@ public class LazyListTest extends TestCase assertTrue(list instanceof List); } - + @Test public void testAddCollection() { ArrayList l=new ArrayList(); @@ -118,6 +115,7 @@ public class LazyListTest extends TestCase assertEquals("b",LazyList.get(list,3)); } + @Test public void testEnsureSize() { assertTrue(LazyList.ensureSize(null,10)!=null); @@ -134,6 +132,7 @@ public class LazyListTest extends TestCase /* * Test for Object remove(Object, Object) */ + @Test public void testRemoveObjectObject() { Object list=null; @@ -166,6 +165,7 @@ public class LazyListTest extends TestCase /* * Test for Object remove(Object, int) */ + @Test public void testRemoveObjectint() { Object list=null; @@ -197,6 +197,7 @@ public class LazyListTest extends TestCase /* * Test for List getList(Object) */ + @Test public void testGetListObject() { assertEquals(0,LazyList.getList(null).size()); @@ -211,12 +212,14 @@ public class LazyListTest extends TestCase /* * Test for List getList(Object, boolean) */ + @Test public void testGetListObjectboolean() { assertEquals(0,LazyList.getList(null,false).size()); assertEquals(null,LazyList.getList(null,true)); } + @Test public void testToStringArray() { assertEquals(0,LazyList.toStringArray(null).length); @@ -237,6 +240,7 @@ public class LazyListTest extends TestCase } + @Test public void testSize() { ArrayList l=new ArrayList(); @@ -249,6 +253,7 @@ public class LazyListTest extends TestCase assertEquals(2,LazyList.size(l)); } + @Test public void testGet() { testAddObjectObject(); @@ -274,6 +279,7 @@ public class LazyListTest extends TestCase } } + @Test public void testContains() { ArrayList l=new ArrayList(); @@ -289,8 +295,7 @@ public class LazyListTest extends TestCase } - - + @Test public void testIterator() { ArrayList l=new ArrayList(); @@ -312,6 +317,7 @@ public class LazyListTest extends TestCase assertFalse(i.hasNext()); } + @Test public void testListIterator() { ArrayList l=new ArrayList(); @@ -341,6 +347,7 @@ public class LazyListTest extends TestCase assertEquals("a",i.previous()); } + @Test public void testCloneToString() { ArrayList l=new ArrayList(); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiExceptionTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiExceptionTest.java index 8bbc66aa99..7777a6779a 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiExceptionTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiExceptionTest.java @@ -3,9 +3,16 @@ package org.eclipse.jetty.util; import java.io.IOException; import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; -public class MultiExceptionTest extends TestCase +import org.junit.Test; + + +public class MultiExceptionTest { + @Test public void testEmpty() throws Exception { MultiException me = new MultiException(); @@ -16,6 +23,7 @@ public class MultiExceptionTest extends TestCase me.ifExceptionThrowRuntime(); } + @Test public void testOne() throws Exception { MultiException me = new MultiException(); @@ -69,6 +77,7 @@ public class MultiExceptionTest extends TestCase } } + @Test public void testTwo() throws Exception { MultiException me = new MultiException(); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/QuotedStringTokenizerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/QuotedStringTokenizerTest.java index 8c2253163a..a6c03c7468 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/QuotedStringTokenizerTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/QuotedStringTokenizerTest.java @@ -13,27 +13,23 @@ package org.eclipse.jetty.util; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + /** * * */ -public class QuotedStringTokenizerTest extends TestCase +public class QuotedStringTokenizerTest { - - /** - * Constructor for QuotedStringTokenizerTest. - * @param arg0 - */ - public QuotedStringTokenizerTest(String arg0) - { - super(arg0); - } - /* * Test for String nextToken() */ + @Test public void testTokenizer0() { QuotedStringTokenizer tok = @@ -44,6 +40,7 @@ public class QuotedStringTokenizerTest extends TestCase /* * Test for String nextToken() */ + @Test public void testTokenizer1() { QuotedStringTokenizer tok = @@ -55,6 +52,7 @@ public class QuotedStringTokenizerTest extends TestCase /* * Test for String nextToken() */ + @Test public void testTokenizer2() { QuotedStringTokenizer tok = @@ -70,6 +68,7 @@ public class QuotedStringTokenizerTest extends TestCase /* * Test for String nextToken() */ + @Test public void testTokenizer3() { QuotedStringTokenizer tok; @@ -91,6 +90,7 @@ public class QuotedStringTokenizerTest extends TestCase checkTok(tok,true,true); } + @Test public void testQuote() { StringBuffer buf = new StringBuffer(); @@ -108,11 +108,11 @@ public class QuotedStringTokenizerTest extends TestCase assertEquals("\"abcefg\\\"\"",buf.toString()); buf.setLength(0); - QuotedStringTokenizer.quoteIfNeeded(buf,"abc \n efg"); + QuotedStringTokenizer.quoteIfNeeded(buf,"abc \n efg","\"\\\n\r\t\f\b%+ ;="); assertEquals("\"abc \\n efg\"",buf.toString()); buf.setLength(0); - QuotedStringTokenizer.quoteIfNeeded(buf,"abcefg"); + QuotedStringTokenizer.quoteIfNeeded(buf,"abcefg","\"\\\n\r\t\f\b%+ ;="); assertEquals("abcefg",buf.toString()); } @@ -120,6 +120,7 @@ public class QuotedStringTokenizerTest extends TestCase /* * Test for String nextToken() */ + @Test public void testTokenizer4() { QuotedStringTokenizer tok = new QuotedStringTokenizer("abc'def,ghi'jkl",","); @@ -150,15 +151,16 @@ public class QuotedStringTokenizerTest extends TestCase /* * Test for String quote(String, String) */ + @Test public void testQuoteString() { - assertEquals("abc",QuotedStringTokenizer.quote("abc", " ,")); - assertEquals("\"a c\"",QuotedStringTokenizer.quote("a c", " ,")); - assertEquals("\"a'c\"",QuotedStringTokenizer.quote("a'c", " ,")); + assertEquals("abc",QuotedStringTokenizer.quoteIfNeeded("abc", " ,")); + assertEquals("\"a c\"",QuotedStringTokenizer.quoteIfNeeded("a c", " ,")); + assertEquals("\"a'c\"",QuotedStringTokenizer.quoteIfNeeded("a'c", " ,")); assertEquals("\"a\\n\\r\\t\"",QuotedStringTokenizer.quote("a\n\r\t")); } - + @Test public void testUnquote() { assertEquals("abc",QuotedStringTokenizer.unquote("abc")); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/RunningStatsTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/RunningStatsTest.java deleted file mode 100644 index e69de29bb2..0000000000 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/RunningStatsTest.java +++ /dev/null diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java index ce27d67600..5f0c075f98 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/StringMapTest.java @@ -13,6 +13,10 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; @@ -20,37 +24,28 @@ import java.io.ObjectOutputStream; import java.util.Map; import java.util.Set; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; /** * * */ -public class StringMapTest extends TestCase +public class StringMapTest { StringMap m0; StringMap m1; StringMap m5; StringMap m5i; - /** - * Constructor for StringMapTest. - * @param arg0 - */ - public StringMapTest(String arg0) - { - super(arg0); - } - /* * @see TestCase#setUp() */ - @Override - protected void setUp() throws Exception + + @Before + public void setUp() throws Exception { - super.setUp(); - m0=new StringMap(); m1=new StringMap(false); m1.put("abc", "0"); @@ -70,15 +65,7 @@ public class StringMapTest extends TestCase m5i.put("bbb", null); } - /* - * @see TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - } - + @Test public void testSize() { assertEquals(0, m0.size()); @@ -96,6 +83,7 @@ public class StringMapTest extends TestCase assertEquals(5, m5i.size()); } + @Test public void testIsEmpty() { assertTrue(m0.isEmpty()); @@ -104,6 +92,7 @@ public class StringMapTest extends TestCase assertFalse(m5i.isEmpty()); } + @Test public void testClear() { m0.clear(); @@ -123,6 +112,7 @@ public class StringMapTest extends TestCase /* * Test for Object put(Object, Object) */ + @Test public void testPutGet() { assertEquals("2",m5.get("abc")); @@ -146,11 +136,10 @@ public class StringMapTest extends TestCase } - - /* * Test for Map.Entry getEntry(String, int, int) */ + @Test public void testGetEntryStringintint() { Map.Entry entry; @@ -187,6 +176,7 @@ public class StringMapTest extends TestCase /* * Test for Map.Entry getEntry(char[], int, int) */ + @Test public void testGetEntrycharArrayintint() { char[] xabcyz = {'x','a','b','c','y','z'}; @@ -210,6 +200,7 @@ public class StringMapTest extends TestCase /* * Test for Object remove(Object) */ + @Test public void testRemove() { m0.remove("abc"); @@ -230,10 +221,10 @@ public class StringMapTest extends TestCase assertEquals(null,m5i.get(null)); } - /* * Test for Set entrySet() */ + @Test public void testEntrySet() { Set es0=m0.entrySet(); @@ -247,6 +238,7 @@ public class StringMapTest extends TestCase /* * Test for boolean containsKey(Object) */ + @Test public void testContainsKey() { assertTrue(m5.containsKey("abc")); @@ -260,6 +252,7 @@ public class StringMapTest extends TestCase assertTrue(m5i.containsKey("ABC")); } + @Test public void testWriteExternal() throws Exception { @@ -288,6 +281,7 @@ public class StringMapTest extends TestCase } + @Test public void testToString() { assertEquals("{}",m0.toString()); @@ -295,7 +289,7 @@ public class StringMapTest extends TestCase assertTrue(m5.toString().indexOf("abc=2")>0); } - + @Test public void testIgnoreCase() { StringMap map = new StringMap(true); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java index 10d2a51bdb..52d9f8fb9a 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/StringUtilTest.java @@ -13,43 +13,20 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; -import junit.framework.TestCase; /** * * */ -public class StringUtilTest extends TestCase +public class StringUtilTest { - - /** - * Constructor for StringUtilTest. - * @param arg0 - */ - public StringUtilTest(String arg0) - { - super(arg0); - } - - /* - * @see TestCase#setUp() - */ - @Override - protected void setUp() throws Exception - { - super.setUp(); - } - - /* - * @see TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - } - + @Test public void testAsciiToLowerCase() { String lc="\u0690bc def 1\u06903"; @@ -57,6 +34,7 @@ public class StringUtilTest extends TestCase assertTrue(StringUtil.asciiToLowerCase(lc)==lc); } + @Test public void testStartsWithIgnoreCase() { @@ -74,6 +52,7 @@ public class StringUtilTest extends TestCase assertFalse(StringUtil.startsWithIgnoreCase("\u0690", "xyz")); } + @Test public void testEndsWithIgnoreCase() { assertTrue(StringUtil.endsWithIgnoreCase("\u0690bcd\u0690f\u0690", "\u0690f\u0690")); @@ -90,6 +69,7 @@ public class StringUtilTest extends TestCase assertFalse(StringUtil.endsWithIgnoreCase("\u0690", "xyz")); } + @Test public void testIndexFrom() { assertEquals(StringUtil.indexFrom("\u0690bcd", "xyz"),-1); @@ -98,6 +78,7 @@ public class StringUtilTest extends TestCase assertEquals(StringUtil.indexFrom("\u0690bcd", "dxy"),3); } + @Test public void testReplace() { String s="\u0690bc \u0690bc \u0690bc"; @@ -109,6 +90,7 @@ public class StringUtilTest extends TestCase } + @Test public void testUnquote() { String uq =" not quoted "; @@ -120,6 +102,7 @@ public class StringUtilTest extends TestCase } + @Test public void testNonNull() { String nn=""; @@ -130,12 +113,14 @@ public class StringUtilTest extends TestCase /* * Test for boolean equals(String, char[], int, int) */ + @Test public void testEqualsStringcharArrayintint() { assertTrue(StringUtil.equals("\u0690bc", new char[] {'x','\u0690','b','c','z'},1,3)); assertFalse(StringUtil.equals("axc", new char[] {'x','a','b','c','z'},1,3)); } + @Test public void testAppend() { StringBuilder buf = new StringBuilder(); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/TestIntrospectionUtil.java b/jetty-util/src/test/java/org/eclipse/jetty/util/TestIntrospectionUtil.java index 91ed6f3acf..e85ee76a16 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/TestIntrospectionUtil.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/TestIntrospectionUtil.java @@ -13,35 +13,40 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + import java.lang.reflect.Field; import java.lang.reflect.Method; -import junit.framework.TestCase; +import org.junit.BeforeClass; +import org.junit.Test; + /** * TestInjection * * */ -public class TestIntrospectionUtil extends TestCase +public class TestIntrospectionUtil { - public final Class[] __INTEGER_ARG = new Class[] {Integer.class}; - Field privateAField; - Field protectedAField; - Field publicAField; - Field defaultAField; - Field privateBField; - Field protectedBField; - Field publicBField; - Field defaultBField; - Method privateCMethod; - Method protectedCMethod; - Method publicCMethod; - Method defaultCMethod; - Method privateDMethod; - Method protectedDMethod; - Method publicDMethod; - Method defaultDMethod; + public final static Class[] __INTEGER_ARG = new Class[] {Integer.class}; + static Field privateAField; + static Field protectedAField; + static Field publicAField; + static Field defaultAField; + static Field privateBField; + static Field protectedBField; + static Field publicBField; + static Field defaultBField; + static Method privateCMethod; + static Method protectedCMethod; + static Method publicCMethod; + static Method defaultCMethod; + static Method privateDMethod; + static Method protectedDMethod; + static Method publicDMethod; + static Method defaultDMethod; public class ServletA { @@ -75,8 +80,8 @@ public class TestIntrospectionUtil extends TestCase void setDefaultD(Integer d) {} } - @Override - public void setUp() + @BeforeClass + public static void setUp() throws Exception { privateAField = ServletA.class.getDeclaredField("privateA"); @@ -97,7 +102,7 @@ public class TestIntrospectionUtil extends TestCase defaultDMethod = ServletD.class.getDeclaredMethod("setDefaultD", __INTEGER_ARG); } - + @Test public void testFieldPrivate () throws Exception { @@ -117,6 +122,7 @@ public class TestIntrospectionUtil extends TestCase } } + @Test public void testFieldProtected() throws Exception { @@ -129,6 +135,7 @@ public class TestIntrospectionUtil extends TestCase assertEquals(f, protectedAField); } + @Test public void testFieldPublic() throws Exception { @@ -141,6 +148,7 @@ public class TestIntrospectionUtil extends TestCase assertEquals(f, publicAField); } + @Test public void testFieldDefault() throws Exception { @@ -153,6 +161,7 @@ public class TestIntrospectionUtil extends TestCase assertEquals(f, defaultAField); } + @Test public void testMethodPrivate () throws Exception { @@ -172,6 +181,7 @@ public class TestIntrospectionUtil extends TestCase } } + @Test public void testMethodProtected () throws Exception { @@ -184,6 +194,7 @@ public class TestIntrospectionUtil extends TestCase assertEquals(m, protectedCMethod); } + @Test public void testMethodPublic () throws Exception { @@ -196,6 +207,7 @@ public class TestIntrospectionUtil extends TestCase assertEquals(m, publicCMethod); } + @Test public void testMethodDefault () throws Exception { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URITest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URITest.java index 80624ebf07..79f350ff1c 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/URITest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URITest.java @@ -13,34 +13,19 @@ package org.eclipse.jetty.util; -import junit.framework.TestSuite; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; /* ------------------------------------------------------------ */ /** Util meta Tests. * */ -public class URITest extends junit.framework.TestCase +public class URITest { - public URITest(String name) - { - super(name); - } - - public static junit.framework.Test suite() { - TestSuite suite = new TestSuite(URITest.class); - return suite; - } - - /* ------------------------------------------------------------ */ - /** main. - */ - public static void main(String[] args) - { - junit.textui.TestRunner.run(suite()); - } - /* ------------------------------------------------------------ */ + @Test public void testEncodePath() { // test basic encode/decode @@ -63,6 +48,7 @@ public class URITest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testDecodePath() { assertEquals("foo%23;,:=b a r",URIUtil.decodePath("foo%2523%3b%2c:%3db%20a%20r")); @@ -72,6 +58,7 @@ public class URITest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testAddPaths() { assertEquals("null+null", URIUtil.addPaths(null,null),null); @@ -161,6 +148,7 @@ public class URITest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testCompactPath() { assertEquals("/foo/bar", URIUtil.compactPath("/foo/bar")); @@ -174,6 +162,7 @@ public class URITest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testParentPath() { assertEquals("parent /aaa/bbb/","/aaa/", URIUtil.parentPath("/aaa/bbb/")); @@ -186,6 +175,7 @@ public class URITest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testCanonicalPath() { String[][] canonical = diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java index 43d7a5d9f1..bee8052f4d 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java @@ -13,38 +13,23 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.io.ByteArrayInputStream; import java.io.UnsupportedEncodingException; -import junit.framework.TestSuite; +import org.junit.Test; /* ------------------------------------------------------------ */ /** Util meta Tests. * */ -public class URLEncodedTest extends junit.framework.TestCase +public class URLEncodedTest { - public URLEncodedTest(String name) - { - super(name); - } - - public static junit.framework.Test suite() { - TestSuite suite = new TestSuite(URLEncodedTest.class); - return suite; - } - - /* ------------------------------------------------------------ */ - /** main. - */ - public static void main(String[] args) - { - junit.textui.TestRunner.run(suite()); - } - - /* -------------------------------------------------------------- */ + @Test public void testUrlEncoded() throws UnsupportedEncodingException { @@ -147,6 +132,7 @@ public class URLEncodedTest extends junit.framework.TestCase /* -------------------------------------------------------------- */ + @Test public void testUrlEncodedStream() throws Exception { @@ -185,6 +171,7 @@ public class URLEncodedTest extends junit.framework.TestCase } /* -------------------------------------------------------------- */ + @Test public void testUtf8() throws Exception { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBufferTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBufferTest.java index 2b65d76185..8601e6205f 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBufferTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBufferTest.java @@ -13,10 +13,14 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; -public class Utf8StringBufferTest extends junit.framework.TestCase -{ +public class Utf8StringBufferTest +{ public void testUtfStringBuffer() throws Exception { @@ -30,6 +34,7 @@ public class Utf8StringBufferTest extends junit.framework.TestCase } + @Test public void testShort() throws Exception { @@ -49,6 +54,7 @@ public class Utf8StringBufferTest extends junit.framework.TestCase } } + @Test public void testLong() throws Exception { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBuilderTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBuilderTest.java index 4a20865f4b..6240218945 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBuilderTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/Utf8StringBuilderTest.java @@ -13,10 +13,15 @@ package org.eclipse.jetty.util; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; -public class Utf8StringBuilderTest extends junit.framework.TestCase -{ +public class Utf8StringBuilderTest +{ + @Test public void testUtfStringBuilder() throws Exception { @@ -29,6 +34,7 @@ public class Utf8StringBuilderTest extends junit.framework.TestCase assertTrue(buffer.toString().endsWith("jetty")); } + @Test public void testShort() throws Exception { @@ -48,6 +54,7 @@ public class Utf8StringBuilderTest extends junit.framework.TestCase } } + @Test public void testLong() throws Exception { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactoryTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactoryTest.java index aea0c8f8c3..c4d78105c3 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactoryTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorFactoryTest.java @@ -13,14 +13,18 @@ package org.eclipse.jetty.util.ajax; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; /** * Test to convert POJOs to JSON and vice versa with automatic convertor creation. */ -public class JSONPojoConvertorFactoryTest extends TestCase { - +public class JSONPojoConvertorFactoryTest +{ + @Test public void testFoo() { JSON jsonOut = new JSON(); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorTest.java index 3f193ba280..4fdd24cbda 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONPojoConvertorTest.java @@ -13,15 +13,20 @@ package org.eclipse.jetty.util.ajax; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + + /** * Test to converts POJOs to JSON and vice versa. - * - * - * */ -public class JSONPojoConvertorTest extends TestCase +public class JSONPojoConvertorTest { + @Test public void testFoo() { JSON json = new JSON(); @@ -66,6 +71,7 @@ public class JSONPojoConvertorTest extends TestCase assertEquals(Color.Green,br.getColor()); } + @Test public void testExclude() { JSON json = new JSON(); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONTest.java index 0b77acc962..3c1799fb3d 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ajax/JSONTest.java @@ -12,6 +12,10 @@ // ======================================================================== package org.eclipse.jetty.util.ajax; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.io.StringReader; import java.lang.reflect.Array; import java.math.BigDecimal; @@ -21,12 +25,13 @@ import java.util.Locale; import java.util.Map; import java.util.TimeZone; -import junit.framework.TestCase; - import org.eclipse.jetty.util.DateCache; import org.eclipse.jetty.util.ajax.JSON.Output; +import org.junit.BeforeClass; +import org.junit.Test; -public class JSONTest extends TestCase + +public class JSONTest { String test="\n\n\n\t\t "+ "// ignore this ,a [ \" \n"+ @@ -45,6 +50,17 @@ public class JSONTest extends TestCase "\"undefined\": undefined," + "}"; + /* ------------------------------------------------------------ */ + /* (non-Javadoc) + * @see junit.framework.TestCase#setUp() + */ + @BeforeClass + public static void setUp() throws Exception + { + JSON.registerConvertor(Gadget.class,new JSONObjectConvertor(false)); + } + + @Test public void testToString() { HashMap map = new HashMap(); @@ -94,26 +110,16 @@ public class JSONTest extends TestCase gadget.setWoggles(new Woggle[]{w0,w1}); s = JSON.toString(new Gadget[]{gadget}); + System.out.println(s); assertTrue(s.startsWith("[")); assertTrue(s.indexOf("\"modulated\":false")>=0); assertTrue(s.indexOf("\"shields\":42")>=0); assertTrue(s.indexOf("\"name\":\"woggle0\"")>=0); assertTrue(s.indexOf("\"name\":\"woggle1\"")>=0); - - } - - - - /* ------------------------------------------------------------ */ - /* (non-Javadoc) - * @see junit.framework.TestCase#setUp() - */ - protected void setUp() throws Exception - { - JSON.registerConvertor(Gadget.class,new JSONObjectConvertor(false)); } /* ------------------------------------------------------------ */ + @Test public void testParse() { Map map = (Map)JSON.parse(test); @@ -134,6 +140,7 @@ public class JSONTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testParseReader() throws Exception { Map map = (Map)JSON.parse(new StringReader(test)); @@ -149,6 +156,7 @@ public class JSONTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testStripComment() { String test="\n\n\n\t\t "+ @@ -171,6 +179,7 @@ public class JSONTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testQuote() { String test="\"abc123|\\\"|\\\\|\\/|\\b|\\f|\\n|\\r|\\t|\\uaaaa|\""; @@ -180,6 +189,7 @@ public class JSONTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testBigDecimal() { Object obj = JSON.parse("1.0E7"); @@ -247,6 +257,7 @@ public class JSONTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testConvertor() { // test case#1 - force timezone to GMT @@ -316,6 +327,7 @@ public class JSONTest extends TestCase enum Color { Red, Green, Blue }; + @Test public void testEnumConvertor() { JSON json = new JSON(); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerTest.java index d70d35741b..9bc149c1f5 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerTest.java @@ -13,34 +13,20 @@ package org.eclipse.jetty.util.component; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; -import junit.textui.TestRunner; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.StdErrLog; +import org.junit.Test; -public class LifeCycleListenerTest extends TestCase + +public class LifeCycleListenerTest { static Exception cause = new Exception("expected test exception"); - public LifeCycleListenerTest(String name) - { - super(name); - } - - public static void main(String[] args) - { - TestRunner.run(suite()); - } - - public static Test suite() - { - TestSuite suite = new TestSuite(LifeCycleListenerTest.class); - return suite; - } - + @Test public void testStart() throws Exception { TestLifeCycle lifecycle = new TestLifeCycle(); @@ -78,6 +64,7 @@ public class LifeCycleListenerTest extends TestCase assertTrue("The lifecycle state is not started",lifecycle.isStarted()); } + @Test public void testStop() throws Exception { TestLifeCycle lifecycle = new TestLifeCycle(); @@ -126,6 +113,7 @@ public class LifeCycleListenerTest extends TestCase } + @Test public void testRemoveLifecycleListener () throws Exception { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/log/LogTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/log/LogTest.java index a200721ffb..957eaee595 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/log/LogTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/log/LogTest.java @@ -13,26 +13,31 @@ package org.eclipse.jetty.util.log; +import static org.junit.Assert.assertTrue; + import java.io.ByteArrayOutputStream; import java.io.PrintStream; -import junit.framework.TestCase; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + -public class LogTest extends TestCase +public class LogTest { - PrintStream _orig= System.err; - ByteArrayOutputStream _out = new ByteArrayOutputStream(); - PrintStream _pout = new PrintStream(_out); + static PrintStream _orig= System.err; + static ByteArrayOutputStream _out = new ByteArrayOutputStream(); + static PrintStream _pout = new PrintStream(_out); - @Override - public void setUp() + @BeforeClass + public static void setUp() { System.setErr(_pout); } - @Override - public void tearDown() + @AfterClass + public static void tearDown() { System.setErr(_orig); } @@ -64,6 +69,7 @@ public class LogTest extends TestCase assertTrue(false); } + @Test public void testStdErrLogFormat() { StdErrLog log = new StdErrLog("test"); @@ -90,6 +96,7 @@ public class LogTest extends TestCase logContains("INFO:test:testing"); } + @Test public void testStdErrLogDebug() { StdErrLog log = new StdErrLog("xxx"); @@ -109,6 +116,7 @@ public class LogTest extends TestCase logNotContains("YOU SHOULD NOT SEE THIS!"); } + @Test public void testStdErrLogName() { StdErrLog log = new StdErrLog("test"); @@ -119,6 +127,7 @@ public class LogTest extends TestCase } + @Test public void testStdErrThrowable() { Throwable th = new Throwable("Message"); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceCollectionTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceCollectionTest.java index 9317e51c39..7bc940bbac 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceCollectionTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceCollectionTest.java @@ -18,10 +18,20 @@ import java.io.File; import java.io.InputStreamReader; import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -public class ResourceCollectionTest extends TestCase +import org.junit.Test; +import org.junit.BeforeClass; +import org.junit.AfterClass; + +public class ResourceCollectionTest { + @Test public void testMutlipleSources1() throws Exception { ResourceCollection rc1 = new ResourceCollection(new String[]{ @@ -47,6 +57,7 @@ public class ResourceCollectionTest extends TestCase System.err.println(s); } + @Test public void testMergedDir() throws Exception { ResourceCollection rc = new ResourceCollection(new String[]{ @@ -63,6 +74,7 @@ public class ResourceCollectionTest extends TestCase assertEquals("3 - three", getContent(rc, "3.txt")); } + @Test public void testCopyTo() throws Exception { ResourceCollection rc = new ResourceCollection(new String[]{ diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java index 19f505efc4..6eadcb76c4 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java @@ -13,6 +13,10 @@ package org.eclipse.jetty.util.resource; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FilePermission; @@ -24,8 +28,11 @@ import java.util.jar.JarInputStream; import junit.framework.TestSuite; import org.eclipse.jetty.util.IO; +import org.junit.BeforeClass; +import org.junit.Test; -public class ResourceTest extends junit.framework.TestCase + +public class ResourceTest { public static String __userDir = System.getProperty("basedir", "."); @@ -36,7 +43,7 @@ public class ResourceTest extends junit.framework.TestCase private static final boolean DIR=true; private static final boolean EXISTS=true; - class Data + static class Data { Resource resource; String test; @@ -93,27 +100,10 @@ public class ResourceTest extends junit.framework.TestCase } public static Data[] data; - - public ResourceTest(String name) - { - super(name); - } - - /* ------------------------------------------------------------ */ - public static void main(String[] args) - { - junit.textui.TestRunner.run(suite()); - } - - /* ------------------------------------------------------------ */ - public static junit.framework.Test suite() - { - return new TestSuite(ResourceTest.class); - } /* ------------------------------------------------------------ */ - @Override - protected void setUp() + @BeforeClass + public static void setUp() throws Exception { if (data!=null) @@ -189,16 +179,8 @@ public class ResourceTest extends junit.framework.TestCase } - - /* ------------------------------------------------------------ */ - @Override - protected void tearDown() - throws Exception - { - } - - /* ------------------------------------------------------------ */ + @Test public void testResourceExists() { for (int i=0;i<data.length;i++) @@ -211,6 +193,7 @@ public class ResourceTest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testResourceDir() { for (int i=0;i<data.length;i++) @@ -223,6 +206,7 @@ public class ResourceTest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testResourceContent() throws Exception { @@ -238,6 +222,7 @@ public class ResourceTest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testEncoding() throws Exception { Resource r =Resource.newResource("/tmp/a file with,spe#ials/"); @@ -246,6 +231,7 @@ public class ResourceTest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testJarFile() throws Exception { @@ -256,9 +242,9 @@ public class ResourceTest extends junit.framework.TestCase JarInputStream jin = new JarInputStream(is); assertNotNull(is); assertNotNull(jin); - } + @Test public void testJarFileIsContainedIn () throws Exception { @@ -276,6 +262,7 @@ public class ResourceTest extends junit.framework.TestCase } /* ------------------------------------------------------------ */ + @Test public void testJarFileCopyToDirectoryTraversal () throws Exception { String s = "jar:"+__userURL+"TestData/extract.zip!/"; @@ -333,6 +320,7 @@ public class ResourceTest extends junit.framework.TestCase /** * Test a class path resource for existence. */ + @Test public void testClassPathResourceClassRelative() { final String classPathName="Resource.class"; @@ -351,6 +339,7 @@ public class ResourceTest extends junit.framework.TestCase /** * Test a class path resource for existence. */ + @Test public void testClassPathResourceClassAbsolute() { final String classPathName="/org/eclipse/jetty/util/resource/Resource.class"; @@ -369,6 +358,7 @@ public class ResourceTest extends junit.framework.TestCase /** * Test a class path resource for directories. */ + @Test public void testClassPathResourceDirectory() throws Exception { final String classPathName="/"; @@ -390,6 +380,7 @@ public class ResourceTest extends junit.framework.TestCase /** * Test a class path resource for a file. */ + @Test public void testClassPathResourceFile() throws Exception { final String fileName="resource.txt"; diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/statistic/SampleStatisticTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/statistic/SampleStatisticTest.java index 3031aefcb8..14be1dd65f 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/statistic/SampleStatisticTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/statistic/SampleStatisticTest.java @@ -1,12 +1,13 @@ package org.eclipse.jetty.util.statistic; -import org.eclipse.jetty.util.statistic.SampleStatistic; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -import junit.framework.TestCase; +import org.junit.Test; /* ------------------------------------------------------------ */ -public class SampleStatisticTest extends TestCase +public class SampleStatisticTest { private static long[][] data = { @@ -26,6 +27,7 @@ public class SampleStatisticTest extends TestCase }; + @Test public void testData() throws Exception { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java index a8910eb342..59cd536b9f 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java @@ -11,14 +11,17 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== - package org.eclipse.jetty.util.thread; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.util.concurrent.atomic.AtomicInteger; -import junit.framework.TestCase; +import org.junit.Test; + -public class QueuedThreadPoolTest extends TestCase +public class QueuedThreadPoolTest { final AtomicInteger _jobs=new AtomicInteger(); volatile long _sleep=100; @@ -44,6 +47,7 @@ public class QueuedThreadPoolTest extends TestCase + @Test public void testThreadPool() throws Exception { _sleep=100; @@ -129,6 +133,7 @@ public class QueuedThreadPoolTest extends TestCase tp.stop(); } + @Test public void testShrink() throws Exception { Runnable job = new Runnable() @@ -184,6 +189,7 @@ public class QueuedThreadPoolTest extends TestCase } + @Test public void testMaxStopTime() throws Exception { _sleep=100; diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java index 11eccd5b15..ceca63281b 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java @@ -13,11 +13,15 @@ package org.eclipse.jetty.util.thread; +import static org.junit.Assert.assertEquals; + import java.util.concurrent.atomic.AtomicIntegerArray; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; + -public class TimeoutTest extends TestCase +public class TimeoutTest { private boolean _stress=Boolean.getBoolean("STRESS"); @@ -29,11 +33,9 @@ public class TimeoutTest extends TestCase /* * @see junit.framework.TestCase#setUp() */ - @Override - protected void setUp() throws Exception + @Before + public void setUp() throws Exception { - super.setUp(); - timeout=new Timeout(lock); tasks= new Timeout.Task[10]; @@ -47,17 +49,7 @@ public class TimeoutTest extends TestCase } /* ------------------------------------------------------------ */ - /* - * @see junit.framework.TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - } - - - /* ------------------------------------------------------------ */ + @Test public void testExpiry() { timeout.setDuration(200); @@ -71,6 +63,7 @@ public class TimeoutTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testCancel() { timeout.setDuration(200); @@ -89,6 +82,7 @@ public class TimeoutTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testTouch() { timeout.setDuration(200); @@ -112,6 +106,7 @@ public class TimeoutTest extends TestCase /* ------------------------------------------------------------ */ + @Test public void testDelay() { Timeout.Task task = new Timeout.Task(); @@ -134,6 +129,7 @@ public class TimeoutTest extends TestCase } /* ------------------------------------------------------------ */ + @Test public void testStress() throws Exception { if ( !_stress ) diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java index d57cc012ca..a7c2185fb6 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java @@ -58,7 +58,7 @@ public class ClasspathPattern * Create a new instance from a String array of classpath patterns * * @param patterns array of classpath patterns - * @return + * @return new instance */ public static ClasspathPattern fromArray(String[] patterns) { @@ -70,7 +70,7 @@ public class ClasspathPattern * Create a new instance from a classpath pattern sring * * @param patterns classpath pattern string - * @return + * @return new instance */ public static ClasspathPattern fromString(String patterns) { diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java index e775e5f324..ca37ab4f42 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java @@ -31,6 +31,7 @@ import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.util.resource.ResourceCollection; /* ------------------------------------------------------------ */ @@ -123,6 +124,26 @@ public class WebAppClassLoader extends URLClassLoader { return _context; } + + /* ------------------------------------------------------------ */ + /** + * @param resource Comma or semicolon separated path of filenames or URLs + * pointing to directories or jar files. Directories should end + * with '/'. + */ + public void addClassPath(Resource resource) + throws IOException + { + if (resource instanceof ResourceCollection) + { + for (Resource r : ((ResourceCollection)resource).getResources()) + addClassPath(r); + } + else + { + addClassPath(resource.toString()); + } + } /* ------------------------------------------------------------ */ /** @@ -188,10 +209,11 @@ public class WebAppClassLoader extends URLClassLoader String[] files=lib.list(); for (int f=0;files!=null && f<files.length;f++) { - try { + try + { Resource fn=lib.addPath(files[f]); String fnlc=fn.getName().toLowerCase(); - if (isFileSupported(fnlc)) + if (!fn.isDirectory() && isFileSupported(fnlc)) { String jar=fn.toString(); jar=StringUtil.replace(jar, ",", "%2C"); diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index 03205d364d..7e9526dba7 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -20,9 +20,7 @@ import java.net.URL; import java.security.PermissionCollection; import java.util.EventListener; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.jar.JarFile; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionAttributeListener; @@ -65,6 +63,7 @@ import org.eclipse.jetty.util.resource.ResourceCollection; public class WebAppContext extends ServletContextHandler { public static final String TEMPDIR = "javax.servlet.context.tempdir"; + public static final String BASETEMPDIR = "org.eclipse.jetty.webapp.basetempdir"; public final static String WEB_DEFAULTS_XML="org/eclipse/jetty/webapp/webdefault.xml"; public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page"; public final static String SERVER_CONFIG = "org.eclipse.jetty.webapp.configuration"; @@ -90,7 +89,7 @@ public class WebAppContext extends ServletContextHandler "javax.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2) "org.xml.", // needed by javax.xml "org.w3c.", // needed by javax.xml - "apache.commons.logging.", // special case + "org.apache.commons.logging.", // TODO: review if special case still needed "org.eclipse.jetty.continuation.", // webapp cannot change continuation classes "org.eclipse.jetty.jndi.", // webapp cannot change naming classes "org.eclipse.jetty.plus.jaas.", // webapp cannot change jaas classes diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java index 1dc26818f6..8fec7624d6 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java @@ -140,7 +140,7 @@ public class WebInfConfiguration implements Configuration // Look for classes directory Resource classes= web_inf.addPath("classes/"); if (classes.exists()) - ((WebAppClassLoader)context.getClassLoader()).addClassPath(classes.toString()); + ((WebAppClassLoader)context.getClassLoader()).addClassPath(classes); // Look for jars Resource lib= web_inf.addPath("lib/"); @@ -225,62 +225,48 @@ public class WebInfConfiguration implements Configuration { //If a tmp directory is already set, we're done File tmpDir = context.getTempDirectory(); - if (tmpDir!=null && tmpDir.isDirectory() && tmpDir.canWrite()) - return; //Already have a suitable tmp dir configured + if (tmpDir != null && tmpDir.isDirectory() && tmpDir.canWrite()) + { + return; // Already have a suitable tmp dir configured + } - //None configured, try and come up with one - //First ... see if one is configured in a context attribute - //either as a File or name of a file - Object t = context.getAttribute(WebAppContext.TEMPDIR); - if (t != null) + // No temp directory configured, try to establish one. + // First we check the context specific, javax.servlet specified, temp directory attribute + File servletTmpDir = asFile(context.getAttribute(WebAppContext.TEMPDIR)); + if (servletTmpDir != null && servletTmpDir.isDirectory() && servletTmpDir.canWrite()) { - //Is it a File? - if (t instanceof File) + // Use as tmpDir + tmpDir = servletTmpDir; + // Ensure Attribute has File object + context.setAttribute(WebAppContext.TEMPDIR,tmpDir); + // Set as TempDir in context. + context.setTempDirectory(tmpDir); + return; + } + + try + { + // Put the tmp dir in the work directory if we had one + File work = new File(System.getProperty("jetty.home"),"work"); + if (work.exists() && work.canWrite() && work.isDirectory()) { - tmpDir=(File)t; - if (tmpDir.isDirectory() && tmpDir.canWrite()) - { - context.setTempDirectory(tmpDir); - return; - } + makeTempDirectory(work, context, false); //make a tmp dir inside work, don't delete if it exists } - // The context attribute specified a name not a File - if (t instanceof String) + else { - try + File baseTemp = asFile(context.getAttribute(WebAppContext.BASETEMPDIR)); + if (baseTemp != null && baseTemp.isDirectory() && baseTemp.canWrite()) { - tmpDir=new File((String)t); - - if (tmpDir.isDirectory() && tmpDir.canWrite()) - { - context.setAttribute(context.TEMPDIR,tmpDir); - context.setTempDirectory(tmpDir); - return; - } + // Use baseTemp directory (allow the funky Jetty_0_0_0_0.. subdirectory logic to kick in + makeTempDirectory(baseTemp,context,false); } - catch(Exception e) + else { - Log.warn(Log.EXCEPTION,e); + makeTempDirectory(new File(System.getProperty("java.io.tmpdir")),context,true); //make a tmpdir, delete if it already exists } } } - - // Second ... make a tmp directory, in a work directory if one exists - String temp = getCanonicalNameForWebAppTmpDir(context); - - try - { - //Put the tmp dir in the work directory if we had one - File work = new File(System.getProperty("jetty.home"),"work"); - if (!work.exists() || !work.canWrite() || !work.isDirectory()) - work = null; - - if (work!=null) - makeTempDirectory(work, context, false); //make a tmp dir inside work, don't delete if it exists - else - makeTempDirectory(new File(System.getProperty("java.io.tmpdir")), context, true); //make a tmpdir, delete if it already exists - } catch(Exception e) { tmpDir=null; @@ -308,7 +294,31 @@ public class WebInfConfiguration implements Configuration } } - + /** + * Given an Object, return File reference for object. + * Typically used to convert anonymous Object from getAttribute() calls to a File object. + * @param fileattr the file attribute to analyze and return from (supports type File and type String, all others return null) + * @return the File object, null if null, or null if not a File or String + */ + private File asFile(Object fileattr) + { + if (fileattr == null) + { + return null; + } + if (fileattr instanceof File) + { + return (File)fileattr; + } + if (fileattr instanceof String) + { + return new File((String)fileattr); + } + return null; + } + + + public void makeTempDirectory (File parent, WebAppContext context, boolean deleteExisting) throws IOException { @@ -364,6 +374,7 @@ public class WebInfConfiguration implements Configuration public void unpack (WebAppContext context) throws IOException { Resource web_app = context.getBaseResource(); + _preUnpackBaseResource = context.getBaseResource(); if (web_app == null) { @@ -465,7 +476,7 @@ public class WebInfConfiguration implements Configuration Log.debug("webapp=" + web_app); } - _preUnpackBaseResource = context.getBaseResource(); + // Do we need to extract WEB-INF/lib? Resource web_inf= web_app.addPath("WEB-INF/"); @@ -501,7 +512,7 @@ public class WebInfConfiguration implements Configuration web_inf_classes.copyTo(webInfClassesDir); } - web_inf=Resource.newResource(extractedWebInfDir.toURL()); + web_inf=Resource.newResource(extractedWebInfDir.getCanonicalPath()); ResourceCollection rc = new ResourceCollection(new Resource[]{web_inf,web_app}); diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java index 6fad762310..469a28b091 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java @@ -29,7 +29,7 @@ public class WebAppClassLoaderTest _loader = new WebAppClassLoader(_context); _loader.addJars(webapp.addPath("WEB-INF/lib")); - _loader.addClassPath(webapp.addPath("WEB-INF/classes").toString()); + _loader.addClassPath(webapp.addPath("WEB-INF/classes")); _loader.setName("test"); } @@ -41,7 +41,7 @@ public class WebAppClassLoaderTest assertTrue(canLoadClass("org.acme.webapp.ClassInJarB")); assertTrue(canLoadClass("org.acme.other.ClassInClassesC")); - assertFalse(canLoadClass("org.eclipse.jetty.webapp.Configuration")); + assertTrue(cantLoadClass("org.eclipse.jetty.webapp.Configuration")); Class clazzA = _loader.loadClass("org.acme.webapp.ClassInJarA"); assertTrue(clazzA.getField("FROM_PARENT")!=null); @@ -55,7 +55,7 @@ public class WebAppClassLoaderTest assertTrue(canLoadClass("org.acme.webapp.ClassInJarB")); assertTrue(canLoadClass("org.acme.other.ClassInClassesC")); - assertFalse(canLoadClass("org.eclipse.jetty.webapp.Configuration")); + assertTrue(cantLoadClass("org.eclipse.jetty.webapp.Configuration")); Class<?> clazzA = _loader.loadClass("org.acme.webapp.ClassInJarA"); try @@ -83,7 +83,7 @@ public class WebAppClassLoaderTest assertTrue(canLoadClass("org.acme.other.ClassInClassesC")); assertTrue(canLoadClass("org.eclipse.jetty.webapp.Configuration")); - assertFalse(canLoadClass("org.eclipse.jetty.webapp.JarScanner")); + assertTrue(cantLoadClass("org.eclipse.jetty.webapp.JarScanner")); } @Test @@ -105,8 +105,8 @@ public class WebAppClassLoaderTest assertTrue(canLoadClass("org.acme.webapp.ClassInJarB")); assertTrue(canLoadClass("org.acme.other.ClassInClassesC")); - assertFalse(canLoadClass("org.eclipse.jetty.webapp.Configuration")); - assertFalse(canLoadClass("org.eclipse.jetty.webapp.JarScanner")); + assertTrue(cantLoadClass("org.eclipse.jetty.webapp.Configuration")); + assertTrue(cantLoadClass("org.eclipse.jetty.webapp.JarScanner")); } @Test @@ -161,15 +161,20 @@ public class WebAppClassLoaderTest return list; } - private boolean canLoadClass(String clazz) + private boolean canLoadClass(String clazz) throws ClassNotFoundException + { + return _loader.loadClass(clazz)!=null; + } + + private boolean cantLoadClass(String clazz) { try { - return _loader.loadClass(clazz)!=null; + return _loader.loadClass(clazz)==null; } catch(ClassNotFoundException e) { - return false; + return true; } } } diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnection.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnection.java index 0935b740e6..4da7611506 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnection.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketConnection.java @@ -1,12 +1,20 @@ package org.eclipse.jetty.websocket; import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.zip.Checksum; +import org.eclipse.jetty.http.HttpParser; +import org.eclipse.jetty.http.security.Credential.MD5; import org.eclipse.jetty.io.AsyncEndPoint; import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.nio.IndirectNIOBuffer; import org.eclipse.jetty.io.nio.SelectChannelEndPoint; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.thread.Timeout; @@ -18,6 +26,9 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound final WebSocketGenerator _generator; final long _timestamp; final WebSocket _websocket; + String _key1; + String _key2; + ByteArrayBuffer _hixie; public WebSocketConnection(WebSocket websocket, EndPoint endpoint) throws IOException @@ -98,6 +109,13 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound }; } } + + public void setHixieKeys(String key1,String key2) + { + _key1=key1; + _key2=key2; + _hixie=new IndirectNIOBuffer(16); + } public Connection handle() throws IOException { @@ -105,6 +123,53 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound try { + // handle stupid hixie random bytes + if (_hixie!=null) + { + while(progress) + { + // take bytes from the parser buffer. + if (_parser.getBuffer().length()>0) + { + int l=_parser.getBuffer().length(); + if (l>8) + l=8; + _hixie.put(_parser.getBuffer().peek(_parser.getBuffer().getIndex(),l)); + _parser.getBuffer().skip(l); + progress=true; + } + + // do we have enough? + if (_hixie.length()<8) + { + // no, then let's fill + int filled=_endp.fill(_hixie); + progress |= filled>0; + + if (filled<0) + { + _endp.close(); + break; + } + } + + // do we now have enough + if (_hixie.length()==8) + { + // we have the silly random bytes + // so let's work out the stupid 16 byte reply. + doTheHixieHixieShake(); + _endp.flush(_hixie); + _hixie=null; + _endp.flush(); + break; + } + } + + return this; + } + + // handle the framing protocol while (progress) { int flushed=_generator.flush(); @@ -121,7 +186,6 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound } catch(IOException e) { - e.printStackTrace(); throw e; } finally @@ -138,6 +202,16 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound return this; } + private void doTheHixieHixieShake() + { + byte[] result=WebSocketGenerator.doTheHixieHixieShake( + WebSocketParser.hixieCrypt(_key1), + WebSocketParser.hixieCrypt(_key2), + _hixie.asArray()); + _hixie.clear(); + _hixie.put(result); + } + public boolean isOpen() { return _endp!=null&&_endp.isOpen(); diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketFactory.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketFactory.java index 6ebd208765..37f5de71d0 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketFactory.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketFactory.java @@ -91,17 +91,38 @@ public class WebSocketFactory HttpConnection http = HttpConnection.getCurrentConnection(); ConnectedEndPoint endp = (ConnectedEndPoint)http.getEndPoint(); WebSocketConnection connection = new WebSocketConnection(websocket,endp,_buffers,http.getTimeStamp(), _maxIdleTime); - + String uri=request.getRequestURI(); + String query=request.getQueryString(); + if (query!=null && query.length()>0) + uri+="?"+query; String host=request.getHeader("Host"); - - response.setHeader("Upgrade","WebSocket"); - response.addHeader("Connection","Upgrade"); - response.addHeader("WebSocket-Origin",origin); - response.addHeader("WebSocket-Location","ws://"+host+uri); - if (protocol!=null) - response.addHeader("WebSocket-Protocol",protocol); - response.sendError(101,"Web Socket Protocol Handshake"); + + String key1 = request.getHeader("Sec-WebSocket-Key1"); + if (key1!=null) + { + String key2 = request.getHeader("Sec-WebSocket-Key2"); + connection.setHixieKeys(key1,key2); + + response.setHeader("Upgrade","WebSocket"); + response.addHeader("Connection","Upgrade"); + response.addHeader("Sec-WebSocket-Origin",origin); + response.addHeader("Sec-WebSocket-Location",(request.isSecure()?"wss://":"ws://")+host+uri); + if (protocol!=null) + response.addHeader("Sec-WebSocket-Protocol",protocol); + response.sendError(101,"WebSocket Protocol Handshake"); + } + else + { + response.setHeader("Upgrade","WebSocket"); + response.addHeader("Connection","Upgrade"); + response.addHeader("WebSocket-Origin",origin); + response.addHeader("WebSocket-Location",(request.isSecure()?"wss://":"ws://")+host+uri); + if (protocol!=null) + response.addHeader("WebSocket-Protocol",protocol); + response.sendError(101,"Web Socket Protocol Handshake"); + } + response.flushBuffer(); connection.fill(((HttpParser)http.getParser()).getHeaderBuffer()); @@ -109,6 +130,5 @@ public class WebSocketFactory websocket.onConnect(connection); request.setAttribute("org.eclipse.jetty.io.Connection",connection); - response.flushBuffer(); } } diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketGenerator.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketGenerator.java index 75b607d757..3666b3b07d 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketGenerator.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketGenerator.java @@ -2,9 +2,14 @@ package org.eclipse.jetty.websocket; import java.io.IOException; import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ @@ -94,6 +99,8 @@ public class WebSocketGenerator private synchronized void bufferPut(byte datum, long blockFor) throws IOException { + if (_buffer==null) + _buffer=_buffers.getDirectBuffer(); _buffer.put(datum); if (_buffer.space() == 0) expelBuffer(blockFor); @@ -124,7 +131,7 @@ public class WebSocketGenerator private synchronized int flushBuffer() throws IOException { if (!_endp.isOpen()) - throw new IOException("Closed"); + throw new EofException(); if (_buffer!=null) return _endp.flush(_buffer); @@ -134,6 +141,8 @@ public class WebSocketGenerator private synchronized int expelBuffer(long blockFor) throws IOException { + if (_buffer==null) + return 0; int result = flushBuffer(); _buffer.compact(); if (!_endp.isBlocking()) @@ -157,4 +166,32 @@ public class WebSocketGenerator { return _buffer==null || _buffer.length()==0; } + + public static byte[] doTheHixieHixieShake(long key1,long key2,byte[] key3) + { + try + { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte [] fodder = new byte[16]; + + fodder[0]=(byte)(0xff&(key1>>24)); + fodder[1]=(byte)(0xff&(key1>>16)); + fodder[2]=(byte)(0xff&(key1>>8)); + fodder[3]=(byte)(0xff&key1); + fodder[4]=(byte)(0xff&(key2>>24)); + fodder[5]=(byte)(0xff&(key2>>16)); + fodder[6]=(byte)(0xff&(key2>>8)); + fodder[7]=(byte)(0xff&key2); + for (int i=0;i<8;i++) + fodder[8+i]=key3[i]; + md.update(fodder); + byte[] result=md.digest(); + return result; + } + catch (NoSuchAlgorithmException e) + { + throw new IllegalStateException(e); + } + } + } diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParser.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParser.java index e0a0160837..49449fbe52 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParser.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketParser.java @@ -190,10 +190,26 @@ public class WebSocketParser _buffer.put(buffer); buffer.clear(); } - - } - + + /* ------------------------------------------------------------ */ + static long hixieCrypt(String key) + { + // Don't ask me what all this is about. + // I think it's pretend secret stuff, kind of + // like talking in pig latin! + long number=0; + int spaces=0; + for (char c : key.toCharArray()) + { + if (Character.isDigit(c)) + number=number*10+(c-'0'); + else if (c==' ') + spaces++; + } + return number/spaces; + } + /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ diff --git a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketServlet.java b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketServlet.java index e89d5f31d0..43abe6e7be 100644 --- a/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketServlet.java +++ b/jetty-websocket/src/main/java/org/eclipse/jetty/websocket/WebSocketServlet.java @@ -49,7 +49,11 @@ public abstract class WebSocketServlet extends HttpServlet { if ("WebSocket".equals(request.getHeader("Upgrade"))) { - String protocol=request.getHeader("WebSocket-Protocol"); + boolean hixie = request.getHeader("Sec-WebSocket-Key1")!=null; + + String protocol=request.getHeader(hixie?"Sec-WebSocket-Protocol":"WebSocket-Protocol"); + if (protocol==null) + protocol=request.getHeader("Sec-WebSocket-Protocol"); WebSocket websocket=doWebSocketConnect(request,protocol); String host=request.getHeader("Host"); @@ -59,7 +63,11 @@ public abstract class WebSocketServlet extends HttpServlet if (websocket!=null) _websocket.upgrade(request,response,websocket,origin,protocol); else + { + if (hixie) + response.setHeader("Connection","close"); response.sendError(503); + } } else super.service(request,response); diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketGeneratorTest.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketGeneratorTest.java index 5fbe1512da..755d905af1 100644 --- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketGeneratorTest.java +++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketGeneratorTest.java @@ -1,8 +1,11 @@ package org.eclipse.jetty.websocket; +import java.security.MessageDigest; + import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.ByteArrayEndPoint; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.TypeUtil; import org.junit.Before; import org.junit.Test; @@ -90,4 +93,35 @@ public class WebSocketGeneratorTest for (int i=0;i<b.length;i++) assertEquals('0'+(i%10),0xff&_out.get()); } + + @Test + public void testHixie() throws Exception + { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] result; + byte[] expected; + + expected=md.digest(TypeUtil.fromHexString("00000000000000000000000000000000")); + result=WebSocketGenerator.doTheHixieHixieShake( + 0 ,0, new byte[8]); + assertEquals(TypeUtil.toHexString(expected),TypeUtil.toHexString(result)); + + expected=md.digest(TypeUtil.fromHexString("01020304050607080000000000000000")); + result=WebSocketGenerator.doTheHixieHixieShake( + 0x01020304, + 0x05060708, + new byte[8]); + assertEquals(TypeUtil.toHexString(expected),TypeUtil.toHexString(result)); + + byte[] random = new byte[8]; + for (int i=0;i<8;i++) + random[i]=(byte)(0xff&"Tm[K T2u".charAt(i)); + result=WebSocketGenerator.doTheHixieHixieShake( + 155712099,173347027,random); + StringBuilder b = new StringBuilder(); + + for (int i=0;i<16;i++) + b.append((char)result[i]); + assertEquals("fQJ,fN/4F4!~K~MH",b.toString()); + } } diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserTest.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserTest.java index 73b387bd2d..8fa1bd27d9 100644 --- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserTest.java +++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserTest.java @@ -129,6 +129,14 @@ public class WebSocketParserTest assertTrue(_parser.getBuffer()==null); } + + @Test + public void testHixieCrypt() throws Exception + { + assertEquals(155712099,WebSocketParser.hixieCrypt("18x 6]8vM;54 *(5: { U1]8 z [ 8")); + assertEquals(173347027,WebSocketParser.hixieCrypt("1_ tx7X d < nw 334J702) 7]o}` 0")); + } + // TODO test: // blocking, // async diff --git a/linux-packaging.xml b/linux-packaging.xml index 1d319a756b..4da7c80062 100644 --- a/linux-packaging.xml +++ b/linux-packaging.xml @@ -202,6 +202,10 @@ <exclude>jetty-annotations</exclude> <exclude>jetty-jaspi</exclude> <exclude>jetty-plus</exclude> + <exclude>example-jetty-embedded</exclude> + <exclude>test-continuation</exclude> + <exclude>test-continuation-jetty6</exclude> + <exclude>test-jetty-servlet</exclude> </project> <!-- Dependencies for OSGI are too complicated to deal with right now --> <project groupId="org.eclipse.jetty.osgi"> @@ -222,6 +226,13 @@ <exclude>jetty-all-server</exclude> <exclude>jetty-all</exclude> </project> + <project groupId="org.eclipse.jetty.tests"> + <exclude>test-sessions-common</exclude> + <exclude>test-jdbc-sessions</exclude> + <exclude>test-hash-sessions</exclude> + <exclude>test-integration</exclude> + <exclude>test-webapp-rfc2616</exclude> + </project> <daemon> <script>jetty-distribution/src/main/resources/bin/jetty.sh</script> <debian>debian/jetty.init</debian> @@ -1,4 +1,3 @@ -<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> @@ -25,6 +24,7 @@ <servlet.spec.groupId>org.mortbay.jetty</servlet.spec.groupId> <servlet.spec.artifactId>servlet-api</servlet.spec.artifactId> <servlet.spec.version>3.0.20100224</servlet.spec.version> + <build-support-version>1.0</build-support-version> </properties> <scm> <connection>scm:svn:http://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/branches/jetty-8</connection> @@ -46,6 +46,7 @@ <artifactId>maven-release-plugin</artifactId> <configuration> <tagBase>svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/tags</tagBase> + <autoVersionSubmodules>true</autoVersionSubmodules> </configuration> </plugin> <plugin> @@ -82,7 +83,7 @@ <archive> <manifestEntries> <Bundle-ManifestVersion>2</Bundle-ManifestVersion> - <Bundle-Name>${name}</Bundle-Name> + <Bundle-Name>${project.name}</Bundle-Name> <Bundle-SymbolicName>${bundle-symbolic-name}.source;singleton:=true</Bundle-SymbolicName> <Bundle-Vendor>Eclipse.org - Jetty</Bundle-Vendor> <Bundle-Version>${parsedVersion.osgiVersion}</Bundle-Version> @@ -138,8 +139,8 @@ <dependencies> <dependency> <groupId>org.eclipse.jetty.toolchain</groupId> - <artifactId>jetty-enforcer-rules</artifactId> - <version>1.1</version> + <artifactId>jetty-build-support</artifactId> + <version>${build-support-version}</version> </dependency> </dependencies> </plugin> @@ -187,7 +188,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> - <version>2.2-beta-3</version> + <version>2.2-beta-5</version> <dependencies> <dependency> <groupId>org.eclipse.jetty.toolchain</groupId> @@ -196,9 +197,50 @@ </dependency> </dependencies> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-pmd-plugin</artifactId> + <version>2.5</version> + <configuration> + <targetJdk>1.5</targetJdk> + <rulesets> + <ruleset>jetty/pmd_ruleset.xml</ruleset> + </rulesets> + </configuration> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty.toolchain</groupId> + <artifactId>jetty-build-support</artifactId> + <version>${build-support-version}</version> + </dependency> + </dependencies> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <version>2.3.1</version> + <configuration> + <findbugsXmlOutput>true</findbugsXmlOutput> + <xmlOutput>true</xmlOutput> + <effort>Max</effort> + <onlyAnalyze>org.eclipse.jetty.*</onlyAnalyze> + </configuration> + </plugin> </plugins> </pluginManagement> </build> + <!-- + <repositories> + <repository> + <snapshots> + <enabled>true</enabled> + </snapshots> + <id>sonatype-snapshots</id> + <name>Sonatype Jetty Snapshots</name> + <url>http://oss.sonatype.org/content/groups/jetty</url> + </repository> + </repositories> + --> <modules> <module>jetty-util</module> <module>jetty-io</module> @@ -313,6 +355,13 @@ <link>http://java.sun.com/javaee/6/docs/api</link> <link>http://junit.sourceforge.net/javadoc/</link> </links> + <tags> + <tag> + <name>org.apache.xbean.XBean</name> + <placement>X</placement> + <head /> + </tag> + </tags> </configuration> </plugin> </plugins> diff --git a/test-jetty-webapp/pom.xml b/test-jetty-webapp/pom.xml index 07b33be590..8495997d80 100644 --- a/test-jetty-webapp/pom.xml +++ b/test-jetty-webapp/pom.xml @@ -47,7 +47,7 @@ <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> - <version>7.0.0.RC2-SNAPSHOT</version> + <version>7.1.1-SNAPSHOT</version> <configuration> <stopPort>8087</stopPort> <stopKey>foo</stopKey> @@ -70,13 +70,12 @@ <loginServices> <loginService implementation="org.eclipse.jetty.security.HashLoginService"> <name>Test Realm</name> - <config>../jetty-server/src/main/config/etc/realm.properties</config> + <config>src/main/config/etc/realm.properties</config> </loginService> </loginServices> </configuration> </plugin> --> - <!-- uncomment to precompile jsps --> <!-- <plugin> diff --git a/test-jetty-webapp/src/main/config/contexts/test.xml b/test-jetty-webapp/src/main/config/contexts/test.xml index fb5f7d31c5..3c36173b13 100644 --- a/test-jetty-webapp/src/main/config/contexts/test.xml +++ b/test-jetty-webapp/src/main/config/contexts/test.xml @@ -75,4 +75,19 @@ detected. </Get> --> + <!-- Add context specific logger + <Set name="handler"> + <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"> + <Set name="requestLog"> + <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog"> + <Set name="filename"><Property name="jetty.logs" default="./logs"/>/test-yyyy_mm_dd.request.log</Set> + <Set name="filenameDateFormat">yyyy_MM_dd</Set> + <Set name="append">true</Set> + <Set name="LogTimeZone">GMT</Set> + </New> + </Set> + </New> + </Set> + --> + </Configure> diff --git a/test-jetty-webapp/src/main/java/com/acme/Dump.java b/test-jetty-webapp/src/main/java/com/acme/Dump.java index 2a37c3f66e..86a04ffbd0 100644 --- a/test-jetty-webapp/src/main/java/com/acme/Dump.java +++ b/test-jetty-webapp/src/main/java/com/acme/Dump.java @@ -13,6 +13,7 @@ package com.acme; import java.io.BufferedWriter; +import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; @@ -20,6 +21,7 @@ import java.io.PrintWriter; import java.io.Reader; import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.util.Date; import java.util.Enumeration; import java.util.Locale; @@ -552,7 +554,6 @@ public class Dump extends HttpServlet pout.write("</pre></td>"); } - pout.write("</tr><tr>\n"); pout.write("<th align=\"left\" colspan=\"2\"><big><br/>Request Attributes:</big></th>"); Enumeration a= request.getAttributeNames(); @@ -561,8 +562,16 @@ public class Dump extends HttpServlet name= (String)a.nextElement(); pout.write("</tr><tr>\n"); pout.write("<th align=\"right\" valign=\"top\">"+name.replace("."," .")+": </th>"); - pout.write("<td>"+"<pre>" + toString(request.getAttribute(name)) + "</pre>"+"</td>"); - } + Object value=request.getAttribute(name); + if (value instanceof File) + { + File file = (File)value; + pout.write("<td>"+"<pre>" + file.getName()+" ("+file.length()+" "+new Date(file.lastModified())+ ")</pre>"+"</td>"); + } + else + pout.write("<td>"+"<pre>" + toString(request.getAttribute(name)) + "</pre>"+"</td>"); + } + request.setAttribute("org.eclipse.jetty.servlet.MultiPartFilter.files",null); pout.write("</tr><tr>\n"); diff --git a/test-jetty-webapp/src/main/java/com/acme/WebSocketChatServlet.java b/test-jetty-webapp/src/main/java/com/acme/WebSocketChatServlet.java index 4ba4b54204..3b1e3090f4 100644 --- a/test-jetty-webapp/src/main/java/com/acme/WebSocketChatServlet.java +++ b/test-jetty-webapp/src/main/java/com/acme/WebSocketChatServlet.java @@ -50,16 +50,21 @@ public class WebSocketChatServlet extends WebSocketServlet public void onMessage(byte frame, String data) { - // Log.info(this+" onMessage: "+data); - for (ChatWebSocket member : _members) + if (data.indexOf("disconnect")>=0) + _outbound.disconnect(); + else { - try + // Log.info(this+" onMessage: "+data); + for (ChatWebSocket member : _members) { - member._outbound.sendMessage(frame,data); - } - catch(IOException e) - { - Log.warn(e); + try + { + member._outbound.sendMessage(frame,data); + } + catch(IOException e) + { + Log.warn(e); + } } } } diff --git a/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml b/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml index d4a53ce751..9cb725596a 100644 --- a/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml +++ b/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml @@ -9,7 +9,7 @@ <context-param> <param-name>org.eclipse.jetty.server.context.ManagedAttributes</param-name> - <param-value>org.eclipse.jetty.servlets.ProxyServlet.Logger,org.eclipse.jetty.servlets.ProxyServlet.ThreadPool,org.eclipse.jetty.servlets.ProxyServlet.HttpClient</param-value> + <param-value>QoSFilter,TransparentProxy.Logger,TransparentProxy.ThreadPool,TransparentProxy.HttpClient</param-value> </context-param> <!-- Declare TestListener, which declares TestFilter --> @@ -38,6 +38,10 @@ <param-name>maxRequests</param-name> <param-value>20</param-value> </init-param> + <init-param> + <param-name>managedAttr</param-name> + <param-value>true</param-value> + </init-param> </filter> <filter-mapping> <filter-name>QoSFilter</filter-name> diff --git a/test-jetty-webapp/src/main/webapp/index.html b/test-jetty-webapp/src/main/webapp/index.html index da9d9d0167..f96f625d95 100644 --- a/test-jetty-webapp/src/main/webapp/index.html +++ b/test-jetty-webapp/src/main/webapp/index.html @@ -10,8 +10,8 @@ <p> This is the Test webapp for the Jetty 8 HTTP Server and Servlet Container. For more information about Jetty, please visit our -<a href="http://jetty.eclipse.org">website</a> -or <a href="http://docs.codehaus.org/display/JETTY/Jetty+Wiki">wiki</a>. +<a href="http://www.eclipse.org/jetty">website</a> +or <a href="http://wiki.eclipse.org/Jetty">wiki</a>. Commercial support for Jetty is available via <a href="http://www.webtide.com">webtide</a>. </p> <p> diff --git a/test-jetty-webapp/src/main/webapp/ws/index.html b/test-jetty-webapp/src/main/webapp/ws/index.html index 9e801eebe0..a88db337ab 100644 --- a/test-jetty-webapp/src/main/webapp/ws/index.html +++ b/test-jetty-webapp/src/main/webapp/ws/index.html @@ -14,7 +14,7 @@ var room = { join: function(name) { this._username=name; - var location = document.location.toString().replace('http:','ws:'); + var location = document.location.toString().replace('http://','ws://').replace('https://','wss://'); this._ws=new WebSocket(location); this._ws.onopen=this._onopen; this._ws.onmessage=this._onmessage; diff --git a/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java b/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java index eeb1a0b379..f38f17d7c3 100644 --- a/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java +++ b/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java @@ -13,6 +13,7 @@ package org.eclipse.jetty; +import java.io.File; import java.lang.management.ManagementFactory; import org.eclipse.jetty.jmx.MBeanContainer; @@ -35,8 +36,7 @@ public class TestServer { public static void main(String[] args) throws Exception { - String jetty_home = System.getProperty("jetty.home","../jetty-distribution/target/distribution"); - System.setProperty("jetty.home",jetty_home); + String jetty_root = ".."; Server server = new Server(); server.setSendDateHeader(true); @@ -63,10 +63,10 @@ public class TestServer SslSelectChannelConnector ssl_connector = new SslSelectChannelConnector(); ssl_connector.setPort(8443); - ssl_connector.setKeystore(jetty_home + "/etc/keystore"); + ssl_connector.setKeystore(jetty_root + "/jetty-server/src/main/config/etc/keystore"); ssl_connector.setPassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); ssl_connector.setKeyPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g"); - ssl_connector.setTruststore(jetty_home + "/etc/keystore"); + ssl_connector.setTruststore(jetty_root + "/jetty-server/src/main/config/etc/keystore"); ssl_connector.setTrustPassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"); server.addConnector(ssl_connector); @@ -82,24 +82,24 @@ public class TestServer HashLoginService login = new HashLoginService(); login.setName("Test Realm"); - login.setConfig(jetty_home + "/etc/realm.properties"); + login.setConfig(jetty_root + "/test-jetty-webapp/src/main/config/etc/realm.properties"); server.addBean(login); - NCSARequestLog requestLog = new NCSARequestLog(jetty_home + "/logs/jetty-yyyy_mm_dd.log"); + File log=File.createTempFile("jetty-yyyy_mm_dd", "log"); + NCSARequestLog requestLog = new NCSARequestLog(log.toString()); requestLog.setExtended(false); requestLogHandler.setRequestLog(requestLog); server.setStopAtShutdown(true); server.setSendServerVersion(true); - WebAppContext webapp = new WebAppContext(); webapp.setParentLoaderPriority(true); webapp.setResourceBase("./src/main/webapp"); + webapp.setAttribute("testAttribute","testValue"); contexts.addHandler(webapp); - server.start(); server.join(); } diff --git a/tests/pom.xml b/tests/pom.xml index 565fb91d4a..d2d4a6677a 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -30,6 +30,14 @@ <build> <plugins> <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <configuration> + <!-- No Point running Findbugs on testing projects --> + <skip>true</skip> + </configuration> + </plugin> + <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-deploy-plugin</artifactId> <configuration> @@ -43,5 +51,6 @@ <module>test-integration</module> <module>test-webapps</module> <module>test-sessions</module> + <module>test-loginservice</module> </modules> </project> diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java index 0aa5393854..6e409e9b24 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java @@ -661,7 +661,8 @@ public abstract class RFC2616BaseTest req2.append("Expect: unknown\n"); // Invalid Expect header. req2.append("Content-Type: text/plain\n"); req2.append("Content-Length: 8\n"); - req2.append("\n"); // No body + req2.append("\n"); + req2.append("12345678\n"); response = http.request(req2); @@ -976,7 +977,6 @@ public abstract class RFC2616BaseTest req2.append("Range: bytes=1-3\n"); // request first 3 bytes req2.append("\n"); - http.enableDebug(); response = http.request(req2); response.assertStatus("10.2.7 Partial Content",HttpStatus.PARTIAL_CONTENT_206); @@ -1260,7 +1260,6 @@ public abstract class RFC2616BaseTest req1.append("\n"); http.setTimeoutMillis(60000); - http.enableDebug(); response = http.request(req1); String msg = "Partial Range (Mixed): 'bytes=a-b,5-8'"; @@ -1449,7 +1448,6 @@ public abstract class RFC2616BaseTest req1.append("Connection: close\n"); req1.append("\n"); - http.enableDebug(); response = http.request(req1); String msg = "Partial (Byte) Range: '" + rangedef + "'"; @@ -1567,7 +1565,6 @@ public abstract class RFC2616BaseTest req1.append("Connection: close\n"); req1.append("\n"); - http.enableDebug(); response = http.request(req1); String msg = "Partial (Byte) Range: '" + rangedef + "'"; @@ -1689,7 +1686,6 @@ public abstract class RFC2616BaseTest req1.append("Connection: close\n"); req1.append("\n"); - http.enableDebug(); response = http.request(req1); specId = "14.39 TE Header"; response.assertStatusOK(specId); diff --git a/tests/test-loginservice/pom.xml b/tests/test-loginservice/pom.xml new file mode 100644 index 0000000000..08d43a86d5 --- /dev/null +++ b/tests/test-loginservice/pom.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +// ======================================================================== +// Copyright (c) Webtide LLC +// +// 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.apache.org/licenses/LICENSE-2.0.txt +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.jetty.tests</groupId> + <artifactId>tests-parent</artifactId> + <version>7.1.5-SNAPSHOT</version> + </parent> + <artifactId>test-loginservice</artifactId> + <name>Jetty Tests :: Login Service</name> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-client</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-security</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.derby</groupId> + <artifactId>derby</artifactId> + <version>10.4.1.3</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.derby</groupId> + <artifactId>derbytools</artifactId> + <version>10.4.1.3</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit4-version}</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java b/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java new file mode 100644 index 0000000000..7b6c2ca9fd --- /dev/null +++ b/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java @@ -0,0 +1,452 @@ +// ======================================================================== +// Copyright (c) 2010 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.sql.Connection; +import java.sql.DriverManager; +import java.util.HashSet; +import java.util.Set; + +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.derby.tools.ij; +import org.eclipse.jetty.client.ContentExchange; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.security.Realm; +import org.eclipse.jetty.client.security.SimpleRealmResolver; +import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.security.Constraint; +import org.eclipse.jetty.io.ByteArrayBuffer; +import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.security.JDBCLoginService; +import org.eclipse.jetty.security.LoginService; +import org.eclipse.jetty.security.authentication.BasicAuthenticator; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.HandlerCollection; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.Loader; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class JdbcLoginServiceTest +{ + private static String _content = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "+ + "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "+ + "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "+ + "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "+ + "at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "+ + "velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "+ + "Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "+ + "eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "+ + "sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "+ + "consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "+ + "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "+ + "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque."; + + private static File _docRoot; + private static Server _server; + private static HttpClient _client; + private static Realm _realm; + private static String _protocol; + private static String _baseUrl; + private static String _requestContent; + + protected static boolean createDB(String homeDir, String fileName, String dbUrl) + { + FileInputStream fileStream = null; + try + { + File scriptFile = new File(fileName); + fileStream = new FileInputStream(scriptFile); + + Loader.loadClass(fileStream.getClass(), "org.apache.derby.jdbc.EmbeddedDriver").newInstance(); + Connection connection = DriverManager.getConnection(dbUrl, "", ""); + + OutputStream out = new ByteArrayOutputStream(); + int result = ij.runScript(connection, fileStream, "UTF-8", out, "UTF-8"); + + return (result==0); + } + catch (Exception e) + { + return false; + } + finally { + if (fileStream!=null) + { + try + { + fileStream.close(); + } + catch (IOException e) {} + } + } + } + + protected static void configureServer(Server server) + throws Exception + { + setProtocol("http"); + setRealm(new Realm() + { + public String getId() + { + return "JdbcRealm"; + } + + public String getPrincipal() + { + return "jetty"; + } + + public String getCredentials() + { + return "jetty"; + } + }); + + SelectChannelConnector connector = new SelectChannelConnector(); + server.addConnector(connector); + + LoginService loginService = new JDBCLoginService("JdbcRealm", "./src/test/resources/jdbcrealm.properties"); + server.addBean(loginService); + + ConstraintSecurityHandler security = new ConstraintSecurityHandler(); + server.setHandler(security); + + Constraint constraint = new Constraint(); + constraint.setName("auth"); + constraint.setAuthenticate( true ); + constraint.setRoles(new String[]{"user", "admin"}); + + ConstraintMapping mapping = new ConstraintMapping(); + mapping.setPathSpec( "/*" ); + mapping.setConstraint( constraint ); + + Set<String> knownRoles = new HashSet<String>(); + knownRoles.add("user"); + knownRoles.add("admin"); + + security.setConstraintMappings(new ConstraintMapping[] {mapping}, knownRoles); + security.setAuthenticator(new BasicAuthenticator()); + security.setLoginService(loginService); + security.setStrict(false); + + ServletContextHandler root = new ServletContextHandler(); + root.setContextPath("/"); + root.setResourceBase(getBasePath()); + ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); + servletHolder.setInitParameter( "gzip", "true" ); + root.addServlet( servletHolder, "/*" ); + + Handler handler = new TestHandler(getBasePath()); + + HandlerCollection handlers = new HandlerCollection(); + handlers.setHandlers(new Handler[]{handler, root}); + security.setHandler(handlers); + } + + @BeforeClass + public static void setUp() + throws Exception + { + _docRoot = new File("target/test-output/docroot/"); + _docRoot.mkdirs(); + _docRoot.deleteOnExit(); + + File content = new File(_docRoot,"input.txt"); + FileOutputStream out = new FileOutputStream(content); + out.write(_content.getBytes("utf-8")); + out.close(); + + File dbRoot = new File("target/test-output/derby"); + String dbPath = dbRoot.getAbsolutePath(); + System.setProperty("derby.system.home", dbPath); + if (!dbRoot.exists()) + { + dbRoot.mkdirs(); + createDB(dbPath, "src/test/resources/createdb.sql", "jdbc:derby:jdbcrealm;create=true"); + } + + _server = new Server(); + configureServer(_server); + _server.start(); + + int port = _server.getConnectors()[0].getLocalPort(); + _baseUrl = _protocol+"://localhost:"+port+ "/"; + } + + @AfterClass + public static void tearDown() + throws Exception + { + if (_server != null) + { + _server.stop(); + _server = null; + } + } + + @Test + public void testPut() throws Exception + { + startClient(_realm); + + ContentExchange putExchange = new ContentExchange(); + putExchange.setURL(getBaseUrl() + "output.txt"); + putExchange.setMethod(HttpMethods.PUT); + putExchange.setRequestContent(new ByteArrayBuffer(_content.getBytes())); + + _client.send(putExchange); + int state = putExchange.waitForDone(); + + int responseStatus = putExchange.getResponseStatus(); + + stopClient(); + + boolean statusOk = (responseStatus == 200 || responseStatus == 201); + assertTrue(statusOk); + + String content = IO.toString(new FileInputStream(new File(_docRoot,"output.txt"))); + assertEquals(_content,content); + } + + @Test + public void testGet() throws Exception + { + startClient(_realm); + + ContentExchange getExchange = new ContentExchange(); + getExchange.setURL(getBaseUrl() + "input.txt"); + getExchange.setMethod(HttpMethods.GET); + + _client.send(getExchange); + int state = getExchange.waitForDone(); + + String content = ""; + int responseStatus = getExchange.getResponseStatus(); + if (responseStatus == HttpStatus.OK_200) + { + content = getExchange.getResponseContent(); + } + + stopClient(); + + assertEquals(HttpStatus.OK_200,responseStatus); + assertEquals(_content,content); + } + + @Test + public void testHead() throws Exception + { + startClient(_realm); + + ContentExchange getExchange = new ContentExchange(); + getExchange.setURL(getBaseUrl() + "input.txt"); + getExchange.setMethod(HttpMethods.HEAD); + + _client.send(getExchange); + int state = getExchange.waitForDone(); + + int responseStatus = getExchange.getResponseStatus(); + + stopClient(); + + assertEquals(HttpStatus.OK_200,responseStatus); + } + + @Test + public void testPost() throws Exception + { + startClient(_realm); + + ContentExchange postExchange = new ContentExchange(); + postExchange.setURL(getBaseUrl() + "test"); + postExchange.setMethod(HttpMethods.POST); + postExchange.setRequestContent(new ByteArrayBuffer(_content.getBytes())); + + _client.send(postExchange); + int state = postExchange.waitForDone(); + + int responseStatus = postExchange.getResponseStatus(); + + stopClient(); + + assertEquals(HttpStatus.OK_200,responseStatus); + assertEquals(_content,_requestContent); + } + + protected void startClient(Realm realm) + throws Exception + { + _client = new HttpClient(); + _client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); + if (realm != null) + _client.setRealmResolver(new SimpleRealmResolver(realm)); + _client.start(); + } + + protected void stopClient() + throws Exception + { + if (_client != null) + { + _client.stop(); + _client = null; + } + } + + protected static String getBasePath() + { + return _docRoot.getAbsolutePath(); + } + + protected String getBaseUrl() + { + return _baseUrl; + } + + protected HttpClient getClient() + { + return _client; + } + + protected Realm getRealm() + { + return _realm; + } + + protected String getContent() + { + return _content; + } + + protected static void setProtocol(String protocol) + { + _protocol = protocol; + } + + protected static void setRealm(Realm realm) + { + _realm = realm; + } + + public static void copyStream(InputStream in, OutputStream out) + { + try + { + byte[] buffer=new byte[1024]; + int len; + while ((len=in.read(buffer))>=0) + { + out.write(buffer,0,len); + } + } + catch (EofException e) + { + System.err.println(e); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + protected static class TestHandler extends AbstractHandler { + private final String resourcePath; + + public TestHandler(String repositoryPath) { + this.resourcePath = repositoryPath; + } + + public void handle(String target, Request baseRequest, + HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + if (baseRequest.isHandled()) + { + return; + } + + OutputStream out = null; + + if (baseRequest.getMethod().equals("PUT")) + { + baseRequest.setHandled(true); + + File file = new File(resourcePath, URLDecoder.decode(request.getPathInfo())); + file.getParentFile().mkdirs(); + file.deleteOnExit(); + + out = new FileOutputStream(file); + + response.setStatus(HttpServletResponse.SC_CREATED); + } + + if (baseRequest.getMethod().equals("POST")) + { + baseRequest.setHandled(true); + out = new ByteArrayOutputStream(); + + response.setStatus(HttpServletResponse.SC_OK); + } + + if (out != null) + { + ServletInputStream in = request.getInputStream(); + try + { + copyStream( in, out ); + } + finally + { + in.close(); + out.close(); + } + + if (!(out instanceof FileOutputStream)) + _requestContent = out.toString(); + } + + } + } +} diff --git a/tests/test-loginservice/src/test/resources/createdb.sql b/tests/test-loginservice/src/test/resources/createdb.sql new file mode 100644 index 0000000000..3953b668a4 --- /dev/null +++ b/tests/test-loginservice/src/test/resources/createdb.sql @@ -0,0 +1,40 @@ +CREATE TABLE roles +( + id INT NOT NULL PRIMARY KEY, + role VARCHAR(100) NOT NULL UNIQUE +); + +CREATE TABLE users +( + id INT NOT NULL PRIMARY KEY, + username VARCHAR(100) NOT NULL UNIQUE, + pwd VARCHAR(50) NOT NULL +); + +CREATE TABLE user_roles +( + user_id INT NOT NULL, + role_id INT NOT NULL, + UNIQUE(user_id, role_id) +); + +INSERT INTO roles VALUES +(0,'user'), +(1,'admin'); + +INSERT INTO users VALUES +(1,'jetty','MD5:164c88b302622e17050af52c89945d44'), +(2,'admin','CRYPT:adpexzg3FUZAk'), +(3,'other','OBF:1xmk1w261u9r1w1c1xmq'), +(4,'plain','plain'), +(5,'user','password'), +(6,'digest','MD5:6e120743ad67abfbc385bc2bb754e297'); + +INSERT INTO user_roles VALUES +(1,1), +(2,1), +(2,2), +(3,1), +(4,1), +(5,1), +(6,1);
\ No newline at end of file diff --git a/tests/test-loginservice/src/test/resources/jdbcrealm.properties b/tests/test-loginservice/src/test/resources/jdbcrealm.properties new file mode 100644 index 0000000000..bb79638ed6 --- /dev/null +++ b/tests/test-loginservice/src/test/resources/jdbcrealm.properties @@ -0,0 +1,15 @@ +jdbcdriver = org.apache.derby.jdbc.EmbeddedDriver +url = jdbc:derby:jdbcrealm +username = +password = +usertable = users +usertablekey = id +usertableuserfield = username +usertablepasswordfield = pwd +roletable = roles +roletablekey = id +roletablerolefield = role +userroletable = user_roles +userroletableuserkey = user_id +userroletablerolekey = role_id +cachetime = 300
\ No newline at end of file diff --git a/tests/test-sessions/test-hash-sessions/pom.xml b/tests/test-sessions/test-hash-sessions/pom.xml index 61d2f686e2..4808c1799e 100644 --- a/tests/test-sessions/test-hash-sessions/pom.xml +++ b/tests/test-sessions/test-hash-sessions/pom.xml @@ -34,13 +34,6 @@ <target>1.5</target> </configuration> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <groups>hash-all</groups> - </configuration> - </plugin> </plugins> </build> <dependencies> @@ -65,10 +58,9 @@ <version>${project.version}</version> </dependency> <dependency> - <groupId>org.testng</groupId> - <artifactId>testng</artifactId> - <version>5.8</version> - <classifier>jdk15</classifier> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> </dependencies> diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java index f5da28ceed..5069ae462d 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java @@ -13,10 +13,7 @@ package org.eclipse.jetty.server.session; - -import org.testng.annotations.Test; - - +import org.junit.Test; public class ClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest { @@ -25,7 +22,7 @@ public class ClientCrossContextSessionTest extends AbstractClientCrossContextSes return new HashTestServer(port); } - @Test(groups={"hash-all"}) + @Test public void testCrossContextDispatch() throws Exception { super.testCrossContextDispatch(); diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java index 5de13caaf2..839e266f42 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java @@ -12,13 +12,11 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; + /** * LightLoadTest - * - * */ - public class LightLoadTest extends AbstractLightLoadTest { @@ -27,7 +25,7 @@ public class LightLoadTest extends AbstractLightLoadTest return new HashTestServer(port); } - @Test(groups={"hash-all"}) + @Test public void testLightLoad() throws Exception { super.testLightLoad(); diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java index d06df8ee8c..3d58bc72f2 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java @@ -12,14 +12,11 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * NewSessionTest - * - * */ - public class NewSessionTest extends AbstractNewSessionTest { @@ -28,10 +25,9 @@ public class NewSessionTest extends AbstractNewSessionTest return new HashTestServer(port,max,scavenge); } - @Test(groups={"hash-all"}) + @Test public void testNewSession() throws Exception { super.testNewSession(); } - } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java index dd6312b8c8..5be9208c1e 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java @@ -12,25 +12,21 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * OrphanedSessionTest - * - * */ public class OrphanedSessionTest extends AbstractOrphanedSessionTest { - public AbstractTestServer createServer(int port, int max, int scavenge) { return new HashTestServer(port,max,scavenge); } - @Test(groups={"hash-all"}) + @Test public void testOrphanedSession() throws Exception { super.testOrphanedSession(); } - } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java index ef29ba1764..35a9c2bb27 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java @@ -12,12 +12,10 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * ReentrantRequestSessionTest - * - * */ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest { @@ -26,7 +24,7 @@ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSession return new HashTestServer(port); } - @Test(groups={"hash-all"}) + @Test public void testReentrantRequestSession() throws Exception { super.testReentrantRequestSession(); diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java index 15a6a93bc2..c95f8dd81c 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java @@ -13,22 +13,18 @@ package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; - - +import org.junit.Test; public class ServerCrossContextSessionTest extends AbstractServerCrossContextSessionTest { - public AbstractTestServer createServer(int port) { return new HashTestServer(port); } - @Test(groups={"hash-all"}) + @Test public void testCrossContextDispatch() throws Exception { super.testCrossContextDispatch(); } - } diff --git a/tests/test-sessions/test-jdbc-sessions/pom.xml b/tests/test-sessions/test-jdbc-sessions/pom.xml index 3e8c42ece8..504047ad05 100644 --- a/tests/test-sessions/test-jdbc-sessions/pom.xml +++ b/tests/test-sessions/test-jdbc-sessions/pom.xml @@ -34,13 +34,6 @@ <target>1.5</target> </configuration> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <groups>jdbc-all</groups> - </configuration> - </plugin> </plugins> </build> <dependencies> @@ -77,10 +70,9 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.testng</groupId> - <artifactId>testng</artifactId> - <version>5.8</version> - <classifier>jdk15</classifier> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>test</scope> </dependency> </dependencies> diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java index 8bfaf60916..4195058cad 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java @@ -12,7 +12,7 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * ClientCrossContextSessionTest @@ -22,19 +22,14 @@ import org.testng.annotations.Test; public class ClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest { - - public AbstractTestServer createServer(int port) { return new JdbcTestServer(port); } - @Test(groups={"jdbc-all"}) + @Test public void testCrossContextDispatch() throws Exception { super.testCrossContextDispatch(); } - - - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java index 538419db9f..2d7ac694ac 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java @@ -12,7 +12,7 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * ImmortalSessionTest @@ -22,18 +22,14 @@ import org.testng.annotations.Test; public class ImmortalSessionTest extends AbstractImmortalSessionTest { - - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs) { return new JdbcTestServer(port, maxInactiveMs, scavengeMs); } - - @Test(groups={"jdbc-all"}) + @Test public void testImmortalSession() throws Exception { super.testImmortalSession(); } - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java index 6babe36161..124486363a 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java @@ -12,14 +12,11 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * InvalidationSessionTest - * - * */ - public class InvalidationSessionTest extends AbstractInvalidationSessionTest { public AbstractTestServer createServer(int port) @@ -43,10 +40,9 @@ public class InvalidationSessionTest extends AbstractInvalidationSessionTest } } - @Test(groups={"jdbc-all"}) + @Test public void testInvalidation() throws Exception { super.testInvalidation(); } - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java index d3c805a0ad..1e900108b2 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java @@ -14,11 +14,10 @@ package org.eclipse.jetty.server.session; import org.eclipse.jetty.server.SessionIdManager; import org.eclipse.jetty.server.SessionManager; +import org.eclipse.jetty.server.session.test.MavenTestingUtils; /** * JdbcTestServer - * - * */ public class JdbcTestServer extends AbstractTestServer { @@ -29,7 +28,7 @@ public class JdbcTestServer extends AbstractTestServer static { - System.setProperty("derby.system.home", System.getProperty("java.io.tmpdir")); + System.setProperty("derby.system.home", MavenTestingUtils.getTargetTestingDir().getAbsolutePath()); } public JdbcTestServer(int port) diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java index 82e89ef0dd..77c96a7afb 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java @@ -12,27 +12,21 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * LastAccessTimeTest - * - * */ - public class LastAccessTimeTest extends AbstractLastAccessTimeTest { - public AbstractTestServer createServer(int port, int max, int scavenge) { return new JdbcTestServer(port,max,scavenge); } - @Test(groups={"jdbc-all"}) + @Test public void testLastAccessTime() throws Exception { super.testLastAccessTime(); } - - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java index 773e5df07b..535ceec460 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java @@ -12,14 +12,11 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * LocalSessionScavengingTest - * - * */ - public class LocalSessionScavengingTest extends AbstractLocalSessionScavengingTest { public void pause (int scavenge) @@ -44,7 +41,7 @@ public class LocalSessionScavengingTest extends AbstractLocalSessionScavengingTe return new JdbcTestServer(port,max,scavenge); } - @Test(groups={"jdbc-all"}) + @Test public void testLocalSessionsScavenging() throws Exception { super.testLocalSessionsScavenging(); diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java index 5fd1d18873..7264696269 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java @@ -12,16 +12,13 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * NewSessionTest - * - * */ public class NewSessionTest extends AbstractNewSessionTest { - /** * @see org.eclipse.jetty.server.session.AbstractNewSessionTest#createServer(int, int, int) */ @@ -30,7 +27,7 @@ public class NewSessionTest extends AbstractNewSessionTest return new JdbcTestServer(port,max,scavenge); } - @Test(groups={"jdbc-all"}) + @Test public void testNewSession() throws Exception { super.testNewSession(); diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java index 5b565bf941..b5e415dce6 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java @@ -12,27 +12,21 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * OrphanedSessionTest - * - * */ public class OrphanedSessionTest extends AbstractOrphanedSessionTest { - public AbstractTestServer createServer(int port, int max, int scavenge) { return new JdbcTestServer(port,max,scavenge); } - @Test(groups={"jdbc-all"}) + @Test public void testOrphanedSession() throws Exception { super.testOrphanedSession(); } - - - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java index 407ccc4352..5bab446e04 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java @@ -12,12 +12,11 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; + /** * ReentrantRequestSessionTest - * - * */ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest { @@ -27,11 +26,9 @@ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSession return new JdbcTestServer(port); } - @Test(groups={"jdbc-all"}) + @Test public void testReentrantRequestSession() throws Exception { super.testReentrantRequestSession(); } - - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java index d7d4a6038d..c6732c34a5 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java @@ -12,12 +12,10 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; /** * ServerCrossContextSessionTest - * - * */ public class ServerCrossContextSessionTest extends AbstractServerCrossContextSessionTest { @@ -27,12 +25,9 @@ public class ServerCrossContextSessionTest extends AbstractServerCrossContextSes return new JdbcTestServer(port); } - @Test(groups={"jdbc-all"}) + @Test public void testCrossContextDispatch() throws Exception { super.testCrossContextDispatch(); } - - - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java index d0a3995de3..3400628007 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java @@ -1,6 +1,5 @@ //======================================================================== -//$Id$ -//Copyright 2010 Mort Bay Consulting Pty. Ltd. +// Copyright 2010 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 @@ -13,11 +12,10 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; + /** * SessionMigrationTest - * - * */ public class SessionMigrationTest extends AbstractSessionMigrationTest { @@ -27,12 +25,9 @@ public class SessionMigrationTest extends AbstractSessionMigrationTest return new JdbcTestServer(port); } - @Test(groups={"jdbc-all"}) + @Test public void testSessionMigration() throws Exception { super.testSessionMigration(); } - - - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java index 43b1ddabf9..4389143b8b 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java @@ -12,7 +12,8 @@ // ======================================================================== package org.eclipse.jetty.server.session; -import org.testng.annotations.Test; +import org.junit.Test; + /** * WebAppObjectInSessionTest * @@ -26,11 +27,9 @@ public class WebAppObjectInSessionTest extends AbstractWebAppObjectInSessionTest return new JdbcTestServer(port); } - @Test(groups={"jdbc-all"}) + @Test public void testWebappObjectInSession() throws Exception { super.testWebappObjectInSession(); } - - } diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml index 900d0bef43..4ebf0bf5eb 100644 --- a/tests/test-sessions/test-sessions-common/pom.xml +++ b/tests/test-sessions/test-sessions-common/pom.xml @@ -44,10 +44,9 @@ <version>${project.version}</version> </dependency> <dependency> - <groupId>org.testng</groupId> - <artifactId>testng</artifactId> - <version>5.8</version> - <classifier>jdk15</classifier> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit4-version}</version> <scope>compile</scope> </dependency> </dependencies> diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java index e79ed1bcc9..0674120620 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java @@ -22,19 +22,16 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; -import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.junit.Test; /** * AbstractClientCrossContextSessionTest - * - * */ - public abstract class AbstractClientCrossContextSessionTest { diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java index 54506a5de8..89f16737b3 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java @@ -23,18 +23,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractImmortalSessionTest - * - * */ - public abstract class AbstractImmortalSessionTest { public abstract AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java index aee0b40297..ecf1008985 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java @@ -22,19 +22,16 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; - +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractInvalidationSessionTest * Goal of the test is to be sure that invalidating a session on one node * result in the session being unavailable in the other node also. - * */ - public abstract class AbstractInvalidationSessionTest { public abstract AbstractTestServer createServer(int port); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java index cac47f0e61..379f6b3b45 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java @@ -21,17 +21,14 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractLastAccessTimeTest - * - * */ - public abstract class AbstractLastAccessTimeTest { public abstract AbstractTestServer createServer(int port, int max, int scavenge); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java index 0df0f27e9a..588ed2b6c8 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java @@ -27,18 +27,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractLightLoadTest - * - * */ - public abstract class AbstractLightLoadTest { protected boolean _stress = Boolean.getBoolean( "STRESS" ); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java index 386c14d8aa..03f8db0c97 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java @@ -21,20 +21,16 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.eclipse.jetty.client.ContentExchange; +import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.SessionManager; -import org.eclipse.jetty.client.ContentExchange; -import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; - +import org.junit.Test; /** * AbstractLocalSessionScavengingTest - * - * */ - public abstract class AbstractLocalSessionScavengingTest { public abstract AbstractTestServer createServer(int port, int max, int scavenge); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java index fa5f53f3c9..4c3867344c 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java @@ -21,18 +21,15 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.HttpMethods; -import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.junit.Test; /** * AbstractNewSessionTest - * - * */ - public abstract class AbstractNewSessionTest { public abstract AbstractTestServer createServer(int port, int max, int scavenge); @@ -48,6 +45,7 @@ public abstract class AbstractNewSessionTest e.printStackTrace(); } } + @Test public void testNewSession() throws Exception { diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java index e223bdaa81..29be97b5f2 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java @@ -23,17 +23,14 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractOrphanedSessionTest - * - * */ - public abstract class AbstractOrphanedSessionTest { @@ -51,18 +48,18 @@ public abstract class AbstractOrphanedSessionTest // Disable scavenging for the first server, so that we simulate its "crash". String contextPath = ""; String servletMapping = "/server"; - int port1 = random.nextInt(50000) + 10000; int inactivePeriod = 5; - AbstractTestServer server1 = createServer(port1, inactivePeriod, -1); + AbstractTestServer server1 = createServer(0, inactivePeriod, -1); server1.addContext(contextPath).addServlet(TestServlet.class, servletMapping); server1.start(); + int port1 = server1.getPort(); try { - int port2 = random.nextInt(50000) + 10000; int scavengePeriod = 2; - AbstractTestServer server2 = createServer(port2, inactivePeriod, scavengePeriod); + AbstractTestServer server2 = createServer(0, inactivePeriod, scavengePeriod); server2.addContext(contextPath).addServlet(TestServlet.class, servletMapping); server2.start(); + int port2 = server2.getPort(); try { HttpClient client = new HttpClient(); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractReentrantRequestSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractReentrantRequestSessionTest.java index ad776a332d..d8d5064172 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractReentrantRequestSessionTest.java @@ -22,18 +22,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractReentrantRequestSessionTest - * - * */ - public abstract class AbstractReentrantRequestSessionTest { public abstract AbstractTestServer createServer(int port); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractServerCrossContextSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractServerCrossContextSessionTest.java index fe07c05da0..e91fffd402 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractServerCrossContextSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractServerCrossContextSessionTest.java @@ -25,18 +25,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; -import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.junit.Test; /** * AbstractServerCrossContextSessionTest - * - * */ - public abstract class AbstractServerCrossContextSessionTest { diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java index 511efbe161..b4584fd5ae 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java @@ -23,17 +23,14 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.HttpClient; -import org.testng.annotations.Test; +import org.eclipse.jetty.http.HttpMethods; +import org.junit.Test; /** * AbstractSessionMigrationTest - * - * */ - public abstract class AbstractSessionMigrationTest { public abstract AbstractTestServer createServer (int port); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java index 8edde246bc..71f592ebc9 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java @@ -60,6 +60,11 @@ public abstract class AbstractTestServer _server.setHandler(_contexts); _server.start(); } + + public int getPort() + { + return _server.getConnectors()[0].getLocalPort(); + } public ServletContextHandler addContext(String contextPath) { diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java index aaaa3c19c3..3679dc9d42 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java @@ -21,13 +21,12 @@ import java.util.Random; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.client.ContentExchange; +import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.client.ContentExchange; -import org.eclipse.jetty.client.HttpClient; - -import org.testng.annotations.Test; +import org.junit.Test; /** * AbstractWebAppObjectInSessionTest @@ -37,9 +36,7 @@ import org.testng.annotations.Test; * the same webapp on nodeB is able to load that object from the session. * * This test is only appropriate for clustered session managers. - * */ - public abstract class AbstractWebAppObjectInSessionTest { public abstract AbstractTestServer createServer(int port); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/test/MavenTestingUtils.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/test/MavenTestingUtils.java new file mode 100644 index 0000000000..028afd3ce1 --- /dev/null +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/test/MavenTestingUtils.java @@ -0,0 +1,221 @@ +// ======================================================================== +// Copyright (c) Webtide LLC +// ------------------------------------------------------------------------ +// 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.apache.org/licenses/LICENSE-2.0.txt +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +package org.eclipse.jetty.server.session.test; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +import junit.framework.TestCase; + +import org.eclipse.jetty.util.IO; + +/** + * Common utility methods for working with JUnit tests cases in a maven friendly way. + */ +public class MavenTestingUtils +{ + private static File basedir; + private static File testResourcesDir; + private static File targetDir; + + // private static Boolean surefireRunning; + + public static File getBasedir() + { + if (basedir == null) + { + String cwd = System.getProperty("basedir"); + + if (cwd == null) + { + cwd = System.getProperty("user.dir"); + } + + basedir = new File(cwd); + } + + return basedir; + } + + /** + * Get the directory to the /target directory for this project. + * + * @return the directory path to the target directory. + */ + public static File getTargetDir() + { + if (targetDir == null) + { + targetDir = new File(getBasedir(),"target"); + PathAssert.assertDirExists("Target Dir",targetDir); + } + return targetDir; + } + + /** + * Create a {@link File} object for a path in the /target directory. + * + * @param path + * the path desired, no validation of existence is performed. + * @return the File to the path. + */ + public static File getTargetFile(String path) + { + return new File(getTargetDir(),path.replace("/",File.separator)); + } + + public static File getTargetTestingDir() + { + File dir = new File(getTargetDir(),"testing"); + if (!dir.exists()) + { + dir.mkdirs(); + } + return dir; + } + + /** + * Get a dir in /target/ that uses the JUnit 3.x {@link TestCase#getName()} to make itself unique. + * + * @param test + * the junit 3.x testcase to base this new directory on. + * @return the File path to the testcase specific testing directory underneath the + * <code>${basedir}/target</code> sub directory + */ + public static File getTargetTestingDir(TestCase test) + { + return getTargetTestingDir(test.getName()); + } + + /** + * Get a dir in /target/ that uses the an arbitrary name. + * + * @param testname + * the testname to create directory against. + * @return the File path to the testname sepecific testing directory underneath the + * <code>${basedir}/target</code> sub directory + */ + public static File getTargetTestingDir(String testname) + { + File dir = new File(getTargetDir(),"test-" + testname); + return dir; + } + + /** + * Get a dir from the src/test/resource directory. + * + * @param name + * the name of the path to get (it must exist as a dir) + * @return the dir in src/test/resource + */ + public static File getTestResourceDir(String name) + { + File dir = new File(getTestResourcesDir(),name); + PathAssert.assertDirExists("Test Resource Dir",dir); + return dir; + } + + /** + * Get a file from the src/test/resource directory. + * + * @param name + * the name of the path to get (it must exist as a file) + * @return the file in src/test/resource + */ + public static File getTestResourceFile(String name) + { + File file = new File(getTestResourcesDir(),name); + PathAssert.assertFileExists("Test Resource File",file); + return file; + } + + /** + * Get a path resource (File or Dir) from the src/test/resource directory. + * + * @param name + * the name of the path to get (it must exist) + * @return the path in src/test/resource + */ + public static File getTestResourcePath(String name) + { + File path = new File(getTestResourcesDir(),name); + PathAssert.assertExists("Test Resource Path",path); + return path; + } + + /** + * Get the directory to the src/test/resource directory + * + * @return the directory {@link File} to the src/test/resources directory + */ + public static File getTestResourcesDir() + { + if (testResourcesDir == null) + { + testResourcesDir = new File(basedir,"src/test/resources".replace("/",File.separator)); + PathAssert.assertDirExists("Test Resources Dir",testResourcesDir); + } + return testResourcesDir; + } + + /** + * Read the contents of a file into a String and return it. + * + * @param file + * the file to read. + * @return the contents of the file. + * @throws IOException + * if unable to read the file. + */ + public static String readToString(File file) throws IOException + { + FileReader reader = null; + try + { + reader = new FileReader(file); + return IO.toString(reader); + } + finally + { + IO.close(reader); + } + } + + public static String getTestID() + { + StackTraceElement stacked[] = new Throwable().getStackTrace(); + + String name = null; + + for(StackTraceElement stack: stacked) { + if(stack.getClassName().endsWith("Test")) + { + name = stack.getClassName(); + if (stack.getMethodName().startsWith("test")) + { + return stack.getClassName() + "#" + stack.getMethodName(); + } + } + } + + if(name == null) + { + return "Unidentified_Test"; + } + return name; + } +} diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/test/PathAssert.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/test/PathAssert.java new file mode 100644 index 0000000000..f85a0976df --- /dev/null +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/test/PathAssert.java @@ -0,0 +1,40 @@ +// ======================================================================== +// Copyright (c) Webtide LLC +// ------------------------------------------------------------------------ +// 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.apache.org/licenses/LICENSE-2.0.txt +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +package org.eclipse.jetty.server.session.test; + +import java.io.File; + +import org.junit.Assert; + +public class PathAssert +{ + public static void assertDirExists(String msg, File path) + { + assertExists(msg,path); + Assert.assertTrue(msg + " path should be a Dir : " + path.getAbsolutePath(),path.isDirectory()); + } + + public static void assertFileExists(String msg, File path) + { + assertExists(msg,path); + Assert.assertTrue(msg + " path should be a File : " + path.getAbsolutePath(),path.isFile()); + } + + public static void assertExists(String msg, File path) + { + Assert.assertTrue(msg + " path should exist: " + path.getAbsolutePath(),path.exists()); + } +} |