diff --git a/VERSION.txt b/VERSION.txt index b2cc3a8ca9d..838f1d711b4 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -64,6 +64,31 @@ jetty-8.1.10.v20130312 - 12 March 2013 + 402833 Test harness for global error page and hide exception message from reason string +jetty-7.6.11.v20130520 - 20 May 2013 + + 402844 STOP.PORT & STOP.KEY behaviour has changed + + 403281 jetty.sh waits for started or failure before returning + + 403513 jetty:run goal cannot be executed twice during the maven build + + 403570 Asynchronous Request Logging + + 404010 fix cast exception in mongodb session manager + + 404128 Add Vary headers rather than set them + + 404283 org.eclipse.jetty.util.Scanner.scanFile() dies with an NPE if + listFiles() returns null + + 404325 data constraint redirection does send default port + + 404517 Close connection if request received after half close + + 404789 Support IPv6 addresses in DoSFilter white list. + + 404958 Fixed Resource.newSystemResource striped / handling + + 405281 allow filemappedbuffers to not be used + + 405537 NPE in rendering JSP using SPDY and wrapped ServletRequest + + 406437 Digest Auth supports out of order nc + + 406923 CR line termination + + 407136 @PreDestroy called after Servlet.destroy() + + 407173 java.lang.IllegalStateException: null when using JDBCSessionManager + + 407976 JDBCSessionIdManager potentially leaves server in bad state after + startup + + 408077 HashSessionManager leaves file handles open after being stopped + + 408446 Multipart parsing issue with boundry and charset in ContentType + header + jetty-7.6.10.v20130312 - 12 March 2013 + 376273 Early EOF because of SSL Protocol Error on https://api-3t.paypal.com/nvp. diff --git a/example-async-rest/async-rest-jar/pom.xml b/example-async-rest/async-rest-jar/pom.xml index b69b81e5c27..442669b4770 100644 --- a/example-async-rest/async-rest-jar/pom.xml +++ b/example-async-rest/async-rest-jar/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty example-async-rest - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 org.eclipse.jetty.example-async-rest diff --git a/example-async-rest/async-rest-webapp/pom.xml b/example-async-rest/async-rest-webapp/pom.xml index 814fa404eb5..428e919eaf0 100644 --- a/example-async-rest/async-rest-webapp/pom.xml +++ b/example-async-rest/async-rest-webapp/pom.xml @@ -2,13 +2,14 @@ org.eclipse.jetty example-async-rest - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 org.eclipse.jetty.example-async-rest example-async-rest-webapp - war Example Async Rest :: Webapp + http://www.eclipse.org/jetty + war async-rest diff --git a/example-async-rest/pom.xml b/example-async-rest/pom.xml index da218b72177..a6141e85385 100644 --- a/example-async-rest/pom.xml +++ b/example-async-rest/pom.xml @@ -2,13 +2,14 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 org.eclipse.jetty example-async-rest pom Example Async Rest + http://www.eclipse.org/jetty async-rest-jar async-rest-webapp diff --git a/example-jetty-embedded/pom.xml b/example-jetty-embedded/pom.xml index 3f9ed05c94b..7d97e4d7b5a 100644 --- a/example-jetty-embedded/pom.xml +++ b/example-jetty-embedded/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 example-jetty-embedded Example :: Jetty Embedded Jetty Embedded Examples + http://www.eclipse.org/jetty org.eclipse.jetty diff --git a/jetty-aggregate/jetty-all-server/pom.xml b/jetty-aggregate/jetty-all-server/pom.xml index 9a654517909..ba069e99443 100644 --- a/jetty-aggregate/jetty-all-server/pom.xml +++ b/jetty-aggregate/jetty-all-server/pom.xml @@ -2,11 +2,12 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-all-server Jetty :: Aggregate :: All Server + http://www.eclipse.org/jetty ${project.groupId}.${project.artifactId} diff --git a/jetty-aggregate/jetty-all/pom.xml b/jetty-aggregate/jetty-all/pom.xml index 4a70e60d66f..b7e6dc49341 100644 --- a/jetty-aggregate/jetty-all/pom.xml +++ b/jetty-aggregate/jetty-all/pom.xml @@ -2,11 +2,12 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-all Jetty :: Aggregate :: All core Jetty + http://www.eclipse.org/jetty ${project.build.directory}/sources diff --git a/jetty-aggregate/jetty-client/pom.xml b/jetty-aggregate/jetty-client/pom.xml index e123c9451e1..f1d3cdb9ab8 100644 --- a/jetty-aggregate/jetty-client/pom.xml +++ b/jetty-aggregate/jetty-client/pom.xml @@ -2,12 +2,12 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-client Jetty :: Aggregate :: HTTP Client - + http://www.eclipse.org/jetty ${project.build.directory}/sources diff --git a/jetty-aggregate/jetty-plus/pom.xml b/jetty-aggregate/jetty-plus/pom.xml index 93111784f6a..dbde12da812 100644 --- a/jetty-aggregate/jetty-plus/pom.xml +++ b/jetty-aggregate/jetty-plus/pom.xml @@ -2,12 +2,12 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-plus Jetty :: Aggregate :: Plus Server - + http://www.eclipse.org/jetty ${project.build.directory}/sources diff --git a/jetty-aggregate/jetty-server/pom.xml b/jetty-aggregate/jetty-server/pom.xml index 3b53fe916e4..24c157327ad 100644 --- a/jetty-aggregate/jetty-server/pom.xml +++ b/jetty-aggregate/jetty-server/pom.xml @@ -2,12 +2,12 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-server Jetty :: Aggregate :: HTTP Server - + http://www.eclipse.org/jetty ${project.build.directory}/sources diff --git a/jetty-aggregate/jetty-servlet/pom.xml b/jetty-aggregate/jetty-servlet/pom.xml index 904c2a1fae1..5a0c363ee7d 100644 --- a/jetty-aggregate/jetty-servlet/pom.xml +++ b/jetty-aggregate/jetty-servlet/pom.xml @@ -2,12 +2,12 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-servlet Jetty :: Aggregate :: Servlet Server - + http://www.eclipse.org/jetty ${project.build.directory}/sources diff --git a/jetty-aggregate/jetty-webapp/pom.xml b/jetty-aggregate/jetty-webapp/pom.xml index 3b39eb5163d..95688163a89 100644 --- a/jetty-aggregate/jetty-webapp/pom.xml +++ b/jetty-aggregate/jetty-webapp/pom.xml @@ -2,12 +2,12 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-webapp Jetty :: Aggregate :: WebApp Server - + http://www.eclipse.org/jetty ${project.build.directory}/sources diff --git a/jetty-aggregate/jetty-websocket/pom.xml b/jetty-aggregate/jetty-websocket/pom.xml index ed335898227..7fc517e7d98 100644 --- a/jetty-aggregate/jetty-websocket/pom.xml +++ b/jetty-aggregate/jetty-websocket/pom.xml @@ -2,12 +2,12 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-websocket Jetty :: Aggregate :: Websocket - + http://www.eclipse.org/jetty ${project.build.directory}/sources diff --git a/jetty-aggregate/pom.xml b/jetty-aggregate/pom.xml index 06493499dba..b1b1d65ff32 100644 --- a/jetty-aggregate/pom.xml +++ b/jetty-aggregate/pom.xml @@ -4,11 +4,12 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT org.eclipse.jetty.aggregate jetty-aggregate-project Jetty :: Aggregate Project + http://www.eclipse.org/jetty pom diff --git a/jetty-ajp/pom.xml b/jetty-ajp/pom.xml index 1ebb19be6c6..c63631d29e9 100644 --- a/jetty-ajp/pom.xml +++ b/jetty-ajp/pom.xml @@ -2,11 +2,12 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-ajp Jetty :: AJP + http://www.eclipse.org/jetty ${project.groupId}.ajp diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml index 366f5f60243..f2abb23510b 100644 --- a/jetty-annotations/pom.xml +++ b/jetty-annotations/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-annotations Jetty :: Servlet Annotations Annotation support for deploying servlets in jetty. + http://www.eclipse.org/jetty ${project.groupId}.annotations 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 85c366073f0..2d46715c4a2 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 @@ -23,24 +23,17 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ServiceLoader; -import java.util.Set; import javax.servlet.ServletContainerInitializer; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; import javax.servlet.annotation.HandlesTypes; - import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; import org.eclipse.jetty.plus.annotation.ContainerInitializer; import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.webapp.Configuration; import org.eclipse.jetty.webapp.AbstractConfiguration; -import org.eclipse.jetty.webapp.Descriptor; -import org.eclipse.jetty.webapp.DiscoveredAnnotation; import org.eclipse.jetty.webapp.FragmentDescriptor; import org.eclipse.jetty.webapp.MetaDataComplete; import org.eclipse.jetty.webapp.WebAppContext; @@ -56,18 +49,31 @@ public class AnnotationConfiguration extends AbstractConfiguration private static final Logger LOG = Log.getLogger(AnnotationConfiguration.class); public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap"; public static final String CONTAINER_INITIALIZERS = "org.eclipse.jetty.containerInitializers"; + public static final String CONTAINER_INITIALIZER_LISTENER = "org.eclipse.jetty.containerInitializerListener"; protected List _discoverableAnnotationHandlers = new ArrayList(); protected ClassInheritanceHandler _classInheritanceHandler; protected List _containerInitializerAnnotationHandlers = new ArrayList(); + - + @Override public void preConfigure(final WebAppContext context) throws Exception { } - + @Override + public void deconfigure(WebAppContext context) throws Exception + { + context.removeAttribute(CLASS_INHERITANCE_MAP); + context.removeAttribute(CONTAINER_INITIALIZERS); + ServletContainerInitializerListener listener = (ServletContainerInitializerListener)context.getAttribute(CONTAINER_INITIALIZER_LISTENER); + if (listener != null) + { + context.removeBean(listener); + context.removeAttribute(CONTAINER_INITIALIZER_LISTENER); + } + } /** * @see org.eclipse.jetty.webapp.AbstractConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext) @@ -225,8 +231,12 @@ public class AnnotationConfiguration extends AbstractConfiguration //add a bean which will call the servletcontainerinitializers when appropriate - ServletContainerInitializerListener listener = new ServletContainerInitializerListener(); + ServletContainerInitializerListener listener = (ServletContainerInitializerListener)context.getAttribute(CONTAINER_INITIALIZER_LISTENER); + if (listener != null) + throw new IllegalStateException("ServletContainerInitializerListener already exists"); + listener = new ServletContainerInitializerListener(); listener.setWebAppContext(context); + context.setAttribute(CONTAINER_INITIALIZER_LISTENER, listener); context.addBean(listener, true); } diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml index 9d6afab1558..25d51b1d8d4 100644 --- a/jetty-client/pom.xml +++ b/jetty-client/pom.xml @@ -2,19 +2,17 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-client Jetty :: Asynchronous HTTP Client - {$jetty.url} - + http://www.eclipse.org/jetty ${project.groupId}.client target/test-policy - 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 1181eb80592..73c85d23161 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 @@ -52,10 +52,10 @@ public class HttpDestination implements Dumpable { private static final Logger LOG = Log.getLogger(HttpDestination.class); - private final List _queue = new LinkedList(); + private final List _exchanges = new LinkedList(); private final List _connections = new LinkedList(); - private final BlockingQueue _newQueue = new ArrayBlockingQueue(10, true); - private final List _idle = new ArrayList(); + private final BlockingQueue _reservedConnections = new ArrayBlockingQueue(10, true); + private final List _idleConnections = new ArrayList(); private final HttpClient _client; private final Address _address; private final boolean _ssl; @@ -63,14 +63,12 @@ public class HttpDestination implements Dumpable private volatile int _maxConnections; private volatile int _maxQueueSize; private int _pendingConnections = 0; - private int _newConnection = 0; + private int _pendingReservedConnections = 0; private volatile Address _proxy; private Authentication _proxyAuthentication; private PathMap _authorizations; private List _cookies; - - HttpDestination(HttpClient client, Address address, boolean ssl) { _client = client; @@ -136,7 +134,7 @@ public class HttpDestination implements Dumpable { synchronized (this) { - return _idle.size(); + return _idleConnections.size(); } } @@ -185,7 +183,7 @@ public class HttpDestination implements Dumpable int totalConnections = _connections.size() + _pendingConnections; if (totalConnections < _maxConnections) { - _newConnection++; + _pendingReservedConnections++; startConnection = true; } } @@ -195,7 +193,7 @@ public class HttpDestination implements Dumpable startNewConnection(); try { - Object o = _newQueue.take(); + Object o = _reservedConnections.take(); if (o instanceof AbstractHttpConnection) { connection = (AbstractHttpConnection)o; @@ -246,15 +244,15 @@ public class HttpDestination implements Dumpable connection.close(); connection = null; } - if (_idle.size() > 0) - connection = _idle.remove(_idle.size() - 1); + if (_idleConnections.size() > 0) + connection = _idleConnections.remove(_idleConnections.size() - 1); } if (connection == null) { return null; } - + // Check if the connection was idle, // but it expired just a moment ago if (connection.cancelIdleTimeout()) @@ -291,20 +289,20 @@ public class HttpDestination implements Dumpable synchronized (this) { _pendingConnections--; - if (_newConnection > 0) + if (_pendingReservedConnections > 0) { connect_failure = throwable; - _newConnection--; + _pendingReservedConnections--; } - else if (_queue.size() > 0) + else if (_exchanges.size() > 0) { - HttpExchange ex = _queue.remove(0); + HttpExchange ex = _exchanges.remove(0); if (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()) + if (!_exchanges.isEmpty() && _client.isStarted()) startConnection = true; } } @@ -316,7 +314,7 @@ public class HttpDestination implements Dumpable { try { - _newQueue.put(connect_failure); + _reservedConnections.put(connect_failure); } catch (InterruptedException e) { @@ -330,10 +328,10 @@ public class HttpDestination implements Dumpable synchronized (this) { _pendingConnections--; - if (_queue.size() > 0) + if (_exchanges.size() > 0) { - HttpExchange ex = _queue.remove(0); - if(ex.setStatus(HttpExchange.STATUS_EXCEPTED)) + HttpExchange ex = _exchanges.remove(0); + if (ex.setStatus(HttpExchange.STATUS_EXCEPTED)) ex.getEventListener().onException(throwable); } } @@ -341,47 +339,53 @@ public class HttpDestination implements Dumpable public void onNewConnection(final AbstractHttpConnection connection) throws IOException { - Connection q_connection = null; + Connection reservedConnection = null; synchronized (this) { _pendingConnections--; _connections.add(connection); - if (_newConnection > 0) + if (_pendingReservedConnections > 0) { - q_connection = connection; - _newConnection--; - } - else if (_queue.size() == 0) - { - connection.setIdleTimeout(); - _idle.add(connection); + reservedConnection = connection; + _pendingReservedConnections--; } else { + // Establish the tunnel if needed EndPoint endPoint = connection.getEndPoint(); if (isProxied() && endPoint instanceof SelectConnector.UpgradableEndPoint) { SelectConnector.UpgradableEndPoint proxyEndPoint = (SelectConnector.UpgradableEndPoint)endPoint; - HttpExchange exchange = _queue.get(0); - ConnectExchange connect = new ConnectExchange(getAddress(), proxyEndPoint, exchange); + ConnectExchange connect = new ConnectExchange(getAddress(), proxyEndPoint); connect.setAddress(getProxy()); + LOG.debug("Establishing tunnel to {} via {}", getAddress(), getProxy()); send(connection, connect); } else { - HttpExchange exchange = _queue.remove(0); - send(connection, exchange); + // Another connection stole the exchange that caused the creation of this connection ? + if (_exchanges.size() == 0) + { + LOG.debug("No exchanges for new connection {}", connection); + connection.setIdleTimeout(); + _idleConnections.add(connection); + } + else + { + HttpExchange exchange = _exchanges.remove(0); + send(connection, exchange); + } } } } - if (q_connection != null) + if (reservedConnection != null) { try { - _newQueue.put(q_connection); + _reservedConnections.put(reservedConnection); } catch (InterruptedException e) { @@ -414,14 +418,14 @@ public class HttpDestination implements Dumpable { synchronized (this) { - if (_queue.size() == 0) + if (_exchanges.size() == 0) { connection.setIdleTimeout(); - _idle.add(connection); + _idleConnections.add(connection); } else { - HttpExchange ex = _queue.remove(0); + HttpExchange ex = _exchanges.remove(0); send(connection, ex); } this.notifyAll(); @@ -433,7 +437,7 @@ public class HttpDestination implements Dumpable synchronized (this) { _connections.remove(connection); - if (!_queue.isEmpty()) + if (!_exchanges.isEmpty()) startConnection = true; } @@ -445,16 +449,16 @@ public class HttpDestination implements Dumpable public void returnIdleConnection(AbstractHttpConnection connection) { // TODO work out the real idle time; - long idleForMs=connection!=null&&connection.getEndPoint()!=null?connection.getEndPoint().getMaxIdleTime():-1; + long idleForMs = connection.getEndPoint() != null ? connection.getEndPoint().getMaxIdleTime() : -1; connection.onIdleExpired(idleForMs); boolean startConnection = false; synchronized (this) { - _idle.remove(connection); + _idleConnections.remove(connection); _connections.remove(connection); - if (!_queue.isEmpty() && _client.isStarted()) + if (!_exchanges.isEmpty() && _client.isStarted()) startConnection = true; } @@ -472,10 +476,9 @@ public class HttpDestination implements Dumpable for (int i = listeners.size(); i > 0; --i) { String listenerClass = listeners.get(i - 1); - try { - Class listener = Class.forName(listenerClass); + Class listener = Class.forName(listenerClass); Constructor constructor = listener.getDeclaredConstructor(HttpDestination.class, HttpExchange.class); HttpEventListener elistener = (HttpEventListener)constructor.newInstance(this, ex); ex.setEventListener(elistener); @@ -484,7 +487,9 @@ public class HttpDestination implements Dumpable { throw new IOException("Unable to instantiate registered listener for destination: " + listenerClass) { - {initCause(e);} + { + initCause(e); + } }; } } @@ -549,10 +554,10 @@ public class HttpDestination implements Dumpable boolean startConnection = false; synchronized (this) { - if (_queue.size() == _maxQueueSize) + if (_exchanges.size() == _maxQueueSize) throw new RejectedExecutionException("Queue full for address " + _address); - _queue.add(ex); + _exchanges.add(ex); if (_connections.size() + _pendingConnections < _maxConnections) startConnection = true; } @@ -568,7 +573,7 @@ public class HttpDestination implements Dumpable // destination queue, make sure it is removed synchronized (this) { - _queue.remove(exchange); + _exchanges.remove(exchange); } } @@ -581,7 +586,7 @@ public class HttpDestination implements Dumpable if (!connection.send(exchange)) { if (exchange.getStatus() <= HttpExchange.STATUS_WAITING_FOR_CONNECTION) - _queue.add(0, exchange); + _exchanges.add(0, exchange); returnIdleConnection(connection); } } @@ -590,7 +595,7 @@ public class HttpDestination implements Dumpable @Override public synchronized String toString() { - return String.format("HttpDestination@%x//%s:%d(%d/%d,%d,%d/%d)%n",hashCode(),_address.getHost(),_address.getPort(),_connections.size(),_maxConnections,_idle.size(),_queue.size(),_maxQueueSize); + return String.format("HttpDestination@%x//%s:%d(%d/%d,%d,%d/%d)%n", hashCode(), _address.getHost(), _address.getPort(), _connections.size(), _maxConnections, _idleConnections.size(), _exchanges.size(), _maxQueueSize); } public synchronized String toDetailString() @@ -603,7 +608,7 @@ public class HttpDestination implements Dumpable for (AbstractHttpConnection connection : _connections) { b.append(connection.toDetailString()); - if (_idle.contains(connection)) + if (_idleConnections.contains(connection)) b.append(" IDLE"); b.append('\n'); } @@ -650,39 +655,33 @@ public class HttpDestination implements Dumpable } } - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.util.component.Dumpable#dump() - */ public String dump() { return AggregateLifeCycle.dump(this); } - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.util.component.Dumpable#dump(java.lang.Appendable, java.lang.String) - */ public void dump(Appendable out, String indent) throws IOException { synchronized (this) { - out.append(String.valueOf(this)+"idle="+_idle.size()+" pending="+_pendingConnections).append("\n"); - AggregateLifeCycle.dump(out,indent,_connections); + out.append(String.valueOf(this)); + out.append("idle="); + out.append(String.valueOf(_idleConnections.size())); + out.append(" pending="); + out.append(String.valueOf(_pendingConnections)); + out.append("\n"); + AggregateLifeCycle.dump(out, indent, _connections); } } private class ConnectExchange extends ContentExchange { private final SelectConnector.UpgradableEndPoint proxyEndPoint; - private final HttpExchange exchange; - public ConnectExchange(Address serverAddress, SelectConnector.UpgradableEndPoint proxyEndPoint, HttpExchange exchange) + public ConnectExchange(Address serverAddress, SelectConnector.UpgradableEndPoint proxyEndPoint) { this.proxyEndPoint = proxyEndPoint; - this.exchange = exchange; setMethod(HttpMethods.CONNECT); - setVersion(exchange.getVersion()); String serverHostAndPort = serverAddress.toString(); setRequestURI(serverHostAndPort); addRequestHeader(HttpHeaders.HOST, serverHostAndPort); @@ -698,13 +697,13 @@ public class HttpDestination implements Dumpable { proxyEndPoint.upgrade(); } - else if(responseStatus == HttpStatus.GATEWAY_TIMEOUT_504) + else if (responseStatus == HttpStatus.GATEWAY_TIMEOUT_504) { onExpire(); } else { - onException(new ProtocolException("Proxy: " + proxyEndPoint.getRemoteAddr() +":" + proxyEndPoint.getRemotePort() + " didn't return http return code 200, but " + responseStatus + " while trying to request: " + exchange.getAddress().toString())); + onException(new ProtocolException("Proxy: " + proxyEndPoint.getRemoteAddr() + ":" + proxyEndPoint.getRemotePort() + " didn't return http return code 200, but " + responseStatus)); } } @@ -717,18 +716,27 @@ public class HttpDestination implements Dumpable @Override protected void onException(Throwable x) { - _queue.remove(exchange); - if (exchange.setStatus(STATUS_EXCEPTED)) + HttpExchange exchange = null; + synchronized (HttpDestination.this) + { + if (!_exchanges.isEmpty()) + exchange = _exchanges.remove(0); + } + if (exchange != null && exchange.setStatus(STATUS_EXCEPTED)) exchange.getEventListener().onException(x); } @Override protected void onExpire() { - _queue.remove(exchange); - if (exchange.setStatus(STATUS_EXPIRED)) + HttpExchange exchange = null; + synchronized (HttpDestination.this) + { + if (!_exchanges.isEmpty()) + exchange = _exchanges.remove(0); + } + if (exchange != null && exchange.setStatus(STATUS_EXPIRED)) exchange.getEventListener().onExpire(); } - } } 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 6fe61048eb0..0877dd803e5 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 @@ -125,10 +125,10 @@ public class HttpExchange protected void expire(HttpDestination destination) { + AbstractHttpConnection connection = _connection; if (getStatus() < HttpExchange.STATUS_COMPLETED) setStatus(HttpExchange.STATUS_EXPIRED); destination.exchangeExpired(this); - AbstractHttpConnection connection = _connection; if (connection != null) connection.exchangeExpired(this); } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/IdleTimeoutTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/IdleTimeoutTest.java index 930a378d284..ed2b29425ce 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/IdleTimeoutTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/IdleTimeoutTest.java @@ -18,13 +18,28 @@ package org.eclipse.jetty.client; +import java.io.IOException; +import java.net.URI; 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 org.eclipse.jetty.http.HttpMethods; +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.junit.Assert; import org.junit.Ignore; import org.junit.Test; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + /** * IdleTimeoutTest * @@ -77,4 +92,56 @@ public class IdleTimeoutTest Assert.fail("Test did not complete in time"); } + + @Test + public void testConnectionsAreReleasedWhenExpired() throws Exception + { + // we need a server that times out and a client with shorter timeout settings, so we need to create new ones + Server server = new Server(); + Connector connector = new SelectChannelConnector(); + server.addConnector(connector); + server.setHandler(new AbstractHandler() + { + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + if (request.getParameter("timeout") != null) + { + try + { + Thread.sleep(1000); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + baseRequest.setHandled(true); + response.getWriter().write("Hello world"); + } + }); + server.start(); + + HttpClient httpClient = new HttpClient(); + httpClient.setMaxConnectionsPerAddress(1); + httpClient.setConnectTimeout(200); + httpClient.setTimeout(200); + httpClient.setIdleTimeout(200); + httpClient.start(); + + String uriString = "http://localhost:" + connector.getLocalPort() + "/"; + + HttpExchange httpExchange = new HttpExchange(); + httpExchange.setURI(URI.create(uriString).resolve("?timeout=true")); + httpExchange.setMethod(HttpMethods.GET); + httpClient.send(httpExchange); + int status = httpExchange.waitForDone(); + assertThat("First request expired", status, is(8)); + + httpExchange = new HttpExchange(); + httpExchange.setURI(URI.create(uriString)); + httpExchange.setMethod(HttpMethods.GET); + httpClient.send(httpExchange); + status = httpExchange.waitForDone(); + assertThat("Second request was successful as timeout is not set", status, is(7)); + } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyTunnellingTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyTunnellingTest.java index 521710c057c..550c5418ea0 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyTunnellingTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyTunnellingTest.java @@ -18,13 +18,12 @@ package org.eclipse.jetty.client; -import static org.junit.Assert.*; - import java.io.IOException; +import java.io.InterruptedIOException; import java.net.URLEncoder; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - +import java.util.concurrent.atomic.AtomicReference; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; @@ -32,6 +31,7 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpHeaders; import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.server.Connector; @@ -45,8 +45,12 @@ import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.After; +import org.junit.Assert; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + public class ProxyTunnellingTest { private Server server; @@ -113,7 +117,7 @@ public class ProxyTunnellingTest } @Test - public void testOneMessageSSL() throws Exception + public void testOneExchangeViaSSL() throws Exception { startSSLServer(new ServerHandler()); startProxy(); @@ -141,7 +145,7 @@ public class ProxyTunnellingTest } @Test - public void testTwoMessagesSSL() throws Exception + public void testTwoExchangesViaSSL() throws Exception { startSSLServer(new ServerHandler()); startProxy(); @@ -181,6 +185,85 @@ public class ProxyTunnellingTest } } + @Test + public void testTwoConcurrentExchangesViaSSL() throws Exception + { + startSSLServer(new ServerHandler()); + startProxy(); + + final HttpClient httpClient = new HttpClient(); + httpClient.setProxy(new Address("localhost", proxyPort())); + httpClient.start(); + + try + { + final AtomicReference connection = new AtomicReference(); + final CountDownLatch connectionLatch = new CountDownLatch(1); + ContentExchange exchange1 = new ContentExchange(true) + { + @Override + protected void onRequestCommitted() throws IOException + { + // Simulate the concurrent send of a second exchange which + // triggers the opening of a second connection but then + // it's "stolen" by the first connection, so that the + // second connection is put into the idle connections. + + HttpDestination destination = httpClient.getDestination(new Address("localhost", serverConnector.getLocalPort()), true); + destination.startNewConnection(); + + // Wait until we have the new connection + AbstractHttpConnection httpConnection = null; + while (httpConnection == null) + { + try + { + Thread.sleep(10); + httpConnection = destination.getIdleConnection(); + } + catch (InterruptedException x) + { + throw new InterruptedIOException(); + } + } + + connection.set(httpConnection); + connectionLatch.countDown(); + } + }; + exchange1.setMethod(HttpMethods.GET); + String body1 = "BODY"; + exchange1.setURL("https://localhost:" + serverConnector.getLocalPort() + "/echo?body=" + URLEncoder.encode(body1, "UTF-8")); + + httpClient.send(exchange1); + assertEquals(HttpExchange.STATUS_COMPLETED, exchange1.waitForDone()); + assertEquals(HttpStatus.OK_200, exchange1.getResponseStatus()); + String content1 = exchange1.getResponseContent(); + assertEquals(body1, content1); + + Assert.assertTrue(connectionLatch.await(5, TimeUnit.SECONDS)); + + ContentExchange exchange2 = new ContentExchange(true); + exchange2.setMethod(HttpMethods.POST); + exchange2.setURL("https://localhost:" + serverConnector.getLocalPort() + "/echo"); + exchange2.setRequestHeader(HttpHeaders.CONTENT_TYPE, MimeTypes.FORM_ENCODED); + String body2 = "body=" + body1; + exchange2.setRequestHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(body2.length())); + exchange2.setRequestContent(new ByteArrayBuffer(body2, "UTF-8")); + + // Make sure the second connection can send the exchange via the tunnel + connection.get().send(exchange2); + assertEquals(HttpExchange.STATUS_COMPLETED, exchange2.waitForDone()); + assertEquals(HttpStatus.OK_200, exchange2.getResponseStatus()); + String content2 = exchange2.getResponseContent(); + assertEquals(body1, content2); + } + finally + { + httpClient.stop(); + } + } + @Test public void testProxyDown() throws Exception { diff --git a/jetty-continuation/pom.xml b/jetty-continuation/pom.xml index c5eddeaa4f8..0ce442dc914 100644 --- a/jetty-continuation/pom.xml +++ b/jetty-continuation/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-continuation Jetty :: Continuation Asynchronous API + http://www.eclipse.org/jetty ${project.groupId}.continuation diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml index b38826df46e..46ad91ff5d8 100644 --- a/jetty-deploy/pom.xml +++ b/jetty-deploy/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-deploy Jetty :: Deployers Jetty deployers + http://www.eclipse.org/jetty ${project.groupId}.deploy diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java index c127b7a5eff..34d36151ab2 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java @@ -25,10 +25,12 @@ import org.eclipse.jetty.deploy.AppProvider; import org.eclipse.jetty.deploy.DeploymentManager; import org.eclipse.jetty.deploy.test.XmlConfiguredJetty; import org.eclipse.jetty.toolchain.test.OS; +import org.eclipse.jetty.toolchain.test.TestTracker; import org.eclipse.jetty.toolchain.test.TestingDir; import org.eclipse.jetty.util.Scanner; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.Resource; import org.junit.After; import org.junit.Assume; import org.junit.Before; @@ -43,6 +45,9 @@ public class ScanningAppProviderRuntimeUpdatesTest { private static final Logger LOG = Log.getLogger(ScanningAppProviderRuntimeUpdatesTest.class); + @Rule + public TestTracker tracker = new TestTracker(); + @Rule public TestingDir testdir = new TestingDir(); private static XmlConfiguredJetty jetty; @@ -52,6 +57,9 @@ public class ScanningAppProviderRuntimeUpdatesTest @Before public void setupEnvironment() throws Exception { + testdir.ensureEmpty(); + Resource.setDefaultUseCaches(false); + jetty = new XmlConfiguredJetty(testdir); jetty.addConfiguration("jetty.xml"); jetty.addConfiguration("jetty-deploymgr-contexts.xml"); @@ -90,7 +98,7 @@ public class ScanningAppProviderRuntimeUpdatesTest public void waitForDirectoryScan() { - int scan=_scans.get()+2*_providers; + int scan=_scans.get()+(2*_providers); do { try @@ -167,8 +175,8 @@ public class ScanningAppProviderRuntimeUpdatesTest waitForDirectoryScan(); System.out.println("Updating war files"); - jetty.copyContext("foo.xml","foo.xml"); // essentially "touch" the context xml jetty.copyWebapp("foo-webapp-2.war","foo.war"); + jetty.copyContext("foo.xml","foo.xml"); // essentially "touch" the context xml // This should result in the existing foo.war being replaced with the new foo.war waitForDirectoryScan(); 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 d538e8d1dae..c2f61be5b51 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 @@ -18,6 +18,8 @@ package org.eclipse.jetty.deploy.test; +import static org.hamcrest.Matchers.*; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -213,6 +215,7 @@ public class XmlConfiguredJetty if (context.getContextPath().equals(expectedPath)) { found = true; + Assert.assertThat("Context[" + context.getContextPath() + "].state", context.getState(), is("STARTED")); break; } } diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index 4c2a1136031..2f03b881c76 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -3,10 +3,11 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT jetty-distribution Jetty :: Distribution Assemblies + http://www.eclipse.org/jetty pom target/distribution diff --git a/jetty-http-spi/pom.xml b/jetty-http-spi/pom.xml index 3ad42d7bcb0..be5e0e1c977 100644 --- a/jetty-http-spi/pom.xml +++ b/jetty-http-spi/pom.xml @@ -2,11 +2,12 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-http-spi Jetty :: Http Service Provider Interface + http://www.eclipse.org/jetty ${project.groupId}.http.spi diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index f79bc4c470f..3bf55e28758 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -3,11 +3,12 @@ jetty-project org.eclipse.jetty - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-http Jetty :: Http Utility + http://www.eclipse.org/jetty ${project.groupId}.http 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 cd3edea4cba..85d70df09ab 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 @@ -1015,14 +1015,17 @@ public class HttpGenerator extends AbstractGenerator // If we need EOC and everything written if (_needEOC && (_content == null || _content.length() == 0)) { + if (_header == null && _buffer == null) + _header = _buffers.getHeader(); + if (_needCRLF) { - if (_buffer == null && _header != null && _header.space() >= 2) + if (_buffer == null && _header != null && _header.space() >= HttpTokens.CRLF.length) { _header.put(HttpTokens.CRLF); _needCRLF = false; } - else if (_buffer!=null && _buffer.space() >= 2) + else if (_buffer!=null && _buffer.space() >= HttpTokens.CRLF.length) { _buffer.put(HttpTokens.CRLF); _needCRLF = false; diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedStream.java index 3094d3a4661..4ff08a43eed 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedStream.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedStream.java @@ -65,22 +65,31 @@ public abstract class AbstractCompressedStream extends ServletOutputStream doCompress(); } + /* ------------------------------------------------------------ */ /** * Reset buffer. */ public void resetBuffer() { - if (_response.isCommitted()) + if (_response.isCommitted() || _compressedOutputStream!=null ) throw new IllegalStateException("Committed"); _closed = false; _out = null; _bOut = null; - if (_compressedOutputStream != null) - _response.setHeader("Content-Encoding",null); - _compressedOutputStream = null; _doNotCompress = false; } + /* ------------------------------------------------------------ */ + public void setBufferSize(int bufferSize) + { + if (_bOut!=null && _bOut.getBuf().length 0 && length < _wrapper.getMinCompressSize()) + if (length >= 0 && length < _wrapper.getMinCompressSize()) doNotCompress(false); else doCompress(); @@ -298,22 +307,38 @@ public abstract class AbstractCompressedStream extends ServletOutputStream throw new IOException("CLOSED"); if (_out == null) - { - long length=_wrapper.getContentLength(); - if (_response.isCommitted() || (length >= 0 && length < _wrapper.getMinCompressSize())) - doNotCompress(false); - else if (lengthToWrite > _wrapper.getMinCompressSize()) - doCompress(); + { + // If this first write is larger than buffer size, then we are committing now + if (lengthToWrite>_wrapper.getBufferSize()) + { + // if we know this is all the content and it is less than minimum, then do not compress, otherwise do compress + long length=_wrapper.getContentLength(); + if (length>=0 && length<_wrapper.getMinCompressSize()) + doNotCompress(false); // Not compressing by size, so no vary on request headers + else + doCompress(); + } else + { + // start aggregating writes into a buffered output stream _out = _bOut = new ByteArrayOutputStream2(_wrapper.getBufferSize()); + } } - else if (_bOut != null) + // else are we aggregating writes? + else if (_bOut !=null) { - long length=_wrapper.getContentLength(); - if (_response.isCommitted() || (length >= 0 && length < _wrapper.getMinCompressSize())) - doNotCompress(false); - else if (lengthToWrite >= (_bOut.getBuf().length - _bOut.getCount())) - doCompress(); + // We are aggregating into the buffered output stream. + + // If this write fills the buffer, then we are committing + if (lengthToWrite>=(_bOut.getBuf().length - _bOut.getCount())) + { + // if we know this is all the content and it is less than minimum, then do not compress, otherwise do compress + long length=_wrapper.getContentLength(); + if (length>=0 && length<_wrapper.getMinCompressSize()) + doNotCompress(false); // Not compressing by size, so no vary on request headers + else + doCompress(); + } } } @@ -359,4 +384,5 @@ public abstract class AbstractCompressedStream extends ServletOutputStream */ protected abstract DeflaterOutputStream createStream() throws IOException; + } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedResponseWrapper.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedResponseWrapper.java index 0ddf8199871..1d804f31249 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedResponseWrapper.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedResponseWrapper.java @@ -107,6 +107,8 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp public void setBufferSize(int bufferSize) { _bufferSize = bufferSize; + if (_compressedStream!=null) + _compressedStream.setBufferSize(bufferSize); } /* ------------------------------------------------------------ */ @@ -127,18 +129,21 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp { super.setContentType(ct); - if (ct!=null) + if (!_noCompression) { - int colon=ct.indexOf(";"); - if (colon>0) - ct=ct.substring(0,colon); - } - - if ((_compressedStream==null || _compressedStream.getOutputStream()==null) && - (_mimeTypes==null && ct!=null && ct.contains("gzip") || - _mimeTypes!=null && (ct==null||!_mimeTypes.contains(StringUtil.asciiToLowerCase(ct))))) - { - noCompression(); + if (ct!=null) + { + int colon=ct.indexOf(";"); + if (colon>0) + ct=ct.substring(0,colon); + } + + if ((_compressedStream==null || _compressedStream.getOutputStream()==null) && + (_mimeTypes==null && ct!=null && ct.contains("gzip") || + _mimeTypes!=null && (ct==null||!_mimeTypes.contains(StringUtil.asciiToLowerCase(ct))))) + { + noCompression(); + } } } @@ -173,7 +178,10 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp @Override public void setContentLength(int length) { - setContentLength((long)length); + if (_noCompression) + super.setContentLength(length); + else + setContentLength((long)length); } /* ------------------------------------------------------------ */ @@ -237,7 +245,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp if (_writer!=null) _writer.flush(); if (_compressedStream!=null) - _compressedStream.finish(); + _compressedStream.flush(); else getResponse().flushBuffer(); } @@ -311,6 +319,8 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp */ public void noCompression() { + if (!_noCompression) + setDeferredHeaders(); _noCompression=true; if (_compressedStream!=null) { @@ -335,6 +345,25 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp _writer.flush(); if (_compressedStream!=null) _compressedStream.finish(); + else + setDeferredHeaders(); + } + + /* ------------------------------------------------------------ */ + private void setDeferredHeaders() + { + if (!isCommitted()) + { + if (_contentLength>=0) + { + if (_contentLength < Integer.MAX_VALUE) + super.setContentLength((int)_contentLength); + else + super.setHeader("Content-Length",Long.toString(_contentLength)); + } + if(_etag!=null) + super.setHeader("ETag",_etag); + } } /* ------------------------------------------------------------ */ @@ -344,7 +373,9 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp @Override public void setHeader(String name, String value) { - if ("content-length".equalsIgnoreCase(name)) + if (_noCompression) + super.setHeader(name,value); + else if ("content-length".equalsIgnoreCase(name)) { setContentLength(Long.parseLong(value)); } @@ -370,7 +401,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp @Override public boolean containsHeader(String name) { - if ("etag".equalsIgnoreCase(name) && _etag!=null) + if (!_noCompression && "etag".equalsIgnoreCase(name) && _etag!=null) return true; return super.containsHeader(name); } @@ -385,10 +416,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp if (_compressedStream==null) { if (getResponse().isCommitted() || _noCompression) - { - setContentLength(_contentLength); return getResponse().getOutputStream(); - } _compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse()); } @@ -411,10 +439,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp throw new IllegalStateException("getOutputStream() called"); if (getResponse().isCommitted() || _noCompression) - { - setContentLength(_contentLength); return getResponse().getWriter(); - } _compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse()); _writer=newWriter(_compressedStream,getCharacterEncoding()); diff --git a/jetty-io/pom.xml b/jetty-io/pom.xml index 327f0a4839a..48aa615afc5 100644 --- a/jetty-io/pom.xml +++ b/jetty-io/pom.xml @@ -2,11 +2,12 @@ jetty-project org.eclipse.jetty - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-io Jetty :: IO Utility + http://www.eclipse.org/jetty ${project.groupId}.io diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/DirectNIOBuffer.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/DirectNIOBuffer.java index c8e4aecda68..ee0b0719e74 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/DirectNIOBuffer.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/DirectNIOBuffer.java @@ -31,6 +31,9 @@ import java.nio.channels.WritableByteChannel; import org.eclipse.jetty.io.AbstractBuffer; import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; /* ------------------------------------------------------------------------------- */ /** @@ -39,6 +42,8 @@ import org.eclipse.jetty.io.Buffer; */ public class DirectNIOBuffer extends AbstractBuffer implements NIOBuffer { + private static final Logger LOG = Log.getLogger(DirectNIOBuffer.class); + protected final ByteBuffer _buf; private ReadableByteChannel _in; private InputStream _inStream; @@ -69,12 +74,22 @@ public class DirectNIOBuffer extends AbstractBuffer implements NIOBuffer public DirectNIOBuffer(File file) throws IOException { super(READONLY,NON_VOLATILE); - FileInputStream fis = new FileInputStream(file); - FileChannel fc = fis.getChannel(); - _buf = fc.map(FileChannel.MapMode.READ_ONLY, 0, file.length()); - setGetIndex(0); - setPutIndex((int)file.length()); - _access=IMMUTABLE; + FileInputStream fis = null; + FileChannel fc = null; + try + { + fis = new FileInputStream(file); + fc = fis.getChannel(); + _buf = fc.map(FileChannel.MapMode.READ_ONLY, 0, file.length()); + setGetIndex(0); + setPutIndex((int)file.length()); + _access=IMMUTABLE; + } + finally + { + if (fc != null) try {fc.close();} catch (IOException e){LOG.ignore(e);} + IO.close(fis); + } } /* ------------------------------------------------------------ */ diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml index ac0d8be4561..c1ffc619afc 100644 --- a/jetty-jaspi/pom.xml +++ b/jetty-jaspi/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-jaspi Jetty :: JASPI Security Jetty security infrastructure + http://www.eclipse.org/jetty ${project.groupId}.jaspi diff --git a/jetty-jmx/pom.xml b/jetty-jmx/pom.xml index 10eaf37b055..865b4bf86aa 100644 --- a/jetty-jmx/pom.xml +++ b/jetty-jmx/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-jmx Jetty :: JMX Management JMX management artifact for jetty. + http://www.eclipse.org/jetty ${project.groupId}.jmx diff --git a/jetty-jndi/pom.xml b/jetty-jndi/pom.xml index 236d2a59df0..4f3ab047747 100644 --- a/jetty-jndi/pom.xml +++ b/jetty-jndi/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-jndi Jetty :: JNDI Naming JNDI spi impl for java namespace. + http://www.eclipse.org/jetty ${project.groupId}.jndi diff --git a/jetty-jsp/pom.xml b/jetty-jsp/pom.xml index 0e90a70830b..6eb510bcd71 100644 --- a/jetty-jsp/pom.xml +++ b/jetty-jsp/pom.xml @@ -2,11 +2,12 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-jsp Jetty :: JSP dependencies + http://www.eclipse.org/jetty jar diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml index 1b93b45c93c..bb7b39c2f85 100644 --- a/jetty-monitor/pom.xml +++ b/jetty-monitor/pom.xml @@ -19,11 +19,12 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-monitor Jetty :: Monitoring + http://www.eclipse.org/jetty Performance monitoring artifact for jetty. ${project.groupId}.monitor diff --git a/jetty-nested/pom.xml b/jetty-nested/pom.xml index 04a34442c4d..93a23e3be54 100644 --- a/jetty-nested/pom.xml +++ b/jetty-nested/pom.xml @@ -4,12 +4,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT jetty-nested Jetty :: Nested jar Local Servlet Connector for jetty. + http://www.eclipse.org/jetty ${project.groupId}.nested diff --git a/jetty-nosql/pom.xml b/jetty-nosql/pom.xml index c6884dddf21..61c848a02cf 100644 --- a/jetty-nosql/pom.xml +++ b/jetty-nosql/pom.xml @@ -2,11 +2,12 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-nosql Jetty :: NoSQL Session Managers + http://www.eclipse.org/jetty ${project.groupId}.nosql diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java index 38f148e6532..3a70ef61dc9 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java @@ -40,6 +40,7 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme private int _savePeriod=0; private int _idlePeriod=-1; private boolean _invalidateOnStop; + private boolean _preserveOnStop; private boolean _saveAllAttributes; /* ------------------------------------------------------------ */ @@ -104,7 +105,10 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme for (NoSqlSession session : sessions) { session.save(false); - removeSession(session,false); + + if (!_preserveOnStop) { + removeSession(session,false); + } } } else @@ -277,6 +281,16 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme return _invalidateOnStop; } + /* ------------------------------------------------------------ */ + /** + * Preserve sessions when the session manager is stopped otherwise remove them from the DB. + * @return the removeOnStop + */ + public boolean isPreserveOnStop() + { + return _preserveOnStop; + } + /* ------------------------------------------------------------ */ /** * Invalidate sessions when the session manager is stopped otherwise save them to the DB. @@ -287,6 +301,16 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme _invalidateOnStop = invalidateOnStop; } + /* ------------------------------------------------------------ */ + /** + * Preserve sessions when the session manager is stopped otherwise remove them from the DB. + * @param removeOnStop the removeOnStop to set + */ + public void setPreserveOnStop(boolean preserveOnStop) + { + _preserveOnStop = preserveOnStop; + } + /* ------------------------------------------------------------ */ /** * Save all attributes of a session or only update the dirty attributes. diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionManager.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionManager.java index 22285ca3517..47d69094ff7 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionManager.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionManager.java @@ -131,25 +131,25 @@ public class MongoSessionManager extends NoSqlSessionManager BasicDBObject sets = new BasicDBObject(); BasicDBObject unsets = new BasicDBObject(); - // handle new or existing - if (version == null) - { - // New session - upsert = true; - version = new Long(1); - sets.put(__CREATED,session.getCreationTime()); - sets.put(__VALID,true); - sets.put(getContextKey(__VERSION),version); - } - else - { - version = new Long(((Number)version).longValue() + 1); - update.put("$inc",__version_1); - } - // handle valid or invalid if (session.isValid()) { + // handle new or existing + if (version == null) + { + // New session + upsert = true; + version = new Long(1); + sets.put(__CREATED,session.getCreationTime()); + sets.put(__VALID,true); + sets.put(getContextKey(__VERSION),version); + } + else + { + version = new Long(((Number)version).longValue() + 1); + update.put("$inc",__version_1); + } + sets.put(__ACCESSED,session.getAccessed()); Set names = session.takeDirty(); if (isSaveAllAttributes() || upsert) @@ -247,6 +247,7 @@ public class MongoSessionManager extends NoSqlSessionManager DBObject attrs = (DBObject)getNestedValue(o,getContextKey()); + if (attrs != null) { for (String name : attrs.keySet()) @@ -280,6 +281,22 @@ public class MongoSessionManager extends NoSqlSessionManager } } + /* + * We are refreshing so we should update the last accessed time. + */ + BasicDBObject key = new BasicDBObject(__ID,session.getClusterId()); + BasicDBObject sets = new BasicDBObject(); + // Form updates + BasicDBObject update = new BasicDBObject(); + sets.put(__ACCESSED,System.currentTimeMillis()); + // Do the upsert + if (!sets.isEmpty()) + { + update.put("$set",sets); + } + + _sessions.update(key,update,false,false); + session.didActivate(); return version; diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml index 37bd9fac351..8ec23ab0e2f 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml @@ -2,13 +2,14 @@ org.eclipse.jetty.osgi jetty-osgi-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT ../pom.xml 4.0.0 jetty-osgi-boot-jsp Jetty :: OSGi :: Boot JSP Jetty OSGi Boot JSP bundle + http://www.eclipse.org/jetty ${project.groupId}.boot.jsp diff --git a/jetty-osgi/jetty-osgi-boot-logback/pom.xml b/jetty-osgi/jetty-osgi-boot-logback/pom.xml deleted file mode 100644 index 1b2368e408e..00000000000 --- a/jetty-osgi/jetty-osgi-boot-logback/pom.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - org.eclipse.jetty.osgi - jetty-osgi-project - 7.6.11-SNAPSHOT - ../pom.xml - - 4.0.0 - jetty-osgi-boot-logback - Jetty :: OSGi :: Boot Logback - Jetty OSGi Boot Logback bundle - - ${project.groupId}.boot.logback - - - - org.eclipse.jetty.osgi - jetty-osgi-boot - ${project.version} - provided - - - org.eclipse.osgi - org.eclipse.osgi - - - org.eclipse.jetty - jetty-webapp - - - org.eclipse.osgi - org.eclipse.osgi.services - - - org.slf4j - slf4j-api - - - org.slf4j - jcl-over-slf4j - - - org.slf4j - log4j-over-slf4j - - - ch.qos.logback - logback-core - - - ch.qos.logback - logback-classic - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - artifact-jar - - jar - - - - test-jar - - test-jar - - - - - - target/classes/META-INF/MANIFEST.MF - - - - - org.apache.felix - maven-bundle-plugin - true - - - bundle-manifest - process-classes - - manifest - - - - - - org.eclipse.jetty.osgi.boot.logback;singleton:=true - Jetty-OSGi-Logback Integration - org.eclipse.jetty.osgi.boot - -ch.qos.logback.access.jetty;version="[0.9,1.1)";resolution:=optional, -ch.qos.logback.access.jetty.v7;version="[0.9,1.1)";resolution:=optional, -ch.qos.logback.*;version="[0.9,1.1)", -org.osgi.framework.*, -org.slf4j.*, -*;resolution:=optional - - -!org.eclipse.jetty.osgi.boot.logback.internal.*, -org.eclipse.jetty.osgi.boot.logback.*;version="${parsedVersion.osgiVersion}" - - <_nouses>true - - - - - org.codehaus.mojo - findbugs-maven-plugin - - org.eclipse.jetty.osgi.boot.logback.* - - - - - - - diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml index d626aaf59d2..b557886e5d7 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml @@ -2,13 +2,14 @@ org.eclipse.jetty.osgi jetty-osgi-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT ../pom.xml 4.0.0 jetty-osgi-boot-warurl Jetty :: OSGi :: Boot :: Warurl Jetty OSGi Boot-Warurl bundle + http://www.eclipse.org/jetty ${project.groupId}.boot.warurl diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml index 75100a4187b..5bd31658aa0 100644 --- a/jetty-osgi/jetty-osgi-boot/pom.xml +++ b/jetty-osgi/jetty-osgi-boot/pom.xml @@ -2,13 +2,14 @@ org.eclipse.jetty.osgi jetty-osgi-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT ../pom.xml 4.0.0 jetty-osgi-boot Jetty :: OSGi :: Boot Jetty OSGi Boot bundle + http://www.eclipse.org/jetty ${project.groupId}.boot diff --git a/jetty-osgi/jetty-osgi-equinoxtools/pom.xml b/jetty-osgi/jetty-osgi-equinoxtools/pom.xml deleted file mode 100644 index a0d3f07ca4e..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/pom.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - org.eclipse.jetty.osgi - jetty-osgi-project - 7.6.11-SNAPSHOT - ../pom.xml - - 4.0.0 - jetty-osgi-equinoxtools - Jetty :: OSGi :: Example Equinox Tools - Jetty OSGi Example Equinox Tools - - ${project.groupId}.equinoxtools - - - - org.eclipse.jetty - jetty-webapp - - - org.eclipse.jetty - jetty-continuation - - - org.eclipse.jetty - jetty-websocket - - - org.eclipse.jetty - jetty-servlet - - - org.eclipse.osgi - org.eclipse.osgi - - - org.eclipse.osgi - org.eclipse.osgi.services - - - - - - - maven-antrun-plugin - - - process-resources - - - - - - - - - run - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - artifact-jar - - jar - - - - test-jar - - test-jar - - - - - - target/classes/META-INF/MANIFEST.MF - - - - - org.apache.felix - maven-bundle-plugin - true - - - bundle-manifest - process-classes - - manifest - - - - - - org.eclipse.jetty.osgi.equinoxtools - Console - org.eclipse.jetty.osgi.equinoxtools.WebEquinoxToolsActivator - org.eclipse.jetty.osgi.equinoxtools;x-internal:=true;version="${parsedVersion.osgiVersion}", - org.eclipse.jetty.osgi.equinoxtools.console;x-internal:=true;version="${parsedVersion.osgiVersion}" - - <_nouses>true - - - - - org.codehaus.mojo - findbugs-maven-plugin - - org.eclipse.jetty.osgi.equinoxtools.* - - - - - - diff --git a/jetty-osgi/jetty-osgi-httpservice/pom.xml b/jetty-osgi/jetty-osgi-httpservice/pom.xml index ec1978aafee..6fbb6536774 100644 --- a/jetty-osgi/jetty-osgi-httpservice/pom.xml +++ b/jetty-osgi/jetty-osgi-httpservice/pom.xml @@ -2,13 +2,14 @@ org.eclipse.jetty.osgi jetty-osgi-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT ../pom.xml 4.0.0 jetty-httpservice Jetty :: OSGi :: HttpService Jetty OSGi HttpService bundle + http://www.eclipse.org/jetty ${project.groupId}.httpservice diff --git a/jetty-osgi/pom.xml b/jetty-osgi/pom.xml index 86f52528382..c71f24161c1 100644 --- a/jetty-osgi/pom.xml +++ b/jetty-osgi/pom.xml @@ -3,12 +3,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT ../pom.xml org.eclipse.jetty.osgi jetty-osgi-project Jetty :: OSGi + http://www.eclipse.org/jetty pom 3.6.0.v20100517 diff --git a/jetty-osgi/test-jetty-osgi-context/pom.xml b/jetty-osgi/test-jetty-osgi-context/pom.xml index 7ebc5f0cb40..98048456ef0 100644 --- a/jetty-osgi/test-jetty-osgi-context/pom.xml +++ b/jetty-osgi/test-jetty-osgi-context/pom.xml @@ -2,13 +2,14 @@ org.eclipse.jetty.osgi jetty-osgi-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT ../pom.xml 4.0.0 test-jetty-osgi-context Jetty :: OSGi :: Context Test Jetty OSGi bundle with a ContextHandler + http://www.eclipse.org/jetty ${project.groupId}.testcontext diff --git a/jetty-osgi/test-jetty-osgi-webapp/pom.xml b/jetty-osgi/test-jetty-osgi-webapp/pom.xml index 47fd315d95f..d94c50237ba 100644 --- a/jetty-osgi/test-jetty-osgi-webapp/pom.xml +++ b/jetty-osgi/test-jetty-osgi-webapp/pom.xml @@ -2,13 +2,14 @@ org.eclipse.jetty.osgi jetty-osgi-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT ../pom.xml 4.0.0 test-jetty-osgi-webapp Jetty :: OSGi :: WebApp Test Jetty OSGi Webapp bundle + http://www.eclipse.org/jetty ${project.groupId}.webapp diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml index 4ecfb6944d9..72500e68ef2 100644 --- a/jetty-osgi/test-jetty-osgi/pom.xml +++ b/jetty-osgi/test-jetty-osgi/pom.xml @@ -2,13 +2,14 @@ org.eclipse.jetty.osgi jetty-osgi-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT ../pom.xml 4.0.0 test-jetty-osgi Jetty :: OSGi :: Test Jetty OSGi Integration test + http://www.eclipse.org/jetty ${project.groupId}.boot.test http://download.eclipse.org/jetty/orbit/ diff --git a/jetty-overlay-deployer/pom.xml b/jetty-overlay-deployer/pom.xml index 622dda5293b..d0020d750c8 100644 --- a/jetty-overlay-deployer/pom.xml +++ b/jetty-overlay-deployer/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-overlay-deployer Jetty :: Overlay Deployer Overlayed deployer + http://www.eclipse.org/jetty diff --git a/jetty-plus/pom.xml b/jetty-plus/pom.xml index 9da8109cc9f..ace5860d73b 100644 --- a/jetty-plus/pom.xml +++ b/jetty-plus/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-plus Jetty :: Plus Jetty JavaEE style services + http://www.eclipse.org/jetty ${project.groupId}.plus diff --git a/jetty-policy/pom.xml b/jetty-policy/pom.xml index 31a3314d10b..2a5c77ef216 100644 --- a/jetty-policy/pom.xml +++ b/jetty-policy/pom.xml @@ -3,11 +3,12 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT jetty-policy Jetty :: Policy Tool jar + http://www.eclipse.org/jetty target/test-policy ${project.groupId}.policy diff --git a/jetty-rewrite/pom.xml b/jetty-rewrite/pom.xml index 58dffa0e4df..a0ac0ee186a 100644 --- a/jetty-rewrite/pom.xml +++ b/jetty-rewrite/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-rewrite Jetty :: Rewrite Handler Jetty Rewrite Handler + http://www.eclipse.org/jetty ${project.groupId}.rewrite diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml index d60a60240e6..69d33c55040 100644 --- a/jetty-security/pom.xml +++ b/jetty-security/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-security Jetty :: Security Jetty security infrastructure + http://www.eclipse.org/jetty ${project.groupId}.security diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml index 2c6de21af45..daab6c48f4d 100644 --- a/jetty-server/pom.xml +++ b/jetty-server/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-server Jetty :: Server Core The core jetty server artifact. + http://www.eclipse.org/jetty ${project.groupId}.server diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java index 0cf91bf7d00..6d572f775a1 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java @@ -469,7 +469,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection info=URIUtil.canonicalPath(path); if (info==null && !_request.getMethod().equals(HttpMethods.CONNECT)) { - if (_uri.getScheme()!=null && _uri.getHost()!=null) + if (path==null && _uri.getScheme()!=null && _uri.getHost()!=null) { info="/"; _request.setRequestURI(""); 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 1b6387bd3d4..b873977d956 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 @@ -19,6 +19,7 @@ package org.eclipse.jetty.server; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -81,6 +82,7 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler.Context; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.AttributesMap; +import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiMap; @@ -363,6 +365,7 @@ public class Request implements HttpServletRequest } } } + } if (_parameters == null) @@ -380,6 +383,28 @@ public class Request implements HttpServletRequest _parameters.add(name,LazyList.get(values,i)); } } + + if (content_type != null && content_type.length()>0 && content_type.startsWith("multipart/form-data") && getAttribute(__MULTIPART_CONFIG_ELEMENT)!=null) + { + try + { + getParts(); + } + catch (IOException e) + { + if (LOG.isDebugEnabled()) + LOG.warn(e); + else + LOG.warn(e.toString()); + } + catch (ServletException e) + { + if (LOG.isDebugEnabled()) + LOG.warn(e); + else + LOG.warn(e.toString()); + } + } } finally { @@ -2014,39 +2039,8 @@ public class Request implements HttpServletRequest /* ------------------------------------------------------------ */ public Part getPart(String name) throws IOException, ServletException - { - if (getContentType() == null || !getContentType().startsWith("multipart/form-data")) - throw new ServletException("Content-Type != multipart/form-data"); - - if (_multiPartInputStream == null) - { - MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT); - - if (config == null) - throw new IllegalStateException("No multipart config for servlet"); - - _multiPartInputStream = new MultiPartInputStream(getInputStream(), - getContentType(),config, - (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); - setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream); - setAttribute(__MULTIPART_CONTEXT, _context); - Collection parts = _multiPartInputStream.getParts(); //causes parsing - for (Part p:parts) - { - MultiPartInputStream.MultiPart mp = (MultiPartInputStream.MultiPart)p; - if (mp.getContentDispositionFilename() == null && mp.getFile() == null) - { - //Servlet Spec 3.0 pg 23, parts without filenames must be put into init params - String charset = null; - if (mp.getContentType() != null) - charset = MimeTypes.getCharsetFromContentType(new ByteArrayBuffer(mp.getContentType())); - - String content=new String(mp.getBytes(),charset==null?StringUtil.__UTF8:charset); - getParameter(""); //cause params to be evaluated - getParameters().add(mp.getName(), content); - } - } - } + { + getParts(); return _multiPartInputStream.getPart(name); } @@ -2056,6 +2050,9 @@ public class Request implements HttpServletRequest if (getContentType() == null || !getContentType().startsWith("multipart/form-data")) throw new ServletException("Content-Type != multipart/form-data"); + if (_multiPartInputStream == null) + _multiPartInputStream = (MultiPartInputStream)getAttribute(__MULTIPART_INPUT_STREAM); + if (_multiPartInputStream == null) { MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT); @@ -2073,19 +2070,32 @@ public class Request implements HttpServletRequest for (Part p:parts) { MultiPartInputStream.MultiPart mp = (MultiPartInputStream.MultiPart)p; - if (mp.getContentDispositionFilename() == null && mp.getFile() == null) + if (mp.getContentDispositionFilename() == null) { //Servlet Spec 3.0 pg 23, parts without filenames must be put into init params String charset = null; if (mp.getContentType() != null) charset = MimeTypes.getCharsetFromContentType(new ByteArrayBuffer(mp.getContentType())); - String content=new String(mp.getBytes(),charset==null?StringUtil.__UTF8:charset); - getParameter(""); //cause params to be evaluated - getParameters().add(mp.getName(), content); + ByteArrayOutputStream os = null; + InputStream is = mp.getInputStream(); //get the bytes regardless of being in memory or in temp file + try + { + os = new ByteArrayOutputStream(); + IO.copy(is, os); + String content=new String(os.toByteArray(),charset==null?StringUtil.__UTF8:charset); + getParameter(""); //cause params to be evaluated + getParameters().add(mp.getName(), content); + } + finally + { + IO.close(os); + IO.close(is); + } } } } + return _multiPartInputStream.getParts(); } 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 b31c5a00036..2ab4e6c9f09 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 @@ -26,6 +26,7 @@ import java.util.Collections; import java.util.Enumeration; import java.util.Locale; +import javax.servlet.RequestDispatcher; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; @@ -341,10 +342,10 @@ public class Response implements HttpServletResponse error_handler = _connection.getConnector().getServer().getBean(ErrorHandler.class); if (error_handler!=null) { - request.setAttribute(Dispatcher.ERROR_STATUS_CODE,new Integer(code)); - request.setAttribute(Dispatcher.ERROR_MESSAGE, message); - request.setAttribute(Dispatcher.ERROR_REQUEST_URI, request.getRequestURI()); - request.setAttribute(Dispatcher.ERROR_SERVLET_NAME,request.getServletName()); + request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(code)); + request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message); + request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI()); + request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,request.getServletName()); error_handler.handle(null,_connection.getRequest(),_connection.getRequest(),this ); } else @@ -580,6 +581,7 @@ public class Response implements HttpServletResponse */ public void addHeader(String name, String value) { + if (_connection.isIncluding()) { if (name.startsWith(SET_INCLUDE_HEADER_PREFIX)) @@ -588,6 +590,12 @@ public class Response implements HttpServletResponse return; } + if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(name)) + { + setContentType(value); + return; + } + _connection.getResponseFields().add(name, value); if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name)) _connection._generator.setContentLength(Long.parseLong(value)); 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 6ad42d3fd86..8a84167fe9b 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 @@ -149,6 +149,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. private Object _contextAttributeListeners; private Object _requestListeners; private Object _requestAttributeListeners; + private Object _durableListeners; private Map _managedAttributes; private String[] _protectedTargets; private final CopyOnWriteArrayList _aliasChecks = new CopyOnWriteArrayList(); @@ -591,6 +592,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. */ public void addEventListener(EventListener listener) { + //Only listeners added before the context starts last through a stop/start cycle + if (!(isStarted() || isStarting())) + _durableListeners = LazyList.add(_durableListeners, listener); + setEventListeners((EventListener[])LazyList.addToArray(getEventListeners(),listener,EventListener.class)); } @@ -607,6 +612,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { } + + /* ------------------------------------------------------------ */ /** * @return true if this context is accepting new requests @@ -816,6 +823,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. ((ServletContextListener)LazyList.get(_contextListeners,i)).contextDestroyed(event); } } + + //remove all non-durable listeners + setEventListeners((EventListener[])LazyList.toArray(_durableListeners, EventListener.class)); + _durableListeners = null; if (_errorHandler != null) _errorHandler.stop(); @@ -1867,13 +1878,14 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. query = uriInContext.substring(q + 1); uriInContext = uriInContext.substring(0,q); } - // if ((q = uriInContext.indexOf(';')) > 0) - // uriInContext = uriInContext.substring(0,q); String pathInContext = URIUtil.canonicalPath(URIUtil.decodePath(uriInContext)); - String uri = URIUtil.addPaths(getContextPath(),uriInContext); - ContextHandler context = ContextHandler.this; - return new Dispatcher(context,uri,pathInContext,query); + if (pathInContext!=null) + { + String uri = URIUtil.addPaths(getContextPath(),uriInContext); + ContextHandler context = ContextHandler.this; + return new Dispatcher(context,uri,pathInContext,query); + } } catch (Exception e) { @@ -2494,7 +2506,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. if (dot<0) return false; String suffix=path.substring(dot); - return resource.getAlias().toString().endsWith(suffix); + return resource.toString().endsWith(suffix); } } @@ -2509,10 +2521,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. public boolean check(String path, Resource resource) { int slash = path.lastIndexOf('/'); - if (slash<0) + if (slash<0 || slash==path.length()-1) return false; String suffix=path.substring(slash); - return resource.getAlias().toString().endsWith(suffix); + return resource.toString().endsWith(suffix); } } /* ------------------------------------------------------------ */ @@ -2525,7 +2537,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. public boolean check(String path, Resource resource) { int slash = path.lastIndexOf('/'); - if (slash<0) + if (slash<0 || resource.exists()) return false; String suffix=path.substring(slash); return resource.getAlias().toString().endsWith(suffix); 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 e9eb6d9afda..d115f542be2 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 @@ -25,21 +25,22 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.continuation.Continuation; +import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.server.AsyncContinuation; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.RequestLog; import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; - /** * RequestLogHandler. * This handler can be used to wrap an individual context for context logging. * - * * @org.apache.xbean.XBean */ public class RequestLogHandler extends HandlerWrapper @@ -53,7 +54,7 @@ public class RequestLogHandler extends HandlerWrapper * @see org.eclipse.jetty.server.server.Handler#handle(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int) */ @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) + public void handle(String target, final Request baseRequest, HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { AsyncContinuation continuation = baseRequest.getAsyncContinuation(); @@ -68,11 +69,25 @@ public class RequestLogHandler extends HandlerWrapper } finally { - if (_requestLog != null && DispatcherType.REQUEST.equals(baseRequest.getDispatcherType())) + if (continuation.isAsync()) { - _requestLog.log(baseRequest, (Response)response); + if (continuation.isInitial()) + continuation.addContinuationListener(new ContinuationListener() + { + + public void onTimeout(Continuation continuation) + { + + } + + public void onComplete(Continuation continuation) + { + _requestLog.log(baseRequest, (Response)response); + } + }); } - + else + _requestLog.log(baseRequest, (Response)response); } } @@ -139,9 +154,13 @@ public class RequestLogHandler extends HandlerWrapper @Override protected void doStart() throws Exception { + if (_requestLog==null) + { + LOG.warn("!RequestLog"); + _requestLog=new NullRequestLog(); + } super.doStart(); - if (_requestLog!=null) - _requestLog.start(); + _requestLog.start(); } /* ------------------------------------------------------------ */ @@ -152,8 +171,19 @@ public class RequestLogHandler extends HandlerWrapper protected void doStop() throws Exception { super.doStop(); - if (_requestLog!=null) - _requestLog.stop(); + _requestLog.stop(); + if (_requestLog instanceof NullRequestLog) + _requestLog=null; + } + + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + private static class NullRequestLog extends AbstractLifeCycle implements RequestLog + { + public void log(Request request, Response response) + { + } } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java index f3393515d8f..2d7f9172148 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java @@ -128,6 +128,66 @@ public class HttpConnectionTest checkContains(response,offset,"pathInfo=/"); } + @Test + public void testBadNoPath() throws Exception + { + String response=connector.getResponses("GET http://localhost:80/../cheat HTTP/1.1\n"+ + "Host: localhost:80\n"+ + "\n"); + int offset=0; + offset = checkContains(response,offset,"HTTP/1.1 400"); + } + + @Test + public void testOKPathDotDotPath() throws Exception + { + String response=connector.getResponses("GET /ooops/../path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 200 OK"); + checkContains(response,0,"pathInfo=/path"); + } + + @Test + public void testBadPathDotDotPath() throws Exception + { + String response=connector.getResponses("GET /ooops/../../path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 400 Bad Request"); + } + + @Test + public void testOKPathEncodedDotDotPath() throws Exception + { + String response=connector.getResponses("GET /ooops/%2e%2e/path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 200 OK"); + checkContains(response,0,"pathInfo=/path"); + } + + @Test + public void testBadPathEncodedDotDotPath() throws Exception + { + String response=connector.getResponses("GET /ooops/%2e%2e/%2e%2e/path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 400 Bad Request"); + } + + @Test + public void testBadDotDotPath() throws Exception + { + String response=connector.getResponses("GET ../path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 400 Bad Request"); + } + + @Test + public void testBadSlashDotDotPath() throws Exception + { + String response=connector.getResponses("GET /../path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 400 Bad Request"); + } + + @Test + public void testEncodedBadDotDotPath() throws Exception + { + String response=connector.getResponses("GET %2e%2e/path HTTP/1.0\nHost: localhost:80\n\n"); + checkContains(response,0,"HTTP/1.1 400 Bad Request"); + } @Test public void testEmpty() throws Exception diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index 3d82e1bbfcc..51f12d32af0 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -998,10 +998,12 @@ public class RequestTest MultipartConfigElement mpce = new MultipartConfigElement(tmpDir.getAbsolutePath(),-1, -1, 2); request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce); + String field1 = request.getParameter("field1"); + assertNotNull(field1); + Part foo = request.getPart("stuff"); assertNotNull(foo); assertTrue(foo.getSize() > 0); - response.setStatus(200); } catch (IllegalStateException e) diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index 2e54f2587e9..efa14613058 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -172,6 +172,10 @@ public class ResponseTest response.setContentType("foo/bar"); assertEquals("foo/bar", response.getContentType()); + response.recycle(); + response.addHeader("Content-Type","text/something"); + assertEquals("text/something",response.getContentType()); + } @Test diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml index f62f45cbd9f..919360453df 100644 --- a/jetty-servlet/pom.xml +++ b/jetty-servlet/pom.xml @@ -3,12 +3,13 @@ jetty-project org.eclipse.jetty - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-servlet Jetty :: Servlet Handling Jetty Servlet Container + http://www.eclipse.org/jetty ${project.groupId}.servlet diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java index 5b5f32b8992..5ddcd6686ba 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java @@ -756,6 +756,8 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory { r.reset(true); r.setStatus(HttpServletResponse.SC_NOT_MODIFIED); + if (_etags) + r.getHttpFields().add(HttpHeaders.ETAG_BUFFER,content.getETag()); r.flushBuffer(); return false; } @@ -769,6 +771,8 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory { r.reset(true); r.setStatus(HttpServletResponse.SC_NOT_MODIFIED); + if (_etags) + r.getHttpFields().add(HttpHeaders.ETAG_BUFFER,content.getETag()); r.flushBuffer(); return false; } diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java index 2afebab93c7..121c27257e6 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java @@ -53,16 +53,15 @@ public class FilterHolder extends Holder */ public FilterHolder() { - super (Source.EMBEDDED); + this(Source.EMBEDDED); } - /* ---------------------------------------------------------------- */ /** Constructor */ public FilterHolder(Holder.Source source) { - super (source); + super(source); } /* ---------------------------------------------------------------- */ @@ -70,7 +69,7 @@ public class FilterHolder extends Holder */ public FilterHolder(Class filter) { - super (Source.EMBEDDED); + this(Source.EMBEDDED); setHeldClass(filter); } @@ -79,7 +78,7 @@ public class FilterHolder extends Holder */ public FilterHolder(Filter filter) { - super (Source.EMBEDDED); + this(Source.EMBEDDED); setFilter(filter); } diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java index f9dd20cd067..f955213fb24 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java @@ -54,7 +54,7 @@ public class Holder extends AbstractLifeCycle implements Dumpable protected String _className; protected String _displayName; protected boolean _extInstance; - protected boolean _asyncSupported=true; + protected boolean _asyncSupported; /* ---------------------------------------------------------------- */ protected String _name; @@ -64,6 +64,16 @@ public class Holder extends AbstractLifeCycle implements Dumpable protected Holder(Source source) { _source=source; + switch(_source) + { + case JAVAX_API: + case DESCRIPTOR: + case ANNOTATION: + _asyncSupported=false; + break; + default: + _asyncSupported=true; + } } public Source getSource() 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 05d0b507ff6..5ec68db9b8e 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 @@ -1007,8 +1007,6 @@ public class ServletContextHandler extends ContextHandler if (!_enabled) throw new UnsupportedOperationException(); - //TODO handle partial registrations - final ServletHandler handler = ServletContextHandler.this.getServletHandler(); ServletHolder holder = handler.getServlet(servletName); if (holder == null) 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 31e19d5b0c2..9aff148ce98 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 @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; +import java.util.ListIterator; import java.util.Set; import java.util.List; import java.util.Map; @@ -37,6 +38,7 @@ import javax.servlet.AsyncContext; import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; +import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -197,28 +199,70 @@ public class ServletHandler extends ScopedHandler throws Exception { super.doStop(); - + // Stop filters + List filterHolders = new ArrayList(); + List filterMappings = LazyList.array2List(_filterMappings); if (_filters!=null) { for (int i=_filters.length; i-->0;) { try { _filters[i].stop(); }catch(Exception e){LOG.warn(Log.EXCEPTION,e);} + if (_filters[i].getSource() != Source.EMBEDDED) + { + //remove all of the mappings that were for non-embedded filters + _filterNameMap.remove(_filters[i].getName()); + //remove any mappings associated with this filter + ListIterator fmitor = filterMappings.listIterator(); + while (fmitor.hasNext()) + { + FilterMapping fm = fmitor.next(); + if (fm.getFilterName().equals(_filters[i].getName())) + fmitor.remove(); + } + } + else + filterHolders.add(_filters[i]); //only retain embedded } } - + _filters = (FilterHolder[]) LazyList.toArray(filterHolders, FilterHolder.class); + _filterMappings = (FilterMapping[]) LazyList.toArray(filterMappings, FilterMapping.class); + _matchAfterIndex = (_filterMappings == null || _filterMappings.length == 0 ? -1 : _filterMappings.length-1); + _matchBeforeIndex = -1; + + // Stop servlets + List servletHolders = new ArrayList(); //will be remaining servlets + List servletMappings = LazyList.array2List(_servletMappings); //will be remaining mappings if (_servlets!=null) { for (int i=_servlets.length; i-->0;) { try { _servlets[i].stop(); }catch(Exception e){LOG.warn(Log.EXCEPTION,e);} + if (_servlets[i].getSource() != Source.EMBEDDED) + { + //remove from servlet name map + _servletNameMap.remove(_servlets[i].getName()); + //remove any mappings associated with this servlet + ListIterator smitor = servletMappings.listIterator(); + while (smitor.hasNext()) + { + ServletMapping sm = smitor.next(); + if (sm.getServletName().equals(_servlets[i].getName())) + smitor.remove(); + } + } + else + servletHolders.add(_servlets[i]); //only retain embedded } } + _servlets = (ServletHolder[]) LazyList.toArray(servletHolders, ServletHolder.class); + _servletMappings = (ServletMapping[])LazyList.toArray(servletMappings, ServletMapping.class); + + //will be regenerated on next start _filterPathMappings=null; - _filterNameMappings=null; - + _filterNameMappings=null; _servletPathMap=null; } @@ -519,8 +563,8 @@ public class ServletHandler extends ScopedHandler if (!response.isCommitted()) { - request.setAttribute(Dispatcher.ERROR_EXCEPTION_TYPE,th.getClass()); - request.setAttribute(Dispatcher.ERROR_EXCEPTION,th); + request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,th.getClass()); + request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,th); if (th instanceof UnavailableException) { UnavailableException ue = (UnavailableException)th; @@ -545,8 +589,8 @@ public class ServletHandler extends ScopedHandler // TODO httpResponse.getHttpConnection().forceClose(); if (!response.isCommitted()) { - request.setAttribute(Dispatcher.ERROR_EXCEPTION_TYPE,e.getClass()); - request.setAttribute(Dispatcher.ERROR_EXCEPTION,e); + request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,e.getClass()); + request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,e); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } else @@ -782,7 +826,7 @@ public class ServletHandler extends ScopedHandler */ public ServletHolder addServletWithMapping (String className,String pathSpec) { - ServletHolder holder = newServletHolder(null); + ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED); holder.setName(className+"-"+LazyList.size(_servlets)); holder.setClassName(className); addServletWithMapping(holder,pathSpec); @@ -797,7 +841,8 @@ public class ServletHandler extends ScopedHandler { ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED); holder.setHeldClass(servlet); - setServlets((ServletHolder[])LazyList.addToArray(getServlets(), holder, ServletHolder.class)); + //DUPLICATES adding servlet from addServletWithMapping(holder, pathSpec)? + //setServlets((ServletHolder[])LazyList.addToArray(getServlets(), holder, ServletHolder.class)); addServletWithMapping(holder,pathSpec); return holder; @@ -969,7 +1014,7 @@ public class ServletHandler extends ScopedHandler */ public FilterHolder addFilterWithMapping (String className,String pathSpec,int dispatches) { - FilterHolder holder = newFilterHolder(null); + FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED); holder.setName(className+"-"+_filters.length); holder.setClassName(className); @@ -1118,7 +1163,7 @@ public class ServletHandler extends ScopedHandler { //programmatically defined filter mappings are prepended to mapping list in the order //in which they were defined. In other words, insert this mapping at the tail of the - //programmatically added filter mappings, BEFORE the first web.xml defined filter mapping. + //programmatically prepended filter mappings, BEFORE the first web.xml defined filter mapping. if (_matchBeforeIndex < 0) { @@ -1161,14 +1206,15 @@ public class ServletHandler extends ScopedHandler { if (pos < 0) throw new IllegalArgumentException("FilterMapping insertion pos < 0"); - FilterMapping[] mappings = getFilterMappings(); + if (mappings==null || mappings.length==0) { return new FilterMapping[] {mapping}; } FilterMapping[] new_mappings = new FilterMapping[mappings.length+1]; + if (before) { //copy existing filter mappings up to but not including the pos diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java index 7b51fe120fd..9dfbcc8a0af 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java @@ -90,7 +90,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope */ public ServletHolder() { - super (Source.EMBEDDED); + this(Source.EMBEDDED); } /* ---------------------------------------------------------------- */ @@ -98,7 +98,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope */ public ServletHolder(Holder.Source creator) { - super (creator); + super(creator); } /* ---------------------------------------------------------------- */ @@ -106,7 +106,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope */ public ServletHolder(Servlet servlet) { - super (Source.EMBEDDED); + this(Source.EMBEDDED); setServlet(servlet); } @@ -115,7 +115,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope */ public ServletHolder(String name, Class servlet) { - super (Source.EMBEDDED); + this(Source.EMBEDDED); setName(name); setHeldClass(servlet); } @@ -125,7 +125,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope */ public ServletHolder(String name, Servlet servlet) { - super (Source.EMBEDDED); + this(Source.EMBEDDED); setName(name); setServlet(servlet); } @@ -135,7 +135,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope */ public ServletHolder(Class servlet) { - super (Source.EMBEDDED); + this(Source.EMBEDDED); setHeldClass(servlet); } @@ -653,6 +653,8 @@ public class ServletHolder extends Holder implements UserIdentity.Scope Servlet servlet=_servlet; synchronized(this) { + if (!isStarted()) + throw new UnavailableException("Servlet not initialized", -1); if (_unavailable!=0 || !_initOnStartup) servlet=getServlet(); if (servlet==null) diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java index 781d06defe8..36c1a88bbab 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java @@ -18,8 +18,10 @@ package org.eclipse.jetty.servlet; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThat; import java.io.IOException; import java.util.Arrays; @@ -57,6 +59,7 @@ import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.util.UrlEncoded; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -223,6 +226,32 @@ public class DispatcherTest assertEquals(expected, responses); } + @Test + public void testServletForwardDotDot() throws Exception + { + _contextHandler.addServlet(DispatchServletServlet.class, "/dispatch/*"); + _contextHandler.addServlet(RogerThatServlet.class, "/roger/that"); + + String requests="GET /context/dispatch/test?forward=/%2e%2e/roger/that HTTP/1.0\n" + "Host: localhost\n\n"; + + String responses = _connector.getResponses(requests); + + assertThat(responses,startsWith("HTTP/1.1 404 ")); + } + + @Test + public void testServletForwardEncodedDotDot() throws Exception + { + _contextHandler.addServlet(DispatchServletServlet.class, "/dispatch/*"); + _contextHandler.addServlet(RogerThatServlet.class, "/roger/that"); + + String requests="GET /context/dispatch/test?forward=/%252e%252e/roger/that HTTP/1.0\n" + "Host: localhost\n\n"; + + String responses = _connector.getResponses(requests); + + assertThat(responses,startsWith("HTTP/1.1 404 ")); + } + @Test public void testServletInclude() throws Exception { @@ -415,7 +444,10 @@ public class DispatcherTest else if(request.getParameter("forward")!=null) { dispatcher = getServletContext().getRequestDispatcher(request.getParameter("forward")); - dispatcher.forward(new ServletRequestWrapper(request), new ServletResponseWrapper(response)); + if (dispatcher!=null) + dispatcher.forward(new ServletRequestWrapper(request), new ServletResponseWrapper(response)); + else + response.sendError(404); } } @@ -587,8 +619,15 @@ public class DispatcherTest assertTrue(requestAttributeNames.containsAll(expectedAttributeNames)); assertEquals(null, request.getPathInfo()); - assertEquals(null, request.getPathTranslated()); - assertTrue(request.getQueryString().startsWith("do=end&else=%D0%B2%D1%8B%D0%B1%D1%80%D0%B0%D0%BD%D0%BE%3D%D0%A2%D0%B5%D0%BC%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D1%83%D1%80%D0%B0&test=1&foreign=")); + assertEquals(null, request.getPathTranslated()); + + UrlEncoded query = new UrlEncoded(request.getQueryString()); + assertThat(query.getString("do"), is("end")); + // Russian for "selected=Temperature" + String russian = new UrlEncoded(query.getString("else")).encode(); + assertThat(russian, is("%D0%B2%D1%8B%D0%B1%D1%80%D0%B0%D0%BD%D0%BE=%D0%A2%D0%B5%D0%BC%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D1%83%D1%80%D0%B0")); + assertThat(query.getString("test"), is("1")); + assertThat(query.containsKey("foreign"), is(true)); String[] vals = request.getParameterValues("foreign"); assertTrue(vals!=null); diff --git a/jetty-servlets/pom.xml b/jetty-servlets/pom.xml index 79670c5114e..4081ff7f175 100644 --- a/jetty-servlets/pom.xml +++ b/jetty-servlets/pom.xml @@ -3,12 +3,13 @@ jetty-project org.eclipse.jetty - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-servlets Jetty :: Utility Servlets and Filters Utility Servlets from Jetty + http://www.eclipse.org/jetty ${project.groupId}.servlets diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java index c7b2b4f1fb7..6bd15d612c6 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java @@ -22,6 +22,8 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; import java.util.Enumeration; import java.util.HashMap; import java.util.Locale; @@ -32,8 +34,11 @@ 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.util.IO; +import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.UrlEncoded; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -222,35 +227,55 @@ public class CGI extends HttpServlet if ((pathTranslated == null) || (pathTranslated.length() == 0)) pathTranslated = path; + String bodyFormEncoded = null; + if ((HttpMethods.POST.equals(req.getMethod()) || HttpMethods.PUT.equals(req.getMethod())) && "application/x-www-form-urlencoded".equals(req.getContentType())) + { + MultiMap parameterMap = new MultiMap(); + Enumeration names = req.getParameterNames(); + while (names.hasMoreElements()) + { + String parameterName = (String)names.nextElement(); + parameterMap.addValues(parameterName, req.getParameterValues(parameterName)); + } + bodyFormEncoded = UrlEncoded.encode(parameterMap, req.getCharacterEncoding(), true); + } + EnvList env = new EnvList(_env); // these ones are from "The WWW Common Gateway Interface Version 1.1" // look at : // http://Web.Golux.Com/coar/cgi/draft-coar-cgi-v11-03-clean.html#6.1.1 - env.set("AUTH_TYPE",req.getAuthType()); - env.set("CONTENT_LENGTH",Integer.toString(len)); - env.set("CONTENT_TYPE",req.getContentType()); - env.set("GATEWAY_INTERFACE","CGI/1.1"); + env.set("AUTH_TYPE", req.getAuthType()); + if (bodyFormEncoded != null) + { + env.set("CONTENT_LENGTH", Integer.toString(bodyFormEncoded.length())); + } + else + { + env.set("CONTENT_LENGTH", Integer.toString(len)); + } + env.set("CONTENT_TYPE", req.getContentType()); + env.set("GATEWAY_INTERFACE", "CGI/1.1"); if ((pathInfo != null) && (pathInfo.length() > 0)) { - env.set("PATH_INFO",pathInfo); + env.set("PATH_INFO", pathInfo); } - env.set("PATH_TRANSLATED",pathTranslated); - env.set("QUERY_STRING",req.getQueryString()); - env.set("REMOTE_ADDR",req.getRemoteAddr()); - env.set("REMOTE_HOST",req.getRemoteHost()); + env.set("PATH_TRANSLATED", pathTranslated); + env.set("QUERY_STRING", req.getQueryString()); + env.set("REMOTE_ADDR", req.getRemoteAddr()); + env.set("REMOTE_HOST", req.getRemoteHost()); // The identity information reported about the connection by a // RFC 1413 [11] request to the remote agent, if // available. Servers MAY choose not to support this feature, or // not to request the data for efficiency reasons. // "REMOTE_IDENT" => "NYI" - env.set("REMOTE_USER",req.getRemoteUser()); - env.set("REQUEST_METHOD",req.getMethod()); - env.set("SCRIPT_NAME",scriptName); - env.set("SCRIPT_FILENAME",scriptPath); - env.set("SERVER_NAME",req.getServerName()); - env.set("SERVER_PORT",Integer.toString(req.getServerPort())); - env.set("SERVER_PROTOCOL",req.getProtocol()); - env.set("SERVER_SOFTWARE",getServletContext().getServerInfo()); + env.set("REMOTE_USER", req.getRemoteUser()); + env.set("REQUEST_METHOD", req.getMethod()); + env.set("SCRIPT_NAME", scriptName); + env.set("SCRIPT_FILENAME", scriptPath); + env.set("SERVER_NAME", req.getServerName()); + env.set("SERVER_PORT", Integer.toString(req.getServerPort())); + env.set("SERVER_PROTOCOL", req.getProtocol()); + env.set("SERVER_SOFTWARE", getServletContext().getServerInfo()); Enumeration enm = req.getHeaderNames(); while (enm.hasMoreElements()) @@ -261,7 +286,7 @@ public class CGI extends HttpServlet } // these extra ones were from printenv on www.dev.nomura.co.uk - env.set("HTTPS",(req.isSecure()?"ON":"OFF")); + env.set("HTTPS", (req.isSecure()?"ON":"OFF")); // "DOCUMENT_ROOT" => root + "/docs", // "SERVER_URL" => "NYI - http://us0245", // "TZ" => System.getProperty("user.timezone"), @@ -275,31 +300,22 @@ public class CGI extends HttpServlet if (_cmdPrefix != null) execCmd = _cmdPrefix + " " + execCmd; - Process p = (dir == null)?Runtime.getRuntime().exec(execCmd,env.getEnvArray()):Runtime.getRuntime().exec(execCmd,env.getEnvArray(),dir); + LOG.debug("Environment: " + env.getExportString()); + LOG.debug("Command: " + execCmd); + + Process p; + if (dir == null) + p = Runtime.getRuntime().exec(execCmd, env.getEnvArray()); + else + p = Runtime.getRuntime().exec(execCmd, env.getEnvArray(), dir); // hook processes input to browser's output (async) - final InputStream inFromReq = req.getInputStream(); - final OutputStream outToCgi = p.getOutputStream(); - final int inLength = len; + if (bodyFormEncoded != null) + writeProcessInput(p, bodyFormEncoded); + else if (len > 0) + writeProcessInput(p, req.getInputStream(), len); - IO.copyThread(p.getErrorStream(),System.err); - - new Thread(new Runnable() - { - public void run() - { - try - { - if (inLength > 0) - IO.copy(inFromReq,outToCgi,inLength); - outToCgi.close(); - } - catch (IOException e) - { - LOG.ignore(e); - } - } - }).start(); + IO.copyThread(p.getErrorStream(), System.err); // hook processes output to browser's input (sync) // if browser closes stream, we should detect it and kill process... @@ -376,15 +392,56 @@ public class CGI extends HttpServlet } catch (Exception e) { - LOG.ignore(e); + LOG.debug(e); } } - os = null; p.destroy(); // LOG.debug("CGI: terminated!"); } } + private static void writeProcessInput(final Process p, final String input) + { + new Thread(new Runnable() + { + public void run() + { + try + { + Writer outToCgi = new OutputStreamWriter(p.getOutputStream()); + outToCgi.write(input); + outToCgi.close(); + } + catch (IOException e) + { + LOG.debug(e); + } + } + }).start(); + } + + private static void writeProcessInput(final Process p, final InputStream input, final int len) + { + if (len <= 0) return; + + new Thread(new Runnable() + { + public void run() + { + try + { + OutputStream outToCgi = p.getOutputStream(); + IO.copy(input, outToCgi, len); + outToCgi.close(); + } + catch (IOException e) + { + LOG.debug(e); + } + } + }).start(); + } + /** * Utility method to get a line of text from the input stream. * @@ -393,7 +450,7 @@ public class CGI extends HttpServlet * @return the line of text * @throws IOException */ - private String getTextLineFromStream(InputStream is) throws IOException + private static String getTextLineFromStream(InputStream is) throws IOException { StringBuilder buffer = new StringBuilder(); int b; @@ -411,16 +468,16 @@ public class CGI extends HttpServlet */ private static class EnvList { - private Map envMap; + private Map envMap; EnvList() { - envMap = new HashMap(); + envMap = new HashMap(); } EnvList(EnvList l) { - envMap = new HashMap(l.envMap); + envMap = new HashMap(l.envMap); } /** @@ -434,7 +491,19 @@ public class CGI extends HttpServlet /** Get representation suitable for passing to exec. */ public String[] getEnvArray() { - return (String[])envMap.values().toArray(new String[envMap.size()]); + return envMap.values().toArray(new String[envMap.size()]); + } + + public String getExportString() + { + StringBuilder sb = new StringBuilder(); + for (String variable : getEnvArray()) + { + sb.append("export \""); + sb.append(variable); + sb.append("\"; "); + } + return sb.toString(); } @Override diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java index 976fc5aa6d8..8277966b9be 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java @@ -49,13 +49,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.Part; - import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.MultiPartInputStream; import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -268,12 +270,11 @@ public class MultiPartFilter implements Filter { try { - String s=new String((byte[])o,_encoding); - return s; + return getParameterBytesAsString(name, (byte[])o); } catch(Exception e) { - e.printStackTrace(); + LOG.warn(e); } } else if (o!=null) @@ -292,8 +293,7 @@ public class MultiPartFilter implements Filter for ( Object key : _params.keySet() ) { - String[] a = LazyList.toStringArray(getParameter((String)key)); - cmap.put((String)key,a); + cmap.put((String)key,getParameterValues((String)key)); } return Collections.unmodifiableMap(cmap); @@ -327,7 +327,7 @@ public class MultiPartFilter implements Filter { try { - v[i]=new String((byte[])o,_encoding); + v[i]=getParameterBytesAsString(name, (byte[])o); } catch(Exception e) { @@ -350,5 +350,23 @@ public class MultiPartFilter implements Filter { _encoding=enc; } + + + /* ------------------------------------------------------------------------------- */ + private String getParameterBytesAsString (String name, byte[] bytes) + throws UnsupportedEncodingException + { + //check if there is a specific encoding for the parameter + Object ct = _params.get(name+CONTENT_TYPE_SUFFIX); + //use default if not + String contentType = _encoding; + if (ct != null) + { + String tmp = MimeTypes.getCharsetFromContentType(new ByteArrayBuffer((String)ct)); + contentType = (tmp == null?_encoding:tmp); + } + + return new String(bytes,contentType); + } } } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java index 0b1d21891bb..a84349eca8e 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.servlets; import java.io.File; import java.util.Arrays; import java.util.List; + import javax.servlet.Servlet; import org.eclipse.jetty.http.HttpStatus; @@ -30,10 +31,14 @@ import org.eclipse.jetty.servlets.gzip.GzipTester; import org.eclipse.jetty.servlets.gzip.TestServletLengthStreamTypeWrite; import org.eclipse.jetty.servlets.gzip.TestServletLengthTypeStreamWrite; import org.eclipse.jetty.servlets.gzip.TestServletStreamLengthTypeWrite; +import org.eclipse.jetty.servlets.gzip.TestServletStreamLengthTypeWriteWithFlush; import org.eclipse.jetty.servlets.gzip.TestServletStreamTypeLengthWrite; import org.eclipse.jetty.servlets.gzip.TestServletTypeLengthStreamWrite; import org.eclipse.jetty.servlets.gzip.TestServletTypeStreamLengthWrite; +import org.eclipse.jetty.testing.HttpTester; import org.eclipse.jetty.toolchain.test.TestingDir; +import org.hamcrest.Matchers; +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -69,12 +74,14 @@ public class GzipFilterContentLengthTest { TestServletLengthStreamTypeWrite.class, GzipFilter.GZIP }, { TestServletLengthTypeStreamWrite.class, GzipFilter.GZIP }, { TestServletStreamLengthTypeWrite.class, GzipFilter.GZIP }, + { TestServletStreamLengthTypeWriteWithFlush.class, GzipFilter.GZIP }, { TestServletStreamTypeLengthWrite.class, GzipFilter.GZIP }, { TestServletTypeLengthStreamWrite.class, GzipFilter.GZIP }, { TestServletTypeStreamLengthWrite.class, GzipFilter.GZIP }, { TestServletLengthStreamTypeWrite.class, GzipFilter.DEFLATE }, { TestServletLengthTypeStreamWrite.class, GzipFilter.DEFLATE }, { TestServletStreamLengthTypeWrite.class, GzipFilter.DEFLATE }, + { TestServletStreamLengthTypeWriteWithFlush.class, GzipFilter.DEFLATE }, { TestServletStreamTypeLengthWrite.class, GzipFilter.DEFLATE }, { TestServletTypeLengthStreamWrite.class, GzipFilter.DEFLATE }, { TestServletTypeStreamLengthWrite.class, GzipFilter.DEFLATE } @@ -131,7 +138,8 @@ public class GzipFilterContentLengthTest try { tester.start(); - tester.assertIsResponseNotGzipCompressed("GET",testfile.getName(),filesize,HttpStatus.OK_200); + HttpTester response = tester.assertIsResponseNotGzipCompressed("GET",testfile.getName(),filesize,HttpStatus.OK_200); + Assert.assertThat(response.getHeader("ETAG"),Matchers.startsWith("W/etag-")); } finally { @@ -139,6 +147,15 @@ public class GzipFilterContentLengthTest } } + /** + * Tests gzip compression of a small size file + */ + @Test + public void testEmpty() throws Exception + { + assertIsNotGzipCompressed("empty.txt",0); + } + /** * Tests gzip compression of a small size file */ diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java index c420c4ce1e4..0298b6e8e61 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java @@ -79,6 +79,7 @@ public class GzipFilterDefaultTest protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setStatus(_status); + resp.setHeader("ETag","W/\"204\""); } } @@ -141,11 +142,40 @@ public class GzipFilterDefaultTest @Override public void service(HttpServletRequest req, HttpServletResponse resp) throws IOException,ServletException { + String uri=req.getRequestURI(); + if (uri.endsWith(".deferred")) + { + // System.err.println("type for "+uri.substring(0,uri.length()-9)+" is "+getServletContext().getMimeType(uri.substring(0,uri.length()-9))); + resp.setContentType(getServletContext().getMimeType(uri.substring(0,uri.length()-9))); + } + doGet(req,resp); } } + + @Test + public void testIsGzipCompressedEmpty() throws Exception + { + GzipTester tester = new GzipTester(testingdir, compressionType); + + // Test content that is smaller than the buffer. + tester.prepareServerFile("empty.txt",0); + + FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class); + holder.setInitParameter("mimeTypes","text/plain"); + + try + { + tester.start(); + HttpTester http = tester.assertIsResponseNotGzipCompressed("GET","empty.txt",0,200); + } + finally + { + tester.stop(); + } + } @Test public void testIsGzipCompressedTiny() throws Exception @@ -243,6 +273,57 @@ public class GzipFilterDefaultTest } } + + @Test + public void testGzipedIfModified() throws Exception + { + GzipTester tester = new GzipTester(testingdir, compressionType); + + // Test content that is smaller than the buffer. + int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4; + tester.prepareServerFile("file.txt",filesize); + + FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class); + holder.setInitParameter("mimeTypes","text/plain"); + + try + { + tester.start(); + HttpTester http = tester.assertIsResponseGzipCompressed("GET","file.txt",System.currentTimeMillis()-4000); + Assert.assertEquals("Accept-Encoding",http.getHeader("Vary")); + } + finally + { + tester.stop(); + } + } + + + @Test + public void testNotGzipedIfNotModified() throws Exception + { + GzipTester tester = new GzipTester(testingdir, compressionType); + + // Test content that is smaller than the buffer. + int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4; + tester.prepareServerFile("file.txt",filesize); + + FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class); + holder.setInitParameter("mimeTypes","text/plain"); + holder.setInitParameter("etags","true"); + + try + { + tester.start(); + HttpTester http = tester.assertIsResponseNotModified("GET","file.txt",System.currentTimeMillis()+4000); + } + finally + { + tester.stop(); + } + } + + @Test public void testIsNotGzipCompressedWithQ() throws Exception { @@ -267,7 +348,7 @@ public class GzipFilterDefaultTest } @Test - public void testIsNotGzipCompressed() throws Exception + public void testIsNotGzipCompressedByContentType() throws Exception { GzipTester tester = new GzipTester(testingdir, compressionType); @@ -289,6 +370,29 @@ public class GzipFilterDefaultTest } } + @Test + public void testIsNotGzipCompressedByDeferredContentType() throws Exception + { + GzipTester tester = new GzipTester(testingdir, compressionType); + + int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4; + tester.prepareServerFile("file.mp3.deferred",filesize); + + FilterHolder holder = tester.setContentServlet(GetServlet.class); + holder.setInitParameter("mimeTypes","text/plain"); + + try + { + tester.start(); + HttpTester http = tester.assertIsResponseNotGzipCompressed("GET","file.mp3.deferred", filesize, HttpStatus.OK_200); + Assert.assertNull(http.getHeader("Vary")); + } + finally + { + tester.stop(); + } + } + @Test public void testIsNotGzipCompressedHttpStatus() throws Exception { diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java deleted file mode 100644 index 19dd9949f3b..00000000000 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java +++ /dev/null @@ -1,266 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2013 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.servlets; - -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.security.DigestOutputStream; -import java.security.MessageDigest; -import java.util.EnumSet; -import java.util.Arrays; -import java.util.Collection; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.zip.GZIPInputStream; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; - -import javax.servlet.DispatcherType; - -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.servlet.DefaultServlet; -import org.eclipse.jetty.servlet.FilterHolder; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.servlets.gzip.Hex; -import org.eclipse.jetty.servlets.gzip.NoOpOutputStream; -import org.eclipse.jetty.toolchain.test.IO; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.toolchain.test.TestingDir; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -/** - * Test the effects of Gzip filtering when in the context of HTTP/1.1 Pipelining. - */ -@RunWith(Parameterized.class) -public class GzipWithPipeliningTest -{ - @Parameters - public static Collection data() - { - // Test different Content-Encoding header combinations. So implicitly testing that gzip is preferred oder deflate - String[][] data = new String[][] - { - { GzipFilter.GZIP }, - { GzipFilter.DEFLATE + ", " + GzipFilter.GZIP }, - { GzipFilter.GZIP + ", " + GzipFilter.DEFLATE }, - { GzipFilter.DEFLATE } - }; - - return Arrays.asList(data); - } - - @Rule - public TestingDir testingdir = new TestingDir(); - - private Server server; - private URI serverUri; - private String encodingHeader; - - - public GzipWithPipeliningTest(String encodingHeader) - { - this.encodingHeader = encodingHeader; - } - - @Before - public void startServer() throws Exception - { - // Configure Server - server = new Server(0); - - ServletContextHandler context = new ServletContextHandler(); - context.setContextPath("/"); - - DefaultServlet servlet = new DefaultServlet(); - ServletHolder holder = new ServletHolder(servlet); - holder.setInitParameter("resourceBase",MavenTestingUtils.getTestResourcesDir().getAbsolutePath()); - context.addServlet(holder,"/"); - - FilterHolder filter = context.addFilter(GzipFilter.class,"/*", EnumSet.of(DispatcherType.REQUEST)); - filter.setInitParameter("mimeTypes","text/plain"); - - server.setHandler(context); - - // Start Server - server.start(); - - Connector conn = server.getConnectors()[0]; - String host = conn.getHost(); - if (host == null) - { - host = "localhost"; - } - int port = conn.getLocalPort(); - serverUri = new URI(String.format("ws://%s:%d/",host,port)); - // System.out.printf("Server URI: %s%n",serverUri); - } - - @After - public void stopServer() throws Exception - { - server.stop(); - } - - @Test - public void testGzipThenImagePipelining() throws Exception - { - testingdir.ensureEmpty(); - File outputDir = testingdir.getDir(); - - PipelineHelper client = new PipelineHelper(serverUri, encodingHeader); - - try - { - File txtFile = MavenTestingUtils.getTestResourceFile("lots-of-fantasy-names.txt"); - File pngFile = MavenTestingUtils.getTestResourceFile("jetty_logo.png"); - - // Size of content, as it exists on disk, without gzip compression. - long rawsize = txtFile.length() + pngFile.length(); - assertThat("Ensure that we have sufficient file size to trigger chunking",rawsize,greaterThan(300000L)); - - String respHeader; - - client.connect(); - - // Request text that will be gzipped + chunked in the response - client.issueGET("/lots-of-fantasy-names.txt",true, false); - - respHeader = client.readResponseHeader(); - System.out.println("Response Header #1 --\n" + respHeader); - String expectedEncodingHeader = encodingHeader.equals(GzipFilter.DEFLATE) ? GzipFilter.DEFLATE : GzipFilter.GZIP; - assertThat("Content-Encoding should be gzipped",respHeader,containsString("Content-Encoding: " + expectedEncodingHeader + "\r\n")); - assertThat("Transfer-Encoding should be chunked",respHeader,containsString("Transfer-Encoding: chunked\r\n")); - - // Raw output / gzipped, writted to disk (checked for sha1sum later) - File rawOutputFile = new File(outputDir, "response-1.gz"); - FileOutputStream rawOutputStream = new FileOutputStream(rawOutputFile); - - long chunkSize = client.readChunkSize(); - System.out.println("Chunk Size: " + chunkSize); - - // Read only 20% - intentionally a partial read. - System.out.println("Attempting to read partial content ..."); - int readBytes = client.readBody(rawOutputStream,(int)(chunkSize * 0.20f)); - System.out.printf("Read %,d bytes%n",readBytes); - - // Issue another request - client.issueGET("/jetty_logo.png",true, false); - - // Finish reading chunks - System.out.println("Finish reading remaining chunks ..."); - String line; - chunkSize = chunkSize - readBytes; - while (chunkSize > 0) - { - readBytes = client.readBody(rawOutputStream,(int)chunkSize); - System.out.printf("Read %,d bytes%n",readBytes); - line = client.readLine(); - assertThat("Chunk delim should be an empty line with CR+LF",line,is("")); - chunkSize = client.readChunkSize(); - System.out.printf("Next Chunk: (0x%X) %,d bytes%n",chunkSize,chunkSize); - } - - // Inter-pipeline delim - line = client.readLine(); - assertThat("Inter-pipeline delim should be an empty line with CR+LF",line,is("")); - - // Sha1tracking for 1st Request - MessageDigest digestTxt = MessageDigest.getInstance("SHA1"); - DigestOutputStream digesterTxt = new DigestOutputStream(new NoOpOutputStream(),digestTxt); - - // Decompress 1st request and calculate sha1sum - IO.close(rawOutputStream); - FileInputStream rawInputStream = new FileInputStream(rawOutputFile); - InputStream uncompressedStream = null; - if (GzipFilter.DEFLATE.equals(encodingHeader)) - { - uncompressedStream = new InflaterInputStream(rawInputStream, new Inflater(true)); - } - else - { - uncompressedStream = new GZIPInputStream(rawInputStream); - } - - IO.copy(uncompressedStream, digesterTxt); - - // Read 2nd request http response header - respHeader = client.readResponseHeader(); - System.out.println("Response Header #2 --\n" + respHeader); - assertThat("Content-Encoding should NOT be gzipped",respHeader,not(containsString("Content-Encoding: gzip\r\n"))); - assertThat("Transfer-Encoding should NOT be chunked",respHeader,not(containsString("Transfer-Encoding: chunked\r\n"))); - - // Sha1tracking for 2nd Request - MessageDigest digestImg = MessageDigest.getInstance("SHA1"); - DigestOutputStream digesterImg = new DigestOutputStream(new NoOpOutputStream(),digestImg); - - // Read 2nd request body - int contentLength = client.getContentLength(respHeader); - assertThat("Image Content Length",(long)contentLength,is(pngFile.length())); - client.readBody(digesterImg,contentLength); - - // Validate checksums - IO.close(rawOutputStream); - assertChecksum("lots-of-fantasy-names.txt",digestTxt); - IO.close(digesterImg); - assertChecksum("jetty_logo.png",digestImg); - } - finally - { - client.disconnect(); - } - } - - private void assertChecksum(String testResourceFile, MessageDigest digest) throws IOException - { - String expectedSha1 = loadSha1sum(testResourceFile + ".sha1"); - String actualSha1 = Hex.asHex(digest.digest()); - assertEquals(testResourceFile + " / SHA1Sum of content",expectedSha1,actualSha1); - } - - private String loadSha1sum(String testResourceSha1Sum) throws IOException - { - File sha1File = MavenTestingUtils.getTestResourceFile(testResourceSha1Sum); - String contents = IO.readToString(sha1File); - Pattern pat = Pattern.compile("^[0-9A-Fa-f]*"); - Matcher mat = pat.matcher(contents); - assertTrue("Should have found HEX code in SHA1 file: " + sha1File,mat.find()); - return mat.group(); - } - -} diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java index 046b4646245..d79fa4809e4 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.servlets; import static org.junit.Assert.*; import static org.hamcrest.Matchers.*; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -38,12 +39,13 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.FilterMapping; import org.eclipse.jetty.testing.HttpTester; import org.eclipse.jetty.testing.ServletTester; import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.QuotedStringTokenizer; +import org.eclipse.jetty.util.StringUtil; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -755,7 +757,7 @@ public class MultipartFilterTest assertTrue(response.getContent().contains("aaaa,bbbbb")); } - + /* * see the testParameterMap test * @@ -768,7 +770,7 @@ public class MultipartFilterTest String[] content = req.getParameterMap().get("\"strup\"Content-Type: application/octet-stream"); assertThat (content[0], containsString("How now brown cow.")); super.doPost(req, resp); - } + } } /** @@ -813,6 +815,66 @@ public class MultipartFilterTest assertTrue(response.getContent().indexOf("brown cow")>=0); } + + public static class TestServletCharSet extends HttpServlet + { + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + //test that the multipart content bytes were converted correctly from their charset to unicode + String content = (String)req.getParameter("ttt"); + assertNotNull(content); + assertEquals("ttt\u01FCzzz",content); + assertEquals("application/octet-stream; charset=UTF-8",req.getParameter("ttt"+MultiPartFilter.CONTENT_TYPE_SUFFIX)); + + + //test that the parameter map retrieves values as String[] + Map map = req.getParameterMap(); + Object o = map.get("ttt"); + assertTrue(o.getClass().isArray()); + super.doPost(req, resp); + } + } + + + @Test + public void testWithCharSet() + throws Exception + { + // generated and parsed test + HttpTester request = new HttpTester() { + + }; + HttpTester response = new HttpTester(); + + tester.addServlet(TestServletCharSet.class,"/test2"); + + // test GET + request.setMethod("POST"); + request.setVersion("HTTP/1.0"); + request.setHeader("Host","tester"); + request.setURI("/context/test2"); + + String boundary="XyXyXy"; + request.setHeader("Content-Type","multipart/form-data; boundary="+boundary); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(("--" + boundary + "\r\n"+ + "Content-Disposition: form-data; name=\"ttt\"\r\n"+ + "Content-Type: application/octet-stream; charset=UTF-8\r\n\r\n").getBytes()); + baos.write("ttt\u01FCzzz".getBytes(StringUtil.__UTF8)); + baos.write(("\r\n--" + boundary + "--\r\n\r\n").getBytes()); + + request.setContentBytes(baos.toByteArray()); + + response.parse(tester.getResponses(new ByteArrayBuffer(request.generate().getBytes(StringUtil.__UTF8))).toString()); + } + + + + public static class DumpServlet extends HttpServlet { private static final long serialVersionUID = 201012011130L; diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java index c4ee7331d8e..f689a6af955 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java @@ -18,13 +18,8 @@ package org.eclipse.jetty.servlets.gzip; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -47,6 +42,8 @@ import java.util.zip.InflaterInputStream; import javax.servlet.Servlet; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeaders; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletHolder; @@ -56,6 +53,7 @@ import org.eclipse.jetty.testing.ServletTester; import org.eclipse.jetty.toolchain.test.IO; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.TestingDir; +import org.hamcrest.Matchers; import org.junit.Assert; public class GzipTester @@ -79,10 +77,20 @@ public class GzipTester { return assertIsResponseGzipCompressed(method,filename,filename); } + + public HttpTester assertIsResponseGzipCompressed(String method,String filename,long ifmodifiedsince) throws Exception + { + return assertIsResponseGzipCompressed(method,filename,filename,ifmodifiedsince); + } public HttpTester assertIsResponseGzipCompressed(String method,String requestedFilename, String serverFilename) throws Exception { - System.err.printf("[GzipTester] requesting /context/%s%n",requestedFilename); + return assertIsResponseGzipCompressed(method,requestedFilename,serverFilename,-1); + } + + public HttpTester assertIsResponseGzipCompressed(String method,String requestedFilename, String serverFilename, long ifmodifiedsince) throws Exception + { + //System.err.printf("[GzipTester] requesting /context/%s%n",requestedFilename); HttpTester request = new HttpTester(); HttpTester response = new HttpTester(); @@ -90,6 +98,8 @@ public class GzipTester request.setVersion("HTTP/1.0"); request.setHeader("Host","tester"); request.setHeader("Accept-Encoding",compressionType); + if (ifmodifiedsince>0) + request.setHeader(HttpHeaders.IF_MODIFIED_SINCE,HttpFields.formatDate(ifmodifiedsince)); if (this.userAgent != null) request.setHeader("User-Agent", this.userAgent); request.setURI("/context/" + requestedFilename); @@ -99,17 +109,31 @@ public class GzipTester // Collect the response(s) ByteArrayBuffer respBuff = servletTester.getResponses(reqsBuff); response.parse(respBuff.asArray()); - + // Assert the response headers Assert.assertThat("Response.method",response.getMethod(),nullValue()); - // Assert.assertThat("Response.status",response.getStatus(),is(HttpServletResponse.SC_OK)); - Assert.assertThat("Response.header[Content-Length]",response.getHeader("Content-Length"),notNullValue()); + + // Response headers should have either a Transfer-Encoding indicating chunked OR a Content-Length + String contentLength = response.getHeader("Content-Length"); + String transferEncoding = response.getHeader("Transfer-Encoding"); + + /* TODO need to check for the 3rd option of EOF content. To do this properly you might need to look at both HTTP/1.1 and HTTP/1.0 requests + boolean chunked = (transferEncoding != null) && (transferEncoding.indexOf("chunk") >= 0); + if(!chunked) { + Assert.assertThat("Response.header[Content-Length]",contentLength,notNullValue()); + } else { + Assert.assertThat("Response.header[Transfer-Encoding]",transferEncoding,notNullValue()); + } + */ + int qindex = compressionType.indexOf(";"); if (qindex < 0) Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),containsString(compressionType)); else Assert.assertThat("Response.header[Content-Encoding]", response.getHeader("Content-Encoding"),containsString(compressionType.substring(0,qindex))); + Assert.assertThat(response.getHeader("ETag"),Matchers.startsWith("W/")); + // Assert that the decompressed contents are what we expect. File serverFile = testdir.getFile(serverFilename); String expected = IO.readToString(serverFile); @@ -144,6 +168,41 @@ public class GzipTester return response; } + + + public HttpTester assertIsResponseNotModified(String method,String requestedFilename, long ifmodifiedsince) throws Exception + { + return assertIsResponseNotModified(method,requestedFilename,requestedFilename,ifmodifiedsince); + } + + public HttpTester assertIsResponseNotModified(String method,String requestedFilename, String serverFilename, long ifmodifiedsince) throws Exception + { + //System.err.printf("[GzipTester] requesting /context/%s%n",requestedFilename); + HttpTester request = new HttpTester(); + HttpTester response = new HttpTester(); + + request.setMethod(method); + request.setVersion("HTTP/1.0"); + request.setHeader("Host","tester"); + request.setHeader("Accept-Encoding",compressionType); + if (ifmodifiedsince>0) + request.setHeader(HttpHeaders.IF_MODIFIED_SINCE,HttpFields.formatDate(ifmodifiedsince)); + if (this.userAgent != null) + request.setHeader("User-Agent", this.userAgent); + request.setURI("/context/" + requestedFilename); + + // Issue the request + ByteArrayBuffer reqsBuff = new ByteArrayBuffer(request.generate().getBytes()); + // Collect the response(s) + ByteArrayBuffer respBuff = servletTester.getResponses(reqsBuff); + response.parse(respBuff.asArray()); + + Assert.assertThat(response.getStatus(),Matchers.equalTo(304)); + Assert.assertThat(response.getHeader("ETag"),Matchers.startsWith("W/")); + + return response; + } + /** * Makes sure that the response contains an unfiltered file contents. @@ -162,7 +221,7 @@ public class GzipTester */ public void assertIsResponseNotGzipFiltered(String requestedFilename, String testResourceSha1Sum, String expectedContentType) throws Exception { - System.err.printf("[GzipTester] requesting /context/%s%n",requestedFilename); + // System.err.printf("[GzipTester] requesting /context/%s%n",requestedFilename); HttpTester request = new HttpTester(); HttpTester response = new HttpTester(); @@ -191,6 +250,8 @@ public class GzipTester Assert.assertThat(prefix + ".header[Content-Type] (should have a Content-Type associated with it)",response.getHeader("Content-Type"),notNullValue()); Assert.assertThat(prefix + ".header[Content-Type]",response.getHeader("Content-Type"),is(expectedContentType)); + Assert.assertThat(response.getHeader("ETAG"),Matchers.startsWith("W/")); + ByteArrayInputStream bais = null; DigestOutputStream digester = null; try @@ -315,11 +376,15 @@ public class GzipTester int serverLength = Integer.parseInt(response.getHeader("Content-Length")); Assert.assertThat("Response.header[Content-Length]",serverLength,is(expectedFilesize)); } + + if (status>=200 && status<300) + Assert.assertThat(response.getHeader("ETAG"),Matchers.startsWith("W/")); + } private HttpTester executeRequest(String method,String uri) throws IOException, Exception { - System.err.printf("[GzipTester] requesting %s%n",uri); + //System.err.printf("[GzipTester] requesting %s%n",uri); HttpTester request = new HttpTester(); HttpTester response = new HttpTester(); @@ -347,11 +412,11 @@ public class GzipTester ByteArrayOutputStream out = null; try { - in = new ByteArrayInputStream(response.getContentBytes()); - out = new ByteArrayOutputStream(); - IO.copy(in,out); - - actual = out.toString(encoding); + byte[] content=response.getContentBytes(); + if (content!=null) + actual=new String(response.getContentBytes(),encoding); + else + actual=""; } finally { @@ -434,7 +499,7 @@ public class GzipTester finally { IO.close(in); - IO.close(fos); + IO.close(fos); } } @@ -466,6 +531,7 @@ public class GzipTester servletTester.setResourceBase(testdir.getDir().getCanonicalPath()); ServletHolder servletHolder = servletTester.addServlet(servletClass,"/"); servletHolder.setInitParameter("baseDir",testdir.getDir().getAbsolutePath()); + servletHolder.setInitParameter("etags","true"); FilterHolder holder = servletTester.addFilter(gzipFilterClass,"/*",EnumSet.allOf(DispatcherType.class)); holder.setInitParameter("vary","Accept-Encoding"); return holder; diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestMinGzipSizeServlet.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestMinGzipSizeServlet.java index 6883f9ab53d..697ee3b3b55 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestMinGzipSizeServlet.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestMinGzipSizeServlet.java @@ -51,6 +51,7 @@ public class TestMinGzipSizeServlet extends TestDirContentServlet byte[] dataBytes = loadContentFileBytes(fileName); response.setContentLength(dataBytes.length); + response.setHeader("ETag","W/etag-"+fileName); if (fileName.endsWith(".js")) { // intentionally long-form content type to test ";" splitting in code diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthStreamTypeWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthStreamTypeWrite.java index 72fa2620ae7..8e873db95b2 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthStreamTypeWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthStreamTypeWrite.java @@ -59,6 +59,7 @@ public class TestServletLengthStreamTypeWrite extends TestDirContentServlet response.setContentType("text/plain"); else if (fileName.endsWith("mp3")) response.setContentType("audio/mpeg"); + response.setHeader("ETag","W/etag-"+fileName); out.write(dataBytes); } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthTypeStreamWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthTypeStreamWrite.java index 84a6ce3a6a8..bcde21bc5ea 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthTypeStreamWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthTypeStreamWrite.java @@ -57,6 +57,7 @@ public class TestServletLengthTypeStreamWrite extends TestDirContentServlet response.setContentType("text/plain"); else if (fileName.endsWith("mp3")) response.setContentType("audio/mpeg"); + response.setHeader("ETag","W/etag-"+fileName); ServletOutputStream out = response.getOutputStream(); out.write(dataBytes); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWrite.java index a5046881e6f..97131cae9ca 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWrite.java @@ -59,6 +59,7 @@ public class TestServletStreamLengthTypeWrite extends TestDirContentServlet response.setContentType("text/plain"); else if (fileName.endsWith("mp3")) response.setContentType("audio/mpeg"); + response.setHeader("ETag","W/etag-"+fileName); out.write(dataBytes); } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWriteWithFlush.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWriteWithFlush.java new file mode 100644 index 00000000000..ff8841c1634 --- /dev/null +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWriteWithFlush.java @@ -0,0 +1,72 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.servlets.gzip; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.servlets.GzipFilter; + +/** + * A sample servlet to serve static content, using a order of construction that has caused problems for + * {@link GzipFilter} in the past. + * + * Using a real-world pattern of: + * + *
+ *  1) get stream
+ *  2) set content length
+ *  3) set content type
+ *  4) write and flush
+ * 
+ * + * @see http://bugs.eclipse.org/354014 + */ +@SuppressWarnings("serial") +public class TestServletStreamLengthTypeWriteWithFlush extends TestDirContentServlet +{ + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + String fileName = request.getServletPath(); + byte[] dataBytes = loadContentFileBytes(fileName); + + ServletOutputStream out = response.getOutputStream(); + + // set content-length of uncompressed content (GzipFilter should handle this) + response.setContentLength(dataBytes.length); + + if (fileName.endsWith("txt")) + response.setContentType("text/plain"); + else if (fileName.endsWith("mp3")) + response.setContentType("audio/mpeg"); + response.setHeader("ETag","W/etag-"+fileName); + + for ( int i = 0 ; i < dataBytes.length ; i++) + { + out.write(dataBytes[i]); + // flush using response object (not the stream itself) + response.flushBuffer(); + } + } +} \ No newline at end of file diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamTypeLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamTypeLengthWrite.java index 7b412d0cf3f..3f216b34338 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamTypeLengthWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamTypeLengthWrite.java @@ -57,6 +57,7 @@ public class TestServletStreamTypeLengthWrite extends TestDirContentServlet response.setContentType("text/plain"); else if (fileName.endsWith("mp3")) response.setContentType("audio/mpeg"); + response.setHeader("ETag","W/etag-"+fileName); response.setContentLength(dataBytes.length); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeLengthStreamWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeLengthStreamWrite.java index 1ae34f0ed54..4650b515d2f 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeLengthStreamWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeLengthStreamWrite.java @@ -55,6 +55,7 @@ public class TestServletTypeLengthStreamWrite extends TestDirContentServlet response.setContentType("text/plain"); else if (fileName.endsWith("mp3")) response.setContentType("audio/mpeg"); + response.setHeader("ETag","W/etag-"+fileName); response.setContentLength(dataBytes.length); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeStreamLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeStreamLengthWrite.java index 0d1def6f9bf..b5152e09cbf 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeStreamLengthWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeStreamLengthWrite.java @@ -55,6 +55,7 @@ public class TestServletTypeStreamLengthWrite extends TestDirContentServlet response.setContentType("text/plain"); else if (fileName.endsWith("mp3")) response.setContentType("audio/mpeg"); + response.setHeader("ETag","W/etag-"+fileName); ServletOutputStream out = response.getOutputStream(); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestStaticMimeTypeServlet.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestStaticMimeTypeServlet.java index 701088adf3b..16f00b0d2ec 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestStaticMimeTypeServlet.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestStaticMimeTypeServlet.java @@ -68,6 +68,7 @@ public class TestStaticMimeTypeServlet extends TestDirContentServlet byte[] dataBytes = loadContentFileBytes(fileName); response.setContentLength(dataBytes.length); + response.setHeader("ETag","W/etag-"+fileName); Buffer buf = mimeTypes.getMimeByExtension(fileName); if (buf == null) diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml index bb79494dc42..f90dd5fd5b3 100644 --- a/jetty-spdy/pom.xml +++ b/jetty-spdy/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 @@ -11,7 +11,7 @@ spdy-parent pom Jetty :: SPDY :: Parent - + http://www.eclipse.org/jetty 1.1.5.v20130313 1.1.0.v20120525 diff --git a/jetty-spdy/spdy-core/pom.xml b/jetty-spdy/spdy-core/pom.xml index b51c8256970..a48cf745e40 100644 --- a/jetty-spdy/spdy-core/pom.xml +++ b/jetty-spdy/spdy-core/pom.xml @@ -3,13 +3,13 @@ org.eclipse.jetty.spdy spdy-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 spdy-core Jetty :: SPDY :: Core - + http://www.eclipse.org/jetty org.eclipse.jetty diff --git a/jetty-spdy/spdy-jetty-http-webapp/pom.xml b/jetty-spdy/spdy-jetty-http-webapp/pom.xml index 5773efab76e..1389db13a7d 100644 --- a/jetty-spdy/spdy-jetty-http-webapp/pom.xml +++ b/jetty-spdy/spdy-jetty-http-webapp/pom.xml @@ -3,13 +3,13 @@ org.eclipse.jetty.spdy spdy-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 spdy-jetty-http-webapp war Jetty :: SPDY :: Jetty HTTP Web Application - + http://www.eclipse.org/jetty diff --git a/jetty-spdy/spdy-jetty-http/pom.xml b/jetty-spdy/spdy-jetty-http/pom.xml index 4b36ab3bae1..dcd90ff5e78 100644 --- a/jetty-spdy/spdy-jetty-http/pom.xml +++ b/jetty-spdy/spdy-jetty-http/pom.xml @@ -3,12 +3,12 @@ org.eclipse.jetty.spdy spdy-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 spdy-jetty-http Jetty :: SPDY :: Jetty HTTP Layer - + http://www.eclipse.org/jetty diff --git a/jetty-spdy/spdy-jetty/pom.xml b/jetty-spdy/spdy-jetty/pom.xml index 1a01152b550..1584ae19422 100644 --- a/jetty-spdy/spdy-jetty/pom.xml +++ b/jetty-spdy/spdy-jetty/pom.xml @@ -3,12 +3,12 @@ org.eclipse.jetty.spdy spdy-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 spdy-jetty Jetty :: SPDY :: Jetty Binding - + http://www.eclipse.org/jetty diff --git a/jetty-start/pom.xml b/jetty-start/pom.xml index 822e790046c..3bc5454bf18 100644 --- a/jetty-start/pom.xml +++ b/jetty-start/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-start Jetty :: Start The start utility + http://www.eclipse.org/jetty diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml index eb887f256f4..b37c2ddd0cf 100644 --- a/jetty-util/pom.xml +++ b/jetty-util/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-util Jetty :: Utilities Utility classes for Jetty + http://www.eclipse.org/jetty ${project.groupId}.util diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java b/jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java index 78dd63c709b..b8da7597b54 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java @@ -350,12 +350,34 @@ public class B64Code { if (encoded==null) return null; + + ByteArrayOutputStream bout = new ByteArrayOutputStream(4*encoded.length()/3); + decode(encoded, bout); + return bout.toByteArray(); + } + + /* ------------------------------------------------------------ */ + /** + * Base 64 decode as described in RFC 2045. + *

Unlike {@link #decode(char[])}, extra whitespace is ignored. + * @param encoded String to decode. + * @param output stream for decoded bytes + * @return byte array containing the decoded form of the input. + * @throws IllegalArgumentException if the input is not a valid + * B64 encoding. + */ + static public void decode (String encoded, ByteArrayOutputStream bout) + { + if (encoded==null) + return; + + if (bout == null) + throw new IllegalArgumentException("No outputstream for decoded bytes"); int ci=0; byte nibbles[] = new byte[4]; int s=0; - ByteArrayOutputStream bout = new ByteArrayOutputStream(4*encoded.length()/3); - + while (ci headers = new MultiMap(); while(true) { @@ -584,13 +587,21 @@ public class MultiPartInputStream continue; } + //Have a new Part + MultiPart part = new MultiPart(name, filename); + part.setHeaders(headers); + part.setContentType(contentType); + _parts.add(name, part); + part.open(); + + InputStream partInput = null; if ("base64".equalsIgnoreCase(contentTransferEncoding)) { - _in = new Base64InputStream(_in); + partInput = new Base64InputStream((ReadLineInputStream)_in); } else if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) { - _in = new FilterInputStream(_in) + partInput = new FilterInputStream(_in) { @Override public int read() throws IOException @@ -611,17 +622,9 @@ public class MultiPartInputStream } }; } - + else + partInput = _in; - - //Have a new Part - MultiPart part = new MultiPart(name, filename); - part.setHeaders(headers); - part.setContentType(contentType); - _parts.add(name, part); - - part.open(); - try { int state=-2; @@ -633,33 +636,38 @@ public class MultiPartInputStream while(true) { int b=0; - while((c=(state!=-2)?state:_in.read())!=-1) + while((c=(state!=-2)?state:partInput.read())!=-1) { total ++; if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) throw new IllegalStateException("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")"); state=-2; + // look for CR and/or LF if(c==13||c==10) { if(c==13) { - _in.mark(1); - int tmp=_in.read(); + partInput.mark(1); + int tmp=partInput.read(); if (tmp!=10) - _in.reset(); + partInput.reset(); else state=tmp; } break; } - // look for boundary + + // Look for boundary if(b>=0&&b0&&b0||c==-1) { + if(b==byteBoundary.length) lastPart=true; if(state==10) state=-2; break; } + // handle CR LF if(cr) part.write(13); @@ -786,14 +798,15 @@ public class MultiPartInputStream private static class Base64InputStream extends InputStream { - BufferedReader _in; + ReadLineInputStream _in; String _line; byte[] _buffer; int _pos; - public Base64InputStream (InputStream in) + + public Base64InputStream(ReadLineInputStream rlis) { - _in = new BufferedReader(new InputStreamReader(in)); + _in = rlis; } @Override @@ -801,18 +814,29 @@ public class MultiPartInputStream { if (_buffer==null || _pos>= _buffer.length) { - _line = _in.readLine(); + //Any CR and LF will be consumed by the readLine() call. + //We need to put them back into the bytes returned from this + //method because the parsing of the multipart content uses them + //as markers to determine when we've reached the end of a part. + _line = _in.readLine(); if (_line==null) - return -1; + return -1; //nothing left if (_line.startsWith("--")) - _buffer=(_line+"\r\n").getBytes(); + _buffer=(_line+"\r\n").getBytes(); //boundary marking end of part else if (_line.length()==0) - _buffer="\r\n".getBytes(); + _buffer="\r\n".getBytes(); //blank line else - _buffer=B64Code.decode(_line); + { + ByteArrayOutputStream baos = new ByteArrayOutputStream((4*_line.length()/3)+2); + B64Code.decode(_line, baos); + baos.write(13); + baos.write(10); + _buffer = baos.toByteArray(); + } _pos=0; } + return _buffer[_pos++]; } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java index 657714c9310..ecda413dcc4 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java @@ -710,6 +710,97 @@ public class MultiPartInputStreamTest extends TestCase assertNotNull(p); assertEquals(5, p.getSize()); } + + + public void testBase64EncodedContent () throws Exception + { + String contentWithEncodedPart = + "--AaB03x\r\n"+ + "Content-disposition: form-data; name=\"other\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "other" + "\r\n"+ + "--AaB03x\r\n"+ + "Content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n"+ + "Content-Transfer-Encoding: base64\r\n"+ + "Content-Type: application/octet-stream\r\n"+ + "\r\n"+ + B64Code.encode("hello jetty") + "\r\n"+ + "--AaB03x\r\n"+ + "Content-disposition: form-data; name=\"final\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "the end" + "\r\n"+ + "--AaB03x--\r\n"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(contentWithEncodedPart.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertEquals(3, parts.size()); + + Part p1 = mpis.getPart("other"); + assertNotNull(p1); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IO.copy(p1.getInputStream(), baos); + assertEquals("other", baos.toString("US-ASCII")); + + Part p2 = mpis.getPart("stuff"); + assertNotNull(p2); + baos = new ByteArrayOutputStream(); + IO.copy(p2.getInputStream(), baos); + assertEquals("hello jetty", baos.toString("US-ASCII")); + + Part p3 = mpis.getPart("final"); + assertNotNull(p3); + baos = new ByteArrayOutputStream(); + IO.copy(p3.getInputStream(), baos); + assertEquals("the end", baos.toString("US-ASCII")); + } + + public void testQuotedPrintableEncoding () throws Exception + { + String contentWithEncodedPart = + "--AaB03x\r\n"+ + "Content-disposition: form-data; name=\"other\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "other" + "\r\n"+ + "--AaB03x\r\n"+ + "Content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n"+ + "Content-Transfer-Encoding: quoted-printable\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "truth=3Dbeauty" + "\r\n"+ + "--AaB03x--\r\n"; + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(contentWithEncodedPart.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + Collection parts = mpis.getParts(); + assertEquals(2, parts.size()); + + Part p1 = mpis.getPart("other"); + assertNotNull(p1); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IO.copy(p1.getInputStream(), baos); + assertEquals("other", baos.toString("US-ASCII")); + + Part p2 = mpis.getPart("stuff"); + assertNotNull(p2); + baos = new ByteArrayOutputStream(); + IO.copy(p2.getInputStream(), baos); + assertEquals("truth=beauty", baos.toString("US-ASCII")); + } + + + + private String createMultipartRequestString(String filename) { diff --git a/jetty-webapp/pom.xml b/jetty-webapp/pom.xml index 77eeb3bfad7..4c6db1ae602 100644 --- a/jetty-webapp/pom.xml +++ b/jetty-webapp/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-webapp Jetty :: Webapp Application Support Jetty web application support + http://www.eclipse.org/jetty ${project.groupId}.webapp diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java index aeb272f121a..820bb13c4df 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java @@ -1170,7 +1170,8 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor String welcome = indexNode.toString(false, true); //Servlet Spec 3.0 p. 74 welcome files are additive - context.setWelcomeFiles((String[])LazyList.addToArray(context.getWelcomeFiles(),welcome,String.class)); + if (welcome != null && welcome.trim().length() > 0) + context.setWelcomeFiles((String[])LazyList.addToArray(context.getWelcomeFiles(),welcome,String.class)); } } 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 a719755798f..00665d4c831 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 @@ -991,16 +991,6 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL } } - /* ------------------------------------------------------------ */ - /** Add EventListener - * Conveniance method that calls {@link #setEventListeners(EventListener[])} - * @param listener - */ - @Override - public void addEventListener(EventListener listener) - { - setEventListeners(LazyList.addToArray(getEventListeners(), listener, EventListener.class)); - } /* ------------------------------------------------------------ */ diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java index aad8c963cd7..8ff887eb8fa 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java @@ -121,16 +121,8 @@ public class WebXmlConfiguration extends AbstractConfiguration @Override public void deconfigure (WebAppContext context) throws Exception { - // TODO preserve any configuration that pre-existed. - ServletHandler _servletHandler = context.getServletHandler(); - _servletHandler.setFilters(null); - _servletHandler.setFilterMappings(null); - _servletHandler.setServlets(null); - _servletHandler.setServletMappings(null); - - context.setEventListeners(null); context.setWelcomeFiles(null); if (context.getErrorHandler() instanceof ErrorPageErrorHandler) diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml index 8c7b2051fb2..59eb77ee784 100644 --- a/jetty-websocket/pom.xml +++ b/jetty-websocket/pom.xml @@ -3,13 +3,13 @@ jetty-project org.eclipse.jetty - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-websocket Jetty :: Websocket - + http://www.eclipse.org/jetty ${project.groupId}.websocket diff --git a/jetty-xml/pom.xml b/jetty-xml/pom.xml index 66bfa21a5e2..b288218c69e 100644 --- a/jetty-xml/pom.xml +++ b/jetty-xml/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 jetty-xml Jetty :: XML utilities The jetty xml utilities. + http://www.eclipse.org/jetty ${project.groupId}.xml diff --git a/pom.xml b/pom.xml index 511bf34ff76..9907225765b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,9 +6,9 @@ 20 jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT Jetty :: Project - ${jetty.url} + http://www.eclipse.org/jetty pom UTF-8 diff --git a/test-continuation-jetty6/pom.xml b/test-continuation-jetty6/pom.xml index d853b66d602..86048b7d319 100644 --- a/test-continuation-jetty6/pom.xml +++ b/test-continuation-jetty6/pom.xml @@ -9,6 +9,7 @@ jar Test :: Continuation - (Jetty 6) Asynchronous API + http://www.eclipse.org/jetty diff --git a/test-continuation/pom.xml b/test-continuation/pom.xml index d2e2be18791..a33fc603dac 100644 --- a/test-continuation/pom.xml +++ b/test-continuation/pom.xml @@ -2,13 +2,14 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 test-continuation jar Test :: Continuation Asynchronous API + http://www.eclipse.org/jetty diff --git a/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java b/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java index 99cc00fd0f0..321cfbd0850 100644 --- a/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java +++ b/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java @@ -21,16 +21,25 @@ package org.eclipse.jetty.continuation; import java.io.IOException; import java.io.InputStream; import java.util.EnumSet; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; import org.eclipse.jetty.continuation.test.ContinuationBase; import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.RequestLog; +import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.component.AbstractLifeCycle; @@ -40,19 +49,27 @@ public class ContinuationTest extends ContinuationBase protected ServletHandler _servletHandler; protected SelectChannelConnector _connector; FilterHolder _filter; + protected List _log = new ArrayList(); @Override protected void setUp() throws Exception { _connector = new SelectChannelConnector(); _server.setConnectors(new Connector[]{ _connector }); + + _log.clear(); + RequestLogHandler requestLogHandler = new RequestLogHandler(); + requestLogHandler.setRequestLog(new Log()); + _server.setHandler(requestLogHandler); + ServletContextHandler servletContext = new ServletContextHandler(ServletContextHandler.NO_SECURITY|ServletContextHandler.NO_SESSIONS); - _server.setHandler(servletContext); + requestLogHandler.setHandler(servletContext); + _servletHandler=servletContext.getServletHandler(); ServletHolder holder=new ServletHolder(_servlet); holder.setAsyncSupported(true); _servletHandler.addServletWithMapping(holder,"/"); - + _server.start(); _port=_connector.getLocalPort(); @@ -61,6 +78,9 @@ public class ContinuationTest extends ContinuationBase @Override protected void tearDown() throws Exception { + Assert.assertEquals(1,_log.size()); + Assert.assertTrue(_log.get(0).startsWith("200 ")); + Assert.assertTrue(_log.get(0).endsWith(" /")); _server.stop(); } @@ -155,4 +175,12 @@ public class ContinuationTest extends ContinuationBase return IO.toString(in); } + class Log extends AbstractLifeCycle implements RequestLog + { + public void log(Request request, Response response) + { + _log.add(response.getStatus()+" "+response.getContentCount()+" "+request.getRequestURI()); + } + + } } diff --git a/test-jetty-nested/pom.xml b/test-jetty-nested/pom.xml index 148b6b2eac4..9a28f3f02f1 100644 --- a/test-jetty-nested/pom.xml +++ b/test-jetty-nested/pom.xml @@ -4,10 +4,11 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT test-jetty-nested Jetty :: Nested Test + http://www.eclipse.org/jetty war diff --git a/test-jetty-servlet/pom.xml b/test-jetty-servlet/pom.xml index 86bb7ed472b..5ef7c9e5488 100644 --- a/test-jetty-servlet/pom.xml +++ b/test-jetty-servlet/pom.xml @@ -2,12 +2,13 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 test-jetty-servlet jar Test :: Jetty Servlet Tester + http://www.eclipse.org/jetty org.eclipse.jetty diff --git a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java index 1621a7ec7aa..ad8e5d9287e 100644 --- a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java +++ b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java @@ -531,6 +531,15 @@ public class HttpTester _genContent=null; } } + + /* ------------------------------------------------------------ */ + public void setContentBytes(byte[] bytes) + { + _parsedContent = null; + _genContent = bytes; + setLongHeader(HttpHeaders.CONTENT_LENGTH, bytes.length); + + } /* ------------------------------------------------------------ */ private class PH extends HttpParser.EventHandler @@ -599,4 +608,12 @@ public class HttpTester } + @Override + public String toString() + { + if (_method!=null) + return super.toString()+" "+_method+" "+_uri+" "+_version+"\n"+_fields.toString(); + + return super.toString()+" HTTP/1.1 "+_status+" "+_reason+"\n"+_fields.toString(); + } } diff --git a/test-jetty-webapp/pom.xml b/test-jetty-webapp/pom.xml index 1bacf0bf2bb..d5df9eb3af3 100644 --- a/test-jetty-webapp/pom.xml +++ b/test-jetty-webapp/pom.xml @@ -2,11 +2,12 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 test-jetty-webapp Test :: Jetty Test Webapp + http://www.eclipse.org/jetty war diff --git a/tests/pom.xml b/tests/pom.xml index 207862d3e15..2a7865ef466 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -21,11 +21,12 @@ org.eclipse.jetty jetty-project - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT org.eclipse.jetty.tests tests-parent Jetty Tests :: Parent + http://www.eclipse.org/jetty pom diff --git a/tests/test-integration/pom.xml b/tests/test-integration/pom.xml index df2ebc00d36..089de4f7c7c 100644 --- a/tests/test-integration/pom.xml +++ b/tests/test-integration/pom.xml @@ -20,12 +20,13 @@ org.eclipse.jetty.tests tests-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT 4.0.0 test-integration jar Jetty Tests :: Integrations + http://www.eclipse.org/jetty ${project.build.directory}/test-wars ${project.build.directory}/test-libs diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithAliasesTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithAliasesTest.java index 82ffc331813..3ba4f2c5e1c 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithAliasesTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithAliasesTest.java @@ -67,6 +67,7 @@ public class JspAndDefaultWithAliasesTest // @formatter:off data.add(new String[] { "false","/dump.jsp" }); + data.add(new String[] { "false","/dump.jsp/" }); data.add(new String[] { "true", "/dump.jsp%00" }); data.add(new String[] { "false","/dump.jsp%00/" }); data.add(new String[] { "false","/dump.jsp%00x/dump.jsp" }); diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithoutAliasesTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithoutAliasesTest.java index ab9f48473fc..5d119f86a02 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithoutAliasesTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithoutAliasesTest.java @@ -68,6 +68,7 @@ public class JspAndDefaultWithoutAliasesTest // @formatter:off data.add(new Object[] { "/dump.jsp" }); + data.add(new Object[] { "/dump.jsp/" }); data.add(new Object[] { "/dump.jsp%00" }); data.add(new Object[] { "/dump.jsp%00x" }); data.add(new Object[] { "/dump.jsp%00x/dump.jsp" }); diff --git a/tests/test-loginservice/pom.xml b/tests/test-loginservice/pom.xml index 642929921b1..f3c7ac8c244 100644 --- a/tests/test-loginservice/pom.xml +++ b/tests/test-loginservice/pom.xml @@ -21,10 +21,11 @@ org.eclipse.jetty.tests tests-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT test-loginservice Jetty Tests :: Login Service + http://www.eclipse.org/jetty org.eclipse.jetty diff --git a/tests/test-sessions/pom.xml b/tests/test-sessions/pom.xml index 298b00f6f40..add39f5cf2c 100644 --- a/tests/test-sessions/pom.xml +++ b/tests/test-sessions/pom.xml @@ -21,10 +21,11 @@ org.eclipse.jetty.tests tests-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT test-sessions-parent Jetty Tests :: Sessions :: Parent + http://www.eclipse.org/jetty pom diff --git a/tests/test-sessions/test-hash-sessions/pom.xml b/tests/test-sessions/test-hash-sessions/pom.xml index 487b7b84cc7..ddfef203d01 100644 --- a/tests/test-sessions/test-hash-sessions/pom.xml +++ b/tests/test-sessions/test-hash-sessions/pom.xml @@ -21,10 +21,11 @@ org.eclipse.jetty.tests test-sessions-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT test-hash-sessions Jetty Tests :: Sessions :: Hash + http://www.eclipse.org/jetty diff --git a/tests/test-sessions/test-jdbc-sessions/pom.xml b/tests/test-sessions/test-jdbc-sessions/pom.xml index 3c3df7e0b72..17cf4d85567 100644 --- a/tests/test-sessions/test-jdbc-sessions/pom.xml +++ b/tests/test-sessions/test-jdbc-sessions/pom.xml @@ -21,10 +21,11 @@ org.eclipse.jetty.tests test-sessions-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT test-jdbc-sessions Jetty Tests :: Sessions :: JDBC + http://www.eclipse.org/jetty diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java index 54094cd206f..3021e8d7c68 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java @@ -18,9 +18,7 @@ package org.eclipse.jetty.server.session; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.io.File; import java.io.FileWriter; @@ -32,35 +30,32 @@ 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.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.TestingDir; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.StdErrLog; +import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.WebAppContext; +import org.junit.Rule; import org.junit.Test; /** * ReloadedSessionMissingClassTest - * - * - * */ public class ReloadedSessionMissingClassTest { + @Rule + public TestingDir testdir = new TestingDir(); @Test public void testSessionReloadWithMissingClass() throws Exception { ((StdErrLog)Log.getLogger(org.eclipse.jetty.server.session.JDBCSessionManager.class)).setHideStacks(true); + Resource.setDefaultUseCaches(false); String contextPath = "/foo"; - File srcDir = new File(System.getProperty("basedir"), "src"); - File targetDir = new File(System.getProperty("basedir"), "target"); - File testDir = new File (srcDir, "test"); - File resourcesDir = new File (testDir, "resources"); - File unpackedWarDir = new File (targetDir, "foo"); - if (unpackedWarDir.exists()) - IO.delete(unpackedWarDir); - unpackedWarDir.mkdir(); + File unpackedWarDir = testdir.getDir(); + testdir.ensureEmpty(); File webInfDir = new File (unpackedWarDir, "WEB-INF"); webInfDir.mkdir(); @@ -81,8 +76,8 @@ public class ReloadedSessionMissingClassTest w.write(xml); w.close(); - File foobarJar = new File (resourcesDir, "foobar.jar"); - File foobarNOfooJar = new File (resourcesDir, "foobarNOfoo.jar"); + File foobarJar = MavenTestingUtils.getTestResourceFile("foobar.jar"); + File foobarNOfooJar = MavenTestingUtils.getTestResourceFile("foobarNOfoo.jar"); URL[] foobarUrls = new URL[]{foobarJar.toURI().toURL()}; URL[] barUrls = new URL[]{foobarNOfooJar.toURI().toURL()}; 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 bc6d47cac69..fe6675b2012 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 @@ -18,6 +18,7 @@ package org.eclipse.jetty.server.session; +import org.eclipse.jetty.util.resource.Resource; import org.junit.Test; /** @@ -30,6 +31,7 @@ public class WebAppObjectInSessionTest extends AbstractWebAppObjectInSessionTest public AbstractTestServer createServer(int port) { + Resource.setDefaultUseCaches(false); return new JdbcTestServer(port); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/resources/foobar.jar b/tests/test-sessions/test-jdbc-sessions/src/test/resources/foobar.jar index 29b46ddee9f..ecf296c75c1 100644 Binary files a/tests/test-sessions/test-jdbc-sessions/src/test/resources/foobar.jar and b/tests/test-sessions/test-jdbc-sessions/src/test/resources/foobar.jar differ diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/resources/foobarNOfoo.jar b/tests/test-sessions/test-jdbc-sessions/src/test/resources/foobarNOfoo.jar index fcb3ddf78c9..593b9b12bd0 100644 Binary files a/tests/test-sessions/test-jdbc-sessions/src/test/resources/foobarNOfoo.jar and b/tests/test-sessions/test-jdbc-sessions/src/test/resources/foobarNOfoo.jar differ diff --git a/tests/test-sessions/test-mongodb-sessions/pom.xml b/tests/test-sessions/test-mongodb-sessions/pom.xml index 473145e4ba6..a091ee1b71c 100644 --- a/tests/test-sessions/test-mongodb-sessions/pom.xml +++ b/tests/test-sessions/test-mongodb-sessions/pom.xml @@ -21,10 +21,11 @@ org.eclipse.jetty.tests test-sessions-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT test-mongodb-sessions Jetty Tests :: Sessions :: Mongo + http://www.eclipse.org/jetty diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/resources/jetty-logging.properties b/tests/test-sessions/test-mongodb-sessions/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..fd2d21f9748 --- /dev/null +++ b/tests/test-sessions/test-mongodb-sessions/src/test/resources/jetty-logging.properties @@ -0,0 +1,4 @@ +# Setup default logging implementation for during testing +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog + +#org.eclipse.jetty.server.LEVEL=DEBUG \ No newline at end of file diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml index db8eefb8f44..ce4f2e93fe0 100644 --- a/tests/test-sessions/test-sessions-common/pom.xml +++ b/tests/test-sessions/test-sessions-common/pom.xml @@ -21,10 +21,11 @@ org.eclipse.jetty.tests test-sessions-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT test-sessions-common Jetty Tests :: Sessions :: Common + http://www.eclipse.org/jetty diff --git a/tests/test-webapps/pom.xml b/tests/test-webapps/pom.xml index 6c85874a706..72fea5e9074 100644 --- a/tests/test-webapps/pom.xml +++ b/tests/test-webapps/pom.xml @@ -21,10 +21,11 @@ org.eclipse.jetty.tests tests-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT test-webapps-parent Jetty Tests :: WebApps :: Parent + http://www.eclipse.org/jetty pom diff --git a/tests/test-webapps/test-webapp-rfc2616/pom.xml b/tests/test-webapps/test-webapp-rfc2616/pom.xml index eab04df47ce..78ce58208f8 100644 --- a/tests/test-webapps/test-webapp-rfc2616/pom.xml +++ b/tests/test-webapps/test-webapp-rfc2616/pom.xml @@ -21,10 +21,11 @@ org.eclipse.jetty.tests test-webapps-parent - 8.1.11.v20130520-SNAPSHOT + 8.1.12-SNAPSHOT test-webapp-rfc2616 Jetty Tests :: WebApp :: RFC2616 + http://www.eclipse.org/jetty war