Merge branch 'jetty-8' into release-8
This commit is contained in:
commit
e3cc7023f8
25
VERSION.txt
25
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.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>example-async-rest</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.example-async-rest</groupId>
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>example-async-rest</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.example-async-rest</groupId>
|
||||
<artifactId>example-async-rest-webapp</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>Example Async Rest :: Webapp</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<packaging>war</packaging>
|
||||
<build>
|
||||
<finalName>async-rest</finalName>
|
||||
</build>
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>example-async-rest</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Example Async Rest</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<modules>
|
||||
<module>async-rest-jar</module>
|
||||
<module>async-rest-webapp</module>
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>example-jetty-embedded</artifactId>
|
||||
<name>Example :: Jetty Embedded</name>
|
||||
<description>Jetty Embedded Examples</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-all-server</artifactId>
|
||||
<name>Jetty :: Aggregate :: All Server</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.${project.artifactId}</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-all</artifactId>
|
||||
<name>Jetty :: Aggregate :: All core Jetty</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<build>
|
||||
<sourceDirectory>${project.build.directory}/sources</sourceDirectory>
|
||||
<plugins>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<name>Jetty :: Aggregate :: HTTP Client</name>
|
||||
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<build>
|
||||
<sourceDirectory>${project.build.directory}/sources</sourceDirectory>
|
||||
<plugins>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
<name>Jetty :: Aggregate :: Plus Server</name>
|
||||
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<build>
|
||||
<sourceDirectory>${project.build.directory}/sources</sourceDirectory>
|
||||
<plugins>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<name>Jetty :: Aggregate :: HTTP Server</name>
|
||||
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<build>
|
||||
<sourceDirectory>${project.build.directory}/sources</sourceDirectory>
|
||||
<plugins>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<name>Jetty :: Aggregate :: Servlet Server</name>
|
||||
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<build>
|
||||
<sourceDirectory>${project.build.directory}/sources</sourceDirectory>
|
||||
<plugins>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<name>Jetty :: Aggregate :: WebApp Server</name>
|
||||
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<build>
|
||||
<sourceDirectory>${project.build.directory}/sources</sourceDirectory>
|
||||
<plugins>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<name>Jetty :: Aggregate :: Websocket</name>
|
||||
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<build>
|
||||
<sourceDirectory>${project.build.directory}/sources</sourceDirectory>
|
||||
<plugins>
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<name>Jetty :: Aggregate Project</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<packaging>pom</packaging>
|
||||
<build>
|
||||
<plugins>
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-ajp</artifactId>
|
||||
<name>Jetty :: AJP</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.ajp</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
<name>Jetty :: Servlet Annotations</name>
|
||||
<description>Annotation support for deploying servlets in jetty.</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.annotations</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -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<DiscoverableAnnotationHandler> _discoverableAnnotationHandlers = new ArrayList<DiscoverableAnnotationHandler>();
|
||||
protected ClassInheritanceHandler _classInheritanceHandler;
|
||||
protected List<ContainerInitializerAnnotationHandler> _containerInitializerAnnotationHandlers = new ArrayList<ContainerInitializerAnnotationHandler>();
|
||||
|
||||
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,19 +2,17 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<name>Jetty :: Asynchronous HTTP Client</name>
|
||||
<url>{$jetty.url}</url>
|
||||
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.client</bundle-symbolic-name>
|
||||
<jetty.test.policy.loc>target/test-policy</jetty.test.policy.loc>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
|
|
@ -52,10 +52,10 @@ public class HttpDestination implements Dumpable
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpDestination.class);
|
||||
|
||||
private final List<HttpExchange> _queue = new LinkedList<HttpExchange>();
|
||||
private final List<HttpExchange> _exchanges = new LinkedList<HttpExchange>();
|
||||
private final List<AbstractHttpConnection> _connections = new LinkedList<AbstractHttpConnection>();
|
||||
private final BlockingQueue<Object> _newQueue = new ArrayBlockingQueue<Object>(10, true);
|
||||
private final List<AbstractHttpConnection> _idle = new ArrayList<AbstractHttpConnection>();
|
||||
private final BlockingQueue<Object> _reservedConnections = new ArrayBlockingQueue<Object>(10, true);
|
||||
private final List<AbstractHttpConnection> _idleConnections = new ArrayList<AbstractHttpConnection>();
|
||||
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<HttpCookie> _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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<AbstractHttpConnection> connection = new AtomicReference<AbstractHttpConnection>();
|
||||
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
|
||||
{
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
<name>Jetty :: Continuation</name>
|
||||
<description>Asynchronous API</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.continuation</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
<name>Jetty :: Deployers</name>
|
||||
<description>Jetty deployers</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.deploy</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>jetty-distribution</artifactId>
|
||||
<name>Jetty :: Distribution Assemblies</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<packaging>pom</packaging>
|
||||
<properties>
|
||||
<assembly-directory>target/distribution</assembly-directory>
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-http-spi</artifactId>
|
||||
<name>Jetty :: Http Service Provider Interface</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.http.spi</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<name>Jetty :: Http Utility</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.http</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<bufferSize)
|
||||
{
|
||||
ByteArrayOutputStream2 b = new ByteArrayOutputStream2(bufferSize);
|
||||
b.write(_bOut.getBuf(),0,_bOut.size());
|
||||
_bOut=b;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setContentLength()
|
||||
{
|
||||
|
@ -170,7 +179,7 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
|||
if (_out == null || _bOut != null)
|
||||
{
|
||||
long length=_wrapper.getContentLength();
|
||||
if (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;
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-io</artifactId>
|
||||
<name>Jetty :: IO Utility</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.io</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jaspi</artifactId>
|
||||
<name>Jetty :: JASPI Security</name>
|
||||
<description>Jetty security infrastructure</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.jaspi</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
<name>Jetty :: JMX Management</name>
|
||||
<description>JMX management artifact for jetty.</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.jmx</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jndi</artifactId>
|
||||
<name>Jetty :: JNDI Naming</name>
|
||||
<description>JNDI spi impl for java namespace.</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.jndi</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-jsp</artifactId>
|
||||
<name>Jetty :: JSP dependencies</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<packaging>jar</packaging>
|
||||
<build>
|
||||
</build>
|
||||
|
|
|
@ -19,11 +19,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-monitor</artifactId>
|
||||
<name>Jetty :: Monitoring</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<description>Performance monitoring artifact for jetty.</description>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.monitor</bundle-symbolic-name>
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>jetty-nested</artifactId>
|
||||
<name>Jetty :: Nested</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Local Servlet Connector for jetty.</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.nested</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-nosql</artifactId>
|
||||
<name>Jetty :: NoSQL Session Managers</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.nosql</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<String> 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;
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-boot-jsp</artifactId>
|
||||
<name>Jetty :: OSGi :: Boot JSP</name>
|
||||
<description>Jetty OSGi Boot JSP bundle</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.boot.jsp</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>7.6.11-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-boot-logback</artifactId>
|
||||
<name>Jetty :: OSGi :: Boot Logback</name>
|
||||
<description>Jetty OSGi Boot Logback bundle</description>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.boot.logback</bundle-symbolic-name>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-boot</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>artifact-jar</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-jar</id>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>target/classes/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>bundle-manifest</id>
|
||||
<phase>process-classes</phase>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>org.eclipse.jetty.osgi.boot.logback;singleton:=true</Bundle-SymbolicName>
|
||||
<Bundle-Name>Jetty-OSGi-Logback Integration</Bundle-Name>
|
||||
<Fragment-Host>org.eclipse.jetty.osgi.boot</Fragment-Host>
|
||||
<Import-Package>
|
||||
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
|
||||
</Import-Package>
|
||||
<Export-Package>
|
||||
!org.eclipse.jetty.osgi.boot.logback.internal.*,
|
||||
org.eclipse.jetty.osgi.boot.logback.*;version="${parsedVersion.osgiVersion}"
|
||||
</Export-Package>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<onlyAnalyze>org.eclipse.jetty.osgi.boot.logback.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
|
@ -2,13 +2,14 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-boot-warurl</artifactId>
|
||||
<name>Jetty :: OSGi :: Boot :: Warurl</name>
|
||||
<description>Jetty OSGi Boot-Warurl bundle</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.boot.warurl</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-boot</artifactId>
|
||||
<name>Jetty :: OSGi :: Boot</name>
|
||||
<description>Jetty OSGi Boot bundle</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.boot</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>7.6.11-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-equinoxtools</artifactId>
|
||||
<name>Jetty :: OSGi :: Example Equinox Tools</name>
|
||||
<description>Jetty OSGi Example Equinox Tools</description>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.equinoxtools</bundle-symbolic-name>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>process-resources</phase>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<copy todir="target/classes/equinoxconsole">
|
||||
<fileset dir="equinoxconsole" />
|
||||
</copy>
|
||||
</tasks>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>artifact-jar</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-jar</id>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>target/classes/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>bundle-manifest</id>
|
||||
<phase>process-classes</phase>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>org.eclipse.jetty.osgi.equinoxtools</Bundle-SymbolicName>
|
||||
<Bundle-Name>Console</Bundle-Name>
|
||||
<Bundle-Activator>org.eclipse.jetty.osgi.equinoxtools.WebEquinoxToolsActivator</Bundle-Activator>
|
||||
<Export-Package>org.eclipse.jetty.osgi.equinoxtools;x-internal:=true;version="${parsedVersion.osgiVersion}",
|
||||
org.eclipse.jetty.osgi.equinoxtools.console;x-internal:=true;version="${parsedVersion.osgiVersion}"
|
||||
</Export-Package>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<onlyAnalyze>org.eclipse.jetty.osgi.equinoxtools.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -2,13 +2,14 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-httpservice</artifactId>
|
||||
<name>Jetty :: OSGi :: HttpService</name>
|
||||
<description>Jetty OSGi HttpService bundle</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.httpservice</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<name>Jetty :: OSGi</name>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<packaging>pom</packaging>
|
||||
<properties>
|
||||
<osgi-version>3.6.0.v20100517</osgi-version>
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-jetty-osgi-context</artifactId>
|
||||
<name>Jetty :: OSGi :: Context</name>
|
||||
<description>Test Jetty OSGi bundle with a ContextHandler</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.testcontext</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-jetty-osgi-webapp</artifactId>
|
||||
<name>Jetty :: OSGi :: WebApp</name>
|
||||
<description>Test Jetty OSGi Webapp bundle</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.webapp</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-jetty-osgi</artifactId>
|
||||
<name>Jetty :: OSGi :: Test</name>
|
||||
<description>Jetty OSGi Integration test</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.boot.test</bundle-symbolic-name>
|
||||
<jetty-orbit-url>http://download.eclipse.org/jetty/orbit/</jetty-orbit-url>
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-overlay-deployer</artifactId>
|
||||
<name>Jetty :: Overlay Deployer</name>
|
||||
<description>Overlayed deployer</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
</properties>
|
||||
<build>
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
<name>Jetty :: Plus</name>
|
||||
<description>Jetty JavaEE style services</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.plus</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>jetty-policy</artifactId>
|
||||
<name>Jetty :: Policy Tool</name>
|
||||
<packaging>jar</packaging>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<jetty.test.policy.loc>target/test-policy</jetty.test.policy.loc>
|
||||
<bundle-symbolic-name>${project.groupId}.policy</bundle-symbolic-name>
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-rewrite</artifactId>
|
||||
<name>Jetty :: Rewrite Handler</name>
|
||||
<description>Jetty Rewrite Handler</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.rewrite</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
<name>Jetty :: Security</name>
|
||||
<description>Jetty security infrastructure</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.security</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<name>Jetty :: Server Core</name>
|
||||
<description>The core jetty server artifact.</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.server</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -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("");
|
||||
|
|
|
@ -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<Part> 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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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<String, Object> _managedAttributes;
|
||||
private String[] _protectedTargets;
|
||||
private final CopyOnWriteArrayList<AliasCheck> _aliasChecks = new CopyOnWriteArrayList<ContextHandler.AliasCheck>();
|
||||
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<name>Jetty :: Servlet Handling</name>
|
||||
<description>Jetty Servlet Container</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.servlet</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -53,16 +53,15 @@ public class FilterHolder extends Holder<Filter>
|
|||
*/
|
||||
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<Filter>
|
|||
*/
|
||||
public FilterHolder(Class<? extends Filter> filter)
|
||||
{
|
||||
super (Source.EMBEDDED);
|
||||
this(Source.EMBEDDED);
|
||||
setHeldClass(filter);
|
||||
}
|
||||
|
||||
|
@ -79,7 +78,7 @@ public class FilterHolder extends Holder<Filter>
|
|||
*/
|
||||
public FilterHolder(Filter filter)
|
||||
{
|
||||
super (Source.EMBEDDED);
|
||||
this(Source.EMBEDDED);
|
||||
setFilter(filter);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ public class Holder<T> 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<T> 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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<FilterHolder> filterHolders = new ArrayList<FilterHolder>();
|
||||
List<FilterMapping> 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<FilterMapping> 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<ServletHolder> servletHolders = new ArrayList<ServletHolder>(); //will be remaining servlets
|
||||
List<ServletMapping> 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<ServletMapping> 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
|
||||
|
|
|
@ -90,7 +90,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
*/
|
||||
public ServletHolder()
|
||||
{
|
||||
super (Source.EMBEDDED);
|
||||
this(Source.EMBEDDED);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
@ -98,7 +98,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
*/
|
||||
public ServletHolder(Holder.Source creator)
|
||||
{
|
||||
super (creator);
|
||||
super(creator);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
@ -106,7 +106,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
*/
|
||||
public ServletHolder(Servlet servlet)
|
||||
{
|
||||
super (Source.EMBEDDED);
|
||||
this(Source.EMBEDDED);
|
||||
setServlet(servlet);
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
*/
|
||||
public ServletHolder(String name, Class<? extends Servlet> servlet)
|
||||
{
|
||||
super (Source.EMBEDDED);
|
||||
this(Source.EMBEDDED);
|
||||
setName(name);
|
||||
setHeldClass(servlet);
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ public class ServletHolder extends Holder<Servlet> 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<Servlet> implements UserIdentity.Scope
|
|||
*/
|
||||
public ServletHolder(Class<? extends Servlet> servlet)
|
||||
{
|
||||
super (Source.EMBEDDED);
|
||||
this(Source.EMBEDDED);
|
||||
setHeldClass(servlet);
|
||||
}
|
||||
|
||||
|
@ -653,6 +653,8 @@ public class ServletHolder extends Holder<Servlet> 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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
<name>Jetty :: Utility Servlets and Filters</name>
|
||||
<description>Utility Servlets from Jetty</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.servlets</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -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<String> parameterMap = new MultiMap<String>();
|
||||
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<String, String> envMap;
|
||||
|
||||
EnvList()
|
||||
{
|
||||
envMap = new HashMap();
|
||||
envMap = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
EnvList(EnvList l)
|
||||
{
|
||||
envMap = new HashMap(l.envMap);
|
||||
envMap = new HashMap<String,String>(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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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<String[]> 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
*
|
||||
* <pre>
|
||||
* 1) get stream
|
||||
* 2) set content length
|
||||
* 3) set content type
|
||||
* 4) write and flush
|
||||
* </pre>
|
||||
*
|
||||
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
|
||||
*/
|
||||
@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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -11,7 +11,7 @@
|
|||
<artifactId>spdy-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Jetty :: SPDY :: Parent</name>
|
||||
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<npn.version>1.1.5.v20130313</npn.version>
|
||||
<npn.api.version>1.1.0.v20120525</npn.api.version>
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-parent</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spdy-core</artifactId>
|
||||
<name>Jetty :: SPDY :: Core</name>
|
||||
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-parent</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spdy-jetty-http-webapp</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>Jetty :: SPDY :: Jetty HTTP Web Application</name>
|
||||
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-parent</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spdy-jetty-http</artifactId>
|
||||
<name>Jetty :: SPDY :: Jetty HTTP Layer</name>
|
||||
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-parent</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spdy-jetty</artifactId>
|
||||
<name>Jetty :: SPDY :: Jetty Binding</name>
|
||||
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-start</artifactId>
|
||||
<name>Jetty :: Start</name>
|
||||
<description>The start utility</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.1.11.v20130520-SNAPSHOT</version>
|
||||
<version>8.1.12-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<name>Jetty :: Utilities</name>
|
||||
<description>Utility classes for Jetty</description>
|
||||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.util</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
|
|
@ -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.
|
||||
* <p>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<encoded.length())
|
||||
{
|
||||
char c=encoded.charAt(ci++);
|
||||
|
@ -390,9 +412,10 @@ public class B64Code
|
|||
|
||||
}
|
||||
|
||||
return bout.toByteArray();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static void encode(int value,Appendable buf) throws IOException
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue