diff --git a/README.TXT b/README.TXT
index 12c781192c9..9157b3eaa56 100644
--- a/README.TXT
+++ b/README.TXT
@@ -1,6 +1,5 @@
This is a source checkout of the Jetty webserver.
-
To build, use:
mvn clean install
diff --git a/VERSION.txt b/VERSION.txt
index 3659df3faa5..e1b0835f12b 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1,3 +1,5 @@
+jetty-9.2.2-SNAPSHOT
+
jetty-9.2.1.v20140609 - 09 June 2014
+ 347110 Supprt ClassFileTransormers in WebAppClassLoader
+ 432192 jetty-start / Allow JETTY_LOGS use for start-log-file
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java
index bd0540fe6ea..482194f351a 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java
@@ -29,6 +29,7 @@ public class SimplestServer
{
Server server = new Server(8080);
server.start();
+ server.dumpStdErr();
server.join();
}
}
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml
index 293de040bca..5d2ac7ae2c2 100644
--- a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml
@@ -3,14 +3,17 @@
-
- spdy/3
- spdy/2
- http/1.1
-
+
+ spdy/3
+ spdy/2
+ http/1.1
+
-
+
http/1.1
+
+
+
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_60.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_60.mod
new file mode 100644
index 00000000000..45bbad75c9f
--- /dev/null
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_60.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_65.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_65.mod
new file mode 100644
index 00000000000..45bbad75c9f
--- /dev/null
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_65.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_11.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_11.mod
new file mode 100644
index 00000000000..65e6cb3c4db
--- /dev/null
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_11.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.0.0.v20140317/alpn-boot-8.0.0.v20140317.jar|lib/alpn/alpn-boot-8.0.0.v20140317.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.0.0.v20140317.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnection.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnection.java
index 509682eb647..e3223c423b2 100644
--- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnection.java
+++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnection.java
@@ -62,7 +62,8 @@ public class ALPNServerConnection extends NegotiatingServerConnection implements
{
negotiated = getDefaultProtocol();
}
- LOG.debug("{} protocol selected {}", this, negotiated);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} protocol selected {}", this, negotiated);
setProtocol(negotiated);
ALPN.remove(getSSLEngine());
return negotiated;
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java
index 4845caaa591..8b8d7e28df1 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java
@@ -36,7 +36,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-
import javax.servlet.ServletContainerInitializer;
import javax.servlet.annotation.HandlesTypes;
@@ -442,14 +441,14 @@ public class AnnotationConfiguration extends AbstractConfiguration
// Resolve container initializers
List initializers =
- (List)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
+ (List)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
if (initializers != null && initializers.size()>0)
{
Map> map = ( Map>) context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP);
if (map == null)
LOG.warn ("ServletContainerInitializers: detected. Class hierarchy: empty");
for (ContainerInitializer i : initializers)
- i.resolveClasses(context,map);
+ i.resolveClasses(context,map);
}
}
@@ -557,16 +556,16 @@ public class AnnotationConfiguration extends AbstractConfiguration
boolean timeout = !latch.await(getMaxScanWait(context), TimeUnit.SECONDS);
if (LOG.isDebugEnabled())
- {
+ {
for (ParserTask p:_parserTasks)
LOG.debug("Scanned {} in {}ms", p.getResource(), TimeUnit.MILLISECONDS.convert(p.getStatistic().getElapsed(), TimeUnit.NANOSECONDS));
+
+ LOG.debug("Scanned {} container path jars, {} WEB-INF/lib jars, {} WEB-INF/classes dirs in {}ms for context {}",
+ _containerPathStats.getTotal(), _webInfLibStats.getTotal(), _webInfClassesStats.getTotal(),
+ (TimeUnit.MILLISECONDS.convert(System.nanoTime()-start, TimeUnit.NANOSECONDS)),
+ context);
}
-
- LOG.debug("Scanned {} container path jars, {} WEB-INF/lib jars, {} WEB-INF/classes dirs in {}ms for context {}",
- _containerPathStats.getTotal(), _webInfLibStats.getTotal(), _webInfClassesStats.getTotal(),
- (TimeUnit.MILLISECONDS.convert(System.nanoTime()-start, TimeUnit.NANOSECONDS)),
- context);
-
+
if (timeout)
me.add(new Exception("Timeout scanning annotations"));
me.ifExceptionThrow();
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializersStarter.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializersStarter.java
index 2ebaa9623a1..387c6f9e368 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializersStarter.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializersStarter.java
@@ -19,12 +19,8 @@
package org.eclipse.jetty.annotations;
import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java
index 743826793a4..8020101faa2 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java
@@ -35,7 +35,6 @@ import org.eclipse.jetty.servlet.ServletMapping;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.security.Constraint;
-import org.eclipse.jetty.webapp.Origin;
import org.eclipse.jetty.webapp.WebAppContext;
/**
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java
index f6eabb6a3b6..306565ed2b9 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java
@@ -86,7 +86,8 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
if (result.isFailed())
{
Throwable failure = result.getFailure();
- LOG.debug("Authentication challenge failed {}", failure);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Authentication challenge failed {}", failure);
forwardFailureComplete(request, result.getRequestFailure(), response, result.getResponseFailure());
return;
}
@@ -95,7 +96,8 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
if (conversation.getAttribute(AUTHENTICATION_ATTRIBUTE) != null)
{
// We have already tried to authenticate, but we failed again
- LOG.debug("Bad credentials for {}", request);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Bad credentials for {}", request);
forwardSuccessComplete(request, response);
return;
}
@@ -104,7 +106,8 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
List headerInfos = parseAuthenticateHeader(response, header);
if (headerInfos.isEmpty())
{
- LOG.debug("Authentication challenge without {} header", header);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Authentication challenge without {} header", header);
forwardFailureComplete(request, null, response, new HttpResponseException("HTTP protocol violation: Authentication challenge without " + header + " header", response));
return;
}
@@ -126,13 +129,15 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
}
if (authentication == null)
{
- LOG.debug("No authentication available for {}", request);
+ if (LOG.isDebugEnabled())
+ LOG.debug("No authentication available for {}", request);
forwardSuccessComplete(request, response);
return;
}
final Authentication.Result authnResult = authentication.authenticate(request, response, headerInfo, conversation);
- LOG.debug("Authentication result {}", authnResult);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Authentication result {}", authnResult);
if (authnResult == null)
{
forwardSuccessComplete(request, response);
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java
index 627228b3e38..53fe5ae2e01 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java
@@ -81,21 +81,24 @@ public class ConnectionPool implements Closeable, Dumpable
if (next > maxConnections)
{
- LOG.debug("Max connections {}/{} reached", current, maxConnections);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Max connections {}/{} reached", current, maxConnections);
// Try again the idle connections
return acquireIdleConnection();
}
if (connectionCount.compareAndSet(current, next))
{
- LOG.debug("Connection {}/{} creation", next, maxConnections);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Connection {}/{} creation", next, maxConnections);
destination.newConnection(new Promise()
{
@Override
public void succeeded(Connection connection)
{
- LOG.debug("Connection {}/{} creation succeeded {}", next, maxConnections, connection);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Connection {}/{} creation succeeded {}", next, maxConnections, connection);
if (activate(connection))
connectionPromise.succeeded(connection);
}
@@ -103,7 +106,8 @@ public class ConnectionPool implements Closeable, Dumpable
@Override
public void failed(Throwable x)
{
- LOG.debug("Connection " + next + "/" + maxConnections + " creation failed", x);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Connection " + next + "/" + maxConnections + " creation failed", x);
connectionCount.decrementAndGet();
connectionPromise.failed(x);
}
@@ -127,13 +131,15 @@ public class ConnectionPool implements Closeable, Dumpable
{
if (activeConnections.offer(connection))
{
- LOG.debug("Connection active {}", connection);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Connection active {}", connection);
acquired(connection);
return true;
}
else
{
- LOG.debug("Connection active overflow {}", connection);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Connection active overflow {}", connection);
connection.close();
return false;
}
@@ -151,12 +157,14 @@ public class ConnectionPool implements Closeable, Dumpable
// Make sure we use "hot" connections first
if (idleConnections.offerFirst(connection))
{
- LOG.debug("Connection idle {}", connection);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Connection idle {}", connection);
return true;
}
else
{
- LOG.debug("Connection idle overflow {}", connection);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Connection idle overflow {}", connection);
connection.close();
}
}
@@ -177,7 +185,8 @@ public class ConnectionPool implements Closeable, Dumpable
if (removed)
{
int pooled = connectionCount.decrementAndGet();
- LOG.debug("Connection removed {} - pooled: {}", connection, pooled);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Connection removed {} - pooled: {}", connection, pooled);
}
return removed;
}
@@ -227,6 +236,11 @@ public class ConnectionPool implements Closeable, Dumpable
@Override
public String toString()
{
- return String.format("%s %d/%d", getClass().getSimpleName(), connectionCount.get(), maxConnections);
+ return String.format("%s[c=%d/%d,a=%d,i=%d]",
+ getClass().getSimpleName(),
+ connectionCount.get(),
+ maxConnections,
+ activeConnections.size(),
+ idleConnections.size());
}
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java b/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java
index ab8f2a40b5f..6a7d6fa8ac0 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java
@@ -251,7 +251,7 @@ public class GZIPContentDecoder implements ContentDecoder
else
{
// Accumulate inflated bytes and loop to see if we have finished
- byte[] newOutput = Arrays.copyOf(output, output.length+decoded);
+ byte[] newOutput = Arrays.copyOf(output, output.length + decoded);
System.arraycopy(bytes, 0, newOutput, output.length, decoded);
output = newOutput;
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java
index f4ee52bf144..3e6c31c0d80 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpChannel.java
@@ -46,7 +46,8 @@ public abstract class HttpChannel
if (this.exchange.compareAndSet(null, exchange))
{
exchange.associate(this);
- LOG.debug("{} associated to {}", exchange, this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} associated to {}", exchange, this);
}
else
{
@@ -59,7 +60,8 @@ public abstract class HttpChannel
HttpExchange exchange = this.exchange.getAndSet(null);
if (exchange != null)
exchange.disassociate(this);
- LOG.debug("{} disassociated from {}", exchange, this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} disassociated from {}", exchange, this);
return exchange;
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java
index 3486c811039..646c36122d9 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java
@@ -24,7 +24,6 @@ import java.net.CookiePolicy;
import java.net.CookieStore;
import java.net.SocketAddress;
import java.net.URI;
-import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -480,9 +479,14 @@ public class HttpClient extends ContainerLifeCycle
{
HttpDestination existing = destinations.putIfAbsent(origin, destination);
if (existing != null)
+ {
destination = existing;
+ }
else
- LOG.debug("Created {}", destination);
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("Created {}", destination);
+ }
if (!isRunning())
destinations.remove(origin);
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java
index 37476d7f6bd..598d11e133f 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java
@@ -24,7 +24,6 @@ import java.util.Collections;
import java.util.Iterator;
import org.eclipse.jetty.client.api.ContentProvider;
-import org.eclipse.jetty.client.util.DeferredContentProvider;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.log.Log;
@@ -130,7 +129,8 @@ public class HttpContent implements Callback, Closeable
if (content != AFTER)
{
content = buffer = AFTER;
- LOG.debug("Advanced content past last chunk");
+ if (LOG.isDebugEnabled())
+ LOG.debug("Advanced content past last chunk");
}
return false;
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java
index cc83372c437..20bbb12ab5a 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java
@@ -175,14 +175,16 @@ public abstract class HttpDestination implements Destination, Closeable, Dumpabl
}
else
{
- LOG.debug("Queued {}", request);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queued {} for {}", request, this);
requestNotifier.notifyQueued(request);
send();
}
}
else
{
- LOG.debug("Max queue size {} exceeded by {}", client.getMaxRequestsQueuedPerDestination(), request);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Max queue size {} exceeded by {} for {}", client.getMaxRequestsQueuedPerDestination(), request, this);
request.abort(new RejectedExecutionException("Max requests per destination " + client.getMaxRequestsQueuedPerDestination() + " exceeded for " + this));
}
}
@@ -212,7 +214,8 @@ public abstract class HttpDestination implements Destination, Closeable, Dumpabl
public void close()
{
abort(new AsynchronousCloseException());
- LOG.debug("Closed {}", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Closed {}", this);
}
public void release(Connection connection)
@@ -256,9 +259,10 @@ public abstract class HttpDestination implements Destination, Closeable, Dumpabl
@Override
public String toString()
{
- return String.format("%s(%s)%s",
+ return String.format("%s[%s]%s,queue=%d",
HttpDestination.class.getSimpleName(),
asString(),
- proxy == null ? "" : " via " + proxy);
+ proxy == null ? "" : "(via " + proxy + ")",
+ exchanges.size());
}
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java
index 704c9c3ccef..a7fde41be98 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpExchange.java
@@ -151,7 +151,8 @@ public class HttpExchange
if ((current & terminated) == terminated)
{
// Request and response terminated
- LOG.debug("{} terminated", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} terminated", this);
return new Result(getRequest(), getRequestFailure(), getResponse(), getResponseFailure());
}
return null;
@@ -174,7 +175,8 @@ public class HttpExchange
requestFailure = failure;
if ((code & 0b0100) == 0b0100)
responseFailure = failure;
- LOG.debug("{} updated", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} updated", this);
}
break;
}
@@ -185,7 +187,8 @@ public class HttpExchange
{
if (destination.remove(this))
{
- LOG.debug("Aborting while queued {}: {}", this, cause);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Aborting while queued {}: {}", this, cause);
return fail(cause);
}
else
@@ -195,7 +198,8 @@ public class HttpExchange
return fail(cause);
boolean aborted = channel.abort(cause);
- LOG.debug("Aborted while active ({}) {}: {}", aborted, this, cause);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Aborted while active ({}) {}: {}", aborted, this, cause);
return aborted;
}
}
@@ -204,7 +208,8 @@ public class HttpExchange
{
if (update(0b0101, cause) == 0b0101)
{
- LOG.debug("Failing {}: {}", this, cause);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Failing {}: {}", this, cause);
destination.getRequestNotifier().notifyFailure(request, cause);
List listeners = getConversation().getResponseListeners();
ResponseNotifier responseNotifier = destination.getResponseNotifier();
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java
index 0faf25e9ea2..5c3ac764fa0 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java
@@ -186,7 +186,8 @@ public class HttpProxy extends ProxyConfiguration.Proxy
// Avoid setting fill interest in the old Connection,
// without closing the underlying EndPoint.
oldConnection.softClose();
- LOG.debug("HTTP tunnel established: {} over {}", oldConnection, newConnection);
+ if (LOG.isDebugEnabled())
+ LOG.debug("HTTP tunnel established: {} over {}", oldConnection, newConnection);
}
catch (Throwable x)
{
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java
index becab10b57a..4b8546594cd 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java
@@ -21,6 +21,7 @@ package org.eclipse.jetty.client;
import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
@@ -49,9 +50,8 @@ import org.eclipse.jetty.util.log.Logger;
* is available
*
{@link #responseHeader(HttpExchange, HttpField)}, when a HTTP field is available
*
{@link #responseHeaders(HttpExchange)}, when all HTTP headers are available
- *
{@link #responseContent(HttpExchange, ByteBuffer, Callback)}, when HTTP content is available; this is the only
- * method that may be invoked multiple times with different buffers containing different content
- *
{@link #responseSuccess(HttpExchange)}, when the response is complete
+ *
{@link #responseContent(HttpExchange, ByteBuffer, Callback)}, when HTTP content is available
+ *
{@link #responseSuccess(HttpExchange)}, when the response is successful
*
* At any time, subclasses may invoke {@link #responseFailure(Throwable)} to indicate that the response has failed
* (for example, because of I/O exceptions).
@@ -69,7 +69,8 @@ public abstract class HttpReceiver
private final AtomicReference responseState = new AtomicReference<>(ResponseState.IDLE);
private final HttpChannel channel;
- private volatile ContentDecoder decoder;
+ private ContentDecoder decoder;
+ private Throwable failure;
protected HttpReceiver(HttpChannel channel)
{
@@ -104,7 +105,7 @@ public abstract class HttpReceiver
*/
protected boolean responseBegin(HttpExchange exchange)
{
- if (!updateResponseState(ResponseState.IDLE, ResponseState.BEGIN))
+ if (!updateResponseState(ResponseState.IDLE, ResponseState.TRANSIENT))
return false;
HttpConversation conversation = exchange.getConversation();
@@ -117,14 +118,19 @@ public abstract class HttpReceiver
if (protocolHandler != null)
{
handlerListener = protocolHandler.getResponseListener();
- LOG.debug("Found protocol handler {}", protocolHandler);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Found protocol handler {}", protocolHandler);
}
exchange.getConversation().updateResponseListeners(handlerListener);
- LOG.debug("Response begin {}", response);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Response begin {}", response);
ResponseNotifier notifier = destination.getResponseNotifier();
notifier.notifyBegin(conversation.getResponseListeners(), response);
+ if (!updateResponseState(ResponseState.TRANSIENT, ResponseState.BEGIN))
+ terminateResponse(exchange, failure);
+
return true;
}
@@ -150,7 +156,7 @@ public abstract class HttpReceiver
case BEGIN:
case HEADER:
{
- if (updateResponseState(current, ResponseState.HEADER))
+ if (updateResponseState(current, ResponseState.TRANSIENT))
break out;
break;
}
@@ -186,6 +192,9 @@ public abstract class HttpReceiver
}
}
+ if (!updateResponseState(ResponseState.TRANSIENT, ResponseState.HEADER))
+ terminateResponse(exchange, failure);
+
return true;
}
@@ -203,7 +212,8 @@ public abstract class HttpReceiver
}
catch (IOException x)
{
- LOG.debug(x);
+ if (LOG.isDebugEnabled())
+ LOG.debug(x);
}
}
@@ -225,7 +235,7 @@ public abstract class HttpReceiver
case BEGIN:
case HEADER:
{
- if (updateResponseState(current, ResponseState.HEADERS))
+ if (updateResponseState(current, ResponseState.TRANSIENT))
break out;
break;
}
@@ -258,6 +268,9 @@ public abstract class HttpReceiver
}
}
+ if (!updateResponseState(ResponseState.TRANSIENT, ResponseState.HEADERS))
+ terminateResponse(exchange, failure);
+
return true;
}
@@ -270,7 +283,7 @@ public abstract class HttpReceiver
* @param buffer the response HTTP content buffer
* @return whether the processing should continue
*/
- protected boolean responseContent(HttpExchange exchange, ByteBuffer buffer, Callback callback)
+ protected boolean responseContent(HttpExchange exchange, ByteBuffer buffer, final Callback callback)
{
out: while (true)
{
@@ -280,7 +293,7 @@ public abstract class HttpReceiver
case HEADERS:
case CONTENT:
{
- if (updateResponseState(current, ResponseState.CONTENT))
+ if (updateResponseState(current, ResponseState.TRANSIENT))
break out;
break;
}
@@ -295,16 +308,49 @@ public abstract class HttpReceiver
if (LOG.isDebugEnabled())
LOG.debug("Response content {}{}{}", response, System.lineSeparator(), BufferUtil.toDetailString(buffer));
+ ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
+ List listeners = exchange.getConversation().getResponseListeners();
+
ContentDecoder decoder = this.decoder;
- if (decoder != null)
+ if (decoder == null)
{
- buffer = decoder.decode(buffer);
- if (LOG.isDebugEnabled())
- LOG.debug("Response content decoded ({}) {}{}{}", decoder, response, System.lineSeparator(), BufferUtil.toDetailString(buffer));
+ notifier.notifyContent(listeners, response, buffer, callback);
+ }
+ else
+ {
+ List decodeds = new ArrayList<>(2);
+ while (buffer.hasRemaining())
+ {
+ ByteBuffer decoded = decoder.decode(buffer);
+ if (!decoded.hasRemaining())
+ continue;
+ decodeds.add(decoded);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Response content decoded ({}) {}{}{}", decoder, response, System.lineSeparator(), BufferUtil.toDetailString(decoded));
+ }
+
+ if (decodeds.isEmpty())
+ {
+ callback.succeeded();
+ }
+ else
+ {
+ Callback partial = new Callback.Adapter()
+ {
+ @Override
+ public void failed(Throwable x)
+ {
+ callback.failed(x);
+ }
+ };
+
+ for (int i = 1, size = decodeds.size(); i <= size; ++i)
+ notifier.notifyContent(listeners, response, decodeds.get(i - 1), i < size ? partial : callback);
+ }
}
- ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
- notifier.notifyContent(exchange.getConversation().getResponseListeners(), response, buffer, callback);
+ if (!updateResponseState(ResponseState.TRANSIENT, ResponseState.CONTENT))
+ terminateResponse(exchange, failure);
return true;
}
@@ -326,32 +372,25 @@ public abstract class HttpReceiver
if (!completed)
return false;
- // Reset to be ready for another response
+ responseState.set(ResponseState.IDLE);
+
+ // Reset to be ready for another response.
reset();
// Mark atomically the response as terminated and succeeded,
// with respect to concurrency between request and response.
- // If there is a non-null result, then both sender and
- // receiver are reset and ready to be reused, and the
- // connection closed/pooled (depending on the transport).
Result result = exchange.terminateResponse(null);
+ // It is important to notify *after* we reset and terminate
+ // because the notification may trigger another request/response.
HttpResponse response = exchange.getResponse();
- LOG.debug("Response success {}", response);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Response success {}", response);
List listeners = exchange.getConversation().getResponseListeners();
ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
notifier.notifySuccess(listeners, response);
- if (result != null)
- {
- boolean ordered = getHttpDestination().getHttpClient().isStrictEventOrdering();
- if (!ordered)
- channel.exchangeTerminated(result);
- LOG.debug("Request/Response succeeded {}", response);
- notifier.notifyComplete(listeners, result);
- if (ordered)
- channel.exchangeTerminated(result);
- }
+ terminateResponse(exchange, result);
return true;
}
@@ -380,7 +419,20 @@ public abstract class HttpReceiver
if (!completed)
return false;
- // Dispose to avoid further responses
+ this.failure = failure;
+
+ // Update the state to avoid more response processing.
+ boolean fail;
+ while (true)
+ {
+ ResponseState current = responseState.get();
+ if (updateResponseState(current, ResponseState.FAILURE))
+ {
+ fail = current != ResponseState.TRANSIENT;
+ break;
+ }
+ }
+
dispose();
// Mark atomically the response as terminated and failed,
@@ -388,23 +440,51 @@ public abstract class HttpReceiver
Result result = exchange.terminateResponse(failure);
HttpResponse response = exchange.getResponse();
- LOG.debug("Response failure {} {}", response, failure);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Response failure {} {}", response, failure);
List listeners = exchange.getConversation().getResponseListeners();
ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
notifier.notifyFailure(listeners, response, failure);
+ if (fail)
+ {
+ terminateResponse(exchange, result);
+ }
+ else
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("Concurrent failure: response termination skipped, performed by helpers");
+ }
+
+ return true;
+ }
+
+ private void terminateResponse(HttpExchange exchange, Throwable failure)
+ {
+ Result result = exchange.terminateResponse(failure);
+ terminateResponse(exchange, result);
+ }
+
+ private void terminateResponse(HttpExchange exchange, Result result)
+ {
+ HttpResponse response = exchange.getResponse();
+
+ if (LOG.isDebugEnabled())
+ LOG.debug("Response complete {}", response);
+
if (result != null)
{
boolean ordered = getHttpDestination().getHttpClient().isStrictEventOrdering();
if (!ordered)
channel.exchangeTerminated(result);
- LOG.debug("Request/Response failed {}", response);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Request/Response {} {}", failure == null ? "succeeded" : "failed", response);
+ List listeners = exchange.getConversation().getResponseListeners();
+ ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
notifier.notifyComplete(listeners, result);
if (ordered)
channel.exchangeTerminated(result);
}
-
- return true;
}
/**
@@ -417,7 +497,6 @@ public abstract class HttpReceiver
protected void reset()
{
decoder = null;
- responseState.set(ResponseState.IDLE);
}
/**
@@ -430,7 +509,6 @@ public abstract class HttpReceiver
protected void dispose()
{
decoder = null;
- responseState.set(ResponseState.FAILURE);
}
public boolean abort(Throwable cause)
@@ -442,7 +520,10 @@ public abstract class HttpReceiver
{
boolean updated = responseState.compareAndSet(from, to);
if (!updated)
- LOG.debug("State update failed: {} -> {}: {}", from, to, responseState.get());
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("State update failed: {} -> {}: {}", from, to, responseState.get());
+ }
return updated;
}
@@ -451,6 +532,10 @@ public abstract class HttpReceiver
*/
private enum ResponseState
{
+ /**
+ * One of the response*() methods is being executed.
+ */
+ TRANSIENT,
/**
* The response is not yet received, the initial state
*/
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java
index 3d7f42d69ec..abcdd40db52 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java
@@ -156,7 +156,8 @@ public class HttpRedirector
URI newURI = extractRedirectURI(response);
if (newURI != null)
{
- LOG.debug("Redirecting to {} (Location: {})", newURI, location);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Redirecting to {} (Location: {})", newURI, location);
return redirect(request, response, listener, newURI);
}
else
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java
index d2e26bdafd2..85d4d0b55ad 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java
@@ -65,7 +65,8 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
private final IteratingCallback contentCallback = new ContentCallback();
private final Callback lastCallback = new LastContentCallback();
private final HttpChannel channel;
- private volatile HttpContent content;
+ private HttpContent content;
+ private Throwable failure;
protected HttpSender(HttpChannel channel)
{
@@ -99,7 +100,8 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
SenderState newSenderState = SenderState.SENDING;
if (updateSenderState(current, newSenderState))
{
- LOG.debug("Deferred content available, {} -> {}", current, newSenderState);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Deferred content available, {} -> {}", current, newSenderState);
contentCallback.iterate();
return;
}
@@ -110,7 +112,8 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
SenderState newSenderState = SenderState.SENDING_WITH_CONTENT;
if (updateSenderState(current, newSenderState))
{
- LOG.debug("Deferred content available, {} -> {}", current, newSenderState);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Deferred content available, {} -> {}", current, newSenderState);
return;
}
break;
@@ -120,7 +123,8 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
SenderState newSenderState = SenderState.EXPECTING_WITH_CONTENT;
if (updateSenderState(current, newSenderState))
{
- LOG.debug("Deferred content available, {} -> {}", current, newSenderState);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Deferred content available, {} -> {}", current, newSenderState);
return;
}
break;
@@ -130,7 +134,8 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
SenderState newSenderState = SenderState.PROCEEDING_WITH_CONTENT;
if (updateSenderState(current, newSenderState))
{
- LOG.debug("Deferred content available, {} -> {}", current, newSenderState);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Deferred content available, {} -> {}", current, newSenderState);
return;
}
break;
@@ -140,7 +145,8 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
case PROCEEDING_WITH_CONTENT:
case WAITING:
{
- LOG.debug("Deferred content available, {}", current);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Deferred content available, {}", current);
return;
}
default:
@@ -192,32 +198,40 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
protected boolean queuedToBegin(Request request)
{
- if (!updateRequestState(RequestState.QUEUED, RequestState.BEGIN))
+ if (!updateRequestState(RequestState.QUEUED, RequestState.TRANSIENT))
return false;
- LOG.debug("Request begin {}", request);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Request begin {}", request);
RequestNotifier notifier = getHttpChannel().getHttpDestination().getRequestNotifier();
notifier.notifyBegin(request);
+ if (!updateRequestState(RequestState.TRANSIENT, RequestState.BEGIN))
+ terminateRequest(getHttpExchange(), failure, false);
return true;
}
protected boolean beginToHeaders(Request request)
{
- if (!updateRequestState(RequestState.BEGIN, RequestState.HEADERS))
+ if (!updateRequestState(RequestState.BEGIN, RequestState.TRANSIENT))
return false;
if (LOG.isDebugEnabled())
LOG.debug("Request headers {}{}{}", request, System.getProperty("line.separator"), request.getHeaders().toString().trim());
RequestNotifier notifier = getHttpChannel().getHttpDestination().getRequestNotifier();
notifier.notifyHeaders(request);
+ if (!updateRequestState(RequestState.TRANSIENT, RequestState.HEADERS))
+ terminateRequest(getHttpExchange(), failure, false);
return true;
}
protected boolean headersToCommit(Request request)
{
- if (!updateRequestState(RequestState.HEADERS, RequestState.COMMIT))
+ if (!updateRequestState(RequestState.HEADERS, RequestState.TRANSIENT))
return false;
- LOG.debug("Request committed {}", request);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Request committed {}", request);
RequestNotifier notifier = getHttpChannel().getHttpDestination().getRequestNotifier();
notifier.notifyCommit(request);
+ if (!updateRequestState(RequestState.TRANSIENT, RequestState.COMMIT))
+ terminateRequest(getHttpExchange(), failure, true);
return true;
}
@@ -229,21 +243,19 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
case COMMIT:
case CONTENT:
{
- if (!updateRequestState(current, RequestState.CONTENT))
+ if (!updateRequestState(current, RequestState.TRANSIENT_CONTENT))
return false;
if (LOG.isDebugEnabled())
LOG.debug("Request content {}{}{}", request, System.getProperty("line.separator"), BufferUtil.toDetailString(content));
RequestNotifier notifier = getHttpChannel().getHttpDestination().getRequestNotifier();
notifier.notifyContent(request, content);
+ if (!updateRequestState(RequestState.TRANSIENT_CONTENT, RequestState.CONTENT))
+ terminateRequest(getHttpExchange(), failure, true);
return true;
}
- case FAILURE:
- {
- return false;
- }
default:
{
- throw new IllegalStateException(current.toString());
+ return false;
}
}
}
@@ -262,41 +274,28 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
if (!completed)
return false;
- // Reset to be ready for another request
+ requestState.set(RequestState.QUEUED);
+
+ // Reset to be ready for another request.
reset();
// Mark atomically the request as terminated and succeeded,
// with respect to concurrency between request and response.
Result result = exchange.terminateRequest(null);
- // It is important to notify completion *after* we reset because
- // the notification may trigger another request/response
Request request = exchange.getRequest();
- LOG.debug("Request success {}", request);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Request success {}", request);
HttpDestination destination = getHttpChannel().getHttpDestination();
destination.getRequestNotifier().notifySuccess(exchange.getRequest());
- if (result != null)
- {
- boolean ordered = destination.getHttpClient().isStrictEventOrdering();
- if (!ordered)
- channel.exchangeTerminated(result);
- LOG.debug("Request/Response succeded {}", request);
- HttpConversation conversation = exchange.getConversation();
- destination.getResponseNotifier().notifyComplete(conversation.getResponseListeners(), result);
- if (ordered)
- channel.exchangeTerminated(result);
- }
+ terminateRequest(exchange, null, true, result);
return true;
}
- case FAILURE:
- {
- return false;
- }
default:
{
- throw new IllegalStateException(current.toString());
+ return false;
}
}
}
@@ -313,42 +312,86 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
if (!completed)
return false;
- // Dispose to avoid further requests
- RequestState requestState = dispose();
+ this.failure = failure;
+
+ // Update the state to avoid more request processing.
+ RequestState current;
+ boolean fail;
+ while (true)
+ {
+ current = requestState.get();
+ if (updateRequestState(current, RequestState.FAILURE))
+ {
+ fail = current != RequestState.TRANSIENT && current != RequestState.TRANSIENT_CONTENT;
+ break;
+ }
+ }
+
+ dispose();
// Mark atomically the request as terminated and failed,
// with respect to concurrency between request and response.
Result result = exchange.terminateRequest(failure);
Request request = exchange.getRequest();
- LOG.debug("Request failure {} {}", exchange, failure);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Request failure {} {}", exchange, failure);
HttpDestination destination = getHttpChannel().getHttpDestination();
destination.getRequestNotifier().notifyFailure(request, failure);
- boolean notCommitted = isBeforeCommit(requestState);
- if (result == null && notCommitted && request.getAbortCause() == null)
+ if (fail)
+ {
+ terminateRequest(exchange, failure, !isBeforeCommit(current), result);
+ }
+ else
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("Concurrent failure: request termination skipped, performed by helpers");
+ }
+
+ return true;
+ }
+
+ private void terminateRequest(HttpExchange exchange, Throwable failure, boolean committed)
+ {
+ if (exchange != null)
+ {
+ Result result = exchange.terminateRequest(failure);
+ terminateRequest(exchange, failure, committed, result);
+ }
+ }
+
+ private void terminateRequest(HttpExchange exchange, Throwable failure, boolean committed, Result result)
+ {
+ Request request = exchange.getRequest();
+
+ if (LOG.isDebugEnabled())
+ LOG.debug("Terminating request {}", request);
+
+ if (failure != null && !committed && result == null && request.getAbortCause() == null)
{
// Complete the response from here
if (exchange.responseComplete())
{
result = exchange.terminateResponse(failure);
- LOG.debug("Failed response from request {}", exchange);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Failed response from request {}", exchange);
}
}
if (result != null)
{
+ HttpDestination destination = getHttpChannel().getHttpDestination();
boolean ordered = destination.getHttpClient().isStrictEventOrdering();
if (!ordered)
channel.exchangeTerminated(result);
- LOG.debug("Request/Response failed {}", request);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Request/Response {} {}", failure == null ? "succeeded" : "failed", request);
HttpConversation conversation = exchange.getConversation();
destination.getResponseNotifier().notifyComplete(conversation.getResponseListeners(), result);
if (ordered)
channel.exchangeTerminated(result);
}
-
- return true;
}
/**
@@ -386,23 +429,14 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
{
content.close();
content = null;
- requestState.set(RequestState.QUEUED);
senderState.set(SenderState.IDLE);
}
- protected RequestState dispose()
+ protected void dispose()
{
- while (true)
- {
- RequestState current = requestState.get();
- if (updateRequestState(current, RequestState.FAILURE))
- {
- HttpContent content = this.content;
- if (content != null)
- content.close();
- return current;
- }
- }
+ HttpContent content = this.content;
+ if (content != null)
+ content.close();
}
public void proceed(HttpExchange exchange, Throwable failure)
@@ -426,7 +460,8 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
// We are still sending the headers, but we already got the 100 Continue.
if (updateSenderState(current, SenderState.PROCEEDING))
{
- LOG.debug("Proceeding while expecting");
+ if (LOG.isDebugEnabled())
+ LOG.debug("Proceeding while expecting");
return;
}
break;
@@ -441,7 +476,8 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
// WritePendingException).
if (updateSenderState(current, SenderState.PROCEEDING_WITH_CONTENT))
{
- LOG.debug("Proceeding while scheduled");
+ if (LOG.isDebugEnabled())
+ LOG.debug("Proceeding while scheduled");
return;
}
break;
@@ -451,7 +487,8 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
// We received the 100 Continue, now send the content if any.
if (!updateSenderState(current, SenderState.SENDING))
throw illegalSenderState(current);
- LOG.debug("Proceeding while waiting");
+ if (LOG.isDebugEnabled())
+ LOG.debug("Proceeding while waiting");
contentCallback.iterate();
return;
}
@@ -470,7 +507,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
return abortable && anyToFailure(failure);
}
- protected boolean updateRequestState(RequestState from, RequestState to)
+ private boolean updateRequestState(RequestState from, RequestState to)
{
boolean updated = requestState.compareAndSet(from, to);
if (!updated)
@@ -490,6 +527,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
{
switch (requestState)
{
+ case TRANSIENT:
case QUEUED:
case BEGIN:
case HEADERS:
@@ -503,6 +541,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
{
switch (requestState)
{
+ case TRANSIENT_CONTENT:
case COMMIT:
case CONTENT:
return true;
@@ -519,8 +558,16 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
/**
* The request states {@link HttpSender} goes through when sending a request.
*/
- protected enum RequestState
+ private enum RequestState
{
+ /**
+ * One of the state transition methods is being executed.
+ */
+ TRANSIENT,
+ /**
+ * The content transition method is being executed.
+ */
+ TRANSIENT_CONTENT,
/**
* The request is queued, the initial state
*/
@@ -758,15 +805,14 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
}
@Override
- public void failed(Throwable failure)
+ public void onCompleteFailure(Throwable failure)
{
content.failed(failure);
- super.failed(failure);
anyToFailure(failure);
}
@Override
- protected void completed()
+ protected void onCompleteSuccess()
{
// Nothing to do, since we always return false from process().
// Termination is obtained via LastContentCallback.
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java
index 475007523fc..e95ecb96a57 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java
@@ -94,7 +94,8 @@ public abstract class MultiplexHttpDestination extends Htt
{
HttpClient client = getHttpClient();
final HttpExchange exchange = getHttpExchanges().poll();
- LOG.debug("Processing {} on {}", exchange, connection);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Processing {} on {}", exchange, connection);
if (exchange == null)
return false;
@@ -102,7 +103,8 @@ public abstract class MultiplexHttpDestination extends Htt
Throwable cause = request.getAbortCause();
if (cause != null)
{
- LOG.debug("Aborted before processing {}: {}", exchange, cause);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Aborted before processing {}: {}", exchange, cause);
// It may happen that the request is aborted before the exchange
// is created. Aborting the exchange a second time will result in
// a no-operation, so we just abort here to cover that edge case.
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java
index 24c77e84d8e..2803276a464 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java
@@ -93,7 +93,8 @@ public abstract class PoolingHttpDestination extends HttpD
{
HttpClient client = getHttpClient();
final HttpExchange exchange = getHttpExchanges().poll();
- LOG.debug("Processing exchange {} on connection {}", exchange, connection);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Processing exchange {} on {} of {}", exchange, connection, this);
if (exchange == null)
{
if (!connectionPool.release(connection))
@@ -101,7 +102,8 @@ public abstract class PoolingHttpDestination extends HttpD
if (!client.isRunning())
{
- LOG.debug("{} is stopping", client);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} is stopping", client);
connection.close();
}
}
@@ -111,7 +113,8 @@ public abstract class PoolingHttpDestination extends HttpD
Throwable cause = request.getAbortCause();
if (cause != null)
{
- LOG.debug("Aborted before processing {}: {}", exchange, cause);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Aborted before processing {}: {}", exchange, cause);
// It may happen that the request is aborted before the exchange
// is created. Aborting the exchange a second time will result in
// a no-operation, so we just abort here to cover that edge case.
@@ -145,18 +148,25 @@ public abstract class PoolingHttpDestination extends HttpD
{
@SuppressWarnings("unchecked")
C connection = (C)c;
- LOG.debug("{} released", connection);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} released", connection);
HttpClient client = getHttpClient();
if (client.isRunning())
{
if (connectionPool.isActive(connection))
+ {
process(connection, false);
+ }
else
- LOG.debug("{} explicit", connection);
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} explicit", connection);
+ }
}
else
{
- LOG.debug("{} is stopped", client);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} is stopped", client);
close(connection);
connection.close();
}
@@ -203,4 +213,10 @@ public abstract class PoolingHttpDestination extends HttpD
{
ContainerLifeCycle.dump(out, indent, Arrays.asList(connectionPool));
}
+
+ @Override
+ public String toString()
+ {
+ return String.format("%s,pool=%s", super.toString(), connectionPool);
+ }
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/Socks4Proxy.java b/jetty-client/src/main/java/org/eclipse/jetty/client/Socks4Proxy.java
index 037871e22fc..6886ef1aa29 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/Socks4Proxy.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/Socks4Proxy.java
@@ -133,7 +133,8 @@ public class Socks4Proxy extends ProxyConfiguration.Proxy
@Override
public void succeeded()
{
- LOG.debug("Written SOCKS4 connect request");
+ if (LOG.isDebugEnabled())
+ LOG.debug("Written SOCKS4 connect request");
fillInterested();
}
@@ -153,7 +154,8 @@ public class Socks4Proxy extends ProxyConfiguration.Proxy
{
ByteBuffer buffer = BufferUtil.allocate(8);
int filled = getEndPoint().fill(buffer);
- LOG.debug("Read SOCKS4 connect response, {} bytes", filled);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Read SOCKS4 connect response, {} bytes", filled);
if (filled != 8)
throw new IOException("Invalid response from SOCKS4 proxy");
int result = buffer.get(1);
@@ -179,7 +181,8 @@ public class Socks4Proxy extends ProxyConfiguration.Proxy
connectionFactory = new SslClientConnectionFactory(client.getSslContextFactory(), client.getByteBufferPool(), client.getExecutor(), connectionFactory);
org.eclipse.jetty.io.Connection connection = connectionFactory.newConnection(getEndPoint(), context);
ClientConnectionFactory.Helper.replaceConnection(this, connection);
- LOG.debug("SOCKS4 tunnel established: {} over {}", this, connection);
+ if (LOG.isDebugEnabled())
+ LOG.debug("SOCKS4 tunnel established: {} over {}", this, connection);
}
catch (Throwable x)
{
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/TimeoutCompleteListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/TimeoutCompleteListener.java
index 80859a439b5..e8e7cebbcd1 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/TimeoutCompleteListener.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/TimeoutCompleteListener.java
@@ -48,7 +48,8 @@ public class TimeoutCompleteListener implements Response.CompleteListener, Runna
if (task != null)
{
boolean cancelled = task.cancel();
- LOG.debug("Cancelled (successfully: {}) timeout task {}", cancelled, task);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Cancelled (successfully: {}) timeout task {}", cancelled, task);
}
}
@@ -58,14 +59,16 @@ public class TimeoutCompleteListener implements Response.CompleteListener, Runna
Scheduler.Task task = scheduler.schedule(this, timeout, TimeUnit.MILLISECONDS);
if (this.task.getAndSet(task) != null)
throw new IllegalStateException();
- LOG.debug("Scheduled timeout task {} in {} ms for {}", task, timeout, request);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Scheduled timeout task {} in {} ms for {}", task, timeout, request);
return true;
}
@Override
public void run()
{
- LOG.debug("Executing timeout task {} for {}", task, request);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Executing timeout task {} for {}", task, request);
request.abort(new TimeoutException("Total timeout elapsed"));
}
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java
index 3c2d2604fa8..a7ab28ce080 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java
@@ -20,8 +20,6 @@ package org.eclipse.jetty.client.api;
import java.io.Closeable;
-import org.eclipse.jetty.util.Promise;
-
/**
* {@link Connection} represent a connection to a {@link Destination} and allow applications to send
* requests via {@link #send(Request, Response.CompleteListener)}.
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java
index 371b22bd821..9833e5beed9 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java
@@ -18,13 +18,7 @@
package org.eclipse.jetty.client.api;
-import java.io.Closeable;
-import java.io.InputStream;
import java.nio.ByteBuffer;
-import java.util.Iterator;
-
-import org.eclipse.jetty.client.util.ByteBufferContentProvider;
-import org.eclipse.jetty.client.util.PathContentProvider;
/**
* {@link ContentProvider} provides a source of request content.
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java
index 9a155644673..53a6f006ef8 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java
@@ -18,8 +18,6 @@
package org.eclipse.jetty.client.api;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Promise;
/**
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java
index f37988cc4bf..3e28e8e759e 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java
@@ -21,7 +21,6 @@ package org.eclipse.jetty.client.api;
import java.io.IOException;
import java.net.HttpCookie;
import java.net.URI;
-import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.util.EventListener;
@@ -31,8 +30,6 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.util.InputStreamResponseListener;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java
index 77d2d597b08..1f92b1eb74d 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java
@@ -22,7 +22,6 @@ import java.nio.ByteBuffer;
import java.util.EventListener;
import java.util.List;
-import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpVersion;
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java
index 0b1b1b0fcf2..d02574417fa 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java
@@ -85,7 +85,8 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec
@Override
protected boolean onReadTimeout()
{
- LOG.debug("{} idle timeout", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} idle timeout", this);
close(new TimeoutException());
return false;
}
@@ -127,9 +128,11 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec
// from an onFailure() handler or by blocking code waiting for completion.
getHttpDestination().close(this);
getEndPoint().shutdownOutput();
- LOG.debug("{} oshut", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} oshut", this);
getEndPoint().close();
- LOG.debug("{} closed", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} closed", this);
abort(failure);
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java
index f98f4828942..37dfdaa802e 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java
@@ -120,7 +120,8 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
}
catch (Throwable x)
{
- LOG.debug(x);
+ if (LOG.isDebugEnabled())
+ LOG.debug(x);
failAndClose(x);
return true;
}
@@ -230,7 +231,8 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
@Override
public void resume()
{
- LOG.debug("Content consumed asynchronously, resuming processing");
+ if (LOG.isDebugEnabled())
+ LOG.debug("Content consumed asynchronously, resuming processing");
process();
}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java
index d176826fc94..c8ce04168ab 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java
@@ -123,7 +123,8 @@ public class HttpSenderOverHTTP extends HttpSender
}
catch (Throwable x)
{
- LOG.debug(x);
+ if (LOG.isDebugEnabled())
+ LOG.debug(x);
callback.failed(x);
}
}
@@ -181,7 +182,8 @@ public class HttpSenderOverHTTP extends HttpSender
}
catch (Exception x)
{
- LOG.debug(x);
+ if (LOG.isDebugEnabled())
+ LOG.debug(x);
callback.failed(x);
}
}
@@ -194,12 +196,11 @@ public class HttpSenderOverHTTP extends HttpSender
}
@Override
- protected RequestState dispose()
+ protected void dispose()
{
generator.abort();
- RequestState result = super.dispose();
+ super.dispose();
shutdownOutput();
- return result;
}
private void shutdownOutput()
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java
index 4302374e79e..7c283464aa1 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java
@@ -21,9 +21,7 @@ package org.eclipse.jetty.client.util;
import java.net.URI;
import java.nio.charset.StandardCharsets;
-import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Authentication;
-import org.eclipse.jetty.client.api.AuthenticationStore;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpHeader;
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java
index e8a695f0d63..724e3bddb6c 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java
@@ -22,8 +22,6 @@ import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.NoSuchElementException;
-import org.eclipse.jetty.client.api.ContentProvider;
-
/**
* A {@link ContentProvider} for {@link ByteBuffer}s.
*
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java
index 7b356ef1a63..d64fa2385c3 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java
@@ -22,8 +22,6 @@ import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.NoSuchElementException;
-import org.eclipse.jetty.client.api.ContentProvider;
-
/**
* A {@link ContentProvider} for byte arrays.
*/
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java
index 3f34a23a6d7..106983190b4 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java
@@ -30,9 +30,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jetty.client.AsyncContentProvider;
-import org.eclipse.jetty.client.api.ContentProvider;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.util.ArrayQueue;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java
index b7a32ab35b5..98b9f940d3a 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java
@@ -33,9 +33,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Authentication;
-import org.eclipse.jetty.client.api.AuthenticationStore;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpHeader;
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/FormContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/FormContentProvider.java
index 39c490a570d..cb626dbfda1 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/FormContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/FormContentProvider.java
@@ -24,7 +24,6 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
-import org.eclipse.jetty.client.api.ContentProvider;
import org.eclipse.jetty.util.Fields;
/**
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java
index 89d3022ae27..0a7e0ae1f9e 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java
@@ -149,7 +149,8 @@ public class InputStreamContentProvider implements ContentProvider
byte[] bytes = new byte[bufferSize];
int read = stream.read(bytes);
- LOG.debug("Read {} bytes from {}", read, stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Read {} bytes from {}", read, stream);
if (read > 0)
{
hasNext = Boolean.TRUE;
@@ -172,7 +173,8 @@ public class InputStreamContentProvider implements ContentProvider
}
catch (Throwable x)
{
- LOG.debug(x);
+ if (LOG.isDebugEnabled())
+ LOG.debug(x);
if (failure == null)
{
failure = x;
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java
index 734e32d0bda..789b525365d 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java
@@ -32,7 +32,6 @@ import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
-import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Response.Listener;
import org.eclipse.jetty.client.api.Result;
@@ -116,23 +115,27 @@ public class InputStreamResponseListener extends Listener.Adapter
byte[] bytes = new byte[remaining];
content.get(bytes);
- LOG.debug("Queuing {}/{} bytes", bytes, remaining);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queuing {}/{} bytes", bytes, remaining);
queue.offer(bytes);
long newLength = length.addAndGet(remaining);
while (newLength >= maxBufferSize)
{
- LOG.debug("Queued bytes limit {}/{} exceeded, waiting", newLength, maxBufferSize);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queued bytes limit {}/{} exceeded, waiting", newLength, maxBufferSize);
// Block to avoid infinite buffering
if (!await())
break;
newLength = length.get();
- LOG.debug("Queued bytes limit {}/{} exceeded, woken up", newLength, maxBufferSize);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queued bytes limit {}/{} exceeded, woken up", newLength, maxBufferSize);
}
}
else
{
- LOG.debug("Queuing skipped, empty content {}", content);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queuing skipped, empty content {}", content);
}
}
else
@@ -141,26 +144,41 @@ public class InputStreamResponseListener extends Listener.Adapter
}
}
+ @Override
+ public void onSuccess(Response response)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queuing end of content {}{}", EOF, "");
+ queue.offer(EOF);
+ signal();
+ }
+
+ @Override
+ public void onFailure(Response response, Throwable failure)
+ {
+ fail(failure);
+ signal();
+ }
+
@Override
public void onComplete(Result result)
{
+ if (result.isFailed() && failure == null)
+ fail(result.getFailure());
this.result = result;
- if (result.isSucceeded())
- {
- LOG.debug("Queuing end of content {}{}", EOF, "");
- queue.offer(EOF);
- }
- else
- {
- LOG.debug("Queuing failure {} {}", FAILURE, failure);
- queue.offer(FAILURE);
- this.failure = result.getFailure();
- responseLatch.countDown();
- }
resultLatch.countDown();
signal();
}
+ private void fail(Throwable failure)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queuing failure {} {}", FAILURE, failure);
+ queue.offer(FAILURE);
+ this.failure = failure;
+ responseLatch.countDown();
+ }
+
protected boolean await()
{
try
@@ -288,7 +306,8 @@ public class InputStreamResponseListener extends Listener.Adapter
else
{
bytes = take();
- LOG.debug("Dequeued {}/{} bytes", bytes, bytes.length);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Dequeued {}/{} bytes", bytes, bytes.length);
}
}
}
@@ -319,7 +338,8 @@ public class InputStreamResponseListener extends Listener.Adapter
if (!closed)
{
super.close();
- LOG.debug("Queuing close {}{}", CLOSED, "");
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queuing close {}{}", CLOSED, "");
queue.offer(CLOSED);
closed = true;
signal();
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/OutputStreamContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/OutputStreamContentProvider.java
index cc90b5178ce..d9203380bea 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/OutputStreamContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/OutputStreamContentProvider.java
@@ -24,9 +24,6 @@ import java.nio.ByteBuffer;
import java.util.Iterator;
import org.eclipse.jetty.client.AsyncContentProvider;
-import org.eclipse.jetty.client.api.ContentProvider;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.client.api.Response;
/**
* A {@link ContentProvider} that provides content asynchronously through an {@link OutputStream}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java
index 676c7916091..e69a2e6e6ac 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java
@@ -30,7 +30,6 @@ import java.nio.file.StandardOpenOption;
import java.util.Iterator;
import java.util.NoSuchElementException;
-import org.eclipse.jetty.client.api.ContentProvider;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -107,7 +106,8 @@ public class PathContentProvider extends AbstractTypedContentProvider
if (channel == null)
{
channel = Files.newByteChannel(filePath, StandardOpenOption.READ);
- LOG.debug("Opened file {}", filePath);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Opened file {}", filePath);
}
buffer.clear();
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java
index 7475c3febf7..d6a58177ea1 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java
@@ -21,8 +21,6 @@ package org.eclipse.jetty.client.util;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
-import org.eclipse.jetty.client.api.ContentProvider;
-
/**
* A {@link ContentProvider} for strings.
*
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java
index 838932fbcac..9147704e970 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java
@@ -116,6 +116,11 @@ public class HostnameVerificationTest
// ExecutionException wraps an SSLHandshakeException
Throwable cause = x.getCause();
+ if (cause==null)
+ {
+ x.printStackTrace();
+ Assert.fail("No cause?");
+ }
if (cause instanceof SSLHandshakeException)
Assert.assertThat(cause.getCause().getCause(), Matchers.instanceOf(CertificateException.class));
else
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java
index 4c287cbdaaf..a0f70f5c18e 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java
@@ -25,6 +25,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -46,6 +47,7 @@ import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.Assert;
@@ -187,7 +189,7 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest
{
baseRequest.setHandled(true);
if (requests.incrementAndGet() == 1)
- response.sendRedirect(scheme + "://" + request.getServerName() + ":" + request.getServerPort() + request.getRequestURI());
+ response.sendRedirect(URIUtil.newURI(scheme,request.getServerName(),request.getServerPort(),request.getRequestURI(),null));
}
});
@@ -226,7 +228,7 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest
{
baseRequest.setHandled(true);
if (request.getRequestURI().endsWith("/redirect"))
- response.sendRedirect(scheme + "://" + request.getServerName() + ":" + request.getServerPort() + "/secure");
+ response.sendRedirect(URIUtil.newURI(scheme,request.getServerName(),request.getServerPort(),"/secure",null));
}
});
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientGZIPTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientGZIPTest.java
new file mode 100644
index 00000000000..98aaf9966c6
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientGZIPTest.java
@@ -0,0 +1,209 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.client;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+import java.util.zip.GZIPOutputStream;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HttpClientGZIPTest extends AbstractHttpClientServerTest
+{
+ public HttpClientGZIPTest(SslContextFactory sslContextFactory)
+ {
+ super(sslContextFactory);
+ }
+
+ @Test
+ public void testGZIPContentEncoding() throws Exception
+ {
+ final byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ start(new AbstractHandler()
+ {
+ @Override
+ public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ baseRequest.setHandled(true);
+ response.setHeader("Content-Encoding", "gzip");
+ GZIPOutputStream gzipOutput = new GZIPOutputStream(response.getOutputStream());
+ gzipOutput.write(data);
+ gzipOutput.finish();
+ }
+ });
+
+ ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+ .scheme(scheme)
+ .timeout(5, TimeUnit.SECONDS)
+ .send();
+
+ Assert.assertEquals(200, response.getStatus());
+ Assert.assertArrayEquals(data, response.getContent());
+ }
+
+ @Test
+ public void testGZIPContentOneByteAtATime() throws Exception
+ {
+ final byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ start(new AbstractHandler()
+ {
+ @Override
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ baseRequest.setHandled(true);
+ response.setHeader("Content-Encoding", "gzip");
+
+ ByteArrayOutputStream gzipData = new ByteArrayOutputStream();
+ GZIPOutputStream gzipOutput = new GZIPOutputStream(gzipData);
+ gzipOutput.write(data);
+ gzipOutput.finish();
+
+ ServletOutputStream output = response.getOutputStream();
+ byte[] gzipBytes = gzipData.toByteArray();
+ for (byte gzipByte : gzipBytes)
+ {
+ output.write(gzipByte);
+ output.flush();
+ sleep(100);
+ }
+ }
+ });
+
+ ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+ .scheme(scheme)
+ .send();
+
+ Assert.assertEquals(200, response.getStatus());
+ Assert.assertArrayEquals(data, response.getContent());
+ }
+
+ @Test
+ public void testGZIPContentSentTwiceInOneWrite() throws Exception
+ {
+ final byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ start(new AbstractHandler()
+ {
+ @Override
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ baseRequest.setHandled(true);
+ response.setHeader("Content-Encoding", "gzip");
+
+ ByteArrayOutputStream gzipData = new ByteArrayOutputStream();
+ GZIPOutputStream gzipOutput = new GZIPOutputStream(gzipData);
+ gzipOutput.write(data);
+ gzipOutput.finish();
+
+ byte[] gzipBytes = gzipData.toByteArray();
+ byte[] content = Arrays.copyOf(gzipBytes, 2 * gzipBytes.length);
+ System.arraycopy(gzipBytes, 0, content, gzipBytes.length, gzipBytes.length);
+
+ ServletOutputStream output = response.getOutputStream();
+ output.write(content);
+ }
+ });
+
+ ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+ .scheme(scheme)
+ .send();
+
+ Assert.assertEquals(200, response.getStatus());
+
+ byte[] expected = Arrays.copyOf(data, 2 * data.length);
+ System.arraycopy(data, 0, expected, data.length, data.length);
+ Assert.assertArrayEquals(expected, response.getContent());
+ }
+
+ @Test
+ public void testGZIPContentFragmentedBeforeTrailer() throws Exception
+ {
+ // There are 8 trailer bytes to gzip encoding.
+ testGZIPContentFragmented(9);
+ }
+
+ @Test
+ public void testGZIPContentFragmentedAtTrailer() throws Exception
+ {
+ // There are 8 trailer bytes to gzip encoding.
+ testGZIPContentFragmented(1);
+ }
+
+ private void testGZIPContentFragmented(final int fragment) throws Exception
+ {
+ final byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ start(new AbstractHandler()
+ {
+ @Override
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ baseRequest.setHandled(true);
+ response.setHeader("Content-Encoding", "gzip");
+
+ ByteArrayOutputStream gzipData = new ByteArrayOutputStream();
+ GZIPOutputStream gzipOutput = new GZIPOutputStream(gzipData);
+ gzipOutput.write(data);
+ gzipOutput.finish();
+
+ byte[] gzipBytes = gzipData.toByteArray();
+ byte[] chunk1 = Arrays.copyOfRange(gzipBytes, 0, gzipBytes.length - fragment);
+ byte[] chunk2 = Arrays.copyOfRange(gzipBytes, gzipBytes.length - fragment, gzipBytes.length);
+
+ ServletOutputStream output = response.getOutputStream();
+ output.write(chunk1);
+ output.flush();
+
+ sleep(500);
+
+ output.write(chunk2);
+ output.flush();
+ }
+ });
+
+ ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+ .scheme(scheme)
+ .send();
+
+ Assert.assertEquals(200, response.getStatus());
+ Assert.assertArrayEquals(data, response.getContent());
+ }
+
+ private static void sleep(long ms) throws IOException
+ {
+ try
+ {
+ TimeUnit.MILLISECONDS.sleep(ms);
+ }
+ catch (InterruptedException x)
+ {
+ throw new InterruptedIOException();
+ }
+ }
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java
index 9b77675ff08..1cab93ae99a 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java
@@ -43,8 +43,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.zip.GZIPOutputStream;
-
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
@@ -672,32 +670,6 @@ public class HttpClientTest extends AbstractHttpClientServerTest
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
}
- @Test
- public void test_GZIP_ContentEncoding() throws Exception
- {
- final byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- start(new AbstractHandler()
- {
- @Override
- public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
- {
- baseRequest.setHandled(true);
- response.setHeader("Content-Encoding", "gzip");
- GZIPOutputStream gzipOutput = new GZIPOutputStream(response.getOutputStream());
- gzipOutput.write(data);
- gzipOutput.finish();
- }
- });
-
- ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
- .scheme(scheme)
- .timeout(5, TimeUnit.SECONDS)
- .send();
-
- Assert.assertEquals(200, response.getStatus());
- Assert.assertArrayEquals(data, response.getContent());
- }
-
@Slow
@Test
public void test_Request_IdleTimeout() throws Exception
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTimeoutTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTimeoutTest.java
index 84a18b66fec..dced77f5b78 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTimeoutTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTimeoutTest.java
@@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+
import javax.net.ssl.SSLEngine;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -56,6 +57,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Assume;
+import org.junit.Ignore;
import org.junit.Test;
public class HttpClientTimeoutTest extends AbstractHttpClientServerTest
@@ -299,6 +301,7 @@ public class HttpClientTimeoutTest extends AbstractHttpClientServerTest
}
}
+ @Ignore
@Slow
@Test
public void testConnectTimeoutFailsRequest() throws Exception
@@ -330,6 +333,7 @@ public class HttpClientTimeoutTest extends AbstractHttpClientServerTest
Assert.assertNotNull(request.getAbortCause());
}
+ @Ignore
@Slow
@Test
public void testConnectTimeoutIsCancelledByShorterTimeout() throws Exception
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseConcurrentAbortTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseConcurrentAbortTest.java
new file mode 100644
index 00000000000..a6089421150
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseConcurrentAbortTest.java
@@ -0,0 +1,198 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.client;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.client.api.Response;
+import org.eclipse.jetty.client.api.Result;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HttpResponseConcurrentAbortTest extends AbstractHttpClientServerTest
+{
+ private final CountDownLatch callbackLatch = new CountDownLatch(1);
+ private final CountDownLatch failureLatch = new CountDownLatch(1);
+ private final CountDownLatch completeLatch = new CountDownLatch(1);
+ private final AtomicBoolean success = new AtomicBoolean();
+
+ public HttpResponseConcurrentAbortTest(SslContextFactory sslContextFactory)
+ {
+ super(sslContextFactory);
+ }
+
+ @Test
+ public void testAbortOnBegin() throws Exception
+ {
+ start(new EmptyServerHandler());
+
+ client.newRequest("localhost", connector.getLocalPort())
+ .scheme(scheme)
+ .onResponseBegin(new Response.BeginListener()
+ {
+ @Override
+ public void onBegin(Response response)
+ {
+ abort(response);
+ }
+ })
+ .send(new TestResponseListener());
+ Assert.assertTrue(callbackLatch.await(5, TimeUnit.SECONDS));
+ Assert.assertTrue(completeLatch.await(6, TimeUnit.SECONDS));
+ Assert.assertTrue(success.get());
+ }
+
+ @Test
+ public void testAbortOnHeader() throws Exception
+ {
+ start(new EmptyServerHandler());
+
+ client.newRequest("localhost", connector.getLocalPort())
+ .scheme(scheme)
+ .onResponseHeader(new Response.HeaderListener()
+ {
+ @Override
+ public boolean onHeader(Response response, HttpField field)
+ {
+ abort(response);
+ return true;
+ }
+ })
+ .send(new TestResponseListener());
+ Assert.assertTrue(callbackLatch.await(5, TimeUnit.SECONDS));
+ Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
+ Assert.assertTrue(success.get());
+ }
+
+ @Test
+ public void testAbortOnHeaders() throws Exception
+ {
+ start(new EmptyServerHandler());
+
+ client.newRequest("localhost", connector.getLocalPort())
+ .scheme(scheme)
+ .onResponseHeaders(new Response.HeadersListener()
+ {
+ @Override
+ public void onHeaders(Response response)
+ {
+ abort(response);
+ }
+ })
+ .send(new TestResponseListener());
+ Assert.assertTrue(callbackLatch.await(5, TimeUnit.SECONDS));
+ Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
+ Assert.assertTrue(success.get());
+ }
+
+ @Test
+ public void testAbortOnContent() throws Exception
+ {
+ start(new AbstractHandler()
+ {
+ @Override
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ baseRequest.setHandled(true);
+ OutputStream output = response.getOutputStream();
+ output.write(1);
+ output.flush();
+ }
+ });
+
+ client.newRequest("localhost", connector.getLocalPort())
+ .scheme(scheme)
+ .onResponseContent(new Response.ContentListener()
+ {
+ @Override
+ public void onContent(Response response, ByteBuffer content)
+ {
+ abort(response);
+ }
+ })
+ .send(new TestResponseListener());
+ Assert.assertTrue(callbackLatch.await(5, TimeUnit.SECONDS));
+ Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
+ Assert.assertTrue(success.get());
+ }
+
+ private void abort(final Response response)
+ {
+ Logger logger = Log.getLogger(getClass());
+
+ new Thread("abort")
+ {
+ @Override
+ public void run()
+ {
+ response.abort(new Exception());
+ }
+ }.start();
+
+ try
+ {
+ // The failure callback must be executed asynchronously.
+ boolean latched = failureLatch.await(4, TimeUnit.SECONDS);
+ success.set(latched);
+ logger.info("SIMON - STEP 1");
+
+ // The complete callback must not be executed
+ // until we return from this callback.
+ latched = completeLatch.await(1, TimeUnit.SECONDS);
+ success.set(!latched);
+ logger.info("SIMON - STEP 2");
+
+ callbackLatch.countDown();
+ }
+ catch (InterruptedException x)
+ {
+ throw new RuntimeException(x);
+ }
+ }
+
+ private class TestResponseListener extends Response.Listener.Adapter
+ {
+ @Override
+ public void onFailure(Response response, Throwable failure)
+ {
+ failureLatch.countDown();
+ }
+
+ @Override
+ public void onComplete(Result result)
+ {
+ Assert.assertTrue(result.isFailed());
+ completeLatch.countDown();
+ }
+ }
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java
index 0be2b913973..e7564b5e641 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java
@@ -18,23 +18,18 @@
package org.eclipse.jetty.client.http;
-import java.io.ByteArrayOutputStream;
import java.io.EOFException;
-import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import java.util.zip.GZIPOutputStream;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpExchange;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.HttpResponseException;
import org.eclipse.jetty.client.Origin;
-import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.util.FutureResponseListener;
import org.eclipse.jetty.http.HttpFields;
@@ -205,58 +200,4 @@ public class HttpReceiverOverHTTPTest
Assert.assertTrue(e.getCause() instanceof HttpResponseException);
}
}
-
- @Test
- public void test_Receive_GZIPResponseContent_Fragmented() throws Exception
- {
- byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try (GZIPOutputStream gzipOutput = new GZIPOutputStream(baos))
- {
- gzipOutput.write(data);
- }
- byte[] gzip = baos.toByteArray();
-
- endPoint.setInput("" +
- "HTTP/1.1 200 OK\r\n" +
- "Content-Length: " + gzip.length + "\r\n" +
- "Content-Encoding: gzip\r\n" +
- "\r\n");
-
- HttpRequest request = (HttpRequest)client.newRequest("http://localhost");
- final CountDownLatch latch = new CountDownLatch(1);
- FutureResponseListener listener = new FutureResponseListener(request)
- {
- @Override
- public void onContent(Response response, ByteBuffer content)
- {
- super.onContent(response, content);
- latch.countDown();
- }
- };
- HttpExchange exchange = new HttpExchange(destination, request, Collections.singletonList(listener));
- connection.getHttpChannel().associate(exchange);
- exchange.requestComplete();
- exchange.terminateRequest(null);
- connection.getHttpChannel().receive();
- endPoint.reset();
-
- ByteBuffer buffer = ByteBuffer.wrap(gzip);
- int fragment = buffer.limit() - 1;
- buffer.limit(fragment);
- endPoint.setInput(buffer);
- connection.getHttpChannel().receive();
- endPoint.reset();
-
- buffer.limit(gzip.length);
- buffer.position(fragment);
- endPoint.setInput(buffer);
- connection.getHttpChannel().receive();
-
- ContentResponse response = listener.get(5, TimeUnit.SECONDS);
- Assert.assertNotNull(response);
- Assert.assertEquals(200, response.getStatus());
- Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
- Assert.assertArrayEquals(data, response.getContent());
- }
}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java
index bdef5f21fd9..1f4077f83c3 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java
@@ -1049,9 +1049,9 @@ public class SslBytesServerTest extends SslBytesTest
@Test
public void testRequestWithBigContentWriteBlockedThenReset() throws Exception
{
- // Don't run on Windows (buggy JVM)
- Assume.assumeTrue(!OS.IS_WINDOWS);
-
+ // Don't run on Windows (buggy JVM)
+ Assume.assumeTrue(!OS.IS_WINDOWS);
+
final SSLSocket client = newClient();
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
@@ -1110,10 +1110,10 @@ public class SslBytesServerTest extends SslBytesTest
@Test
public void testRequestWithBigContentReadBlockedThenReset() throws Exception
{
- // Don't run on Windows (buggy JVM)
- Assume.assumeTrue(!OS.IS_WINDOWS);
-
- final SSLSocket client = newClient();
+ // Don't run on Windows (buggy JVM)
+ Assume.assumeTrue(!OS.IS_WINDOWS);
+
+ final SSLSocket client = newClient();
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
client.startHandshake();
diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java
index 0eb8ca0efdc..da0239cb7e3 100644
--- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java
+++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java
@@ -18,12 +18,7 @@
package org.eclipse.jetty.continuation;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.Servlet;
-import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
-import javax.servlet.ServletResponseWrapper;
/* ------------------------------------------------------------ */
/**
diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java
index 4b960d5f098..b6c337e9dd8 100644
--- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java
+++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java
@@ -20,8 +20,6 @@ package org.eclipse.jetty.continuation;
import java.util.EventListener;
-import javax.servlet.ServletRequestListener;
-
/* ------------------------------------------------------------ */
/** A Continuation Listener
diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppProvider.java
index 1ad17bc235f..a0e84ee3628 100644
--- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppProvider.java
+++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppProvider.java
@@ -18,8 +18,6 @@
package org.eclipse.jetty.deploy;
-import java.io.IOException;
-
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.component.LifeCycle;
diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java
index 7e50a964333..d8d5b150538 100644
--- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java
+++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java
@@ -25,7 +25,6 @@ import java.util.Locale;
import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.ConfigurationManager;
import org.eclipse.jetty.deploy.util.FileID;
-import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java
index 78f113967d9..d296611946d 100644
--- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java
+++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java
@@ -36,10 +36,10 @@ import org.junit.Test;
*/
public class AppLifeCycleTest
{
- @Rule
- public TestingDir testdir = new TestingDir();
+ @Rule
+ public TestingDir testdir = new TestingDir();
- private void assertNoPath(String from, String to)
+ private void assertNoPath(String from, String to)
{
assertPath(from,to,new ArrayList());
}
diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBindingTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBindingTest.java
index 3acec97f295..7d80fc092c2 100644
--- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBindingTest.java
+++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBindingTest.java
@@ -26,7 +26,6 @@ import static org.hamcrest.Matchers.not;
import java.io.File;
import java.util.List;
-import org.eclipse.jetty.deploy.providers.ScanningAppProvider;
import org.eclipse.jetty.deploy.test.XmlConfiguredJetty;
import org.eclipse.jetty.toolchain.test.IO;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderStartupTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderStartupTest.java
index eb7e0c0e698..949acfd626f 100644
--- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderStartupTest.java
+++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderStartupTest.java
@@ -30,8 +30,8 @@ import org.junit.Test;
*/
public class ScanningAppProviderStartupTest
{
- @Rule
- public TestingDir testdir = new TestingDir();
+ @Rule
+ public TestingDir testdir = new TestingDir();
private static XmlConfiguredJetty jetty;
@Before
diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml
index bf5ae62b310..c08257930b2 100644
--- a/jetty-distribution/pom.xml
+++ b/jetty-distribution/pom.xml
@@ -302,7 +302,7 @@
org.eclipse.jettyorg.eclipse.jetty.orbit,org.eclipse.jetty.spdy,org.eclipse.jetty.websocket,org.eclipse.jetty.fcgi,org.eclipse.jetty.toolchain,org.apache.taglibs
- jetty-all,jetty-jsp,apache-jsp,jetty-start,jetty-monitor
+ jetty-all,jetty-jsp,apache-jsp,jetty-start,jetty-monitor,jetty-springjar${assembly-directory}/lib
@@ -332,6 +332,19 @@
${assembly-directory}/lib/fcgi
+
+ copy-lib-spring-deps
+ generate-resources
+
+ copy-dependencies
+
+
+ org.eclipse.jetty
+ jetty-spring
+ jar
+ ${assembly-directory}/lib/spring
+
+ copy-lib-monitor-depsgenerate-resources
@@ -765,6 +778,11 @@
fcgi-server${project.version}
+
+ org.eclipse.jetty
+ jetty-spring
+ ${project.version}
+
{} {}",state,next,this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{}-->{} {}",state,next,this);
if (next!=state)
next.onEnter(AbstractConnection.this);
return true;
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java
index 8fa2cc86ef9..6f2b011db66 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java
@@ -94,7 +94,8 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
@Override
public void onOpen()
{
- LOG.debug("onOpen {}",this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("onOpen {}",this);
super.onOpen();
}
@@ -102,7 +103,8 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
public void onClose()
{
super.onClose();
- LOG.debug("onClose {}",this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("onClose {}",this);
_writeFlusher.onClose();
_fillInterest.onClose();
}
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java
index c65ca0ccfc8..7c80d06bcad 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java
@@ -61,7 +61,8 @@ public class ChannelEndPoint extends AbstractEndPoint
protected void shutdownInput()
{
- LOG.debug("ishut {}", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("ishut {}", this);
_ishut=true;
if (_oshut)
close();
@@ -70,7 +71,8 @@ public class ChannelEndPoint extends AbstractEndPoint
@Override
public void shutdownOutput()
{
- LOG.debug("oshut {}", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("oshut {}", this);
_oshut = true;
if (_channel.isOpen())
{
@@ -109,7 +111,8 @@ public class ChannelEndPoint extends AbstractEndPoint
public void close()
{
super.close();
- LOG.debug("close {}", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("close {}", this);
try
{
_channel.close();
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java
index 96baa01676f..7bd08ad66fd 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java
@@ -20,8 +20,6 @@ package org.eclipse.jetty.io;
import java.io.Closeable;
-import org.eclipse.jetty.util.Callback;
-
/**
*
A {@link Connection} is associated to an {@link EndPoint} so that I/O events
* happening on the {@link EndPoint} can be processed by the {@link Connection}.
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java
index 87adb40be1f..4aa404fe3ba 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java
@@ -26,8 +26,6 @@ import java.nio.channels.ReadPendingException;
import java.nio.channels.WritePendingException;
import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.FutureCallback;
-
/**
*
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/IdleTimeout.java b/jetty-io/src/main/java/org/eclipse/jetty/io/IdleTimeout.java
index 8b251ac862c..64b996f021e 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/IdleTimeout.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/IdleTimeout.java
@@ -142,13 +142,15 @@ public abstract class IdleTimeout
long idleElapsed = System.currentTimeMillis() - idleTimestamp;
long idleLeft = idleTimeout - idleElapsed;
- LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
if (idleTimestamp != 0 && idleTimeout > 0)
{
if (idleLeft <= 0)
{
- LOG.debug("{} idle timeout expired", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} idle timeout expired", this);
try
{
onIdleExpired(new TimeoutException("Idle timeout expired: " + idleElapsed + "/" + idleTimeout + " ms"));
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java
index a4b6f7d2a16..25093f02bc4 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java
@@ -25,7 +25,6 @@ import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.List;
-import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Scheduler;
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java
index 30504029947..e60c9fa706b 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java
@@ -132,18 +132,21 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements SelectorMa
{
if (_interestOps.compareAndSet(oldInterestOps, newInterestOps))
{
- LOG.debug("Local interests updated {} -> {} for {}", oldInterestOps, newInterestOps, this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Local interests updated {} -> {} for {}", oldInterestOps, newInterestOps, this);
_selector.updateKey(_updateTask);
}
else
{
- LOG.debug("Local interests update conflict: now {}, was {}, attempted {} for {}", _interestOps.get(), oldInterestOps, newInterestOps, this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Local interests update conflict: now {}, was {}, attempted {} for {}", _interestOps.get(), oldInterestOps, newInterestOps, this);
continue;
}
}
else
{
- LOG.debug("Ignoring local interests update {} -> {} for {}", oldInterestOps, newInterestOps, this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Ignoring local interests update {} -> {} for {}", oldInterestOps, newInterestOps, this);
}
break;
}
@@ -152,7 +155,8 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements SelectorMa
private void setKeyInterests(int oldInterestOps, int newInterestOps)
{
- LOG.debug("Key interests updated {} -> {}", oldInterestOps, newInterestOps);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Key interests updated {} -> {}", oldInterestOps, newInterestOps);
_key.interestOps(newInterestOps);
}
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java
index fd3c6c6b9ee..0e6fd889da6 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java
@@ -21,8 +21,6 @@ package org.eclipse.jetty.io;
import java.io.Closeable;
import java.io.IOException;
import java.net.ConnectException;
-import java.net.Socket;
-import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.SelectionKey;
@@ -377,11 +375,13 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
@Override
protected void doStop() throws Exception
{
- LOG.debug("Stopping {}", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Stopping {}", this);
Stop stop = new Stop();
submit(stop);
stop.await(getStopTimeout());
- LOG.debug("Stopped {}", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Stopped {}", this);
}
/**
@@ -419,7 +419,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
// change to the queue and process the state.
_changes.offer(change);
- LOG.debug("Queued change {}", change);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queued change {}", change);
out: while (true)
{
@@ -463,7 +464,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
try
{
- LOG.debug("Running change {}", change);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Running change {}", change);
change.run();
}
catch (Throwable x)
@@ -480,14 +482,17 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
try
{
_thread.setName(name + "-selector-" + SelectorManager.this.getClass().getSimpleName()+"@"+Integer.toHexString(SelectorManager.this.hashCode())+"/"+_id);
- LOG.debug("Starting {} on {}", _thread, this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Starting {} on {}", _thread, this);
while (isRunning())
select();
- runChanges();
+ while(isStopping())
+ runChanges();
}
finally
{
- LOG.debug("Stopped {} on {}", _thread, this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Stopped {} on {}", _thread, this);
_thread.setName(name);
}
}
@@ -671,13 +676,15 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
Connection connection = newConnection(channel, endPoint, selectionKey.attachment());
endPoint.setConnection(connection);
connectionOpened(connection);
- LOG.debug("Created {}", endPoint);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Created {}", endPoint);
return endPoint;
}
public void destroyEndPoint(EndPoint endPoint)
{
- LOG.debug("Destroyed {}", endPoint);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Destroyed {}", endPoint);
Connection connection = endPoint.getConnection();
if (connection != null)
connectionClosed(connection);
@@ -792,7 +799,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
try
{
SelectionKey key = _channel.register(_selector, SelectionKey.OP_ACCEPT, null);
- LOG.debug("{} acceptor={}", this, key);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} acceptor={}", this, key);
}
catch (Throwable x)
{
@@ -881,7 +889,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
SocketChannel channel = connect.channel;
if (channel.isConnectionPending())
{
- LOG.debug("Channel {} timed out while connecting, closing it", channel);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Channel {} timed out while connecting, closing it", channel);
connect.failed(new SocketTimeoutException());
}
}
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java b/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java
index 6898ddfb93f..66e90a2c746 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java
@@ -129,7 +129,8 @@ public class UncheckedPrintWriter extends PrintWriter
_ioException.initCause(th);
}
- LOG.debug(th);
+ if (LOG.isDebugEnabled())
+ LOG.debug(th);
}
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java
index ee9e449b151..95b9c8bcd12 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java
@@ -38,7 +38,6 @@ import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.FillInterest;
import org.eclipse.jetty.io.RuntimeIOException;
-import org.eclipse.jetty.io.SelectChannelEndPoint;
import org.eclipse.jetty.io.WriteFlusher;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
@@ -820,7 +819,6 @@ public class SslConnection extends AbstractConnection
}
catch (Exception e)
{
- getEndPoint().close();
throw e;
}
finally
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java
index a46ff320348..d850e65ad4c 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java
@@ -210,7 +210,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
}
else if (callback instanceof RequestParameterCallback)
{
- HttpChannel channel = HttpChannel.getCurrentHttpChannel();
+ HttpChannel channel = HttpChannel.getCurrentHttpChannel();
if (channel == null)
return;
diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java
index fbe2b62b950..9215eddaf00 100644
--- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java
+++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java
@@ -92,6 +92,9 @@ public class FormAuthModule extends BaseAuthModule
setErrorPage(errorPage);
}
+ /**
+ * @deprecated
+ */
public FormAuthModule(CallbackHandler callbackHandler, CrossContextPsuedoSession ssoSource,
String loginPage, String errorPage)
{
diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java
index 40624001859..343de02d9b3 100644
--- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java
+++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java
@@ -82,23 +82,23 @@ public class ConnectorServer extends AbstractLifeCycle
public ConnectorServer(JMXServiceURL svcUrl, Map environment, String name)
throws Exception
{
- String urlPath = svcUrl.getURLPath();
- int idx = urlPath.indexOf("rmi://");
- if (idx > 0)
- {
- String hostPort = urlPath.substring(idx+6, urlPath.indexOf('/', idx+6));
- String regHostPort = startRegistry(hostPort);
- if (regHostPort != null) {
- urlPath = urlPath.replace(hostPort,regHostPort);
- svcUrl = new JMXServiceURL(svcUrl.getProtocol(), svcUrl.getHost(), svcUrl.getPort(), urlPath);
- }
- }
+ String urlPath = svcUrl.getURLPath();
+ int idx = urlPath.indexOf("rmi://");
+ if (idx > 0)
+ {
+ String hostPort = urlPath.substring(idx+6, urlPath.indexOf('/', idx+6));
+ String regHostPort = startRegistry(hostPort);
+ if (regHostPort != null) {
+ urlPath = urlPath.replace(hostPort,regHostPort);
+ svcUrl = new JMXServiceURL(svcUrl.getProtocol(), svcUrl.getHost(), svcUrl.getPort(), urlPath);
+ }
+ }
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
_connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(svcUrl, environment, mbeanServer);
mbeanServer.registerMBean(_connectorServer,new ObjectName(name));
}
- /* ------------------------------------------------------------ */
+ /* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
*/
diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java
index 35be7d6177f..e5386f19b2b 100644
--- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java
+++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java
@@ -128,7 +128,8 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable
@Override
public void beanAdded(Container parent, Object obj)
{
- LOG.debug("beanAdded {}->{}",parent,obj);
+ if (LOG.isDebugEnabled())
+ LOG.debug("beanAdded {}->{}",parent,obj);
// Is their an object name for the parent
ObjectName pname=null;
@@ -206,7 +207,8 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable
}
ObjectInstance oinstance = _mbeanServer.registerMBean(mbean, oname);
- LOG.debug("Registered {}", oinstance.getObjectName());
+ if (LOG.isDebugEnabled())
+ LOG.debug("Registered {}", oinstance.getObjectName());
_beans.put(obj, oinstance.getObjectName());
}
@@ -219,7 +221,8 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable
@Override
public void beanRemoved(Container parent, Object obj)
{
- LOG.debug("beanRemoved {}",obj);
+ if (LOG.isDebugEnabled())
+ LOG.debug("beanRemoved {}",obj);
ObjectName bean = _beans.remove(obj);
if (bean != null)
@@ -227,7 +230,8 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable
try
{
_mbeanServer.unregisterMBean(bean);
- LOG.debug("Unregistered {}", bean);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Unregistered {}", bean);
}
catch (javax.management.InstanceNotFoundException e)
{
diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java
index 4445294a2f6..5a7ab0b4851 100644
--- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java
+++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java
@@ -132,7 +132,8 @@ public class ObjectMBean implements DynamicMBean
{
Class> mClass = (Object.class.equals(oClass))?oClass=ObjectMBean.class:Loader.loadClass(oClass,mName);
- LOG.debug("ObjectMbean: mbeanFor {} mClass={}", o, mClass);
+ if (LOG.isDebugEnabled())
+ LOG.debug("ObjectMbean: mbeanFor {} mClass={}", o, mClass);
try
{
@@ -149,7 +150,8 @@ public class ObjectMBean implements DynamicMBean
}
}
- LOG.debug("mbeanFor {} is {}", o, mbean);
+ if (LOG.isDebugEnabled())
+ LOG.debug("mbeanFor {} is {}", o, mbean);
return mbean;
}
@@ -241,7 +243,8 @@ public class ObjectMBean implements DynamicMBean
Class> o_class=_managed.getClass();
List> influences = findInfluences(new ArrayList>(), _managed.getClass());
- LOG.debug("Influence Count: {}", influences.size() );
+ if (LOG.isDebugEnabled())
+ LOG.debug("Influence Count: {}", influences.size() );
// Process Type Annotations
ManagedObject primary = o_class.getAnnotation( ManagedObject.class);
@@ -252,7 +255,8 @@ public class ObjectMBean implements DynamicMBean
}
else
{
- LOG.debug("No @ManagedObject declared on {}", _managed.getClass());
+ if (LOG.isDebugEnabled())
+ LOG.debug("No @ManagedObject declared on {}", _managed.getClass());
}
@@ -263,10 +267,13 @@ public class ObjectMBean implements DynamicMBean
ManagedObject typeAnnotation = oClass.getAnnotation( ManagedObject.class );
- LOG.debug("Influenced by: " + oClass.getCanonicalName() );
+ if (LOG.isDebugEnabled())
+ LOG.debug("Influenced by: " + oClass.getCanonicalName() );
+
if ( typeAnnotation == null )
{
- LOG.debug("Annotations not found for: {}", oClass.getCanonicalName() );
+ if (LOG.isDebugEnabled())
+ LOG.debug("Annotations not found for: {}", oClass.getCanonicalName() );
continue;
}
@@ -279,7 +286,8 @@ public class ObjectMBean implements DynamicMBean
if (methodAttributeAnnotation != null)
{
// TODO sort out how a proper name could get here, its a method name as an attribute at this point.
- LOG.debug("Attribute Annotation found for: {}", method.getName());
+ if (LOG.isDebugEnabled())
+ LOG.debug("Attribute Annotation found for: {}", method.getName());
MBeanAttributeInfo mai = defineAttribute(method,methodAttributeAnnotation);
if ( mai != null )
{
@@ -291,9 +299,9 @@ public class ObjectMBean implements DynamicMBean
if (methodOperationAnnotation != null)
{
- LOG.debug("Method Annotation found for: {}", method.getName());
+ if (LOG.isDebugEnabled())
+ LOG.debug("Method Annotation found for: {}", method.getName());
MBeanOperationInfo oi = defineOperation(method,methodOperationAnnotation);
-
if (oi != null)
{
operations.add(oi);
@@ -480,7 +488,8 @@ public class ObjectMBean implements DynamicMBean
/* ------------------------------------------------------------ */
public AttributeList setAttributes(AttributeList attrs)
{
- LOG.debug("setAttributes");
+ if (LOG.isDebugEnabled())
+ LOG.debug("setAttributes");
AttributeList results = new AttributeList(attrs.size());
Iterator
*
- * There is a reference guide to the configuration parameters for this plugin, and more detailed information
- * with examples in the Configuration Guide.
+ * Unlike the other jetty goals, this does NOT support the scanIntervalSeconds parameter: the webapp will be deployed only once.
+ *
+ *
+ * The stopKey, stopPort configuration elements can be used to control the stopping of the forked process. By default, this plugin will launch
+ * the forked jetty instance and wait for it to complete (in which case it acts much like the jetty:run goal, and you will need to Cntrl-C to stop).
+ * By setting the configuration element waitForChild to false, the plugin will terminate after having forked the jetty process. In this case
+ * you can use the jetty:stop goal to terminate the process.
+ *
*
* @goal run-forked
@@ -75,50 +77,18 @@ import org.eclipse.jetty.util.resource.ResourceCollection;
* @description Runs Jetty in forked JVM on an unassembled webapp
*
*/
-public class JettyRunForkedMojo extends AbstractMojo
+public class JettyRunForkedMojo extends JettyRunMojo
{
public static final String DEFAULT_WEBAPP_SRC = "src"+File.separator+"main"+File.separator+"webapp";
public static final String FAKE_WEBAPP = "webapp-tmp";
public String PORT_SYSPROPERTY = "jetty.port";
-
- /**
- * Whether or not to include dependencies on the plugin's classpath with <scope>provided</scope>
- * Use WITH CAUTION as you may wind up with duplicate jars/classes.
- * @parameter default-value="false"
- */
- protected boolean useProvidedScope;
-
-
- /**
- * The maven project.
- *
- * @parameter expression="${project}"
- * @required
- * @readonly
- */
- private MavenProject project;
- /**
- * If true, the <testOutputDirectory>
- * and the dependencies of <scope>test<scope>
- * will be put first on the runtime classpath.
- * @parameter alias="useTestClasspath" default-value="false"
- */
- private boolean useTestScope;
+
- /**
- * The default location of the web.xml file. Will be used
- * if <webAppConfig><descriptor> is not set.
- *
- * @parameter expression="${basedir}/src/main/webapp/WEB-INF/web.xml"
- * @readonly
- */
- private String webXml;
-
/**
* The target directory
@@ -129,118 +99,13 @@ public class JettyRunForkedMojo extends AbstractMojo
*/
protected File target;
-
/**
- * The temporary directory to use for the webapp.
- * Defaults to target/tmp
- *
- * @parameter alias="tmpDirectory" expression="${project.build.directory}/tmp"
- * @required
- * @readonly
- */
- protected File tempDirectory;
-
-
-
- /**
- * Whether temporary directory contents should survive webapp restarts.
+ * The file into which to generate the quickstart web xml for the forked process to use
*
- * @parameter default-value="false"
+ * @parameter expression="${project.build.directory}/fork-web.xml"
*/
- private boolean persistTempDirectory;
-
+ protected File forkWebXml;
- /**
- * The directory containing generated classes.
- *
- * @parameter expression="${project.build.outputDirectory}"
- * @required
- *
- */
- private File classesDirectory;
-
-
- /**
- * The directory containing generated test classes.
- *
- * @parameter expression="${project.build.testOutputDirectory}"
- * @required
- */
- private File testClassesDirectory;
-
-
- /**
- * Root directory for all html/jsp etc files
- *
- * @parameter expression="${basedir}/src/main/webapp"
- *
- */
- private File webAppSourceDirectory;
-
- /**
- * Resource Bases
- *
- * @parameter
- *
- */
- private String[] resourceBases;
-
- /**
- * If true, the webAppSourceDirectory will be first on the list of
- * resources that form the resource base for the webapp. If false,
- * it will be last.
- *
- * @parameter default-value="true"
- */
- private boolean baseAppFirst;
-
-
- /**
- * Location of jetty xml configuration files whose contents
- * will be applied before any plugin configuration. Optional.
- * @parameter
- */
- private String jettyXml;
-
- /**
- * The context path for the webapp. Defaults to / for jetty-9
- *
- * @parameter expression="/"
- */
- private String contextPath;
-
-
- /**
- * Location of a context xml configuration file whose contents
- * will be applied to the webapp AFTER anything in <webAppConfig>.Optional.
- * @parameter
- */
- private String contextXml;
-
-
- /**
- * @parameter expression="${jetty.skip}" default-value="false"
- */
- private boolean skip;
-
-
- /**
- * Port to listen to stop jetty on executing -DSTOP.PORT=<stopPort>
- * -DSTOP.KEY=<stopKey> -jar start.jar --stop
- * @parameter
- * @required
- */
- protected int stopPort;
-
-
- /**
- * Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey>
- * -DSTOP.PORT=<stopPort> -jar start.jar --stop
- * @parameter
- * @required
- */
- protected String stopKey;
-
/**
* Arbitrary jvm args to pass to the forked process
@@ -284,9 +149,9 @@ public class JettyRunForkedMojo extends AbstractMojo
*/
private Random random;
+
-
-
+ private Resource originalBaseResource;
/**
@@ -360,332 +225,71 @@ public class JettyRunForkedMojo extends AbstractMojo
*/
public void execute() throws MojoExecutionException, MojoFailureException
{
- getLog().info("Configuring Jetty for project: " + project.getName());
- if (skip)
- {
- getLog().info("Skipping Jetty start: jetty.skip==true");
- return;
- }
- PluginLog.setLog(getLog());
Runtime.getRuntime().addShutdownHook(new ShutdownThread());
random = new Random();
- startJettyRunner();
+ super.execute();
}
-
-
- /**
- * @return
- * @throws MojoExecutionException
- */
- public List getProvidedJars() throws MojoExecutionException
- {
- //if we are configured to include the provided dependencies on the plugin's classpath
- //(which mimics being on jetty's classpath vs being on the webapp's classpath), we first
- //try and filter out ones that will clash with jars that are plugin dependencies, then
- //create a new classloader that we setup in the parent chain.
- if (useProvidedScope)
- {
-
- List provided = new ArrayList();
- for ( Iterator iter = project.getArtifacts().iterator(); iter.hasNext(); )
- {
- Artifact artifact = iter.next();
- if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()) && !isPluginArtifact(artifact))
- {
- provided.add(artifact.getFile().getAbsolutePath());
- if (getLog().isDebugEnabled()) { getLog().debug("Adding provided artifact: "+artifact);}
- }
- }
- return provided;
- }
- else
- return null;
- }
-
-
-
-
- /**
- * @return
- * @throws MojoExecutionException
- */
- public File prepareConfiguration() throws MojoExecutionException
+
+ @Override
+ public void startJetty() throws MojoExecutionException
{
- try
- {
- //work out the configuration based on what is configured in the pom
- File propsFile = new File (target, "fork.props");
- if (propsFile.exists())
- propsFile.delete();
-
- propsFile.createNewFile();
- //propsFile.deleteOnExit();
-
- Properties props = new Properties();
-
-
- //web.xml
- if (webXml != null)
- props.put("web.xml", webXml);
-
- //sort out the context path
- if (contextPath != null)
- props.put("context.path", contextPath);
-
- //sort out the tmp directory (make it if it doesn't exist)
- if (tempDirectory != null)
- {
- if (!tempDirectory.exists())
- tempDirectory.mkdirs();
- props.put("tmp.dir", tempDirectory.getAbsolutePath());
- }
-
- props.put("tmp.dir.persist", Boolean.toString(persistTempDirectory));
-
- if (resourceBases == null)
- {
- //sort out base dir of webapp
- if (webAppSourceDirectory == null || !webAppSourceDirectory.exists())
- {
- webAppSourceDirectory = new File (project.getBasedir(), DEFAULT_WEBAPP_SRC);
- if (!webAppSourceDirectory.exists())
- {
- //try last resort of making a fake empty dir
- File target = new File(project.getBuild().getDirectory());
- webAppSourceDirectory = new File(target, FAKE_WEBAPP);
- if (!webAppSourceDirectory.exists())
- webAppSourceDirectory.mkdirs();
- }
- }
- resourceBases = new String[] { webAppSourceDirectory.getAbsolutePath() };
- }
- StringBuffer rb = new StringBuffer(resourceBases[0]);
- for (int i=1; i classDirs = getClassesDirs();
- StringBuffer strbuff = new StringBuffer();
- for (int i=0; i deps = getDependencyFiles();
- strbuff.setLength(0);
- for (int i=0; i warArtifacts = getWarArtifacts();
- for (int i=0; i configs = warPlugin.getMavenWarOverlayConfigs();
- int i=0;
- for (OverlayConfig c:configs)
- {
- props.put("maven.war.overlay."+(i++), c.toString());
- }
-
- try (OutputStream out = new BufferedOutputStream(new FileOutputStream(propsFile)))
- {
- props.store(out, "properties for forked webapp");
- }
- return propsFile;
- }
- catch (Exception e)
- {
- throw new MojoExecutionException("Prepare webapp configuration", e);
- }
- }
-
-
-
-
- /**
- * @return
- */
- private List getClassesDirs ()
- {
- List classesDirs = new ArrayList();
+ //Only do enough setup to be able to produce a quickstart-web.xml file to
+ //pass onto the forked process to run
- //if using the test classes, make sure they are first
- //on the list
- if (useTestScope && (testClassesDirectory != null))
- classesDirs.add(testClassesDirectory);
+ if (forkWebXml == null)
+ forkWebXml = new File (target, "fork-web.xml");
- if (classesDirectory != null)
- classesDirs.add(classesDirectory);
-
- return classesDirs;
- }
-
-
-
-
- /**
- * @return
- * @throws MalformedURLException
- * @throws IOException
- */
- private List getWarArtifacts()
- throws MalformedURLException, IOException
- {
- List warArtifacts = new ArrayList();
- for ( Iterator iter = project.getArtifacts().iterator(); iter.hasNext(); )
- {
- Artifact artifact = (Artifact) iter.next();
-
- if (artifact.getType().equals("war"))
- warArtifacts.add(artifact);
- }
-
- return warArtifacts;
- }
-
-
-
-
- /**
- * @return
- */
- private List getDependencyFiles ()
- {
- List dependencyFiles = new ArrayList();
-
- for ( Iterator iter = project.getArtifacts().iterator(); iter.hasNext(); )
- {
- Artifact artifact = (Artifact) iter.next();
- // Test never appears here !
- if (((!Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) && (!Artifact.SCOPE_TEST.equals( artifact.getScope())))
- ||
- (useTestScope && Artifact.SCOPE_TEST.equals( artifact.getScope())))
- {
- dependencyFiles.add(artifact.getFile());
- getLog().debug( "Adding artifact " + artifact.getFile().getName() + " for WEB-INF/lib " );
- }
- }
-
- return dependencyFiles;
- }
-
-
-
-
- /**
- * @param artifact
- * @return
- */
- public boolean isPluginArtifact(Artifact artifact)
- {
- if (pluginArtifacts == null || pluginArtifacts.isEmpty())
- return false;
-
- boolean isPluginArtifact = false;
- for (Iterator iter = pluginArtifacts.iterator(); iter.hasNext() && !isPluginArtifact; )
- {
- Artifact pluginArtifact = iter.next();
- if (getLog().isDebugEnabled()) { getLog().debug("Checking "+pluginArtifact);}
- if (pluginArtifact.getGroupId().equals(artifact.getGroupId()) && pluginArtifact.getArtifactId().equals(artifact.getArtifactId()))
- isPluginArtifact = true;
- }
-
- return isPluginArtifact;
- }
-
-
-
-
- /**
- * @return
- * @throws Exception
- */
- private Set getExtraJars()
- throws Exception
- {
- Set extraJars = new HashSet();
-
-
- List l = pluginArtifacts;
- Artifact pluginArtifact = null;
-
- if (l != null)
- {
- Iterator itor = l.iterator();
- while (itor.hasNext() && pluginArtifact == null)
- {
- Artifact a = (Artifact)itor.next();
- if (a.getArtifactId().equals(plugin.getArtifactId())) //get the jetty-maven-plugin jar
- {
- extraJars.add(a);
- }
- }
- }
-
- return extraJars;
- }
-
-
-
-
- /**
- * @throws MojoExecutionException
- */
- public void startJettyRunner() throws MojoExecutionException
- {
try
{
-
+ printSystemProperties();
+
+ //do NOT apply the jettyXml configuration - as the jvmArgs may be needed for it to work
+
+ //ensure handler structure enabled
+ server.configureHandlers();
+
+ //ensure config of the webapp based on settings in plugin
+ configureWebApplication();
+
+ //copy the base resource as configured by the plugin
+ originalBaseResource = webApp.getBaseResource();
+
+ //set the webapp up to do very little other than generate the quickstart-web.xml
+ webApp.setCopyWebDir(false);
+ webApp.setCopyWebInf(false);
+ webApp.setGenerateQuickStart(true);
+
+ if (!forkWebXml.getParentFile().exists())
+ forkWebXml.getParentFile().mkdirs();
+ if (!forkWebXml.exists())
+ forkWebXml.createNewFile();
+
+ webApp.setQuickStartWebDescriptor(Resource.newResource(forkWebXml));
+
+ //add webapp to our fake server instance
+ server.addWebApplication(webApp);
+
+ //if our server has a thread pool associated we can do annotation scanning multithreaded,
+ //otherwise scanning will be single threaded
+ QueuedThreadPool tpool = server.getBean(QueuedThreadPool.class);
+ if (tpool != null)
+ tpool.start();
+ else
+ webApp.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE.toString());
+
+ webApp.start(); //just enough to generate the quickstart
+
+ //save config of the webapp BEFORE we stop
File props = prepareConfiguration();
+ webApp.stop();
+
+ if (tpool != null)
+ tpool.stop();
+
List cmd = new ArrayList();
cmd.add(getJavaBin());
@@ -699,7 +303,7 @@ public class JettyRunForkedMojo extends AbstractMojo
}
}
- String classPath = getClassPath();
+ String classPath = getContainerClassPath();
if (classPath != null && classPath.length() > 0)
{
cmd.add("-cp");
@@ -803,15 +407,262 @@ public class JettyRunForkedMojo extends AbstractMojo
throw new MojoExecutionException("Failed to create Jetty process", ex);
}
}
+
+
+
+
+ /**
+ * @return
+ * @throws MojoExecutionException
+ */
+ public List getProvidedJars() throws MojoExecutionException
+ {
+ //if we are configured to include the provided dependencies on the plugin's classpath
+ //(which mimics being on jetty's classpath vs being on the webapp's classpath), we first
+ //try and filter out ones that will clash with jars that are plugin dependencies, then
+ //create a new classloader that we setup in the parent chain.
+ if (useProvidedScope)
+ {
+
+ List provided = new ArrayList();
+ for ( Iterator iter = project.getArtifacts().iterator(); iter.hasNext(); )
+ {
+ Artifact artifact = iter.next();
+ if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()) && !isPluginArtifact(artifact))
+ {
+ provided.add(artifact.getFile().getAbsolutePath());
+ if (getLog().isDebugEnabled()) { getLog().debug("Adding provided artifact: "+artifact);}
+ }
+ }
+ return provided;
+
+ }
+ else
+ return null;
+ }
-
+
+
+
+ /**
+ * @return
+ * @throws MojoExecutionException
+ */
+ public File prepareConfiguration() throws MojoExecutionException
+ {
+ try
+ {
+ //work out the configuration based on what is configured in the pom
+ File propsFile = new File (target, "fork.props");
+ if (propsFile.exists())
+ propsFile.delete();
+
+ propsFile.createNewFile();
+ //propsFile.deleteOnExit();
+
+ Properties props = new Properties();
+
+
+ //web.xml
+ if (webApp.getDescriptor() != null)
+ {
+ props.put("web.xml", webApp.getDescriptor());
+ }
+
+ if (webApp.getQuickStartWebDescriptor() != null)
+ {
+ props.put("quickstart.web.xml", webApp.getQuickStartWebDescriptor().getFile().getAbsolutePath());
+ }
+
+ //sort out the context path
+ if (webApp.getContextPath() != null)
+ {
+ props.put("context.path", webApp.getContextPath());
+ }
+
+ //tmp dir
+ props.put("tmp.dir", webApp.getTempDirectory().getAbsolutePath());
+ props.put("tmp.dir.persist", Boolean.toString(webApp.isPersistTempDirectory()));
+
+ //resource bases - these are what has been configured BEFORE the webapp started and
+ //potentially reordered them and included any resources from META-INF
+ if (originalBaseResource != null)
+ {
+ StringBuffer rb = new StringBuffer();
+ if (originalBaseResource instanceof ResourceCollection)
+ {
+ ResourceCollection resources = ((ResourceCollection)originalBaseResource);
+ for (Resource r:resources.getResources())
+ {
+ if (rb.length() > 0) rb.append(",");
+ rb.append(r.toString());
+ }
+ }
+ else
+ rb.append(originalBaseResource.toString());
+
+ props.put("base.dirs", rb.toString());
+ }
+
+ //sort out the resource base directories of the webapp
+ props.put("base.first", Boolean.toString(webApp.getBaseAppFirst()));
+
+ //web-inf classes
+ if (webApp.getClasses() != null)
+ {
+ props.put("classes.dir",webApp.getClasses().getAbsolutePath());
+ }
+
+ if (useTestScope && webApp.getTestClasses() != null)
+ {
+ props.put("testClasses.dir", webApp.getTestClasses().getAbsolutePath());
+ }
+
+ //web-inf lib
+ List deps = webApp.getWebInfLib();
+ StringBuffer strbuff = new StringBuffer();
+ for (int i=0; i warArtifacts = getWarArtifacts();
+ for (int i=0; i configs = warPlugin.getMavenWarOverlayConfigs();
+ int i=0;
+ for (OverlayConfig c:configs)
+ {
+ props.put("maven.war.overlay."+(i++), c.toString());
+ }
+
+ try (OutputStream out = new BufferedOutputStream(new FileOutputStream(propsFile)))
+ {
+ props.store(out, "properties for forked webapp");
+ }
+ return propsFile;
+ }
+ catch (Exception e)
+ {
+ throw new MojoExecutionException("Prepare webapp configuration", e);
+ }
+ }
+
+
+
+
+
+
+ /**
+ * @return
+ * @throws MalformedURLException
+ * @throws IOException
+ */
+ private List getWarArtifacts()
+ throws MalformedURLException, IOException
+ {
+ List warArtifacts = new ArrayList();
+ for ( Iterator iter = project.getArtifacts().iterator(); iter.hasNext(); )
+ {
+ Artifact artifact = (Artifact) iter.next();
+
+ if (artifact.getType().equals("war"))
+ warArtifacts.add(artifact);
+ }
+
+ return warArtifacts;
+ }
+
+
+
+
+
+
+ /**
+ * @param artifact
+ * @return
+ */
+ public boolean isPluginArtifact(Artifact artifact)
+ {
+ if (pluginArtifacts == null || pluginArtifacts.isEmpty())
+ return false;
+
+ boolean isPluginArtifact = false;
+ for (Iterator iter = pluginArtifacts.iterator(); iter.hasNext() && !isPluginArtifact; )
+ {
+ Artifact pluginArtifact = iter.next();
+ if (getLog().isDebugEnabled()) { getLog().debug("Checking "+pluginArtifact);}
+ if (pluginArtifact.getGroupId().equals(artifact.getGroupId()) && pluginArtifact.getArtifactId().equals(artifact.getArtifactId()))
+ isPluginArtifact = true;
+ }
+
+ return isPluginArtifact;
+ }
+
+
+
+
+ /**
+ * @return
+ * @throws Exception
+ */
+ private Set getExtraJars()
+ throws Exception
+ {
+ Set extraJars = new HashSet();
+
+
+ List l = pluginArtifacts;
+ Artifact pluginArtifact = null;
+
+ if (l != null)
+ {
+ Iterator itor = l.iterator();
+ while (itor.hasNext() && pluginArtifact == null)
+ {
+ Artifact a = (Artifact)itor.next();
+ if (a.getArtifactId().equals(plugin.getArtifactId())) //get the jetty-maven-plugin jar
+ {
+ extraJars.add(a);
+ }
+ }
+ }
+
+ return extraJars;
+ }
+
+
+
+
/**
* @return
* @throws Exception
*/
- public String getClassPath() throws Exception
+ public String getContainerClassPath() throws Exception
{
StringBuilder classPath = new StringBuilder();
for (Object obj : pluginArtifacts)
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java
index 41147fca0de..130dd52504a 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java
@@ -55,8 +55,7 @@ import org.eclipse.jetty.webapp.WebAppContext;
* This can be used, for example, to deploy a static webapp that is not part of your maven build.
*
*
- * There is a reference guide to the configuration parameters for this plugin, and more detailed information
- * with examples in the Configuration Guide.
+ * There is a reference guide to the configuration parameters for this plugin.
*
*
*
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyServer.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyServer.java
index de5da154e1d..3e60e1008b3 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyServer.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyServer.java
@@ -19,6 +19,12 @@
package org.eclipse.jetty.maven.plugin;
+import java.io.File;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
@@ -27,6 +33,8 @@ import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.xml.XmlConfiguration;
+
/**
* JettyServer
@@ -109,4 +117,43 @@ public class JettyServer extends org.eclipse.jetty.server.Server
}
}
}
+
+ /**
+ * Apply xml files to server startup, passing in ourselves as the
+ * "Server" instance.
+ *
+ * @param files
+ * @throws Exception
+ */
+ public void applyXmlConfigurations (List files)
+ throws Exception
+ {
+ if (files == null || files.isEmpty())
+ return;
+
+ Map lastMap = Collections.singletonMap("Server", (Object)this);
+
+ for ( File xmlFile : files )
+ {
+ if (PluginLog.getLog() != null)
+ PluginLog.getLog().info( "Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath() );
+
+
+ XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(xmlFile));
+
+ //chain ids from one config file to another
+ if (lastMap != null)
+ xmlConfiguration.getIdMap().putAll(lastMap);
+
+ //Set the system properties each time in case the config file set a new one
+ Enumeration> ensysprop = System.getProperties().propertyNames();
+ while (ensysprop.hasMoreElements())
+ {
+ String name = (String)ensysprop.nextElement();
+ xmlConfiguration.getProperties().put(name,System.getProperty(name));
+ }
+ xmlConfiguration.configure();
+ lastMap = xmlConfiguration.getIdMap();
+ }
+ }
}
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java
index 700d0b9372b..6bdb0134128 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java
@@ -19,6 +19,7 @@
package org.eclipse.jetty.maven.plugin;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
@@ -32,6 +33,8 @@ import java.util.TreeSet;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
+import org.eclipse.jetty.quickstart.PreconfigureDescriptorProcessor;
+import org.eclipse.jetty.quickstart.QuickStartDescriptorGenerator;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ServletHolder;
@@ -61,20 +64,40 @@ import org.eclipse.jetty.webapp.WebXmlConfiguration;
public class JettyWebAppContext extends WebAppContext
{
private static final Logger LOG = Log.getLogger(JettyWebAppContext.class);
+
+
- private static final String DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN = ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$|.*javax.servlet.jsp.jstl-[^/]*\\.jar";
+ private static final String DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN = ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$|.*javax.servlet.jsp.jstl-[^/]*\\.jar|.*taglibs-standard-impl-.*\\.jar";
private static final String WEB_INF_CLASSES_PREFIX = "/WEB-INF/classes";
private static final String WEB_INF_LIB_PREFIX = "/WEB-INF/lib";
+ private final Configuration[] _defaultConfigurations = {
+ new MavenWebInfConfiguration(),
+ new WebXmlConfiguration(),
+ new MetaInfConfiguration(),
+ new FragmentConfiguration(),
+ new EnvConfiguration(),
+ new PlusConfiguration(),
+ new AnnotationConfiguration(),
+ new JettyWebXmlConfiguration()
+ };
+
+ private final Configuration[] _quickStartConfigurations = {
+ new MavenQuickStartConfiguration(),
+ new EnvConfiguration(),
+ new PlusConfiguration(),
+ new JettyWebXmlConfiguration()
+ };
+
private File _classes = null;
private File _testClasses = null;
private final List _webInfClasses = new ArrayList();
private final List _webInfJars = new ArrayList();
private final Map _webInfJarMap = new HashMap();
- private final EnvConfiguration _envConfig;
private List _classpathFiles; //webInfClasses+testClasses+webInfJars
private String _jettyEnvXml;
private List _overlays;
+ private Resource _quickStartWebXml;
@@ -99,28 +122,24 @@ public class JettyWebAppContext extends WebAppContext
*/
private boolean _baseAppFirst = true;
+
+
+ private boolean _isGenerateQuickStart;
+ private PreconfigureDescriptorProcessor _preconfigProcessor;
+
+
public JettyWebAppContext ()
throws Exception
{
super();
- setConfigurations(new Configuration[]{
- new MavenWebInfConfiguration(),
- new WebXmlConfiguration(),
- new MetaInfConfiguration(),
- new FragmentConfiguration(),
- _envConfig = new EnvConfiguration(),
- new PlusConfiguration(),
- new AnnotationConfiguration(),
- new JettyWebXmlConfiguration()
- });
// Turn off copyWebInf option as it is not applicable for plugin.
super.setCopyWebInf(false);
}
public void setContainerIncludeJarPattern(String pattern)
{
- _containerIncludeJarPattern = pattern;
+ _containerIncludeJarPattern = pattern;
}
public String getContainerIncludeJarPattern()
@@ -131,7 +150,7 @@ public class JettyWebAppContext extends WebAppContext
public String getWebInfIncludeJarPattern()
{
- return _webInfIncludeJarPattern;
+ return _webInfIncludeJarPattern;
}
public void setWebInfIncludeJarPattern(String pattern)
{
@@ -209,7 +228,19 @@ public class JettyWebAppContext extends WebAppContext
{
return _baseAppFirst;
}
-
+
+ /* ------------------------------------------------------------ */
+ public void setQuickStartWebDescriptor (Resource quickStartWebXml)
+ {
+ _quickStartWebXml = quickStartWebXml;
+ }
+
+ /* ------------------------------------------------------------ */
+ public Resource getQuickStartWebDescriptor ()
+ {
+ return _quickStartWebXml;
+ }
+
/* ------------------------------------------------------------ */
/**
* This method is provided as a convenience for jetty maven plugin configuration
@@ -233,9 +264,65 @@ public class JettyWebAppContext extends WebAppContext
{
return _webInfJars;
}
+
+ public void setGenerateQuickStart (boolean quickStart)
+ {
+ _isGenerateQuickStart = quickStart;
+ }
+
+ public boolean isGenerateQuickStart()
+ {
+ return _isGenerateQuickStart;
+ }
+
+
+
+
+ @Override
+ protected void startWebapp() throws Exception
+ {
+ if (isGenerateQuickStart())
+ {
+ if (getQuickStartWebDescriptor() == null)
+ throw new IllegalStateException ("No location to generate quickstart descriptor");
+ QuickStartDescriptorGenerator generator = new QuickStartDescriptorGenerator(this, _preconfigProcessor.getXML());
+ try (FileOutputStream fos = new FileOutputStream(getQuickStartWebDescriptor().getFile()))
+ {
+ generator.generateQuickStartWebXml(fos);
+ }
+ }
+ else
+ super.startWebapp();
+ }
+
+
+ @Override
public void doStart () throws Exception
{
+ //choose if this will be a quickstart or normal start
+ if (!isGenerateQuickStart() && getQuickStartWebDescriptor() != null)
+ setConfigurations(_quickStartConfigurations);
+ else
+ {
+ setConfigurations(_defaultConfigurations);
+ if (isGenerateQuickStart())
+ {
+ _preconfigProcessor = new PreconfigureDescriptorProcessor();
+ getMetaData().addDescriptorProcessor(_preconfigProcessor);
+ }
+ }
+
+
+ //inject configurations with config from maven plugin
+ for (Configuration c:getConfigurations())
+ {
+ if (c instanceof EnvConfiguration && getJettyEnvXml() != null)
+ ((EnvConfiguration)c).setJettyEnvXml(Resource.toURL(new File(getJettyEnvXml())));
+ else if (c instanceof MavenQuickStartConfiguration && getQuickStartWebDescriptor() != null)
+ ((MavenQuickStartConfiguration)c).setQuickStartWebXml(getQuickStartWebDescriptor());
+ }
+
//Set up the pattern that tells us where the jars are that need scanning
//Allow user to set up pattern for names of jars from the container classpath
@@ -273,9 +360,6 @@ public class JettyWebAppContext extends WebAppContext
if (fileName.endsWith(".jar"))
_webInfJarMap.put(fileName, file);
}
-
- if (this._jettyEnvXml != null)
- _envConfig.setJettyEnvXml(Resource.toURL(new File(this._jettyEnvXml)));
// CHECK setShutdown(false);
super.doStart();
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenQuickStartConfiguration.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenQuickStartConfiguration.java
new file mode 100644
index 00000000000..295bd062424
--- /dev/null
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenQuickStartConfiguration.java
@@ -0,0 +1,92 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+
+package org.eclipse.jetty.maven.plugin;
+
+import java.io.File;
+import java.util.Iterator;
+
+import org.eclipse.jetty.quickstart.QuickStartConfiguration;
+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.WebAppClassLoader;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * MavenQuickStartConfiguration
+ *
+ *
+ */
+public class MavenQuickStartConfiguration extends QuickStartConfiguration
+{
+ private static final Logger LOG = Log.getLogger(QuickStartConfiguration.class);
+
+ private Resource _quickStartWebXml;
+
+
+ public void setQuickStartWebXml (Resource r)
+ {
+ _quickStartWebXml = r;
+ }
+
+
+
+ @Override
+ public Resource getQuickStartWebXml(WebAppContext context) throws Exception
+ {
+ return _quickStartWebXml;
+ }
+
+
+
+ @Override
+ public void configure(WebAppContext context) throws Exception
+ {
+
+ JettyWebAppContext jwac = (JettyWebAppContext)context;
+
+ //put the classes dir and all dependencies into the classpath
+ if (jwac.getClassPathFiles() != null)
+ {
+ if (LOG.isDebugEnabled()) LOG.debug("Setting up classpath ...");
+ Iterator itor = jwac.getClassPathFiles().iterator();
+ while (itor.hasNext())
+ ((WebAppClassLoader)context.getClassLoader()).addClassPath(((File)itor.next()).getCanonicalPath());
+ }
+
+ //Set up the quickstart environment for the context
+ super.configure(context);
+
+ // knock out environmental maven and plexus classes from webAppContext
+ String[] existingServerClasses = context.getServerClasses();
+ String[] newServerClasses = new String[2+(existingServerClasses==null?0:existingServerClasses.length)];
+ newServerClasses[0] = "org.apache.maven.";
+ newServerClasses[1] = "org.codehaus.plexus.";
+ System.arraycopy( existingServerClasses, 0, newServerClasses, 2, existingServerClasses.length );
+ if (LOG.isDebugEnabled())
+ {
+ LOG.debug("Server classes:");
+ for (int i=0;i fragAndRequiredBundles = (Set)context.getAttribute(OSGiWebInfConfiguration.FRAGMENT_AND_REQUIRED_BUNDLES);
if (fragAndRequiredBundles != null)
{
//index and scan fragments
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiMetaInfConfiguration.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiMetaInfConfiguration.java
deleted file mode 100644
index 7b85f62a2d2..00000000000
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiMetaInfConfiguration.java
+++ /dev/null
@@ -1,129 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
-// ------------------------------------------------------------------------
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the Eclipse Public License v1.0
-// and Apache License v2.0 which accompanies this distribution.
-//
-// The Eclipse Public License is available at
-// http://www.eclipse.org/legal/epl-v10.html
-//
-// The Apache License v2.0 is available at
-// http://www.opensource.org/licenses/apache2.0.php
-//
-// You may elect to redistribute this code under either of these licenses.
-// ========================================================================
-//
-
-package org.eclipse.jetty.osgi.boot;
-
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
-import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
-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.MetaInfConfiguration;
-import org.eclipse.jetty.webapp.WebAppContext;
-import org.osgi.framework.Bundle;
-
-/**
- * OSGiMetaInfConfiguration
- *
- * Extension of standard Jetty MetaInfConfiguration class to handle OSGi bundle
- * fragments that may also need to be scanned for META-INF info.
- *
- * @deprecated
- */
-public class OSGiMetaInfConfiguration extends MetaInfConfiguration
-{
- private static final Logger LOG = Log.getLogger(OSGiMetaInfConfiguration.class);
-
-
- /**
- * Inspect bundle fragments associated with the bundle of the webapp for web-fragment, resources, tlds.
- *
- * @see org.eclipse.jetty.webapp.MetaInfConfiguration#preConfigure(org.eclipse.jetty.webapp.WebAppContext)
- */
- @Override
- public void preConfigure(final WebAppContext context) throws Exception
- {
- Map frags = (Map) context.getAttribute(METAINF_FRAGMENTS);
- Set resfrags = (Set) context.getAttribute(METAINF_RESOURCES);
- List tldfrags = (List) context.getAttribute(METAINF_TLDS);
-
- Bundle[] fragments = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles((Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE));
- //TODO not convinced we need to do this, as we added any fragment jars to the MetaData.webInfJars in OSGiWebInfConfiguration,
- //so surely the web-fragments and resources tlds etc can be discovered normally?
- for (Bundle frag : fragments)
- {
- URL webFrag = frag.getEntry("/META-INF/web-fragment.xml");
- Enumeration resEnum = frag.findEntries("/META-INF/resources", "*", true);
- Enumeration tldEnum = frag.findEntries("/META-INF", "*.tld", false);
- if (webFrag != null || (resEnum != null && resEnum.hasMoreElements()) || (tldEnum != null && tldEnum.hasMoreElements()))
- {
- try
- {
- if (webFrag != null)
- {
- if (frags == null)
- {
- frags = new HashMap();
- context.setAttribute(METAINF_FRAGMENTS, frags);
- }
- frags.put(Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(frag).toURI()),
- Resource.newResource(webFrag));
- }
- if (resEnum != null && resEnum.hasMoreElements())
- {
- URL resourcesEntry = frag.getEntry("/META-INF/resources/");
- if (resourcesEntry == null)
- {
- // probably we found some fragments to a
- // bundle.
- // those are already contributed.
- // so we skip this.
- }
- else
- {
- if (resfrags == null)
- {
- resfrags = new HashSet();
- context.setAttribute(METAINF_RESOURCES, resfrags);
- }
- resfrags.add(Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(resourcesEntry)));
- }
- }
- if (tldEnum != null && tldEnum.hasMoreElements())
- {
- if (tldfrags == null)
- {
- tldfrags = new ArrayList();
- context.setAttribute(METAINF_TLDS, tldfrags);
- }
- while (tldEnum.hasMoreElements())
- {
- URL tldUrl = tldEnum.nextElement();
- tldfrags.add(Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(tldUrl)));
- }
- }
- }
- catch (Exception e)
- {
- LOG.warn("Unable to locate the bundle " + frag.getBundleId(), e);
- }
- }
- }
-
- super.preConfigure(context);
- }
-}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java
index ce3c141ae5a..69a7ce8cdb9 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java
@@ -23,6 +23,7 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.regex.Pattern;
@@ -51,6 +52,9 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration
public static final String CONTAINER_BUNDLE_PATTERN = "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern";
+ public static final String FRAGMENT_AND_REQUIRED_BUNDLES = "org.eclipse.jetty.osgi.fragmentAndRequiredBundles";
+ public static final String FRAGMENT_AND_REQUIRED_RESOURCES = "org.eclipse.jetty.osgi.fragmentAndRequiredResources";
+
/* ------------------------------------------------------------ */
/**
@@ -87,7 +91,6 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration
while (tokenizer.hasMoreTokens())
names.add(tokenizer.nextToken());
}
-
HashSet matchingResources = new HashSet();
if ( !names.isEmpty() || pattern != null)
{
@@ -111,14 +114,20 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration
matchingResources.addAll(getBundleAsResource(bundle));
}
}
- }
-
+ }
for (Resource r:matchingResources)
{
context.getMetaData().addContainerResource(r);
}
}
+ @Override
+ public void postConfigure(WebAppContext context) throws Exception
+ {
+ context.setAttribute(FRAGMENT_AND_REQUIRED_BUNDLES, null);
+ context.setAttribute(FRAGMENT_AND_REQUIRED_RESOURCES, null);
+ super.postConfigure(context);
+ }
/* ------------------------------------------------------------ */
/**
@@ -137,12 +146,34 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration
if (webInfJars != null)
mergedResources.addAll(webInfJars);
- //add fragment jars as if in WEB-INF/lib of the associated webapp
- Bundle[] fragments = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles((Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE));
- for (Bundle frag : fragments)
+ //add fragment jars and any Required-Bundles as if in WEB-INF/lib of the associated webapp
+ Bundle[] bundles = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles((Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE));
+ if (bundles != null && bundles.length > 0)
{
- File fragFile = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(frag);
- mergedResources.add(Resource.newResource(fragFile.toURI()));
+ Set fragsAndReqsBundles = (Set)context.getAttribute(FRAGMENT_AND_REQUIRED_BUNDLES);
+ if (fragsAndReqsBundles == null)
+ {
+ fragsAndReqsBundles = new HashSet();
+ context.setAttribute(FRAGMENT_AND_REQUIRED_BUNDLES, fragsAndReqsBundles);
+ }
+
+ Set fragsAndReqsResources = (Set)context.getAttribute(FRAGMENT_AND_REQUIRED_RESOURCES);
+ if (fragsAndReqsResources == null)
+ {
+ fragsAndReqsResources = new HashSet();
+ context.setAttribute(FRAGMENT_AND_REQUIRED_RESOURCES, fragsAndReqsResources);
+ }
+
+ for (Bundle b : bundles)
+ {
+ //add to context attribute storing associated fragments and required bundles
+ fragsAndReqsBundles.add(b);
+ File f = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(b);
+ Resource r = Resource.newResource(f.toURI());
+ //add to convenience context attribute storing fragments and required bundles as Resources
+ fragsAndReqsResources.add(r);
+ mergedResources.add(r);
+ }
}
return mergedResources;
@@ -165,9 +196,8 @@ public class OSGiWebInfConfiguration extends WebInfConfiguration
Bundle bundle = (Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
if (bundle != null)
{
- //TODO anything we need to do to improve PackageAdminServiceTracker?
- Bundle[] fragments = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles(bundle);
- if (fragments != null && fragments.length != 0)
+ Set fragments = (Set)context.getAttribute(FRAGMENT_AND_REQUIRED_BUNDLES);
+ if (fragments != null && !fragments.isEmpty())
{
// sorted extra resource base found in the fragments.
// the resources are either overriding the resourcebase found in the
diff --git a/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorHandlerHelper.java b/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorHandlerHelper.java
index 35f186681fd..f8fdc636f8a 100644
--- a/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorHandlerHelper.java
+++ b/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorHandlerHelper.java
@@ -30,16 +30,16 @@ import javax.servlet.http.HttpServlet;
*/
public class HttpServiceErrorHandlerHelper
{
- private static HttpServlet _customErrorHandler;
+ private static HttpServlet _customErrorHandler;
- public static HttpServlet getCustomErrorHandler()
- {
- return _customErrorHandler;
- }
-
- public static void setHttpServiceErrorHandler(HttpServlet servlet)
- {
- _customErrorHandler = servlet;
- }
-
+ public static HttpServlet getCustomErrorHandler()
+ {
+ return _customErrorHandler;
+ }
+
+ public static void setHttpServiceErrorHandler(HttpServlet servlet)
+ {
+ _customErrorHandler = servlet;
+ }
+
}
diff --git a/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorPageErrorHandler.java b/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorPageErrorHandler.java
index 1b08f9b13a9..e9ebc855620 100644
--- a/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorPageErrorHandler.java
+++ b/jetty-osgi/jetty-osgi-httpservice/src/main/java/org/eclipse/jetty/osgi/httpservice/HttpServiceErrorPageErrorHandler.java
@@ -35,46 +35,46 @@ import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
public class HttpServiceErrorPageErrorHandler extends ErrorPageErrorHandler
{
- private static HttpServiceErrorPageErrorHandler INSTANCE;
-
- public static HttpServiceErrorPageErrorHandler getInstance()
- {
- return INSTANCE;
- }
-
- public HttpServiceErrorPageErrorHandler()
- {
- INSTANCE = this;
- }
+ private static HttpServiceErrorPageErrorHandler INSTANCE;
+
+ public static HttpServiceErrorPageErrorHandler getInstance()
+ {
+ return INSTANCE;
+ }
+
+ public HttpServiceErrorPageErrorHandler()
+ {
+ INSTANCE = this;
+ }
- @Override
- public void handle(String target, Request baseRequest,
- HttpServletRequest request, HttpServletResponse response)
- throws IOException {
- if (HttpServiceErrorHandlerHelper.getCustomErrorHandler() != null)
- {
- try
- {
- HttpServiceErrorHandlerHelper.getCustomErrorHandler().service(request, response);
- }
- catch (ServletException e)
- {
- //well
- }
- }
- if (!response.isCommitted())
- {
- super.handle(target, baseRequest, request, response);
- }
- }
+ @Override
+ public void handle(String target, Request baseRequest,
+ HttpServletRequest request, HttpServletResponse response)
+ throws IOException {
+ if (HttpServiceErrorHandlerHelper.getCustomErrorHandler() != null)
+ {
+ try
+ {
+ HttpServiceErrorHandlerHelper.getCustomErrorHandler().service(request, response);
+ }
+ catch (ServletException e)
+ {
+ //well
+ }
+ }
+ if (!response.isCommitted())
+ {
+ super.handle(target, baseRequest, request, response);
+ }
+ }
- @Override
- protected void doStop() throws Exception
- {
- INSTANCE = null;
- super.doStop();
- }
-
-
-
+ @Override
+ protected void doStop() throws Exception
+ {
+ INSTANCE = null;
+ super.doStop();
+ }
+
+
+
}
diff --git a/jetty-overlay-deployer/src/test/java/org/eclipse/jetty/overlays/OverlayServer.java b/jetty-overlay-deployer/src/test/java/org/eclipse/jetty/overlays/OverlayServer.java
index 8a6f4e7f7a1..c7cb7d977e7 100644
--- a/jetty-overlay-deployer/src/test/java/org/eclipse/jetty/overlays/OverlayServer.java
+++ b/jetty-overlay-deployer/src/test/java/org/eclipse/jetty/overlays/OverlayServer.java
@@ -86,7 +86,7 @@ public class OverlayServer
server.setStopAtShutdown(true);
//server.setSendServerVersion(true);
- // Uncomment to work with JNDI examples
+ // Uncomment to work with JNDI examples
// new org.eclipse.jetty.plus.jndi.Transaction(new com.atomikos.icatch.jta.UserTransactionImp());
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java
index 321a9ab7f5f..8176916cc54 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java
@@ -19,7 +19,6 @@
package org.eclipse.jetty.plus.annotation;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -158,7 +157,7 @@ public class ContainerInitializer
interested.add(c.getName());
}
- return String.format("ContainerInitializer{%s,interested=%s,applicable=%s,annotated=%s}",_target.getClass().getName(),interested,_applicableTypeNames,_annotatedTypeNames);
+ return String.format("ContainerInitializer{%s,interested=%s,applicable=%s,annotated=%s}",_target.getClass().getName(),interested,_applicableTypeNames,_annotatedTypeNames);
}
public void resolveClasses(WebAppContext context, Map> classMap)
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java
index b315682f8fc..1c8edde16ba 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java
@@ -41,12 +41,11 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.security.Password;
+import org.eclipse.jetty.util.security.Credential;
/**
*
- * //TODO JASPI cf JDBCLoginService
* DataSourceUserRealm
*
* Obtain user/password/role information from a database
@@ -70,6 +69,7 @@ public class DataSourceLoginService extends MappedLoginService
private String _userRoleTableUserKey = "user_id";
private String _userRoleTableRoleKey = "role_id";
private int _cacheMs = 30000;
+ private long _lastPurge = 0;
private String _userSql;
private String _roleSql;
private boolean _createTables = false;
@@ -282,7 +282,9 @@ public class DataSourceLoginService extends MappedLoginService
protected void loadUsers()
{
}
-
+
+
+
/* ------------------------------------------------------------ */
/** Load user's info from database.
*
@@ -293,9 +295,8 @@ public class DataSourceLoginService extends MappedLoginService
{
try
{
- initDb();
try (Connection connection = getConnection();
- PreparedStatement statement1 = connection.prepareStatement(_userSql))
+ PreparedStatement statement1 = connection.prepareStatement(_userSql))
{
statement1.setObject(1, userName);
try (ResultSet rs1 = statement1.executeQuery())
@@ -311,10 +312,12 @@ public class DataSourceLoginService extends MappedLoginService
try (ResultSet rs2 = statement2.executeQuery())
{
while (rs2.next())
+ {
roles.add(rs2.getString(_roleTableRoleField));
+ }
}
}
- return putUser(userName,new Password(credentials), roles.toArray(new String[roles.size()]));
+ return putUser(userName, Credential.getCredential(credentials), roles.toArray(new String[roles.size()]));
}
}
}
@@ -329,6 +332,22 @@ public class DataSourceLoginService extends MappedLoginService
}
return null;
}
+
+
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public UserIdentity login(String username, Object credentials)
+ {
+ long now = System.currentTimeMillis();
+ if (now - _lastPurge > _cacheMs || _cacheMs == 0)
+ {
+ _users.clear();
+ _lastPurge = now;
+ }
+
+ return super.login(username,credentials);
+ }
/* ------------------------------------------------------------ */
/**
@@ -347,7 +366,7 @@ public class DataSourceLoginService extends MappedLoginService
InitialContext ic = new InitialContext();
assert ic!=null;
- //TODO webapp scope?
+ //TODO Should we try webapp scope too?
//try finding the datasource in the Server scope
if (_server != null)
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java
index 068c03b0afd..ed609ba2a47 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java
@@ -40,7 +40,6 @@ import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.AbstractConfiguration;
-import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java
index 6ebc85ca219..518051d6901 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java
@@ -60,7 +60,8 @@ public class AsyncProxyServlet extends ProxyServlet
{
try
{
- _log.debug("{} proxying content to downstream: {} bytes", getRequestId(request), length);
+ if (_log.isDebugEnabled())
+ _log.debug("{} proxying content to downstream: {} bytes", getRequestId(request), length);
StreamWriter writeListener = (StreamWriter)request.getAttribute(WRITE_LISTENER_ATTRIBUTE);
if (writeListener == null)
{
@@ -130,24 +131,30 @@ public class AsyncProxyServlet extends ProxyServlet
{
int requestId = getRequestId(request);
ServletInputStream input = request.getInputStream();
- _log.debug("{} asynchronous read start on {}", requestId, input);
+ if (_log.isDebugEnabled())
+ _log.debug("{} asynchronous read start on {}", requestId, input);
// First check for isReady() because it has
// side effects, and then for isFinished().
while (input.isReady() && !input.isFinished())
{
int read = input.read(buffer);
- _log.debug("{} asynchronous read {} bytes on {}", requestId, read, input);
+ if (_log.isDebugEnabled())
+ _log.debug("{} asynchronous read {} bytes on {}", requestId, read, input);
if (read > 0)
{
- _log.debug("{} proxying content to upstream: {} bytes", requestId, read);
+ if (_log.isDebugEnabled())
+ _log.debug("{} proxying content to upstream: {} bytes", requestId, read);
onRequestContent(proxyRequest, request, provider, buffer, 0, read, this);
// Do not call isReady() so that we can apply backpressure.
break;
}
}
if (!input.isFinished())
- _log.debug("{} asynchronous read pending on {}", requestId, input);
+ {
+ if (_log.isDebugEnabled())
+ _log.debug("{} asynchronous read pending on {}", requestId, input);
+ }
}
protected void onRequestContent(Request proxyRequest, HttpServletRequest request, DeferredContentProvider provider, byte[] buffer, int offset, int length, Callback callback)
@@ -158,7 +165,8 @@ public class AsyncProxyServlet extends ProxyServlet
@Override
public void onAllDataRead() throws IOException
{
- _log.debug("{} proxying content to upstream completed", getRequestId(request));
+ if (_log.isDebugEnabled())
+ _log.debug("{} proxying content to upstream completed", getRequestId(request));
provider.close();
}
@@ -225,23 +233,27 @@ public class AsyncProxyServlet extends ProxyServlet
if (state == WriteState.READY)
{
// There is data to write.
- _log.debug("{} asynchronous write start of {} bytes on {}", requestId, length, output);
+ if (_log.isDebugEnabled())
+ _log.debug("{} asynchronous write start of {} bytes on {}", requestId, length, output);
output.write(buffer, offset, length);
state = WriteState.PENDING;
if (output.isReady())
{
- _log.debug("{} asynchronous write of {} bytes completed on {}", requestId, length, output);
+ if (_log.isDebugEnabled())
+ _log.debug("{} asynchronous write of {} bytes completed on {}", requestId, length, output);
complete();
}
else
{
- _log.debug("{} asynchronous write of {} bytes pending on {}", requestId, length, output);
+ if (_log.isDebugEnabled())
+ _log.debug("{} asynchronous write of {} bytes pending on {}", requestId, length, output);
}
}
else if (state == WriteState.PENDING)
{
// The write blocked but is now complete.
- _log.debug("{} asynchronous write of {} bytes completing on {}", requestId, length, output);
+ if (_log.isDebugEnabled())
+ _log.debug("{} asynchronous write of {} bytes completing on {}", requestId, length, output);
complete();
}
else
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/BalancerServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/BalancerServlet.java
index 68771345216..ff4ae867dbb 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/BalancerServlet.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/BalancerServlet.java
@@ -26,12 +26,13 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
-
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
+import org.eclipse.jetty.util.URIUtil;
+
public class BalancerServlet extends ProxyServlet
{
private static final String BALANCER_MEMBER_PREFIX = "balancerMember.";
@@ -86,7 +87,7 @@ public class BalancerServlet extends ProxyServlet
}
}
- private void initStickySessions() throws ServletException
+ private void initStickySessions()
{
_stickySessions = Boolean.parseBoolean(getServletConfig().getInitParameter("stickySessions"));
}
@@ -131,7 +132,8 @@ public class BalancerServlet extends ProxyServlet
protected URI rewriteURI(HttpServletRequest request)
{
BalancerMember balancerMember = selectBalancerMember(request);
- _log.debug("Selected {}", balancerMember);
+ if (_log.isDebugEnabled())
+ _log.debug("Selected {}", balancerMember);
String path = request.getRequestURI();
String query = request.getQueryString();
if (query != null)
@@ -219,17 +221,17 @@ public class BalancerServlet extends ProxyServlet
URI locationURI = URI.create(headerValue).normalize();
if (locationURI.isAbsolute() && isBackendLocation(locationURI))
{
- String newURI = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
+ StringBuilder newURI = URIUtil.newURIBuilder(request.getScheme(), request.getServerName(), request.getServerPort());
String component = locationURI.getRawPath();
if (component != null)
- newURI += component;
+ newURI.append(component);
component = locationURI.getRawQuery();
if (component != null)
- newURI += "?" + component;
+ newURI.append('?').append(component);
component = locationURI.getRawFragment();
if (component != null)
- newURI += "#" + component;
- return URI.create(newURI).normalize().toString();
+ newURI.append('#').append(component);
+ return URI.create(newURI.toString()).normalize().toString();
}
}
return headerValue;
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java
index 5a550145976..b43ce7338c3 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java
@@ -186,7 +186,8 @@ public class ConnectHandler extends HandlerWrapper
if (HttpMethod.CONNECT.is(request.getMethod()))
{
String serverAddress = request.getRequestURI();
- LOG.debug("CONNECT request for {}", serverAddress);
+ if (LOG.isDebugEnabled())
+ LOG.debug("CONNECT request for {}", serverAddress);
try
{
handleConnect(baseRequest, request, response, serverAddress);
@@ -222,7 +223,8 @@ public class ConnectHandler extends HandlerWrapper
boolean proceed = handleAuthentication(request, response, serverAddress);
if (!proceed)
{
- LOG.debug("Missing proxy authentication");
+ if (LOG.isDebugEnabled())
+ LOG.debug("Missing proxy authentication");
sendConnectResponse(request, response, HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED);
return;
}
@@ -238,7 +240,8 @@ public class ConnectHandler extends HandlerWrapper
if (!validateDestination(host, port))
{
- LOG.debug("Destination {}:{} forbidden", host, port);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Destination {}:{} forbidden", host, port);
sendConnectResponse(request, response, HttpServletResponse.SC_FORBIDDEN);
return;
}
@@ -252,7 +255,8 @@ public class ConnectHandler extends HandlerWrapper
AsyncContext asyncContext = request.startAsync();
asyncContext.setTimeout(0);
- LOG.debug("Connecting to {}", address);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Connecting to {}", address);
ConnectContext connectContext = new ConnectContext(request, response, asyncContext, HttpConnection.getCurrentConnection());
selector.connect(channel, connectContext);
}
@@ -286,7 +290,8 @@ public class ConnectHandler extends HandlerWrapper
upstreamConnection.setConnection(downstreamConnection);
downstreamConnection.setConnection(upstreamConnection);
- LOG.debug("Connection setup completed: {}<->{}", downstreamConnection, upstreamConnection);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Connection setup completed: {}<->{}", downstreamConnection, upstreamConnection);
HttpServletResponse response = connectContext.getResponse();
sendConnectResponse(request, response, HttpServletResponse.SC_OK);
@@ -297,7 +302,8 @@ public class ConnectHandler extends HandlerWrapper
protected void onConnectFailure(HttpServletRequest request, HttpServletResponse response, AsyncContext asyncContext, Throwable failure)
{
- LOG.debug("CONNECT failed", failure);
+ if (LOG.isDebugEnabled())
+ LOG.debug("CONNECT failed", failure);
sendConnectResponse(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
if (asyncContext != null)
asyncContext.complete();
@@ -311,7 +317,8 @@ public class ConnectHandler extends HandlerWrapper
if (statusCode != HttpServletResponse.SC_OK)
response.setHeader(HttpHeader.CONNECTION.asString(), HttpHeaderValue.CLOSE.asString());
response.getOutputStream().close();
- LOG.debug("CONNECT response sent {} {}", request.getProtocol(), response.getStatus());
+ if (LOG.isDebugEnabled())
+ LOG.debug("CONNECT response sent {} {}", request.getProtocol(), response.getStatus());
}
catch (IOException x)
{
@@ -353,7 +360,8 @@ public class ConnectHandler extends HandlerWrapper
// so that Jetty understands that it has to upgrade the connection
request.setAttribute(HttpConnection.UPGRADE_CONNECTION_ATTRIBUTE, connection);
response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
- LOG.debug("Upgraded connection to {}", connection);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Upgraded connection to {}", connection);
}
/**
@@ -379,7 +387,8 @@ public class ConnectHandler extends HandlerWrapper
*/
protected void write(EndPoint endPoint, ByteBuffer buffer, Callback callback)
{
- LOG.debug("{} writing {} bytes", this, buffer.remaining());
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} writing {} bytes", this, buffer.remaining());
endPoint.write(callback, buffer);
}
@@ -407,7 +416,8 @@ public class ConnectHandler extends HandlerWrapper
{
if (!whiteList.contains(hostPort))
{
- LOG.debug("Host {}:{} not whitelisted", host, port);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Host {}:{} not whitelisted", host, port);
return false;
}
}
@@ -415,7 +425,8 @@ public class ConnectHandler extends HandlerWrapper
{
if (blackList.contains(hostPort))
{
- LOG.debug("Host {}:{} blacklisted", host, port);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Host {}:{} blacklisted", host, port);
return false;
}
}
@@ -445,7 +456,8 @@ public class ConnectHandler extends HandlerWrapper
@Override
public Connection newConnection(SocketChannel channel, EndPoint endpoint, Object attachment) throws IOException
{
- ConnectHandler.LOG.debug("Connected to {}", channel.getRemoteAddress());
+ if (ConnectHandler.LOG.isDebugEnabled())
+ ConnectHandler.LOG.debug("Connected to {}", channel.getRemoteAddress());
ConnectContext connectContext = (ConnectContext)attachment;
UpstreamConnection connection = newUpstreamConnection(endpoint, connectContext);
connection.setInputBufferSize(getBufferSize());
@@ -565,14 +577,16 @@ public class ConnectHandler extends HandlerWrapper
@Override
public void succeeded()
{
- LOG.debug("{} wrote initial {} bytes to server", DownstreamConnection.this, remaining);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} wrote initial {} bytes to server", DownstreamConnection.this, remaining);
fillInterested();
}
@Override
public void failed(Throwable x)
{
- LOG.debug(this + " failed to write initial " + remaining + " bytes to server", x);
+ if (LOG.isDebugEnabled())
+ LOG.debug(this + " failed to write initial " + remaining + " bytes to server", x);
close();
getConnection().close();
}
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyConnection.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyConnection.java
index 697de4fa4ce..3a620f43a17 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyConnection.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyConnection.java
@@ -28,13 +28,13 @@ import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.ForkInvoker;
+import org.eclipse.jetty.util.IteratingCallback;
import org.eclipse.jetty.util.log.Logger;
public abstract class ProxyConnection extends AbstractConnection
{
protected static final Logger LOG = ConnectHandler.LOG;
- private final ForkInvoker invoker = new ProxyForkInvoker();
+ private final IteratingCallback pipe = new ProxyIteratingCallback();
private final ByteBufferPool bufferPool;
private final ConcurrentMap context;
private Connection connection;
@@ -69,50 +69,7 @@ public abstract class ProxyConnection extends AbstractConnection
@Override
public void onFillable()
{
- final ByteBuffer buffer = getByteBufferPool().acquire(getInputBufferSize(), true);
- try
- {
- final int filled = read(getEndPoint(), buffer);
- LOG.debug("{} filled {} bytes", this, filled);
- if (filled > 0)
- {
- write(getConnection().getEndPoint(), buffer, new Callback()
- {
- @Override
- public void succeeded()
- {
- LOG.debug("{} wrote {} bytes", this, filled);
- bufferPool.release(buffer);
- invoker.invoke(null);
- }
-
- @Override
- public void failed(Throwable x)
- {
- LOG.debug(this + " failed to write " + filled + " bytes", x);
- bufferPool.release(buffer);
- connection.close();
- }
- });
- }
- else if (filled == 0)
- {
- bufferPool.release(buffer);
- fillInterested();
- }
- else
- {
- bufferPool.release(buffer);
- connection.getEndPoint().shutdownOutput();
- }
- }
- catch (IOException x)
- {
- LOG.debug(this + " could not fill", x);
- bufferPool.release(buffer);
- close();
- connection.close();
- }
+ pipe.iterate();
}
protected abstract int read(EndPoint endPoint, ByteBuffer buffer) throws IOException;
@@ -128,29 +85,74 @@ public abstract class ProxyConnection extends AbstractConnection
getEndPoint().getRemoteAddress().getPort());
}
- private class ProxyForkInvoker extends ForkInvoker implements Runnable
+ private class ProxyIteratingCallback extends IteratingCallback
{
- private ProxyForkInvoker()
+ private ByteBuffer buffer;
+ private int filled;
+
+ @Override
+ protected Action process() throws Exception
{
- super(4);
+ buffer = bufferPool.acquire(getInputBufferSize(), true);
+ try
+ {
+ int filled = this.filled = read(getEndPoint(), buffer);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} filled {} bytes", ProxyConnection.this, filled);
+ if (filled > 0)
+ {
+ write(connection.getEndPoint(), buffer, this);
+ return Action.SCHEDULED;
+ }
+ else if (filled == 0)
+ {
+ bufferPool.release(buffer);
+ fillInterested();
+ return Action.IDLE;
+ }
+ else
+ {
+ bufferPool.release(buffer);
+ connection.getEndPoint().shutdownOutput();
+ return Action.SUCCEEDED;
+ }
+ }
+ catch (IOException x)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug(ProxyConnection.this + " could not fill", x);
+ disconnect();
+ return Action.SUCCEEDED;
+ }
}
@Override
- public void fork(Void arg)
+ public void succeeded()
{
- getExecutor().execute(this);
- }
-
- @Override
- public void run()
- {
- onFillable();
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} wrote {} bytes", ProxyConnection.this, filled);
+ bufferPool.release(buffer);
+ super.succeeded();
}
@Override
- public void call(Void arg)
+ protected void onCompleteSuccess()
{
- onFillable();
+ }
+
+ @Override
+ protected void onCompleteFailure(Throwable x)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug(ProxyConnection.this + " failed to write " + filled + " bytes", x);
+ disconnect();
+ }
+
+ private void disconnect()
+ {
+ bufferPool.release(buffer);
+ ProxyConnection.this.close();
+ connection.close();
}
}
}
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java
index 7dbe2a9bb48..ed00af25641 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java
@@ -201,7 +201,8 @@ public class ProxyServlet extends HttpServlet
}
catch (Exception x)
{
- _log.debug(x);
+ if (_log.isDebugEnabled())
+ _log.debug(x);
}
}
@@ -362,7 +363,8 @@ public class ProxyServlet extends HttpServlet
{
if (!_whiteList.contains(hostPort))
{
- _log.debug("Host {}:{} not whitelisted", host, port);
+ if (_log.isDebugEnabled())
+ _log.debug("Host {}:{} not whitelisted", host, port);
return false;
}
}
@@ -370,7 +372,8 @@ public class ProxyServlet extends HttpServlet
{
if (_blackList.contains(hostPort))
{
- _log.debug("Host {}:{} blacklisted", host, port);
+ if (_log.isDebugEnabled())
+ _log.debug("Host {}:{} blacklisted", host, port);
return false;
}
}
@@ -389,7 +392,8 @@ public class ProxyServlet extends HttpServlet
StringBuffer uri = request.getRequestURL();
if (request.getQueryString() != null)
uri.append("?").append(request.getQueryString());
- _log.debug("{} rewriting: {} -> {}", requestId, uri, rewrittenURI);
+ if (_log.isDebugEnabled())
+ _log.debug("{} rewriting: {} -> {}", requestId, uri, rewrittenURI);
}
if (rewrittenURI == null)
@@ -493,7 +497,8 @@ public class ProxyServlet extends HttpServlet
protected void onClientRequestFailure(Request proxyRequest, HttpServletRequest request, Throwable failure)
{
- _log.debug(getRequestId(request) + " client request failure", failure);
+ if (_log.isDebugEnabled())
+ _log.debug(getRequestId(request) + " client request failure", failure);
proxyRequest.abort(failure);
}
@@ -517,10 +522,6 @@ public class ProxyServlet extends HttpServlet
protected void onResponseHeaders(HttpServletRequest request, HttpServletResponse response, Response proxyResponse)
{
- // Clear the response headers in case it comes with predefined ones.
- for (String name : response.getHeaderNames())
- response.setHeader(name, null);
-
for (HttpField field : proxyResponse.getHeaders())
{
String headerName = field.getName();
@@ -540,7 +541,8 @@ public class ProxyServlet extends HttpServlet
{
try
{
- _log.debug("{} proxying content to downstream: {} bytes", getRequestId(request), length);
+ if (_log.isDebugEnabled())
+ _log.debug("{} proxying content to downstream: {} bytes", getRequestId(request), length);
response.getOutputStream().write(buffer, offset, length);
callback.succeeded();
}
@@ -552,16 +554,34 @@ public class ProxyServlet extends HttpServlet
protected void onResponseSuccess(HttpServletRequest request, HttpServletResponse response, Response proxyResponse)
{
- _log.debug("{} proxying successful", getRequestId(request));
+ if (_log.isDebugEnabled())
+ _log.debug("{} proxying successful", getRequestId(request));
AsyncContext asyncContext = request.getAsyncContext();
asyncContext.complete();
}
protected void onResponseFailure(HttpServletRequest request, HttpServletResponse response, Response proxyResponse, Throwable failure)
{
- _log.debug(getRequestId(request) + " proxying failed", failure);
- if (!response.isCommitted())
+ if (_log.isDebugEnabled())
+ _log.debug(getRequestId(request) + " proxying failed", failure);
+ if (response.isCommitted())
{
+ try
+ {
+ // Use Jetty specific behavior to close connection.
+ response.sendError(-1);
+ AsyncContext asyncContext = request.getAsyncContext();
+ asyncContext.complete();
+ }
+ catch (IOException x)
+ {
+ if (_log.isDebugEnabled())
+ _log.debug(getRequestId(request) + " could not close the connection", failure);
+ }
+ }
+ else
+ {
+ response.resetBuffer();
if (failure instanceof TimeoutException)
response.setStatus(HttpServletResponse.SC_GATEWAY_TIMEOUT);
else
@@ -674,7 +694,8 @@ public class ProxyServlet extends HttpServlet
String contextPath = config.getServletContext().getContextPath();
_prefix = _prefix == null ? contextPath : (contextPath + _prefix);
- proxyServlet._log.debug(config.getServletName() + " @ " + _prefix + " to " + _proxyTo);
+ if (proxyServlet._log.isDebugEnabled())
+ proxyServlet._log.debug(config.getServletName() + " @ " + _prefix + " to " + _proxyTo);
}
protected URI rewriteURI(HttpServletRequest request)
@@ -794,7 +815,8 @@ public class ProxyServlet extends HttpServlet
onResponseSuccess(request, response, result.getResponse());
else
onResponseFailure(request, response, result.getResponse(), result.getFailure());
- _log.debug("{} proxying complete", getRequestId(request));
+ if (_log.isDebugEnabled())
+ _log.debug("{} proxying complete", getRequestId(request));
}
}
@@ -819,7 +841,8 @@ public class ProxyServlet extends HttpServlet
@Override
protected ByteBuffer onRead(byte[] buffer, int offset, int length)
{
- _log.debug("{} proxying content to upstream: {} bytes", getRequestId(request), length);
+ if (_log.isDebugEnabled())
+ _log.debug("{} proxying content to upstream: {} bytes", getRequestId(request), length);
return onRequestContent(proxyRequest, request, buffer, offset, length);
}
diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java
index 5884a14f829..9641c88163c 100644
--- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java
+++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java
@@ -19,8 +19,10 @@
package org.eclipse.jetty.proxy;
import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ConnectException;
@@ -30,6 +32,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -42,7 +45,14 @@ import java.util.zip.GZIPOutputStream;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@@ -55,11 +65,16 @@ import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
+import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.client.util.BytesContentProvider;
+import org.eclipse.jetty.client.util.InputStreamResponseListener;
import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
@@ -95,6 +110,7 @@ public class ProxyServletTest
private HttpClient client;
private Server proxy;
private ServerConnector proxyConnector;
+ private ServletContextHandler proxyContext;
private ProxyServlet proxyServlet;
private Server server;
private ServerConnector serverConnector;
@@ -112,13 +128,20 @@ public class ProxyServletTest
private void prepareProxy(Map initParams) throws Exception
{
proxy = new Server();
- proxyConnector = new ServerConnector(proxy);
+
+ HttpConfiguration configuration = new HttpConfiguration();
+ configuration.setSendDateHeader(false);
+ configuration.setSendServerVersion(false);
+ String value = initParams.get("outputBufferSize");
+ if (value != null)
+ configuration.setOutputBufferSize(Integer.valueOf(value));
+ proxyConnector = new ServerConnector(proxy, new HttpConnectionFactory(configuration));
proxy.addConnector(proxyConnector);
- ServletContextHandler proxyCtx = new ServletContextHandler(proxy, "/", true, false);
+ proxyContext = new ServletContextHandler(proxy, "/", true, false);
ServletHolder proxyServletHolder = new ServletHolder(proxyServlet);
proxyServletHolder.setInitParameters(initParams);
- proxyCtx.addServlet(proxyServletHolder, "/*");
+ proxyContext.addServlet(proxyServletHolder, "/*");
proxy.start();
@@ -899,5 +922,184 @@ public class ProxyServletTest
Assert.assertTrue(response3.getHeaders().containsKey(PROXIED_HEADER));
}
+ @Test
+ public void testProxyRequestFailureInTheMiddleOfProxyingSmallContent() throws Exception
+ {
+ final long proxyTimeout = 1000;
+ Map proxyParams = new HashMap<>();
+ proxyParams.put("timeout", String.valueOf(proxyTimeout));
+ prepareProxy(proxyParams);
+
+ final CountDownLatch chunk1Latch = new CountDownLatch(1);
+ final int chunk1 = 'q';
+ final int chunk2 = 'w';
+ prepareServer(new HttpServlet()
+ {
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ ServletOutputStream output = response.getOutputStream();
+ output.write(chunk1);
+ response.flushBuffer();
+
+ // Wait for the client to receive this chunk.
+ await(chunk1Latch, 5000);
+
+ // Send second chunk, must not be received by proxy.
+ output.write(chunk2);
+ }
+
+ private boolean await(CountDownLatch latch, long ms) throws IOException
+ {
+ try
+ {
+ return latch.await(ms, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException x)
+ {
+ throw new InterruptedIOException();
+ }
+ }
+ });
+
+ HttpClient client = prepareClient();
+ InputStreamResponseListener listener = new InputStreamResponseListener();
+ int port = serverConnector.getLocalPort();
+ client.newRequest("localhost", port).send(listener);
+
+ // Make the proxy request fail; given the small content, the
+ // proxy-to-client response is not committed yet so it will be reset.
+ TimeUnit.MILLISECONDS.sleep(2 * proxyTimeout);
+
+ Response response = listener.get(5, TimeUnit.SECONDS);
+ Assert.assertEquals(504, response.getStatus());
+
+ // Make sure there is no content, as the proxy-to-client response has been reset.
+ InputStream input = listener.getInputStream();
+ Assert.assertEquals(-1, input.read());
+
+ chunk1Latch.countDown();
+
+ // Result succeeds because a 504 is a valid HTTP response.
+ Result result = listener.await(5, TimeUnit.SECONDS);
+ Assert.assertTrue(result.isSucceeded());
+
+ // Make sure the proxy does not receive chunk2.
+ Assert.assertEquals(-1, input.read());
+
+ HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination("http", "localhost", port);
+ Assert.assertEquals(0, destination.getConnectionPool().getIdleConnections().size());
+ }
+
+ @Test
+ public void testProxyRequestFailureInTheMiddleOfProxyingBigContent() throws Exception
+ {
+ final long proxyTimeout = 1000;
+ int outputBufferSize = 1024;
+ Map proxyParams = new HashMap<>();
+ proxyParams.put("timeout", String.valueOf(proxyTimeout));
+ proxyParams.put("outputBufferSize", String.valueOf(outputBufferSize));
+ prepareProxy(proxyParams);
+
+ final CountDownLatch chunk1Latch = new CountDownLatch(1);
+ final byte[] chunk1 = new byte[outputBufferSize];
+ new Random().nextBytes(chunk1);
+ final int chunk2 = 'w';
+ prepareServer(new HttpServlet()
+ {
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ ServletOutputStream output = response.getOutputStream();
+ output.write(chunk1);
+ response.flushBuffer();
+
+ // Wait for the client to receive this chunk.
+ await(chunk1Latch, 5000);
+
+ // Send second chunk, must not be received by proxy.
+ output.write(chunk2);
+ }
+
+ private boolean await(CountDownLatch latch, long ms) throws IOException
+ {
+ try
+ {
+ return latch.await(ms, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException x)
+ {
+ throw new InterruptedIOException();
+ }
+ }
+ });
+
+ HttpClient client = prepareClient();
+ InputStreamResponseListener listener = new InputStreamResponseListener();
+ int port = serverConnector.getLocalPort();
+ client.newRequest("localhost", port).send(listener);
+
+ Response response = listener.get(5, TimeUnit.SECONDS);
+ Assert.assertEquals(200, response.getStatus());
+
+ InputStream input = listener.getInputStream();
+ for (int i = 0; i < chunk1.length; ++i)
+ Assert.assertEquals(chunk1[i] & 0xFF, input.read());
+
+ TimeUnit.MILLISECONDS.sleep(2 * proxyTimeout);
+
+ chunk1Latch.countDown();
+
+ try
+ {
+ // Make sure the proxy does not receive chunk2.
+ input.read();
+ Assert.fail();
+ }
+ catch (EOFException x)
+ {
+ // Expected
+ }
+
+ HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination("http", "localhost", port);
+ Assert.assertEquals(0, destination.getConnectionPool().getIdleConnections().size());
+ }
+
+ @Test
+ public void testResponseHeadersAreNotRemoved() throws Exception
+ {
+ prepareProxy();
+ proxyContext.stop();
+ final String headerName = "X-Test";
+ final String headerValue = "test-value";
+ proxyContext.addFilter(new FilterHolder(new Filter()
+ {
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException
+ {
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
+ {
+ ((HttpServletResponse)response).addHeader(headerName, headerValue);
+ chain.doFilter(request, response);
+ }
+
+ @Override
+ public void destroy()
+ {
+ }
+ }), "/*", EnumSet.of(DispatcherType.REQUEST));
+ proxyContext.start();
+ prepareServer(new EmptyHttpServlet());
+
+ HttpClient client = prepareClient();
+ ContentResponse response = client.newRequest("localhost", serverConnector.getLocalPort()).send();
+
+ Assert.assertEquals(200, response.getStatus());
+ Assert.assertEquals(headerValue, response.getHeaders().get(headerName));
+ }
+
// TODO: test proxy authentication
}
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java
index 313c5c03c86..85f95dcb6ab 100644
--- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java
@@ -72,7 +72,23 @@ public class QuickStartConfiguration extends WebInfConfiguration
LOG.debug("webapp={}",webApp);
- //look for effective-web.xml in WEB-INF of webapp
+ //look for quickstart-web.xml in WEB-INF of webapp
+ Resource quickStartWebXml = getQuickStartWebXml(context);
+ LOG.debug("quickStartWebXml={}",quickStartWebXml);
+
+ context.getMetaData().setWebXml(quickStartWebXml);
+ }
+
+
+ /**
+ * Get the quickstart-web.xml file as a Resource.
+ *
+ * @param context
+ * @return
+ * @throws Exception
+ */
+ public Resource getQuickStartWebXml (WebAppContext context) throws Exception
+ {
Resource webInf = context.getWebInf();
if (webInf == null || !webInf.exists())
throw new IllegalStateException("No WEB-INF");
@@ -81,11 +97,10 @@ public class QuickStartConfiguration extends WebInfConfiguration
Resource quickStartWebXml = webInf.addPath("quickstart-web.xml");
if (!quickStartWebXml.exists())
throw new IllegalStateException ("No WEB-INF/quickstart-web.xml");
- LOG.debug("quickStartWebXml={}",quickStartWebXml);
-
- context.getMetaData().setWebXml(quickStartWebXml);
+ return quickStartWebXml;
}
-
+
+
/**
* @see org.eclipse.jetty.webapp.AbstractConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext)
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java
new file mode 100644
index 00000000000..5a56625fb00
--- /dev/null
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java
@@ -0,0 +1,659 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+
+package org.eclipse.jetty.quickstart;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.MultipartConfigElement;
+import javax.servlet.ServletContext;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.descriptor.JspPropertyGroupDescriptor;
+import javax.servlet.descriptor.TaglibDescriptor;
+
+import org.eclipse.jetty.annotations.AnnotationConfiguration;
+import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.plus.annotation.LifeCycleCallback;
+import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
+import org.eclipse.jetty.security.ConstraintAware;
+import org.eclipse.jetty.security.ConstraintMapping;
+import org.eclipse.jetty.security.SecurityHandler;
+import org.eclipse.jetty.security.authentication.FormAuthenticator;
+import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlet.FilterMapping;
+import org.eclipse.jetty.servlet.Holder;
+import org.eclipse.jetty.servlet.ServletHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.servlet.ServletMapping;
+import org.eclipse.jetty.servlet.ServletContextHandler.JspConfig;
+import org.eclipse.jetty.util.QuotedStringTokenizer;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.security.Constraint;
+import org.eclipse.jetty.webapp.MetaData;
+import org.eclipse.jetty.webapp.MetaData.OriginInfo;
+import org.eclipse.jetty.webapp.MetaInfConfiguration;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.xml.XmlAppendable;
+
+
+
+/**
+ * QuickStartDescriptorGenerator
+ *
+ * Generate an effective web.xml from a WebAppContext, including all components
+ * from web.xml, web-fragment.xmls annotations etc.
+ */
+public class QuickStartDescriptorGenerator
+{
+ private static final Logger LOG = Log.getLogger(QuickStartDescriptorGenerator.class);
+
+ public static final String DEFAULT_QUICKSTART_DESCRIPTOR_NAME = "quickstart-web.xml";
+
+ protected WebAppContext _webApp;
+ protected String _extraXML;
+
+
+
+ /**
+ * @param w the source WebAppContext
+ * @param extraXML any extra xml snippet to append
+ */
+ public QuickStartDescriptorGenerator (WebAppContext w, String extraXML)
+ {
+ _webApp = w;
+ _extraXML = extraXML;
+ }
+
+
+ /**
+ * Perform the generation of the xml file
+ * @throws IOException
+ * @throws FileNotFoundException
+ * @throws Exception
+ */
+ public void generateQuickStartWebXml (OutputStream stream) throws FileNotFoundException, IOException
+ {
+ if (_webApp == null)
+ throw new IllegalStateException("No webapp for quickstart generation");
+ if (stream == null)
+ throw new IllegalStateException("No output for quickstart generation");
+
+ _webApp.getMetaData().getOrigins();
+
+ if (_webApp.getBaseResource()==null)
+ throw new IllegalArgumentException("No base resource for "+this);
+
+ LOG.info("Quickstart generating");
+
+ XmlAppendable out = new XmlAppendable(stream,"UTF-8");
+
+ MetaData md = _webApp.getMetaData();
+
+ Map webappAttr = new HashMap<>();
+ webappAttr.put("xmlns","http://xmlns.jcp.org/xml/ns/javaee");
+ webappAttr.put("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
+ webappAttr.put("xsi:schemaLocation","http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd");
+ webappAttr.put("metadata-complete","true");
+ webappAttr.put("version","3.1");
+
+ out.openTag("web-app",webappAttr);
+ if (_webApp.getDisplayName() != null)
+ out.tag("display-name",_webApp.getDisplayName());
+
+ // Set some special context parameters
+
+ // The location of the war file on disk
+ String resourceBase = _webApp.getBaseResource().getFile().getCanonicalFile().getAbsoluteFile().toURI().toString();
+
+ // The library order
+ addContextParamFromAttribute(out,ServletContext.ORDERED_LIBS);
+ //the servlet container initializers
+ addContextParamFromAttribute(out,AnnotationConfiguration.CONTAINER_INITIALIZERS);
+ //the tlds discovered
+ addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_TLDS,resourceBase);
+ //the META-INF/resources discovered
+ addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_RESOURCES,resourceBase);
+
+
+ // init params
+ for (String p : _webApp.getInitParams().keySet())
+ out.openTag("context-param",origin(md,"context-param." + p))
+ .tag("param-name",p)
+ .tag("param-value",_webApp.getInitParameter(p))
+ .closeTag();
+
+ if (_webApp.getEventListeners() != null)
+ for (EventListener e : _webApp.getEventListeners())
+ out.openTag("listener",origin(md,e.getClass().getCanonicalName() + ".listener"))
+ .tag("listener-class",e.getClass().getCanonicalName())
+ .closeTag();
+
+ ServletHandler servlets = _webApp.getServletHandler();
+
+ if (servlets.getFilters() != null)
+ {
+ for (FilterHolder holder : servlets.getFilters())
+ outholder(out,md,"filter",holder);
+ }
+
+ if (servlets.getFilterMappings() != null)
+ {
+ for (FilterMapping mapping : servlets.getFilterMappings())
+ {
+ out.openTag("filter-mapping");
+ out.tag("filter-name",mapping.getFilterName());
+ if (mapping.getPathSpecs() != null)
+ for (String s : mapping.getPathSpecs())
+ out.tag("url-pattern",s);
+ if (mapping.getServletNames() != null)
+ for (String n : mapping.getServletNames())
+ out.tag("servlet-name",n);
+
+ if (!mapping.isDefaultDispatches())
+ {
+ if (mapping.appliesTo(DispatcherType.REQUEST))
+ out.tag("dispatcher","REQUEST");
+ if (mapping.appliesTo(DispatcherType.ASYNC))
+ out.tag("dispatcher","ASYNC");
+ if (mapping.appliesTo(DispatcherType.ERROR))
+ out.tag("dispatcher","ERROR");
+ if (mapping.appliesTo(DispatcherType.FORWARD))
+ out.tag("dispatcher","FORWARD");
+ if (mapping.appliesTo(DispatcherType.INCLUDE))
+ out.tag("dispatcher","INCLUDE");
+ }
+ out.closeTag();
+ }
+ }
+
+ if (servlets.getServlets() != null)
+ {
+ for (ServletHolder holder : servlets.getServlets())
+ outholder(out,md,"servlet",holder);
+ }
+
+ if (servlets.getServletMappings() != null)
+ {
+ for (ServletMapping mapping : servlets.getServletMappings())
+ {
+ out.openTag("servlet-mapping",origin(md,mapping.getServletName() + ".servlet.mappings"));
+ out.tag("servlet-name",mapping.getServletName());
+ if (mapping.getPathSpecs() != null)
+ for (String s : mapping.getPathSpecs())
+ out.tag("url-pattern",s);
+ out.closeTag();
+ }
+ }
+
+ // Security elements
+ SecurityHandler security =_webApp. getSecurityHandler();
+
+ if (security!=null && (security.getRealmName()!=null || security.getAuthMethod()!=null))
+ {
+ out.openTag("login-config");
+ if (security.getAuthMethod()!=null)
+ out.tag("auth-method",origin(md,"auth-method"),security.getAuthMethod());
+ if (security.getRealmName()!=null)
+ out.tag("realm-name",origin(md,"realm-name"),security.getRealmName());
+
+
+ if (Constraint.__FORM_AUTH.equalsIgnoreCase(security.getAuthMethod()))
+ {
+ out.openTag("form-login-config");
+ out.tag("form-login-page",origin(md,"form-login-page"),security.getInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE));
+ out.tag("form-error-page",origin(md,"form-error-page"),security.getInitParameter(FormAuthenticator.__FORM_ERROR_PAGE));
+ out.closeTag();
+ }
+
+ out.closeTag();
+ }
+
+ if (security instanceof ConstraintAware)
+ {
+ ConstraintAware ca = (ConstraintAware)security;
+ for (String r:ca.getRoles())
+ out.openTag("security-role")
+ .tag("role-name",r)
+ .closeTag();
+
+ for (ConstraintMapping m : ca.getConstraintMappings())
+ {
+ out.openTag("security-constraint");
+
+ if (m.getConstraint().getAuthenticate())
+ {
+ out.openTag("auth-constraint");
+ if (m.getConstraint().getRoles()!=null)
+ for (String r : m.getConstraint().getRoles())
+ out.tag("role-name",r);
+
+ out.closeTag();
+ }
+
+ switch (m.getConstraint().getDataConstraint())
+ {
+ case Constraint.DC_NONE:
+ out.openTag("user-data-constraint").tag("transport-guarantee","NONE").closeTag();
+ break;
+
+ case Constraint.DC_INTEGRAL:
+ out.openTag("user-data-constraint").tag("transport-guarantee","INTEGRAL").closeTag();
+ break;
+
+ case Constraint.DC_CONFIDENTIAL:
+ out.openTag("user-data-constraint").tag("transport-guarantee","CONFIDENTIAL").closeTag();
+ break;
+
+ default:
+ break;
+
+ }
+
+ out.openTag("web-resource-collection");
+ {
+ if (m.getConstraint().getName()!=null)
+ out.tag("web-resource-name",m.getConstraint().getName());
+ if (m.getPathSpec()!=null)
+ out.tag("url-pattern",origin(md,"constraint.url."+m.getPathSpec()),m.getPathSpec());
+ if (m.getMethod()!=null)
+ out.tag("http-method",m.getMethod());
+
+ if (m.getMethodOmissions()!=null)
+ for (String o:m.getMethodOmissions())
+ out.tag("http-method-omission",o);
+
+ out.closeTag();
+ }
+
+ out.closeTag();
+
+ }
+ }
+
+ if (_webApp.getWelcomeFiles() != null)
+ {
+ out.openTag("welcome-file-list");
+ for (String welcomeFile:_webApp.getWelcomeFiles())
+ {
+ out.tag("welcome-file", welcomeFile);
+ }
+ out.closeTag();
+ }
+
+ Map localeEncodings = _webApp.getLocaleEncodings();
+ if (localeEncodings != null && !localeEncodings.isEmpty())
+ {
+ out.openTag("locale-encoding-mapping-list");
+ for (Map.Entry entry:localeEncodings.entrySet())
+ {
+ out.openTag("locale-encoding-mapping", origin(md,"locale-encoding."+entry.getKey()));
+ out.tag("locale", entry.getKey());
+ out.tag("encoding", entry.getValue());
+ out.closeTag();
+ }
+ out.closeTag();
+ }
+
+ //session-config
+ if (_webApp.getSessionHandler().getSessionManager() != null)
+ {
+ out.openTag("session-config");
+ int maxInactiveSec = _webApp.getSessionHandler().getSessionManager().getMaxInactiveInterval();
+ out.tag("session-timeout", (maxInactiveSec==0?"0":Integer.toString(maxInactiveSec/60)));
+
+ Set modes =_webApp. getSessionHandler().getSessionManager().getEffectiveSessionTrackingModes();
+ if (modes != null)
+ {
+ for (SessionTrackingMode mode:modes)
+ out.tag("tracking-mode", mode.toString());
+ }
+
+ //cookie-config
+ SessionCookieConfig cookieConfig = _webApp.getSessionHandler().getSessionManager().getSessionCookieConfig();
+ if (cookieConfig != null)
+ {
+ out.openTag("cookie-config");
+ if (cookieConfig.getName() != null)
+ out.tag("name", origin(md,"cookie-config.name"), cookieConfig.getName());
+
+ if (cookieConfig.getDomain() != null)
+ out.tag("domain", origin(md, "cookie-config.domain"), cookieConfig.getDomain());
+
+ if (cookieConfig.getPath() != null)
+ out.tag("path", origin(md, "cookie-config.path"), cookieConfig.getPath());
+
+ if (cookieConfig.getComment() != null)
+ out.tag("comment", origin(md, "cookie-config.comment"), cookieConfig.getComment());
+
+ out.tag("http-only", origin(md, "cookie-config.http-only"), Boolean.toString(cookieConfig.isHttpOnly()));
+ out.tag("secure", origin(md, "cookie-config.secure"), Boolean.toString(cookieConfig.isSecure()));
+ out.tag("max-age", origin(md, "cookie-config.max-age"), Integer.toString(cookieConfig.getMaxAge()));
+ out.closeTag();
+ }
+ out.closeTag();
+ }
+
+ //error-pages
+ Map errorPages = ((ErrorPageErrorHandler)_webApp.getErrorHandler()).getErrorPages();
+ if (errorPages != null)
+ {
+ for (Map.Entry entry:errorPages.entrySet())
+ {
+ out.openTag("error-page", origin(md, "error."+entry.getKey()));
+ //a global or default error page has no code or exception
+ if (!ErrorPageErrorHandler.GLOBAL_ERROR_PAGE.equals(entry.getKey()))
+ {
+ if (entry.getKey().matches("\\d{3}"))
+ out.tag("error-code", entry.getKey());
+ else
+ out.tag("exception-type", entry.getKey());
+ }
+ out.tag("location", entry.getValue());
+ out.closeTag();
+ }
+ }
+
+ //mime-types
+ MimeTypes mimeTypes = _webApp.getMimeTypes();
+ if (mimeTypes != null)
+ {
+ for (Map.Entry entry:mimeTypes.getMimeMap().entrySet())
+ {
+ out.openTag("mime-mapping");
+ out.tag("extension", origin(md, "extension."+entry.getKey()), entry.getKey());
+ out.tag("mime-type", entry.getValue());
+ out.closeTag();
+ }
+ }
+
+ //jsp-config
+ JspConfig jspConfig = (JspConfig)_webApp.getServletContext().getJspConfigDescriptor();
+ if (jspConfig != null)
+ {
+ out.openTag("jsp-config");
+ Collection tlds = jspConfig.getTaglibs();
+ if (tlds != null && !tlds.isEmpty())
+ {
+ for (TaglibDescriptor tld:tlds)
+ {
+ out.openTag("taglib");
+ out.tag("taglib-uri", tld.getTaglibURI());
+ out.tag("taglib-location", tld.getTaglibLocation());
+ out.closeTag();
+ }
+ }
+
+ Collection jspPropertyGroups = jspConfig.getJspPropertyGroups();
+ if (jspPropertyGroups != null && !jspPropertyGroups.isEmpty())
+ {
+ for (JspPropertyGroupDescriptor jspPropertyGroup:jspPropertyGroups)
+ {
+ out.openTag("jsp-property-group");
+ Collection strings = jspPropertyGroup.getUrlPatterns();
+ if (strings != null && !strings.isEmpty())
+ {
+ for (String urlPattern:strings)
+ out.tag("url-pattern", urlPattern);
+ }
+
+ if (jspPropertyGroup.getElIgnored() != null)
+ out.tag("el-ignored", jspPropertyGroup.getElIgnored());
+
+ if (jspPropertyGroup.getPageEncoding() != null)
+ out.tag("page-encoding", jspPropertyGroup.getPageEncoding());
+
+ if (jspPropertyGroup.getScriptingInvalid() != null)
+ out.tag("scripting-invalid", jspPropertyGroup.getScriptingInvalid());
+
+ if (jspPropertyGroup.getIsXml() != null)
+ out.tag("is-xml", jspPropertyGroup.getIsXml());
+
+ if (jspPropertyGroup.getDeferredSyntaxAllowedAsLiteral() != null)
+ out.tag("deferred-syntax-allowed-as-literal", jspPropertyGroup.getDeferredSyntaxAllowedAsLiteral());
+
+ if (jspPropertyGroup.getTrimDirectiveWhitespaces() != null)
+ out.tag("trim-directive-whitespaces", jspPropertyGroup.getTrimDirectiveWhitespaces());
+
+ if (jspPropertyGroup.getDefaultContentType() != null)
+ out.tag("default-content-type", jspPropertyGroup.getDefaultContentType());
+
+ if (jspPropertyGroup.getBuffer() != null)
+ out.tag("buffer", jspPropertyGroup.getBuffer());
+
+ if (jspPropertyGroup.getErrorOnUndeclaredNamespace() != null)
+ out.tag("error-on-undeclared-namespace", jspPropertyGroup.getErrorOnUndeclaredNamespace());
+
+ strings = jspPropertyGroup.getIncludePreludes();
+ if (strings != null && !strings.isEmpty())
+ {
+ for (String prelude:strings)
+ out.tag("include-prelude", prelude);
+ }
+
+ strings = jspPropertyGroup.getIncludeCodas();
+ if (strings != null && !strings.isEmpty())
+ {
+ for (String coda:strings)
+ out.tag("include-coda", coda);
+ }
+
+ out.closeTag();
+ }
+ }
+
+ out.closeTag();
+ }
+
+ //lifecycle: post-construct, pre-destroy
+ LifeCycleCallbackCollection lifecycles = ((LifeCycleCallbackCollection)_webApp.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION));
+ if (lifecycles != null)
+ {
+ Collection tmp = lifecycles.getPostConstructCallbacks();
+
+ for (LifeCycleCallback c:tmp)
+ {
+ out.openTag("post-construct");
+ out.tag("lifecycle-callback-class", c.getTargetClassName());
+ out.tag("lifecycle-callback-method", c.getMethodName());
+ out.closeTag();
+ }
+
+ tmp = lifecycles.getPreDestroyCallbacks();
+ for (LifeCycleCallback c:tmp)
+ {
+ out.openTag("pre-destroy");
+ out.tag("lifecycle-callback-class", c.getTargetClassName());
+ out.tag("lifecycle-callback-method", c.getMethodName());
+ out.closeTag();
+ }
+ }
+
+ out.literal(_extraXML);
+
+ out.closeTag();
+ }
+
+ /**
+ * Turn attribute into context-param to store.
+ *
+ * @param out
+ * @param attribute
+ * @throws IOException
+ */
+ private void addContextParamFromAttribute(XmlAppendable out, String attribute) throws IOException
+ {
+ addContextParamFromAttribute(out,attribute,null);
+ }
+
+ /**
+ * Turn context attribute into context-param to store.
+ *
+ * @param out
+ * @param attribute
+ * @param resourceBase
+ * @throws IOException
+ */
+ private void addContextParamFromAttribute(XmlAppendable out, String attribute, String resourceBase) throws IOException
+ {
+ Object o = _webApp.getAttribute(attribute);
+ if (o == null)
+ return;
+
+ Collection> c = (o instanceof Collection)? (Collection>)o:Collections.singletonList(o);
+ StringBuilder v=new StringBuilder();
+ for (Object i:c)
+ {
+ if (i!=null)
+ {
+ if (v.length()>0)
+ v.append(",\n ");
+ else
+ v.append("\n ");
+ if (resourceBase==null)
+ QuotedStringTokenizer.quote(v,i.toString());
+ else
+ QuotedStringTokenizer.quote(v,i.toString().replace(resourceBase,"${WAR}/"));
+ }
+ }
+ out.openTag("context-param")
+ .tag("param-name",attribute)
+ .tagCDATA("param-value",v.toString())
+ .closeTag();
+ }
+
+ /**
+ * Generate xml for a Holder (Filter/Servlet)
+ *
+ * @param out
+ * @param md
+ * @param tag
+ * @param holder
+ * @throws IOException
+ */
+ private void outholder(XmlAppendable out, MetaData md, String tag, Holder> holder) throws IOException
+ {
+ out.openTag(tag,Collections.singletonMap("source",holder.getSource().toString()));
+ String n = holder.getName();
+ out.tag(tag + "-name",n);
+
+ String ot = n + "." + tag + ".";
+
+ if (holder instanceof FilterHolder)
+ out.tag(tag + "-class",origin(md,ot + tag + "-class"),holder.getClassName());
+ else if (holder instanceof ServletHolder)
+ {
+ ServletHolder s = (ServletHolder)holder;
+ if (s.getForcedPath() != null && s.getClassName() == null)
+ out.tag("jsp-file",s.getForcedPath());
+ else
+ out.tag(tag + "-class",origin(md,ot + tag + "-class"),s.getClassName());
+
+ }
+
+ for (String p : holder.getInitParameters().keySet())
+ {
+ if ("scratchdir".equalsIgnoreCase(p)) //don't preconfigure the temp dir for jsp output
+ continue;
+ out.openTag("init-param",origin(md,ot + "init-param." + p))
+ .tag("param-name",p)
+ .tag("param-value",holder.getInitParameter(p))
+ .closeTag();
+ }
+
+ if (holder instanceof ServletHolder)
+ {
+ ServletHolder s = (ServletHolder)holder;
+ if (s.getInitOrder() >= 0)
+ out.tag("load-on-startup",Integer.toString(s.getInitOrder()));
+
+ if (s.getRunAsRole() != null)
+ out.openTag("run-as",origin(md,ot + "run-as"))
+ .tag("role-name",s.getRunAsRole())
+ .closeTag();
+
+ Map roles = s.getRoleRefMap();
+ if (roles!=null)
+ {
+ for (Map.Entry e : roles.entrySet())
+ {
+ out.openTag("security-role-ref",origin(md,ot+"role-name."+e.getKey()))
+ .tag("role-name",e.getKey())
+ .tag("role-link",e.getValue())
+ .closeTag();
+ }
+ }
+
+ if (!s.isEnabled())
+ out.tag("enabled",origin(md,ot + "enabled"),"false");
+
+ //multipart-config
+ MultipartConfigElement multipartConfig = ((ServletHolder.Registration)s.getRegistration()).getMultipartConfig();
+ if (multipartConfig != null)
+ {
+ out.openTag("multipart-config", origin(md, s.getName()+".servlet.multipart-config"));
+ if (multipartConfig.getLocation() != null)
+ out.tag("location", multipartConfig.getLocation());
+ out.tag("max-file-size", Long.toString(multipartConfig.getMaxFileSize()));
+ out.tag("max-request-size", Long.toString(multipartConfig.getMaxRequestSize()));
+ out.tag("file-size-threshold", Long.toString(multipartConfig.getFileSizeThreshold()));
+ out.closeTag();
+ }
+ }
+
+ out.tag("async-supported",origin(md,ot + "async-supported"),holder.isAsyncSupported()?"true":"false");
+ out.closeTag();
+ }
+
+
+
+ /**
+ * Find the origin (web.xml, fragment, annotation etc) of a web artifact from MetaData.
+ *
+ * @param md
+ * @param name
+ * @return
+ */
+ public Map origin(MetaData md, String name)
+ {
+ if (!LOG.isDebugEnabled())
+ return Collections.emptyMap();
+ if (name == null)
+ return Collections.emptyMap();
+ OriginInfo origin = md.getOriginInfo(name);
+ if (LOG.isDebugEnabled()) LOG.debug("origin of "+name+" is "+origin);
+ if (origin == null)
+ return Collections.emptyMap();
+ return Collections.singletonMap("origin",origin.toString());
+ }
+
+}
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartWebApp.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartWebApp.java
index bcbcab80808..0372e52cb99 100644
--- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartWebApp.java
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartWebApp.java
@@ -18,51 +18,13 @@
package org.eclipse.jetty.quickstart;
-import java.io.File;
import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EventListener;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import javax.servlet.DispatcherType;
-import javax.servlet.MultipartConfigElement;
-import javax.servlet.ServletContext;
-import javax.servlet.SessionCookieConfig;
-import javax.servlet.SessionTrackingMode;
-import javax.servlet.descriptor.JspPropertyGroupDescriptor;
-import javax.servlet.descriptor.TaglibDescriptor;
-
-import org.eclipse.jetty.annotations.AnnotationConfiguration;
-import org.eclipse.jetty.http.MimeTypes;
-import org.eclipse.jetty.plus.annotation.LifeCycleCallback;
-import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
-import org.eclipse.jetty.security.ConstraintAware;
-import org.eclipse.jetty.security.ConstraintMapping;
-import org.eclipse.jetty.security.SecurityHandler;
-import org.eclipse.jetty.security.authentication.FormAuthenticator;
-import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
-import org.eclipse.jetty.servlet.FilterHolder;
-import org.eclipse.jetty.servlet.FilterMapping;
-import org.eclipse.jetty.servlet.Holder;
-import org.eclipse.jetty.servlet.ServletHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.servlet.ServletMapping;
-import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.util.security.Constraint;
-import org.eclipse.jetty.webapp.MetaData;
-import org.eclipse.jetty.webapp.MetaData.OriginInfo;
-import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
-import org.eclipse.jetty.xml.XmlAppendable;
/**
* QuickStartWar
@@ -72,6 +34,8 @@ public class QuickStartWebApp extends WebAppContext
{
private static final Logger LOG = Log.getLogger(QuickStartWebApp.class);
+
+
public static final String[] __configurationClasses = new String[]
{
org.eclipse.jetty.quickstart.QuickStartConfiguration.class.getCanonicalName(),
@@ -190,8 +154,7 @@ public class QuickStartWebApp extends WebAppContext
{
LOG.info("Quickstart preconfigure: {}(war={},dir={})",this,war,dir);
- _preconfigProcessor = new PreconfigureDescriptorProcessor();
-
+ _preconfigProcessor = new PreconfigureDescriptorProcessor();
getMetaData().addDescriptorProcessor(_preconfigProcessor);
setPreconfigure(true);
_startWebapp=true;
@@ -203,518 +166,17 @@ public class QuickStartWebApp extends WebAppContext
}
- public void generateQuickstartWebXml(String extraXML) throws IOException
+ public void generateQuickstartWebXml(String extraXML) throws Exception
{
- getMetaData().getOrigins();
- // dumpStdErr();
-
- if (getBaseResource()==null)
- throw new IllegalArgumentException("No base resource for "+this);
-
- File webxml = new File(getWebInf().getFile(),"quickstart-web.xml");
-
- LOG.info("Quickstart generate {}",webxml);
-
- XmlAppendable out = new XmlAppendable(new FileOutputStream(webxml),"UTF-8");
- MetaData md = getMetaData();
-
- Map webappAttr = new HashMap<>();
- webappAttr.put("xmlns","http://xmlns.jcp.org/xml/ns/javaee");
- webappAttr.put("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
- webappAttr.put("xsi:schemaLocation","http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd");
- webappAttr.put("metadata-complete","true");
- webappAttr.put("version","3.1");
-
- out.open("web-app",webappAttr);
-
- if (getDisplayName() != null)
- out.tag("display-name",getDisplayName());
-
- // Set some special context parameters
-
- // The location of the war file on disk
- String resourceBase=getBaseResource().getFile().getCanonicalFile().getAbsoluteFile().toURI().toString();
-
- // The library order
- addContextParamFromAttribute(out,ServletContext.ORDERED_LIBS);
- //the servlet container initializers
- addContextParamFromAttribute(out,AnnotationConfiguration.CONTAINER_INITIALIZERS);
- //the tlds discovered
- addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_TLDS,resourceBase);
- //the META-INF/resources discovered
- addContextParamFromAttribute(out,MetaInfConfiguration.METAINF_RESOURCES,resourceBase);
-
-
- // init params
- for (String p : getInitParams().keySet())
- out.open("context-param",origin(md,"context-param." + p))
- .tag("param-name",p)
- .tag("param-value",getInitParameter(p))
- .close();
-
- if (getEventListeners() != null)
- for (EventListener e : getEventListeners())
- out.open("listener",origin(md,e.getClass().getCanonicalName() + ".listener"))
- .tag("listener-class",e.getClass().getCanonicalName())
- .close();
-
- ServletHandler servlets = getServletHandler();
-
- if (servlets.getFilters() != null)
+ Resource descriptor = getWebInf().addPath(QuickStartDescriptorGenerator.DEFAULT_QUICKSTART_DESCRIPTOR_NAME);
+ if (!descriptor.exists())
+ descriptor.getFile().createNewFile();
+ QuickStartDescriptorGenerator generator = new QuickStartDescriptorGenerator(this, extraXML);
+ try (FileOutputStream fos = new FileOutputStream(descriptor.getFile()))
{
- for (FilterHolder holder : servlets.getFilters())
- outholder(out,md,"filter",holder);
+ generator.generateQuickStartWebXml(fos);
}
-
- if (servlets.getFilterMappings() != null)
- {
- for (FilterMapping mapping : servlets.getFilterMappings())
- {
- out.open("filter-mapping");
- out.tag("filter-name",mapping.getFilterName());
- if (mapping.getPathSpecs() != null)
- for (String s : mapping.getPathSpecs())
- out.tag("url-pattern",s);
- if (mapping.getServletNames() != null)
- for (String n : mapping.getServletNames())
- out.tag("servlet-name",n);
-
- if (!mapping.isDefaultDispatches())
- {
- if (mapping.appliesTo(DispatcherType.REQUEST))
- out.tag("dispatcher","REQUEST");
- if (mapping.appliesTo(DispatcherType.ASYNC))
- out.tag("dispatcher","ASYNC");
- if (mapping.appliesTo(DispatcherType.ERROR))
- out.tag("dispatcher","ERROR");
- if (mapping.appliesTo(DispatcherType.FORWARD))
- out.tag("dispatcher","FORWARD");
- if (mapping.appliesTo(DispatcherType.INCLUDE))
- out.tag("dispatcher","INCLUDE");
- }
- out.close();
- }
- }
-
- if (servlets.getServlets() != null)
- {
- for (ServletHolder holder : servlets.getServlets())
- outholder(out,md,"servlet",holder);
- }
-
- if (servlets.getServletMappings() != null)
- {
- for (ServletMapping mapping : servlets.getServletMappings())
- {
- out.open("servlet-mapping",origin(md,mapping.getServletName() + ".servlet.mappings"));
- out.tag("servlet-name",mapping.getServletName());
- if (mapping.getPathSpecs() != null)
- for (String s : mapping.getPathSpecs())
- out.tag("url-pattern",s);
- out.close();
- }
- }
-
- // Security elements
- SecurityHandler security = getSecurityHandler();
-
- if (security!=null && (security.getRealmName()!=null || security.getAuthMethod()!=null))
- {
- out.open("login-config");
- if (security.getAuthMethod()!=null)
- out.tag("auth-method",origin(md,"auth-method"),security.getAuthMethod());
- if (security.getRealmName()!=null)
- out.tag("realm-name",origin(md,"realm-name"),security.getRealmName());
-
-
- if (Constraint.__FORM_AUTH.equalsIgnoreCase(security.getAuthMethod()))
- {
- out.open("form-login-config");
- out.tag("form-login-page",origin(md,"form-login-page"),security.getInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE));
- out.tag("form-error-page",origin(md,"form-error-page"),security.getInitParameter(FormAuthenticator.__FORM_ERROR_PAGE));
- out.close();
- }
-
- out.close();
- }
-
- if (security instanceof ConstraintAware)
- {
- ConstraintAware ca = (ConstraintAware)security;
- for (String r:ca.getRoles())
- out.open("security-role")
- .tag("role-name",r)
- .close();
-
- for (ConstraintMapping m : ca.getConstraintMappings())
- {
- out.open("security-constraint");
-
- if (m.getConstraint().getAuthenticate())
- {
- out.open("auth-constraint");
- if (m.getConstraint().getRoles()!=null)
- for (String r : m.getConstraint().getRoles())
- out.tag("role-name",r);
-
- out.close();
- }
-
- switch (m.getConstraint().getDataConstraint())
- {
- case Constraint.DC_NONE:
- out.open("user-data-constraint").tag("transport-guarantee","NONE").close();
- break;
-
- case Constraint.DC_INTEGRAL:
- out.open("user-data-constraint").tag("transport-guarantee","INTEGRAL").close();
- break;
-
- case Constraint.DC_CONFIDENTIAL:
- out.open("user-data-constraint").tag("transport-guarantee","CONFIDENTIAL").close();
- break;
-
- default:
- break;
-
- }
-
- out.open("web-resource-collection");
- {
- if (m.getConstraint().getName()!=null)
- out.tag("web-resource-name",m.getConstraint().getName());
- if (m.getPathSpec()!=null)
- out.tag("url-pattern",origin(md,"constraint.url."+m.getPathSpec()),m.getPathSpec());
- if (m.getMethod()!=null)
- out.tag("http-method",m.getMethod());
-
- if (m.getMethodOmissions()!=null)
- for (String o:m.getMethodOmissions())
- out.tag("http-method-omission",o);
-
- out.close();
- }
-
- out.close();
-
- }
- }
-
- if (getWelcomeFiles() != null)
- {
- out.open("welcome-file-list");
- for (String welcomeFile:getWelcomeFiles())
- {
- out.tag("welcome-file", welcomeFile);
- }
- out.close();
- }
-
- Map localeEncodings = getLocaleEncodings();
- if (localeEncodings != null && !localeEncodings.isEmpty())
- {
- out.open("locale-encoding-mapping-list");
- for (Map.Entry entry:localeEncodings.entrySet())
- {
- out.open("locale-encoding-mapping", origin(md,"locale-encoding."+entry.getKey()));
- out.tag("locale", entry.getKey());
- out.tag("encoding", entry.getValue());
- out.close();
- }
- out.close();
- }
-
- //session-config
- if (getSessionHandler().getSessionManager() != null)
- {
- out.open("session-config");
- int maxInactiveSec = getSessionHandler().getSessionManager().getMaxInactiveInterval();
- out.tag("session-timeout", (maxInactiveSec==0?"0":Integer.toString(maxInactiveSec/60)));
-
- Set modes = getSessionHandler().getSessionManager().getEffectiveSessionTrackingModes();
- if (modes != null)
- {
- for (SessionTrackingMode mode:modes)
- out.tag("tracking-mode", mode.toString());
- }
-
- //cookie-config
- SessionCookieConfig cookieConfig = getSessionHandler().getSessionManager().getSessionCookieConfig();
- if (cookieConfig != null)
- {
- out.open("cookie-config");
- if (cookieConfig.getName() != null)
- out.tag("name", origin(md,"cookie-config.name"), cookieConfig.getName());
-
- if (cookieConfig.getDomain() != null)
- out.tag("domain", origin(md, "cookie-config.domain"), cookieConfig.getDomain());
-
- if (cookieConfig.getPath() != null)
- out.tag("path", origin(md, "cookie-config.path"), cookieConfig.getPath());
-
- if (cookieConfig.getComment() != null)
- out.tag("comment", origin(md, "cookie-config.comment"), cookieConfig.getComment());
-
- out.tag("http-only", origin(md, "cookie-config.http-only"), Boolean.toString(cookieConfig.isHttpOnly()));
- out.tag("secure", origin(md, "cookie-config.secure"), Boolean.toString(cookieConfig.isSecure()));
- out.tag("max-age", origin(md, "cookie-config.max-age"), Integer.toString(cookieConfig.getMaxAge()));
- out.close();
- }
- out.close();
- }
-
- //error-pages
- Map errorPages = ((ErrorPageErrorHandler)getErrorHandler()).getErrorPages();
- if (errorPages != null)
- {
- for (Map.Entry entry:errorPages.entrySet())
- {
- out.open("error-page", origin(md, "error."+entry.getKey()));
- //a global or default error page has no code or exception
- if (!ErrorPageErrorHandler.GLOBAL_ERROR_PAGE.equals(entry.getKey()))
- {
- if (entry.getKey().matches("\\d{3}"))
- out.tag("error-code", entry.getKey());
- else
- out.tag("exception-type", entry.getKey());
- }
- out.tag("location", entry.getValue());
- out.close();
- }
- }
-
- //mime-types
- MimeTypes mimeTypes = getMimeTypes();
- if (mimeTypes != null)
- {
- for (Map.Entry entry:mimeTypes.getMimeMap().entrySet())
- {
- out.open("mime-mapping");
- out.tag("extension", origin(md, "extension."+entry.getKey()), entry.getKey());
- out.tag("mime-type", entry.getValue());
- out.close();
- }
- }
-
- //jsp-config
- JspConfig jspConfig = (JspConfig)getServletContext().getJspConfigDescriptor();
- if (jspConfig != null)
- {
- out.open("jsp-config");
- Collection tlds = jspConfig.getTaglibs();
- if (tlds != null && !tlds.isEmpty())
- {
- for (TaglibDescriptor tld:tlds)
- {
- out.open("taglib");
- out.tag("taglib-uri", tld.getTaglibURI());
- out.tag("taglib-location", tld.getTaglibLocation());
- out.close();
- }
- }
-
- Collection jspPropertyGroups = jspConfig.getJspPropertyGroups();
- if (jspPropertyGroups != null && !jspPropertyGroups.isEmpty())
- {
- for (JspPropertyGroupDescriptor jspPropertyGroup:jspPropertyGroups)
- {
- out.open("jsp-property-group");
- Collection strings = jspPropertyGroup.getUrlPatterns();
- if (strings != null && !strings.isEmpty())
- {
- for (String urlPattern:strings)
- out.tag("url-pattern", urlPattern);
- }
-
- if (jspPropertyGroup.getElIgnored() != null)
- out.tag("el-ignored", jspPropertyGroup.getElIgnored());
-
- if (jspPropertyGroup.getPageEncoding() != null)
- out.tag("page-encoding", jspPropertyGroup.getPageEncoding());
-
- if (jspPropertyGroup.getScriptingInvalid() != null)
- out.tag("scripting-invalid", jspPropertyGroup.getScriptingInvalid());
-
- if (jspPropertyGroup.getIsXml() != null)
- out.tag("is-xml", jspPropertyGroup.getIsXml());
-
- if (jspPropertyGroup.getDeferredSyntaxAllowedAsLiteral() != null)
- out.tag("deferred-syntax-allowed-as-literal", jspPropertyGroup.getDeferredSyntaxAllowedAsLiteral());
-
- if (jspPropertyGroup.getTrimDirectiveWhitespaces() != null)
- out.tag("trim-directive-whitespaces", jspPropertyGroup.getTrimDirectiveWhitespaces());
-
- if (jspPropertyGroup.getDefaultContentType() != null)
- out.tag("default-content-type", jspPropertyGroup.getDefaultContentType());
-
- if (jspPropertyGroup.getBuffer() != null)
- out.tag("buffer", jspPropertyGroup.getBuffer());
-
- if (jspPropertyGroup.getErrorOnUndeclaredNamespace() != null)
- out.tag("error-on-undeclared-namespace", jspPropertyGroup.getErrorOnUndeclaredNamespace());
-
- strings = jspPropertyGroup.getIncludePreludes();
- if (strings != null && !strings.isEmpty())
- {
- for (String prelude:strings)
- out.tag("include-prelude", prelude);
- }
-
- strings = jspPropertyGroup.getIncludeCodas();
- if (strings != null && !strings.isEmpty())
- {
- for (String coda:strings)
- out.tag("include-coda", coda);
- }
-
- out.close();
- }
- }
-
- out.close();
- }
-
- //lifecycle: post-construct, pre-destroy
- LifeCycleCallbackCollection lifecycles = ((LifeCycleCallbackCollection)getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION));
- if (lifecycles != null)
- {
- Collection tmp = lifecycles.getPostConstructCallbacks();
-
- for (LifeCycleCallback c:tmp)
- {
- out.open("post-construct");
- out.tag("lifecycle-callback-class", c.getTargetClassName());
- out.tag("lifecycle-callback-method", c.getMethodName());
- out.close();
- }
-
- tmp = lifecycles.getPreDestroyCallbacks();
- for (LifeCycleCallback c:tmp)
- {
- out.open("pre-destroy");
- out.tag("lifecycle-callback-class", c.getTargetClassName());
- out.tag("lifecycle-callback-method", c.getMethodName());
- out.close();
- }
- }
-
- out.literal(extraXML);
-
- out.close();
}
- private void addContextParamFromAttribute(XmlAppendable out, String attribute) throws IOException
- {
- addContextParamFromAttribute(out,attribute,null);
- }
-
- private void addContextParamFromAttribute(XmlAppendable out, String attribute, String resourceBase) throws IOException
- {
- Object o=getAttribute(attribute);
- if (o==null)
- return;
-
- Collection> c = (o instanceof Collection)? (Collection>)o:Collections.singletonList(o);
- StringBuilder v=new StringBuilder();
- for (Object i:c)
- {
- if (i!=null)
- {
- if (v.length()>0)
- v.append(",\n ");
- else
- v.append("\n ");
- if (resourceBase==null)
- QuotedStringTokenizer.quote(v,i.toString());
- else
- QuotedStringTokenizer.quote(v,i.toString().replace(resourceBase,"${WAR}/"));
- }
- }
- out.open("context-param")
- .tag("param-name",attribute)
- .tagCDATA("param-value",v.toString())
- .close();
- }
-
- private static void outholder(XmlAppendable out, MetaData md, String tag, Holder> holder) throws IOException
- {
- out.open(tag,Collections.singletonMap("source",holder.getSource().toString()));
- String n = holder.getName();
- out.tag(tag + "-name",n);
-
- String ot = n + "." + tag + ".";
-
- out.tag(tag + "-class",origin(md,ot + tag + "-class"),holder.getClassName());
-
- for (String p : holder.getInitParameters().keySet())
- {
- if ("scratchdir".equalsIgnoreCase(p)) //don't preconfigure the temp dir for jsp output
- continue;
- out.open("init-param",origin(md,ot + "init-param." + p))
- .tag("param-name",p)
- .tag("param-value",holder.getInitParameter(p))
- .close();
- }
-
- if (holder instanceof ServletHolder)
- {
- ServletHolder s = (ServletHolder)holder;
- if (s.getForcedPath() != null)
- out.tag("jsp-file",s.getForcedPath());
-
- if (s.getInitOrder() != 0)
- out.tag("load-on-startup",Integer.toString(s.getInitOrder()));
-
- if (s.getRunAsRole() != null)
- out.open("run-as",origin(md,ot + "run-as"))
- .tag("role-name",s.getRunAsRole())
- .close();
-
- Map roles = s.getRoleRefMap();
- if (roles!=null)
- {
- for (Map.Entry e : roles.entrySet())
- {
- out.open("security-role-ref",origin(md,ot+"role-name."+e.getKey()))
- .tag("role-name",e.getKey())
- .tag("role-link",e.getValue())
- .close();
- }
- }
-
- if (!s.isEnabled())
- out.tag("enabled",origin(md,ot + "enabled"),"false");
-
- //multipart-config
- MultipartConfigElement multipartConfig = ((ServletHolder.Registration)s.getRegistration()).getMultipartConfig();
- if (multipartConfig != null)
- {
- out.open("multipart-config", origin(md, s.getName()+".servlet.multipart-config"));
- if (multipartConfig.getLocation() != null)
- out.tag("location", multipartConfig.getLocation());
- out.tag("max-file-size", Long.toString(multipartConfig.getMaxFileSize()));
- out.tag("max-request-size", Long.toString(multipartConfig.getMaxRequestSize()));
- out.tag("file-size-threshold", Long.toString(multipartConfig.getFileSizeThreshold()));
- out.close();
- }
- }
-
- out.tag("async-supported",origin(md,ot + "async-supported"),holder.isAsyncSupported()?"true":"false");
- out.close();
- }
-
- public static Map origin(MetaData md, String name)
- {
- if (!LOG.isDebugEnabled())
- return Collections.emptyMap();
- if (name == null)
- return Collections.emptyMap();
- OriginInfo origin = md.getOriginInfo(name);
- // System.err.println("origin of "+name+" is "+origin);
- if (origin == null)
- return Collections.emptyMap();
- return Collections.singletonMap("origin",origin.toString());
-
- }
-
+
}
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java
index eea013eee3b..f20e9142c79 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java
@@ -27,7 +27,6 @@ import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.ArrayUtil;
import org.eclipse.jetty.util.URIUtil;
-import org.eclipse.jetty.util.UrlEncoded;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ValidUrlRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ValidUrlRuleTest.java
index 47fa517d9b0..e8d6cda940e 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ValidUrlRuleTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ValidUrlRuleTest.java
@@ -45,7 +45,7 @@ public class ValidUrlRuleTest extends AbstractRuleTestCase
_rule.matchAndApply(_request.getRequestURI(), _request, _response);
- assertEquals(0,_response.getStatus());
+ assertEquals(200,_response.getStatus());
}
@Test
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/GatewayServer.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/GatewayServer.java
index 83068d10d73..713b4fe0eee 100644
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/GatewayServer.java
+++ b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/GatewayServer.java
@@ -102,7 +102,7 @@ public class GatewayServer extends Server
public GatewayServer()
{
- this("",DFT_EXT_PATH,DFT_CONNECT_PATH,new StandardTargetIdRetriever());
+ this("",DFT_EXT_PATH,DFT_CONNECT_PATH,new StandardTargetIdRetriever());
}
public GatewayServer(String contextPath, String externalServletPath,String gatewayServletPath, TargetIdRetriever targetIdRetriever)
@@ -145,7 +145,7 @@ public class GatewayServer extends Server
public Gateway getGateway()
{
- return gateway;
+ return gateway;
}
public ServletHolder getExternalServlet()
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java
index 201618d89d1..7b7f2a395e0 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java
@@ -46,6 +46,7 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.security.Constraint;
@@ -510,21 +511,6 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
mappings.put(ALL_METHODS,roleInfo);
}
}
- else
- {
- //combine with any entry that covers all methods
- if (httpMethod == null)
- {
- for (Map.Entry entry : mappings.entrySet())
- {
- if (entry.getKey() != null)
- {
- RoleInfo specific = entry.getValue();
- specific.combine(roleInfo);
- }
- }
- }
- }
}
/* ------------------------------------------------------------ */
@@ -627,7 +613,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
@Override
protected RoleInfo prepareConstraintInfo(String pathInContext, Request request)
{
- Map mappings = (Map)_constraintMap.match(pathInContext);
+ Map mappings = _constraintMap.match(pathInContext);
if (mappings != null)
{
@@ -700,11 +686,8 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
{
String scheme = httpConfig.getSecureScheme();
int port = httpConfig.getSecurePort();
- String url = ("https".equalsIgnoreCase(scheme) && port==443)
- ? "https://"+request.getServerName()+request.getRequestURI()
- : scheme + "://" + request.getServerName() + ":" + port + request.getRequestURI();
- if (request.getQueryString() != null)
- url += "?" + request.getQueryString();
+
+ String url = URIUtil.newURI(scheme, request.getServerName(), port,request.getRequestURI(),request.getQueryString());
response.setContentLength(0);
response.sendRedirect(url);
}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java b/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java
index e2de9f7db22..a67eb96d6fc 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java
@@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletResponse;
/**
* @version $Rev: 4466 $ $Date: 2009-02-10 23:42:54 +0100 (Tue, 10 Feb 2009) $
+ * @deprecated
*/
public interface CrossContextPsuedoSession
{
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java b/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java
index 8499a609d3a..2f94908acb3 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java
@@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
/**
* @version $Rev: 4660 $ $Date: 2009-02-25 17:29:53 +0100 (Wed, 25 Feb 2009) $
+ * @deprecated
*/
public class HashCrossContextPsuedoSession implements CrossContextPsuedoSession
{
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java
index 99094c17a9e..21eba251640 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java
@@ -22,7 +22,6 @@ import java.security.Principal;
import javax.security.auth.Subject;
-import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;
/* ------------------------------------------------------------ */
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java
index a6e108e9a70..9460736f470 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java
@@ -43,7 +43,6 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandler.Context;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.session.AbstractSession;
-import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java
index df0f7d92f3a..fe4c64b8bbb 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java
@@ -331,28 +331,28 @@ public class DeferredAuthentication implements Authentication.Deferred
}
@Override
- public Collection getHeaderNames()
- {
- return Collections.emptyList();
- }
-
- @Override
- public String getHeader(String arg0)
- {
- return null;
- }
-
- @Override
- public Collection getHeaders(String arg0)
- {
+ public Collection getHeaderNames()
+ {
return Collections.emptyList();
- }
+ }
- @Override
- public int getStatus()
- {
- return 0;
- }
+ @Override
+ public String getHeader(String arg0)
+ {
+ return null;
+ }
+
+ @Override
+ public Collection getHeaders(String arg0)
+ {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public int getStatus()
+ {
+ return 0;
+ }
};
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java
index 13537e6cb75..be5db7ef7bf 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java
@@ -34,7 +34,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.security.ServerAuthException;
import org.eclipse.jetty.security.UserAuthentication;
import org.eclipse.jetty.server.Authentication;
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java
index 8469c0a800d..e0248b2e595 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java
@@ -50,7 +50,7 @@ public class SpnegoAuthenticator extends LoginAuthenticator
*/
public SpnegoAuthenticator( String authMethod )
{
- _authMethod = authMethod;
+ _authMethod = authMethod;
}
@Override
@@ -77,10 +77,10 @@ public class SpnegoAuthenticator extends LoginAuthenticator
{
try
{
- if (DeferredAuthentication.isDeferred(res))
- {
+ if (DeferredAuthentication.isDeferred(res))
+ {
return Authentication.UNAUTHENTICATED;
- }
+ }
LOG.debug("SpengoAuthenticator: sending challenge");
res.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), HttpHeader.NEGOTIATE.asString());
diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/AliasedConstraintTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/AliasedConstraintTest.java
new file mode 100644
index 00000000000..6267cf9ad65
--- /dev/null
+++ b/jetty-security/src/test/java/org/eclipse/jetty/security/AliasedConstraintTest.java
@@ -0,0 +1,174 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.security;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.LocalConnector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.ResourceHandler;
+import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.util.security.Constraint;
+import org.eclipse.jetty.util.security.Password;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Some requests for static data that is served by ResourceHandler, but some is secured.
+ *
+ * This is mainly here to test security bypass techniques using aliased names that should be caught.
+ */
+@RunWith(Parameterized.class)
+public class AliasedConstraintTest
+{
+ private static final String TEST_REALM = "TestRealm";
+ private static Server server;
+ private static LocalConnector connector;
+ private static ConstraintSecurityHandler security;
+
+ @BeforeClass
+ public static void startServer() throws Exception
+ {
+ server = new Server();
+ connector = new LocalConnector(server);
+ server.setConnectors(new Connector[] { connector });
+
+ ContextHandler context = new ContextHandler();
+ SessionHandler session = new SessionHandler();
+
+ HashLoginService loginService = new HashLoginService(TEST_REALM);
+ loginService.putUser("user0",new Password("password"),new String[] {});
+ loginService.putUser("user",new Password("password"),new String[] { "user" });
+ loginService.putUser("user2",new Password("password"),new String[] { "user" });
+ loginService.putUser("admin",new Password("password"),new String[] { "user", "administrator" });
+ loginService.putUser("user3",new Password("password"),new String[] { "foo" });
+
+ context.setContextPath("/ctx");
+ context.setResourceBase(MavenTestingUtils.getTestResourceDir("docroot").getAbsolutePath());
+ server.setHandler(context);
+ context.setHandler(session);
+ // context.addAliasCheck(new AllowSymLinkAliasChecker());
+
+ server.addBean(loginService);
+
+ security = new ConstraintSecurityHandler();
+ session.setHandler(security);
+ ResourceHandler handler = new ResourceHandler();
+ security.setHandler(handler);
+
+ List constraints = new ArrayList<>();
+
+ Constraint constraint0 = new Constraint();
+ constraint0.setAuthenticate(true);
+ constraint0.setName("forbid");
+ ConstraintMapping mapping0 = new ConstraintMapping();
+ mapping0.setPathSpec("/forbid/*");
+ mapping0.setConstraint(constraint0);
+ constraints.add(mapping0);
+
+ Set knownRoles = new HashSet<>();
+ knownRoles.add("user");
+ knownRoles.add("administrator");
+
+ security.setConstraintMappings(constraints,knownRoles);
+ server.start();
+ }
+
+ @AfterClass
+ public static void stopServer() throws Exception
+ {
+ server.stop();
+ }
+
+ @Parameters(name = "{0}: {1}")
+ public static Collection
+ *
* This filter is ideal to prevent wasting threads waiting for slow/limited
* resources such as a JDBC connection pool. It avoids the situation where all of a
* containers thread pool may be consumed blocking on such a slow resource.
* By limiting the number of active threads, a smaller thread pool may be used as
* the threads are not wasted waiting. Thus more memory may be available for use by
* the active threads.
- *
+ *
* Furthermore, this filter uses a priority when resuming waiting requests. So that if
* a container is under load, and there are many requests waiting for resources,
* the {@link #getPriority(ServletRequest)} method is used, so that more important
@@ -64,175 +65,168 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
* maxRequest limit slightly smaller than the containers thread pool and a high priority
* allocated to admin users. Thus regardless of load, admin users would always be
* able to access the web application.
- *
+ *
* The maxRequest limit is policed by a {@link Semaphore} and the filter will wait a short while attempting to acquire
* the semaphore. This wait is controlled by the "waitMs" init parameter and allows the expense of a suspend to be
* avoided if the semaphore is shortly available. If the semaphore cannot be obtained, the request will be suspended
* for the default suspend period of the container or the valued set as the "suspendMs" init parameter.
- *
+ *
* If the "managedAttr" init parameter is set to true, then this servlet is set as a {@link ServletContext} attribute with the
* filter name as the attribute name. This allows context external mechanism (eg JMX via {@link ContextHandler#MANAGED_ATTRIBUTES}) to
* manage the configuration of the filter.
- *
- *
- *
*/
@ManagedObject("Quality of Service Filter")
public class QoSFilter implements Filter
{
- final static int __DEFAULT_MAX_PRIORITY=10;
- final static int __DEFAULT_PASSES=10;
- final static int __DEFAULT_WAIT_MS=50;
- final static long __DEFAULT_TIMEOUT_MS = -1;
+ private static final Logger LOG = Log.getLogger(QoSFilter.class);
- final static String MANAGED_ATTR_INIT_PARAM="managedAttr";
- final static String MAX_REQUESTS_INIT_PARAM="maxRequests";
- final static String MAX_PRIORITY_INIT_PARAM="maxPriority";
- final static String MAX_WAIT_INIT_PARAM="waitMs";
- final static String SUSPEND_INIT_PARAM="suspendMs";
+ static final int __DEFAULT_MAX_PRIORITY = 10;
+ static final int __DEFAULT_PASSES = 10;
+ static final int __DEFAULT_WAIT_MS = 50;
+ static final long __DEFAULT_TIMEOUT_MS = -1;
- ServletContext _context;
-
- protected long _waitMs;
- protected long _suspendMs;
- protected int _maxRequests;
+ static final String MANAGED_ATTR_INIT_PARAM = "managedAttr";
+ static final String MAX_REQUESTS_INIT_PARAM = "maxRequests";
+ static final String MAX_PRIORITY_INIT_PARAM = "maxPriority";
+ static final String MAX_WAIT_INIT_PARAM = "waitMs";
+ static final String SUSPEND_INIT_PARAM = "suspendMs";
+ private final String _suspended = "QoSFilter@" + Integer.toHexString(hashCode()) + ".SUSPENDED";
+ private final String _resumed = "QoSFilter@" + Integer.toHexString(hashCode()) + ".RESUMED";
+ private long _waitMs;
+ private long _suspendMs;
+ private int _maxRequests;
private Semaphore _passes;
- private Queue[] _queue;
- private ContinuationListener[] _listener;
- private String _suspended="QoSFilter@"+this.hashCode();
+ private Queue[] _queues;
+ private AsyncListener[] _listeners;
- /* ------------------------------------------------------------ */
- /**
- * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
- */
public void init(FilterConfig filterConfig)
{
- _context=filterConfig.getServletContext();
-
- int max_priority=__DEFAULT_MAX_PRIORITY;
- if (filterConfig.getInitParameter(MAX_PRIORITY_INIT_PARAM)!=null)
- max_priority=Integer.parseInt(filterConfig.getInitParameter(MAX_PRIORITY_INIT_PARAM));
- _queue=new Queue[max_priority+1];
- _listener = new ContinuationListener[max_priority + 1];
- for (int p=0;p<_queue.length;p++)
+ int max_priority = __DEFAULT_MAX_PRIORITY;
+ if (filterConfig.getInitParameter(MAX_PRIORITY_INIT_PARAM) != null)
+ max_priority = Integer.parseInt(filterConfig.getInitParameter(MAX_PRIORITY_INIT_PARAM));
+ _queues = new Queue[max_priority + 1];
+ _listeners = new AsyncListener[_queues.length];
+ for (int p = 0; p < _queues.length; ++p)
{
- _queue[p]=new ConcurrentLinkedQueue();
-
- final int priority=p;
- _listener[p] = new ContinuationListener()
- {
- public void onComplete(Continuation continuation)
- {}
-
- public void onTimeout(Continuation continuation)
- {
- _queue[priority].remove(continuation);
- }
- };
+ _queues[p] = new ConcurrentLinkedQueue<>();
+ _listeners[p] = new QoSAsyncListener(p);
}
- int maxRequests=__DEFAULT_PASSES;
- if (filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM)!=null)
- maxRequests=Integer.parseInt(filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM));
- _passes=new Semaphore(maxRequests,true);
+ int maxRequests = __DEFAULT_PASSES;
+ if (filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM) != null)
+ maxRequests = Integer.parseInt(filterConfig.getInitParameter(MAX_REQUESTS_INIT_PARAM));
+ _passes = new Semaphore(maxRequests, true);
_maxRequests = maxRequests;
long wait = __DEFAULT_WAIT_MS;
- if (filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM)!=null)
- wait=Integer.parseInt(filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM));
- _waitMs=wait;
+ if (filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM) != null)
+ wait = Integer.parseInt(filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM));
+ _waitMs = wait;
long suspend = __DEFAULT_TIMEOUT_MS;
- if (filterConfig.getInitParameter(SUSPEND_INIT_PARAM)!=null)
- suspend=Integer.parseInt(filterConfig.getInitParameter(SUSPEND_INIT_PARAM));
- _suspendMs=suspend;
+ if (filterConfig.getInitParameter(SUSPEND_INIT_PARAM) != null)
+ suspend = Integer.parseInt(filterConfig.getInitParameter(SUSPEND_INIT_PARAM));
+ _suspendMs = suspend;
- if (_context!=null && Boolean.parseBoolean(filterConfig.getInitParameter(MANAGED_ATTR_INIT_PARAM)))
- _context.setAttribute(filterConfig.getFilterName(),this);
+ ServletContext context = filterConfig.getServletContext();
+ if (context != null && Boolean.parseBoolean(filterConfig.getInitParameter(MANAGED_ATTR_INIT_PARAM)))
+ context.setAttribute(filterConfig.getFilterName(), this);
}
- /* ------------------------------------------------------------ */
- /**
- * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
- */
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
- boolean accepted=false;
+ boolean accepted = false;
try
{
- if (request.getAttribute(_suspended)==null)
+ Boolean suspended = (Boolean)request.getAttribute(_suspended);
+ if (suspended == null)
{
- accepted=_passes.tryAcquire(_waitMs,TimeUnit.MILLISECONDS);
+ accepted = _passes.tryAcquire(getWaitMs(), TimeUnit.MILLISECONDS);
if (accepted)
{
- request.setAttribute(_suspended,Boolean.FALSE);
+ request.setAttribute(_suspended, Boolean.FALSE);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Accepted {}", request);
}
else
{
- request.setAttribute(_suspended,Boolean.TRUE);
+ request.setAttribute(_suspended, Boolean.TRUE);
int priority = getPriority(request);
- Continuation continuation = ContinuationSupport.getContinuation(request);
- if (_suspendMs>0)
- continuation.setTimeout(_suspendMs);
- continuation.suspend();
- continuation.addContinuationListener(_listener[priority]);
- _queue[priority].add(continuation);
+ AsyncContext asyncContext = request.startAsync();
+ long suspendMs = getSuspendMs();
+ if (suspendMs > 0)
+ asyncContext.setTimeout(suspendMs);
+ asyncContext.addListener(_listeners[priority]);
+ _queues[priority].add(asyncContext);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Suspended {}", request);
return;
}
}
else
{
- Boolean suspended=(Boolean)request.getAttribute(_suspended);
-
- if (suspended.booleanValue())
+ if (suspended)
{
- request.setAttribute(_suspended,Boolean.FALSE);
- if (request.getAttribute("javax.servlet.resumed")==Boolean.TRUE)
+ request.setAttribute(_suspended, Boolean.FALSE);
+ Boolean resumed = (Boolean)request.getAttribute(_resumed);
+ if (resumed == Boolean.TRUE)
{
_passes.acquire();
- accepted=true;
+ accepted = true;
+ if (LOG.isDebugEnabled())
+ LOG.debug("Resumed {}", request);
}
else
{
// Timeout! try 1 more time.
- accepted = _passes.tryAcquire(_waitMs,TimeUnit.MILLISECONDS);
+ accepted = _passes.tryAcquire(getWaitMs(), TimeUnit.MILLISECONDS);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Timeout {}", request);
}
}
else
{
- // pass through resume of previously accepted request
+ // Pass through resume of previously accepted request.
_passes.acquire();
accepted = true;
+ if (LOG.isDebugEnabled())
+ LOG.debug("Passthrough {}", request);
}
}
if (accepted)
{
- chain.doFilter(request,response);
+ chain.doFilter(request, response);
}
else
{
+ if (LOG.isDebugEnabled())
+ LOG.debug("Rejected {}", request);
((HttpServletResponse)response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
}
}
- catch(InterruptedException e)
+ catch (InterruptedException e)
{
- _context.log("QoS",e);
((HttpServletResponse)response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
}
finally
{
if (accepted)
{
- for (int p=_queue.length;p-->0;)
+ for (int p = _queues.length - 1; p >= 0; --p)
{
- Continuation continutaion=_queue[p].poll();
- if (continutaion!=null && continutaion.isSuspended())
+ AsyncContext asyncContext = _queues[p].poll();
+ if (asyncContext != null)
{
- continutaion.resume();
- break;
+ ServletRequest candidate = asyncContext.getRequest();
+ Boolean suspended = (Boolean)candidate.getAttribute(_suspended);
+ if (suspended == Boolean.TRUE)
+ {
+ candidate.setAttribute(_resumed, Boolean.TRUE);
+ asyncContext.dispatch();
+ break;
+ }
}
}
_passes.release();
@@ -241,40 +235,40 @@ public class QoSFilter implements Filter
}
/**
- * Get the request Priority.
- *
The default implementation assigns the following priorities:
- *
2 - for a authenticated request
- *
1 - for a request with valid /non new session
+ * Computes the request priority.
+ *
+ * The default implementation assigns the following priorities:
+ *
+ *
2 - for an authenticated request
+ *
1 - for a request with valid / non new session
*
0 - for all other requests.
*
- * This method may be specialised to provide application specific priorities.
+ * This method may be overridden to provide application specific priorities.
*
- * @param request
- * @return the request priority
+ * @param request the incoming request
+ * @return the computed request priority
*/
protected int getPriority(ServletRequest request)
{
HttpServletRequest baseRequest = (HttpServletRequest)request;
- if (baseRequest.getUserPrincipal() != null )
+ if (baseRequest.getUserPrincipal() != null)
+ {
return 2;
+ }
else
{
HttpSession session = baseRequest.getSession(false);
- if (session!=null && !session.isNew())
+ if (session != null && !session.isNew())
return 1;
else
return 0;
}
}
+ public void destroy()
+ {
+ }
- /* ------------------------------------------------------------ */
- /**
- * @see javax.servlet.Filter#destroy()
- */
- public void destroy(){}
-
- /* ------------------------------------------------------------ */
/**
* Get the (short) amount of time (in milliseconds) that the filter would wait
* for the semaphore to become available before suspending a request.
@@ -287,7 +281,6 @@ public class QoSFilter implements Filter
return _waitMs;
}
- /* ------------------------------------------------------------ */
/**
* Set the (short) amount of time (in milliseconds) that the filter would wait
* for the semaphore to become available before suspending a request.
@@ -299,7 +292,6 @@ public class QoSFilter implements Filter
_waitMs = value;
}
- /* ------------------------------------------------------------ */
/**
* Get the amount of time (in milliseconds) that the filter would suspend
* a request for while waiting for the semaphore to become available.
@@ -312,7 +304,6 @@ public class QoSFilter implements Filter
return _suspendMs;
}
- /* ------------------------------------------------------------ */
/**
* Set the amount of time (in milliseconds) that the filter would suspend
* a request for while waiting for the semaphore to become available.
@@ -324,7 +315,6 @@ public class QoSFilter implements Filter
_suspendMs = value;
}
- /* ------------------------------------------------------------ */
/**
* Get the maximum number of requests allowed to be processed
* at the same time.
@@ -337,7 +327,6 @@ public class QoSFilter implements Filter
return _maxRequests;
}
- /* ------------------------------------------------------------ */
/**
* Set the maximum number of requests allowed to be processed
* at the same time.
@@ -346,8 +335,42 @@ public class QoSFilter implements Filter
*/
public void setMaxRequests(int value)
{
- _passes = new Semaphore((value-_maxRequests+_passes.availablePermits()), true);
+ _passes = new Semaphore((value - getMaxRequests() + _passes.availablePermits()), true);
_maxRequests = value;
}
+ private class QoSAsyncListener implements AsyncListener
+ {
+ private final int priority;
+
+ public QoSAsyncListener(int priority)
+ {
+ this.priority = priority;
+ }
+
+ @Override
+ public void onStartAsync(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onComplete(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onTimeout(AsyncEvent event) throws IOException
+ {
+ // Remove before it's redispatched, so it won't be
+ // redispatched again at the end of the filtering.
+ AsyncContext asyncContext = event.getAsyncContext();
+ _queues[priority].remove(asyncContext);
+ asyncContext.dispatch();
+ }
+
+ @Override
+ public void onError(AsyncEvent event) throws IOException
+ {
+ }
+ }
}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/WelcomeFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/WelcomeFilter.java
index e628ed1b5cb..a17818e8d37 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/WelcomeFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/WelcomeFilter.java
@@ -49,15 +49,15 @@ public class WelcomeFilter implements Filter
public void init(FilterConfig filterConfig)
{
welcome=filterConfig.getInitParameter("welcome");
- if (welcome==null)
- welcome="index.html";
+ if (welcome==null)
+ welcome="index.html";
}
/* ------------------------------------------------------------ */
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
- throws IOException, ServletException
+ throws IOException, ServletException
{
String path=((HttpServletRequest)request).getServletPath();
if (welcome!=null && path.endsWith("/"))
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java
index 44d34d1f055..365dd164bf5 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java
@@ -262,6 +262,7 @@ public class GzipHandler extends HandlerWrapper
_mimeTypes.add("application/gzip");
}
}
+ super.doStart();
}
/* ------------------------------------------------------------ */
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java
index 3151ab8e5a9..636eab2b53c 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java
@@ -151,6 +151,16 @@ public class GzipHttpOutput extends HttpOutput
}
}
+ // Has the Content-Encoding header already been set?
+ String ce=getHttpChannel().getResponse().getHeader("Content-Encoding");
+ if (ce != null)
+ {
+ LOG.debug("{} exclude by content-encoding {}",this,ce);
+ noCompression();
+ super.write(content,complete,callback);
+ return;
+ }
+
// Are we the thread that commits?
if (_state.compareAndSet(GZState.MIGHT_COMPRESS,GZState.COMMITTING))
{
@@ -188,6 +198,7 @@ public class GzipHttpOutput extends HttpOutput
gzip(content,complete,callback);
}
+ // TODO else ?
}
public void noCompression()
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java
index cb97090d5be..e0804d6781d 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java
@@ -57,6 +57,6 @@ public class CloseableDoSFilterTest extends AbstractDoSFilterTest
public void testUnresponsiveClient() throws Exception
{
// TODO work out why this intermittently fails
- LOG.warn("Ignored Closeable testUnresponsiveClient");
+ LOG.warn("Ignored Closeable testUnresponsiveClient");
}
}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java
index 69353f6a9ef..66f787e9d58 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java
@@ -18,12 +18,8 @@
package org.eclipse.jetty.servlets;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
import java.util.ArrayList;
import java.util.List;
-
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -34,6 +30,9 @@ import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
public class DoSFilterTest extends AbstractDoSFilterTest
{
private static final Logger LOG = Log.getLogger(DoSFilterTest.class);
@@ -62,7 +61,7 @@ public class DoSFilterTest extends AbstractDoSFilterTest
}
@Test
- public void isRateExceededTest() throws InterruptedException
+ public void testRateIsRateExceeded() throws InterruptedException
{
DoSFilter doSFilter = new DoSFilter();
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java
index f6b16d24cd0..4aa434e68f7 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java
@@ -25,7 +25,6 @@ import java.util.List;
import javax.servlet.Filter;
-import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlets.gzip.GzipTester;
import org.eclipse.jetty.servlets.gzip.TestStaticMimeTypeServlet;
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java
index 81aa29ec97a..ce743ad6a9b 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java
@@ -20,7 +20,6 @@ package org.eclipse.jetty.servlets;
import java.io.IOException;
import java.util.Arrays;
-import java.util.Collection;
import java.util.List;
import javax.servlet.Filter;
@@ -273,6 +272,24 @@ public class GzipFilterDefaultTest
}
}
+ @Test
+ public void testGzippedIfSVG() throws Exception
+ {
+ GzipTester tester = new GzipTester(testingdir, compressionType);
+ tester.setGzipFilterClass(testFilter);
+ tester.copyTestServerFile("test.svg");
+ FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
+ try
+ {
+ tester.start();
+ HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET","test.svg",System.currentTimeMillis()-4000);
+ Assert.assertEquals("Accept-Encoding",http.get("Vary"));
+ }
+ finally
+ {
+ tester.stop();
+ }
+ }
@Test
public void testNotGzipedIfNotModified() throws Exception
@@ -371,6 +388,60 @@ public class GzipFilterDefaultTest
}
}
+
+ @Test
+ public void testIsNotGzipCompressedByExcludedContentType() throws Exception
+ {
+ GzipTester tester = new GzipTester(testingdir, compressionType);
+ tester.setGzipFilterClass(testFilter);
+
+ int filesize = tester.getOutputBufferSize() * 4;
+ tester.prepareServerFile("test_quotes.txt", filesize);
+
+
+ FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
+ holder.setInitParameter("excludedMimeTypes","text/plain");
+
+ try
+ {
+ tester.start();
+ HttpTester.Response http = tester.assertIsResponseNotGzipCompressed("GET","test_quotes.txt", filesize, HttpStatus.OK_200);
+ Assert.assertNull(http.get("Vary"));
+ }
+ finally
+ {
+ tester.stop();
+ }
+ }
+
+
+ @Test
+ public void testIsNotGzipCompressedByExcludedContentTypeWithCharset() throws Exception
+ {
+ GzipTester tester = new GzipTester(testingdir, compressionType);
+ tester.setGzipFilterClass(testFilter);
+
+ int filesize = tester.getOutputBufferSize() * 4;
+ tester.prepareServerFile("test_quotes.txt", filesize);
+ tester.addMimeType("txt","text/plain;charset=UTF-8");
+
+ FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
+ holder.setInitParameter("excludedMimeTypes","text/plain");
+
+ try
+ {
+ tester.start();
+ HttpTester.Response http = tester.assertIsResponseNotGzipCompressed("GET","test_quotes.txt", filesize, HttpStatus.OK_200);
+ Assert.assertNull(http.get("Vary"));
+ }
+ finally
+ {
+ tester.stop();
+ }
+ }
+
+
+
@Test
public void testGzipCompressedByContentTypeWithEncoding() throws Exception
{
@@ -553,4 +624,24 @@ public class GzipFilterDefaultTest
tester.stop();
}
}
+
+
+ @Test
+ public void testIsNotGzipCompressedSVGZ() throws Exception
+ {
+ GzipTester tester = new GzipTester(testingdir,compressionType);
+ tester.setGzipFilterClass(testFilter);
+
+ FilterHolder holder = tester.setContentServlet(DefaultServlet.class);
+ tester.copyTestServerFile("test.svgz");
+ try
+ {
+ tester.start();
+ tester.assertIsResponseNotGzipFiltered("test.svgz", "test.svgz.sha1", "image/svg+xml", "gzip");
+ }
+ finally
+ {
+ tester.stop();
+ }
+ }
}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java
index a7516228b41..1ab5204c345 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java
@@ -18,16 +18,12 @@
package org.eclipse.jetty.servlets;
-import static org.junit.Assert.assertTrue;
-
import java.io.IOException;
import java.net.URL;
import java.util.EnumSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-
import javax.servlet.DispatcherType;
-import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServlet;
@@ -64,14 +60,14 @@ public class QoSFilterTest
_tester = new ServletTester();
_tester.setContextPath("/context");
_tester.addServlet(TestServlet.class, "/test");
- TestServlet.__maxSleepers=0;
- TestServlet.__sleepers=0;
+ TestServlet.__maxSleepers = 0;
+ TestServlet.__sleepers = 0;
_connectors = new LocalConnector[NUM_CONNECTIONS];
- for(int i = 0; i < _connectors.length; ++i)
+ for (int i = 0; i < _connectors.length; ++i)
_connectors[i] = _tester.createLocalConnector();
- _doneRequests = new CountDownLatch(NUM_CONNECTIONS*NUM_LOOPS);
+ _doneRequests = new CountDownLatch(NUM_CONNECTIONS * NUM_LOOPS);
_tester.start();
}
@@ -85,17 +81,17 @@ public class QoSFilterTest
@Test
public void testNoFilter() throws Exception
{
- for(int i = 0; i < NUM_CONNECTIONS; ++i )
+ for (int i = 0; i < NUM_CONNECTIONS; ++i)
{
new Thread(new Worker(i)).start();
}
- _doneRequests.await(10,TimeUnit.SECONDS);
+ _doneRequests.await(10, TimeUnit.SECONDS);
- if (TestServlet.__maxSleepers<=MAX_QOS)
+ if (TestServlet.__maxSleepers <= MAX_QOS)
LOG.warn("TEST WAS NOT PARALLEL ENOUGH!");
else
- Assert.assertThat(TestServlet.__maxSleepers,Matchers.lessThanOrEqualTo(NUM_CONNECTIONS));
+ Assert.assertThat(TestServlet.__maxSleepers, Matchers.lessThanOrEqualTo(NUM_CONNECTIONS));
}
@Test
@@ -103,19 +99,19 @@ public class QoSFilterTest
{
FilterHolder holder = new FilterHolder(QoSFilter2.class);
holder.setAsyncSupported(true);
- holder.setInitParameter(QoSFilter.MAX_REQUESTS_INIT_PARAM, ""+MAX_QOS);
- _tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
+ holder.setInitParameter(QoSFilter.MAX_REQUESTS_INIT_PARAM, "" + MAX_QOS);
+ _tester.getContext().getServletHandler().addFilterWithMapping(holder, "/*", EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC));
- for(int i = 0; i < NUM_CONNECTIONS; ++i )
+ for (int i = 0; i < NUM_CONNECTIONS; ++i)
{
new Thread(new Worker(i)).start();
}
- _doneRequests.await(10,TimeUnit.SECONDS);
- if (TestServlet.__maxSleepers __maxSleepers)
+ if (__sleepers > __maxSleepers)
__maxSleepers = __sleepers;
}
Thread.sleep(50);
- synchronized(TestServlet.class)
+ synchronized (TestServlet.class)
{
- // System.err.println(_count++);
__sleepers--;
- if(__sleepers > __maxSleepers)
- __maxSleepers = __sleepers;
}
response.setContentType("text/plain");
@@ -234,7 +229,6 @@ public class QoSFilterTest
}
catch (InterruptedException e)
{
- e.printStackTrace();
response.sendError(500);
}
}
@@ -246,7 +240,7 @@ public class QoSFilterTest
public int getPriority(ServletRequest request)
{
String p = request.getParameter("priority");
- if (p!=null)
+ if (p != null)
return Integer.parseInt(p);
return 0;
}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java
index f6bfbb8c1cb..66bf12a58b8 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java
@@ -282,6 +282,27 @@ public class GzipTester
* @param expectedContentType
*/
public void assertIsResponseNotGzipFiltered(String requestedFilename, String testResourceSha1Sum, String expectedContentType) throws Exception
+ {
+ assertIsResponseNotGzipFiltered(requestedFilename, testResourceSha1Sum, expectedContentType,null);
+ }
+
+ /**
+ * Makes sure that the response contains an unfiltered file contents.
+ *
+ * This is used to test exclusions and passthroughs in the GzipFilter.
+ *
+ * An example is to test that it is possible to configure GzipFilter to not recompress content that shouldn't be
+ * compressed by the GzipFilter.
+ *
+ * @param requestedFilename
+ * the filename used to on the GET request,.
+ * @param testResourceSha1Sum
+ * the sha1sum file that contains the SHA1SUM checksum that will be used to verify that the response
+ * contents are what is intended.
+ * @param expectedContentType
+ * @param expectedContentEncoding can be non-null in some circumstances, eg when dealing with pre-gzipped .svgz files
+ */
+ public void assertIsResponseNotGzipFiltered(String requestedFilename, String testResourceSha1Sum, String expectedContentType, String expectedContentEncoding) throws Exception
{
//System.err.printf("[GzipTester] requesting /context/%s%n",requestedFilename);
HttpTester.Request request = HttpTester.newRequest();
@@ -304,7 +325,10 @@ public class GzipTester
String prefix = requestedFilename + " / Response";
Assert.assertThat(prefix + ".status",response.getStatus(),is(HttpServletResponse.SC_OK));
Assert.assertThat(prefix + ".header[Content-Length]",response.get("Content-Length"),notNullValue());
- Assert.assertThat(prefix + ".header[Content-Encoding] (should not be recompressed by GzipFilter)",response.get("Content-Encoding"),nullValue());
+ Assert.assertThat(prefix + ".header[Content-Encoding] (should not be recompressed by GzipFilter)",response.get("Content-Encoding"),
+ expectedContentEncoding == null? nullValue() : notNullValue());
+ if (expectedContentEncoding != null)
+ Assert.assertThat(prefix + ".header[Content-Encoding]",response.get("Content-Encoding"),is(expectedContentEncoding));
Assert.assertThat(prefix + ".header[Content-Type] (should have a Content-Type associated with it)",response.get("Content-Type"),notNullValue());
Assert.assertThat(prefix + ".header[Content-Type]",response.get("Content-Type"),is(expectedContentType));
@@ -339,7 +363,7 @@ public class GzipTester
{
String name = names.nextElement();
String value = message.get(name);
- //System.out.printf(" [%s] = %s%n",name,value);
+ //System.out.printf(" [%s] = %s%n",name,value);
}
}
@@ -371,7 +395,6 @@ public class GzipTester
String uri = "/context/"+filename;
HttpTester.Response response = executeRequest(method,uri);
assertResponseHeaders(expectedFilesize,status,response);
-
// Assert that the contents are what we expect.
if (filename != null)
{
@@ -612,6 +635,11 @@ public class GzipTester
{
this.userAgent = ua;
}
+
+ public void addMimeType (String extension, String mimetype)
+ {
+ this.tester.getContext().getMimeTypes().addMimeMapping(extension, mimetype);
+ }
public void start() throws Exception
{
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletBufferTypeLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletBufferTypeLengthWrite.java
index 032bdca31c0..16a66ddce11 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletBufferTypeLengthWrite.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletBufferTypeLengthWrite.java
@@ -27,7 +27,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.HttpOutput;
-import org.eclipse.jetty.servlets.GzipFilter;
/**
* A sample servlet to serve static content, using a order of construction that has caused problems for
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthStreamTypeWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthStreamTypeWrite.java
index 8c45a7b3462..52a1b648a38 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthStreamTypeWrite.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthStreamTypeWrite.java
@@ -25,8 +25,6 @@ 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.
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthTypeStreamWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthTypeStreamWrite.java
index 08caf7b3e46..5ccb44aa42f 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthTypeStreamWrite.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthTypeStreamWrite.java
@@ -25,8 +25,6 @@ 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.
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWrite.java
index fe2b0f060c2..f945d1817c1 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWrite.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWrite.java
@@ -25,8 +25,6 @@ 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.
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWriteWithFlush.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWriteWithFlush.java
index f77356ab62e..91d63231f5d 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWriteWithFlush.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWriteWithFlush.java
@@ -25,8 +25,6 @@ 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.
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamTypeLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamTypeLengthWrite.java
index b2c4fa3ad5e..7fdcc8355b8 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamTypeLengthWrite.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamTypeLengthWrite.java
@@ -25,8 +25,6 @@ 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.
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeLengthStreamWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeLengthStreamWrite.java
index a6be524dbd7..b266e9e430b 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeLengthStreamWrite.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeLengthStreamWrite.java
@@ -25,8 +25,6 @@ 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.
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeStreamLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeStreamLengthWrite.java
index 86a82db5167..40a33fab3ab 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeStreamLengthWrite.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeStreamLengthWrite.java
@@ -25,8 +25,6 @@ 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.
diff --git a/jetty-servlets/src/test/resources/jetty-logging.properties b/jetty-servlets/src/test/resources/jetty-logging.properties
index f97be99cc87..a280c758842 100644
--- a/jetty-servlets/src/test/resources/jetty-logging.properties
+++ b/jetty-servlets/src/test/resources/jetty-logging.properties
@@ -2,3 +2,5 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
#org.eclipse.jetty.LEVEL=DEBUG
#org.eclipse.jetty.servlets.LEVEL=DEBUG
#org.eclipse.jetty.servlets.GzipFilter.LEVEL=DEBUG
+#org.eclipse.jetty.servlets.QoSFilter.LEVEL=DEBUG
+#org.eclipse.jetty.servlets.DoSFilter.LEVEL=DEBUG
diff --git a/jetty-servlets/src/test/resources/test.svg b/jetty-servlets/src/test/resources/test.svg
new file mode 100644
index 00000000000..08fbae33514
--- /dev/null
+++ b/jetty-servlets/src/test/resources/test.svg
@@ -0,0 +1,2101 @@
+
+
+
+
diff --git a/jetty-servlets/src/test/resources/test.svg.sha1 b/jetty-servlets/src/test/resources/test.svg.sha1
new file mode 100644
index 00000000000..3b170f0b098
--- /dev/null
+++ b/jetty-servlets/src/test/resources/test.svg.sha1
@@ -0,0 +1 @@
+1ccb7a0b85585d0e9bdc3863ad093d4e53a9ea68 test.svg
diff --git a/jetty-servlets/src/test/resources/test.svgz b/jetty-servlets/src/test/resources/test.svgz
new file mode 100644
index 00000000000..c4d595ffd0a
Binary files /dev/null and b/jetty-servlets/src/test/resources/test.svgz differ
diff --git a/jetty-servlets/src/test/resources/test.svgz.sha1 b/jetty-servlets/src/test/resources/test.svgz.sha1
new file mode 100644
index 00000000000..e8ec3aa6650
--- /dev/null
+++ b/jetty-servlets/src/test/resources/test.svgz.sha1
@@ -0,0 +1 @@
+62df7c3ac6ee6e4462b6abf9ef15b4e916ecf68f test.svgz
diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYConnection.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYConnection.java
index f7d984b0574..52bc964278f 100644
--- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYConnection.java
+++ b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYConnection.java
@@ -139,11 +139,13 @@ public class SPDYConnection extends AbstractConnection implements Controller, Id
EndPoint endPoint = getEndPoint();
// We need to gently close first, to allow
// SSL close alerts to be sent by Jetty
- LOG.debug("Shutting down output {}", endPoint);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Shutting down output {}", endPoint);
endPoint.shutdownOutput();
if (!onlyOutput)
{
- LOG.debug("Closing {}", endPoint);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Closing {}", endPoint);
endPoint.close();
}
}
@@ -158,7 +160,8 @@ public class SPDYConnection extends AbstractConnection implements Controller, Id
protected boolean onReadTimeout()
{
boolean idle = this.idle;
- LOG.debug("Idle timeout on {}, idle={}", this, idle);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Idle timeout on {}, idle={}", this, idle);
if (idle)
goAway(session);
return false;
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Flusher.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Flusher.java
index 6fb5a78cc1b..9347fc5f432 100644
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Flusher.java
+++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Flusher.java
@@ -218,7 +218,7 @@ public class Flusher
}
@Override
- protected void completed()
+ protected void onCompleteSuccess()
{
// will never be called as process always returns SCHEDULED or IDLE
throw new IllegalStateException();
@@ -242,7 +242,7 @@ public class Flusher
}
@Override
- public void failed(Throwable x)
+ public void onCompleteFailure(Throwable x)
{
List failed = new ArrayList<>();
synchronized (lock)
@@ -261,7 +261,6 @@ public class Flusher
// Notify outside the synchronized block.
for (StandardSession.FrameBytes frame : failed)
frame.failed(x);
- super.failed(x);
}
}
}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java
index 469f3a87f78..8e86eb5ae9b 100644
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java
+++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java
@@ -339,11 +339,13 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
notifyIdle(idleListener, false);
try
{
- LOG.debug("Processing {}", frame);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Processing {}", frame);
if (goAwaySent.get())
{
- LOG.debug("Skipped processing of {}", frame);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Skipped processing of {}", frame);
return;
}
@@ -417,11 +419,13 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
notifyIdle(idleListener, false);
try
{
- LOG.debug("Processing {}, {} data bytes", frame, data.remaining());
+ if (LOG.isDebugEnabled())
+ LOG.debug("Processing {}, {} data bytes", frame, data.remaining());
if (goAwaySent.get())
{
- LOG.debug("Skipped processing of {}", frame);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Skipped processing of {}", frame);
return;
}
@@ -430,7 +434,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
if (stream == null)
{
RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
- LOG.debug("Unknown stream {}", rstInfo);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Unknown stream {}", rstInfo);
rst(rstInfo, Callback.Adapter.INSTANCE);
}
else
@@ -569,13 +574,15 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
throw duplicateIdException;
}
RstInfo rstInfo = new RstInfo(streamId, StreamStatus.PROTOCOL_ERROR);
- LOG.debug("Duplicate stream, {}", rstInfo);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Duplicate stream, {}", rstInfo);
rst(rstInfo, Callback.Adapter.INSTANCE); // We don't care (too much) if the reset fails.
return null;
}
else
{
- LOG.debug("Created {}", stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Created {}", stream);
notifyStreamCreated(stream);
return stream;
}
@@ -617,7 +624,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
if (streamIds.get() % 2 == stream.getId() % 2)
localStreamCount.decrementAndGet();
- LOG.debug("Removed {}", stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Removed {}", stream);
notifyStreamClosed(stream);
}
}
@@ -652,7 +660,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
if (stream == null)
{
RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
- LOG.debug("Unknown stream {}", rstInfo);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Unknown stream {}", rstInfo);
rst(rstInfo, Callback.Adapter.INSTANCE);
}
else
@@ -689,14 +698,16 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{
int windowSize = windowSizeSetting.value();
setWindowSize(windowSize);
- LOG.debug("Updated session window size to {}", windowSize);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Updated session window size to {}", windowSize);
}
Settings.Setting maxConcurrentStreamsSetting = frame.getSettings().get(Settings.ID.MAX_CONCURRENT_STREAMS);
if (maxConcurrentStreamsSetting != null)
{
int maxConcurrentStreamsValue = maxConcurrentStreamsSetting.value();
maxConcurrentLocalStreams = maxConcurrentStreamsValue;
- LOG.debug("Updated session maxConcurrentLocalStreams to {}", maxConcurrentStreamsValue);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Updated session maxConcurrentLocalStreams to {}", maxConcurrentStreamsValue);
}
SettingsInfo settingsInfo = new SettingsInfo(frame.getSettings(), frame.isClearPersisted());
notifyOnSettings(listener, settingsInfo);
@@ -735,7 +746,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
if (stream == null)
{
RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
- LOG.debug("Unknown stream, {}", rstInfo);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Unknown stream, {}", rstInfo);
rst(rstInfo, Callback.Adapter.INSTANCE);
}
else
@@ -777,7 +789,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{
if (listener != null)
{
- LOG.debug("Invoking callback with {} on listener {}", x, listener);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Invoking callback with {} on listener {}", x, listener);
listener.onFailure(this, x);
}
}
@@ -798,7 +811,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{
if (listener == null)
return null;
- LOG.debug("Invoking callback with {} on listener {}", pushInfo, listener);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Invoking callback with {} on listener {}", pushInfo, listener);
return listener.onPush(stream, pushInfo);
}
catch (Exception x)
@@ -819,7 +833,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{
if (listener == null)
return null;
- LOG.debug("Invoking callback with {} on listener {}", synInfo, listener);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Invoking callback with {} on listener {}", synInfo, listener);
return listener.onSyn(stream, synInfo);
}
catch (Exception x)
@@ -840,7 +855,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{
if (listener != null)
{
- LOG.debug("Invoking callback with {} on listener {}", rstInfo, listener);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Invoking callback with {} on listener {}", rstInfo, listener);
listener.onRst(this, rstInfo);
}
}
@@ -861,7 +877,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{
if (listener != null)
{
- LOG.debug("Invoking callback with {} on listener {}", settingsInfo, listener);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Invoking callback with {} on listener {}", settingsInfo, listener);
listener.onSettings(this, settingsInfo);
}
}
@@ -882,7 +899,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{
if (listener != null)
{
- LOG.debug("Invoking callback with {} on listener {}", pingResultInfo, listener);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Invoking callback with {} on listener {}", pingResultInfo, listener);
listener.onPing(this, pingResultInfo);
}
}
@@ -903,7 +921,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{
if (listener != null)
{
- LOG.debug("Invoking callback with {} on listener {}", goAwayResultInfo, listener);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Invoking callback with {} on listener {}", goAwayResultInfo, listener);
listener.onGoAway(this, goAwayResultInfo);
}
}
@@ -936,7 +955,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
synchronized (this)
{
ByteBuffer buffer = generator.control(frame);
- LOG.debug("Queuing {} on {}", frame, stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queuing {} on {}", frame, stream);
frameBytes = new ControlFrameBytes(stream, callback, frame, buffer);
if (timeout > 0)
frameBytes.task = scheduler.schedule(frameBytes, timeout, unit);
@@ -966,7 +986,8 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
@Override
public void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback)
{
- LOG.debug("Queuing {} on {}", dataInfo, stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queuing {} on {}", dataInfo, stream);
DataFrameBytes frameBytes = new DataFrameBytes(stream, callback, dataInfo);
if (timeout > 0)
frameBytes.task = scheduler.schedule(frameBytes, timeout, unit);
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardStream.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardStream.java
index 778fe0b95d5..25389d39681 100644
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardStream.java
+++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardStream.java
@@ -141,7 +141,8 @@ public class StandardStream extends IdleTimeout implements IStream
public void updateWindowSize(int delta)
{
int size = windowSize.addAndGet(delta);
- LOG.debug("Updated window size {} -> {} for {}", size - delta, size, this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Updated window size {} -> {} for {}", size - delta, size, this);
}
@Override
@@ -183,7 +184,8 @@ public class StandardStream extends IdleTimeout implements IStream
@Override
public void updateCloseState(boolean close, boolean local)
{
- LOG.debug("{} close={} local={}", this, close, local);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} close={} local={}", this, close, local);
if (close)
{
switch (closeState)
@@ -265,13 +267,15 @@ public class StandardStream extends IdleTimeout implements IStream
// ignore data frame if this stream is remotelyClosed already
if (isRemotelyClosed())
{
- LOG.debug("Stream is remotely closed, ignoring {}", dataInfo);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Stream is remotely closed, ignoring {}", dataInfo);
return;
}
if (!canReceive())
{
- LOG.debug("Protocol error receiving {}, resetting", dataInfo);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Protocol error receiving {}, resetting", dataInfo);
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), Callback.Adapter.INSTANCE);
return;
}
@@ -301,7 +305,8 @@ public class StandardStream extends IdleTimeout implements IStream
{
if (listener != null)
{
- LOG.debug("Invoking reply callback with {} on listener {}", replyInfo, listener);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Invoking reply callback with {} on listener {}", replyInfo, listener);
listener.onReply(this, replyInfo);
}
}
@@ -323,7 +328,8 @@ public class StandardStream extends IdleTimeout implements IStream
{
if (listener != null)
{
- LOG.debug("Invoking headers callback with {} on listener {}", headersInfo, listener);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Invoking headers callback with {} on listener {}", headersInfo, listener);
listener.onHeaders(this, headersInfo);
}
}
@@ -345,9 +351,11 @@ public class StandardStream extends IdleTimeout implements IStream
{
if (listener != null)
{
- LOG.debug("Invoking data callback with {} on listener {}", dataInfo, listener);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Invoking data callback with {} on listener {}", dataInfo, listener);
listener.onData(this, dataInfo);
- LOG.debug("Invoked data callback with {} on listener {}", dataInfo, listener);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Invoked data callback with {} on listener {}", dataInfo, listener);
}
}
catch (Exception x)
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java
index 37105897357..295a49bf6a2 100644
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java
+++ b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java
@@ -576,7 +576,8 @@ public class StandardSessionTest
StandardSession.FrameBytes frameBytes = (StandardSession.FrameBytes)callback;
int streamId = frameBytes.getStream().getId();
- LOG.debug("last: {}, current: {}", lastStreamId, streamId);
+ if (LOG.isDebugEnabled())
+ LOG.debug("last: {}, current: {}", lastStreamId, streamId);
if (lastStreamId < streamId)
lastStreamId = streamId;
else
diff --git a/jetty-spdy/spdy-example-webapp/pom.xml b/jetty-spdy/spdy-example-webapp/pom.xml
index 907da39c54f..626d1a6fab4 100644
--- a/jetty-spdy/spdy-example-webapp/pom.xml
+++ b/jetty-spdy/spdy-example-webapp/pom.xml
@@ -24,6 +24,13 @@
${basedir}/src/main/config/example-jetty-spdy.xml/
+
+ run
+ run-war
+ deploy
+ start
+ stop
+
@@ -53,6 +60,13 @@
${basedir}/src/main/config/example-jetty-spdy-proxy.xml/
+
+ run
+ run-war
+ deploy
+ start
+ stop
+
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod
new file mode 100644
index 00000000000..639c70e3ffd
--- /dev/null
+++ b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.7.v20140316/npn-boot-1.1.7.v20140316.jar|lib/npn/npn-boot-1.1.7.v20140316.jar
+
+[exec]
+-Xbootclasspath/p:lib/npn/npn-boot-1.1.7.v20140316.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod
new file mode 100644
index 00000000000..639c70e3ffd
--- /dev/null
+++ b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.7.v20140316/npn-boot-1.1.7.v20140316.jar|lib/npn/npn-boot-1.1.7.v20140316.jar
+
+[exec]
+-Xbootclasspath/p:lib/npn/npn-boot-1.1.7.v20140316.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnectionFactory.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnectionFactory.java
index cffdba25e9a..e94ab73d389 100644
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnectionFactory.java
+++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnectionFactory.java
@@ -94,7 +94,8 @@ public class HTTPSPDYServerConnectionFactory extends SPDYServerConnectionFactory
// can arrive on the same connection, so we need to create an
// HttpChannel for each SYN in order to run concurrently.
- LOG.debug("Received {} on {}", synInfo, stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Received {} on {}", synInfo, stream);
Fields headers = synInfo.getHeaders();
// According to SPDY/3 spec section 3.2.1 user-agents MUST support gzip compression. Firefox omits the
@@ -136,7 +137,8 @@ public class HTTPSPDYServerConnectionFactory extends SPDYServerConnectionFactory
@Override
public void onHeaders(Stream stream, HeadersInfo headersInfo)
{
- LOG.debug("Received {} on {}", headersInfo, stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Received {} on {}", headersInfo, stream);
HttpChannelOverSPDY channel = (HttpChannelOverSPDY)stream.getAttribute(CHANNEL_ATTRIBUTE);
channel.requestHeaders(headersInfo.getHeaders(), headersInfo.isClose());
}
@@ -150,7 +152,8 @@ public class HTTPSPDYServerConnectionFactory extends SPDYServerConnectionFactory
@Override
public void onData(Stream stream, final DataInfo dataInfo)
{
- LOG.debug("Received {} on {}", dataInfo, stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Received {} on {}", dataInfo, stream);
HttpChannelOverSPDY channel = (HttpChannelOverSPDY)stream.getAttribute(CHANNEL_ATTRIBUTE);
channel.requestContent(dataInfo, dataInfo.isClose());
}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java
index d032aa1c9e3..3a19386a3d9 100644
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java
+++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java
@@ -67,7 +67,8 @@ public class HttpChannelOverSPDY extends HttpChannel
redispatch=true;
else
{
- LOG.debug("Dispatch {}", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Dispatch {}", this);
dispatched=true;
execute(this);
}
@@ -83,12 +84,14 @@ public class HttpChannelOverSPDY extends HttpChannel
{
try
{
- LOG.debug("Executing {}",this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Executing {}",this);
super.run();
}
finally
{
- LOG.debug("Completing {}", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Completing {}", this);
synchronized (this)
{
dispatched = redispatch;
@@ -130,7 +133,8 @@ public class HttpChannelOverSPDY extends HttpChannel
if (!headersComplete && headerComplete())
dispatch=true;
- LOG.debug("HTTP > {} bytes of content", dataInfo.length());
+ if (LOG.isDebugEnabled())
+ LOG.debug("HTTP > {} bytes of content", dataInfo.length());
// We need to copy the dataInfo since we do not know when its bytes
// will be consumed. When the copy is consumed, we consume also the
@@ -145,7 +149,8 @@ public class HttpChannelOverSPDY extends HttpChannel
dataInfo.consume(delta);
}
};
- LOG.debug("Queuing last={} content {}", endRequest, copyDataInfo);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queuing last={} content {}", endRequest, copyDataInfo);
if (content(copyDataInfo))
dispatch=true;
@@ -184,7 +189,8 @@ public class HttpChannelOverSPDY extends HttpChannel
// that we have to deal with
ByteBuffer uri = BufferUtil.toBuffer(uriHeader.getValue());
- LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.getValue(), httpVersion);
+ if (LOG.isDebugEnabled())
+ LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.getValue(), httpVersion);
startRequest(httpMethod, httpMethod.asString(), uri, httpVersion);
Fields.Field schemeHeader = headers.get(HTTPSPDYHeader.SCHEME.name(version));
@@ -223,7 +229,8 @@ public class HttpChannelOverSPDY extends HttpChannel
{
// Spec says headers must be single valued
String value = header.getValue();
- LOG.debug("HTTP > {}: {}", name, value);
+ if (LOG.isDebugEnabled())
+ LOG.debug("HTTP > {}: {}", name, value);
parsedHeader(new HttpField(name,value));
break;
}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java
index 63ff7a40ffc..520ad181cdd 100644
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java
+++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java
@@ -130,7 +130,8 @@ public class HttpTransportOverSPDY implements HttpTransport
StreamException exception = new StreamException(stream.getId(), StreamStatus.PROTOCOL_ERROR,
"Stream already committed!");
callback.failed(exception);
- LOG.debug("Committed response twice.", exception);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Committed response twice.", exception);
return;
}
sendReply(info, !hasContent ? callback : new Callback.Adapter()
@@ -147,7 +148,8 @@ public class HttpTransportOverSPDY implements HttpTransport
if (hasContent)
{
// send the data and let it call the callback
- LOG.debug("Send content: {} on stream: {} lastContent={}", BufferUtil.toDetailString(content), stream,
+ if (LOG.isDebugEnabled())
+ LOG.debug("Send content: {} on stream: {} lastContent={}", BufferUtil.toDetailString(content), stream,
lastContent);
stream.data(new ByteBufferDataInfo(endPoint.getIdleTimeout(), TimeUnit.MILLISECONDS, content, lastContent
), callback);
@@ -156,7 +158,8 @@ public class HttpTransportOverSPDY implements HttpTransport
else if (lastContent && info == null)
{
// send empty data to close and let the send call the callback
- LOG.debug("No content and lastContent=true. Sending empty ByteBuffer to close stream: {}", stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("No content and lastContent=true. Sending empty ByteBuffer to close stream: {}", stream);
stream.data(new ByteBufferDataInfo(endPoint.getIdleTimeout(), TimeUnit.MILLISECONDS,
BufferUtil.EMPTY_BUFFER, lastContent), callback);
}
@@ -180,7 +183,8 @@ public class HttpTransportOverSPDY implements HttpTransport
if (reason != null)
httpStatus.append(" ").append(reason);
headers.put(HTTPSPDYHeader.STATUS.name(version), httpStatus.toString());
- LOG.debug("HTTP < {} {}", httpVersion, httpStatus);
+ if (LOG.isDebugEnabled())
+ LOG.debug("HTTP < {} {}", httpVersion, httpStatus);
// TODO merge the two Field classes into one
HttpFields fields = info.getHttpFields();
@@ -192,7 +196,8 @@ public class HttpTransportOverSPDY implements HttpTransport
String name = field.getName();
String value = field.getValue();
headers.add(name, value);
- LOG.debug("HTTP < {}: {}", name, value);
+ if (LOG.isDebugEnabled())
+ LOG.debug("HTTP < {}: {}", name, value);
}
}
@@ -202,14 +207,16 @@ public class HttpTransportOverSPDY implements HttpTransport
headers.add(HttpHeader.X_POWERED_BY.asString(), HttpConfiguration.SERVER_VERSION);
ReplyInfo reply = new ReplyInfo(headers, close);
- LOG.debug("Sending reply: {} on stream: {}", reply, stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Sending reply: {} on stream: {}", reply, stream);
reply(stream, reply, callback);
}
@Override
public void completed()
{
- LOG.debug("Completed {}", this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Completed {}", this);
}
private void reply(Stream stream, ReplyInfo replyInfo, Callback callback)
@@ -249,7 +256,8 @@ public class HttpTransportOverSPDY implements HttpTransport
public void completed()
{
Stream stream = getStream();
- LOG.debug("Resource pushed for {} on {}",
+ if (LOG.isDebugEnabled())
+ LOG.debug("Resource pushed for {} on {}",
getRequestHeaders().get(HTTPSPDYHeader.URI.name(version)), stream);
coordinator.complete();
}
@@ -268,7 +276,8 @@ public class HttpTransportOverSPDY implements HttpTransport
private void coordinate()
{
- LOG.debug("Pushing resources: {}", resources);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Pushing resources: {}", resources);
// Must send all push frames to the client at once before we
// return from this method and send the main resource data
for (String pushResource : resources)
@@ -277,13 +286,15 @@ public class HttpTransportOverSPDY implements HttpTransport
private void sendNextResourceData()
{
- LOG.debug("{} sendNextResourceData active: {}", hashCode(), active.get());
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} sendNextResourceData active: {}", hashCode(), active.get());
if (active.compareAndSet(false, true))
{
PushResource resource = queue.poll();
if (resource != null)
{
- LOG.debug("Opening new push channel for: {}", resource);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Opening new push channel for: {}", resource);
HttpChannelOverSPDY pushChannel = newHttpChannelOverSPDY(resource.getPushStream(), resource.getPushRequestHeaders());
pushChannel.requestStart(resource.getPushRequestHeaders(), true);
return;
@@ -322,7 +333,8 @@ public class HttpTransportOverSPDY implements HttpTransport
@Override
public void succeeded(Stream pushStream)
{
- LOG.debug("Headers pushed for {} on {}", pushHeaders.get(HTTPSPDYHeader.URI.name(version)), pushStream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Headers pushed for {} on {}", pushHeaders.get(HTTPSPDYHeader.URI.name(version)), pushStream);
queue.offer(new PushResource(pushStream, pushRequestHeaders));
sendNextResourceData();
}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java
index 9e60819ac9b..3a4652f8c1b 100644
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java
+++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java
@@ -167,7 +167,8 @@ public class ReferrerPushStrategy implements PushStrategy
String origin = scheme + "://" + host;
String url = requestHeaders.get(HTTPSPDYHeader.URI.name(version)).getValue();
String absoluteURL = origin + url;
- LOG.debug("Applying push strategy for {}", absoluteURL);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Applying push strategy for {}", absoluteURL);
if (isMainResource(url, responseHeaders))
{
MainResource mainResource = getOrCreateMainResource(absoluteURL);
@@ -190,7 +191,8 @@ public class ReferrerPushStrategy implements PushStrategy
result = getPushResources(absoluteURL);
}
}
- LOG.debug("Pushing {} resources for {}: {}", result.size(), absoluteURL, result);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Pushing {} resources for {}: {}", result.size(), absoluteURL, result);
}
return result;
}
@@ -208,7 +210,8 @@ public class ReferrerPushStrategy implements PushStrategy
MainResource mainResource = mainResources.get(absoluteURL);
if (mainResource == null)
{
- LOG.debug("Creating new main resource for {}", absoluteURL);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Creating new main resource for {}", absoluteURL);
MainResource value = new MainResource(absoluteURL);
mainResource = mainResources.putIfAbsent(absoluteURL, value);
if (mainResource == null)
@@ -283,7 +286,8 @@ public class ReferrerPushStrategy implements PushStrategy
long delay = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - firstResourceAdded.get());
if (!referrer.startsWith(origin) && !isPushOriginAllowed(origin))
{
- LOG.debug("Skipped store of push metadata {} for {}: Origin: {} doesn't match or origin not allowed",
+ if (LOG.isDebugEnabled())
+ LOG.debug("Skipped store of push metadata {} for {}: Origin: {} doesn't match or origin not allowed",
url, name, origin);
return false;
}
@@ -293,18 +297,21 @@ public class ReferrerPushStrategy implements PushStrategy
// although in rare cases few more resources will be stored
if (resources.size() >= maxAssociatedResources)
{
- LOG.debug("Skipped store of push metadata {} for {}: max associated resources ({}) reached",
+ if (LOG.isDebugEnabled())
+ LOG.debug("Skipped store of push metadata {} for {}: max associated resources ({}) reached",
url, name, maxAssociatedResources);
return false;
}
if (delay > referrerPushPeriod)
{
- LOG.debug("Delay: {}ms longer than referrerPushPeriod ({}ms). Not adding resource: {} for: {}", delay,
- referrerPushPeriod, url, name);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Delay: {}ms longer than referrerPushPeriod ({}ms). Not adding resource: {} for: {}",
+ delay, referrerPushPeriod, url, name);
return false;
}
- LOG.debug("Adding: {} to: {} with delay: {}ms.", url, this, delay);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Adding: {} to: {} with delay: {}ms.", url, this, delay);
resources.add(url);
return true;
}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPProxyEngine.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPProxyEngine.java
index cd656bb31d8..8d500a366ed 100644
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPProxyEngine.java
+++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPProxyEngine.java
@@ -88,7 +88,8 @@ public class HTTPProxyEngine extends ProxyEngine
String host = proxyServerInfo.getHost();
int port = proxyServerInfo.getAddress().getPort();
- LOG.debug("Sending HTTP request to: {}", host + ":" + port);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Sending HTTP request to: {}", host + ":" + port);
final Request request = httpClient.newRequest(host, port)
.path(path)
.method(HttpMethod.fromString(method));
@@ -119,7 +120,8 @@ public class HTTPProxyEngine extends ProxyEngine
@Override
public void onData(Stream clientStream, final DataInfo clientDataInfo)
{
- LOG.debug("received clientDataInfo: {} for stream: {}", clientDataInfo, clientStream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("received clientDataInfo: {} for stream: {}", clientDataInfo, clientStream);
DeferredContentProvider contentProvider = (DeferredContentProvider)request.getContent();
contentProvider.offer(clientDataInfo.asByteBuffer(true));
@@ -139,7 +141,8 @@ public class HTTPProxyEngine extends ProxyEngine
@Override
public void onHeaders(final Response response)
{
- LOG.debug("onHeaders called with response: {}. Sending replyInfo to client.", response);
+ if (LOG.isDebugEnabled())
+ LOG.debug("onHeaders called with response: {}. Sending replyInfo to client.", response);
Fields responseHeaders = createResponseHeaders(clientStream, response);
removeHopHeaders(responseHeaders);
ReplyInfo replyInfo = new ReplyInfo(responseHeaders, false);
@@ -163,7 +166,8 @@ public class HTTPProxyEngine extends ProxyEngine
@Override
public void onContent(final Response response, ByteBuffer content)
{
- LOG.debug("onContent called with response: {} and content: {}. Sending response content to client.",
+ if (LOG.isDebugEnabled())
+ LOG.debug("onContent called with response: {} and content: {}. Sending response content to client.",
response, content);
final ByteBuffer contentCopy = httpClient.getByteBufferPool().acquire(content.remaining(), true);
BufferUtil.flipPutFlip(content, contentCopy);
@@ -194,7 +198,8 @@ public class HTTPProxyEngine extends ProxyEngine
@Override
public void onSuccess(Response response)
{
- LOG.debug("onSuccess called. Closing client stream.");
+ if (LOG.isDebugEnabled())
+ LOG.debug("onSuccess called. Closing client stream.");
clientStream.data(new ByteBufferDataInfo(BufferUtil.EMPTY_BUFFER, true), LOGGING_CALLBACK);
}
@@ -264,7 +269,8 @@ public class HTTPProxyEngine extends ProxyEngine
@Override
public void succeeded()
{
- LOG.debug("succeeded");
+ if (LOG.isDebugEnabled())
+ LOG.debug("succeeded");
}
}
}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngineSelector.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngineSelector.java
index 18b8c5db285..3c41023ee1d 100644
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngineSelector.java
+++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngineSelector.java
@@ -57,7 +57,8 @@ public class ProxyEngineSelector extends ServerSessionFrameListener.Adapter
@Override
public final StreamFrameListener onSyn(final Stream clientStream, SynInfo clientSynInfo)
{
- LOG.debug("C -> P {} on {}", clientSynInfo, clientStream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("C -> P {} on {}", clientSynInfo, clientStream);
final Session clientSession = clientStream.getSession();
short clientVersion = clientSession.getVersion();
@@ -66,7 +67,8 @@ public class ProxyEngineSelector extends ServerSessionFrameListener.Adapter
Fields.Field hostHeader = headers.get(HTTPSPDYHeader.HOST.name(clientVersion));
if (hostHeader == null)
{
- LOG.debug("No host header found: " + headers);
+ if (LOG.isDebugEnabled())
+ LOG.debug("No host header found: " + headers);
rst(clientStream);
return null;
}
@@ -79,7 +81,8 @@ public class ProxyEngineSelector extends ServerSessionFrameListener.Adapter
ProxyServerInfo proxyServerInfo = getProxyServerInfo(host);
if (proxyServerInfo == null)
{
- LOG.debug("No matching ProxyServerInfo found for: " + host);
+ if (LOG.isDebugEnabled())
+ LOG.debug("No matching ProxyServerInfo found for: " + host);
rst(clientStream);
return null;
}
@@ -88,11 +91,13 @@ public class ProxyEngineSelector extends ServerSessionFrameListener.Adapter
ProxyEngine proxyEngine = proxyEngines.get(protocol);
if (proxyEngine == null)
{
- LOG.debug("No matching ProxyEngine found for: " + protocol);
+ if (LOG.isDebugEnabled())
+ LOG.debug("No matching ProxyEngine found for: " + protocol);
rst(clientStream);
return null;
}
- LOG.debug("Forwarding request: {} -> {}", clientSynInfo, proxyServerInfo);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Forwarding request: {} -> {}", clientSynInfo, proxyServerInfo);
return proxyEngine.proxy(clientStream, clientSynInfo, proxyServerInfo);
}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/SPDYProxyEngine.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/SPDYProxyEngine.java
index 5316575bb5c..8042d584226 100644
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/SPDYProxyEngine.java
+++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/SPDYProxyEngine.java
@@ -154,7 +154,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
@Override
public void onData(Stream clientStream, final DataInfo clientDataInfo)
{
- LOG.debug("C -> P {} on {}", clientDataInfo, clientStream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("C -> P {} on {}", clientDataInfo, clientStream);
ByteBufferDataInfo serverDataInfo = new ByteBufferDataInfo(clientDataInfo.asByteBuffer(false), clientDataInfo.isClose())
{
@@ -185,7 +186,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
{
SPDYClient client = factory.newSPDYClient(version);
session = client.connect(address, sessionListener);
- LOG.debug("Proxy session connected to {}", address);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Proxy session connected to {}", address);
Session existing = serverSessions.putIfAbsent(host, session);
if (existing != null)
{
@@ -237,7 +239,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
@Override
public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
{
- LOG.debug("S -> P pushed {} on {}. Opening new PushStream P -> C now.", pushInfo, stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("S -> P pushed {} on {}. Opening new PushStream P -> C now.", pushInfo, stream);
PushStreamPromise newPushStreamPromise = new PushStreamPromise(stream, pushInfo);
this.pushStreamPromise.push(newPushStreamPromise);
return new ProxyPushStreamFrameListener(newPushStreamPromise);
@@ -259,7 +262,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
@Override
public void onData(Stream serverStream, final DataInfo serverDataInfo)
{
- LOG.debug("S -> P pushed {} on {}", serverDataInfo, serverStream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("S -> P pushed {} on {}", serverDataInfo, serverStream);
ByteBufferDataInfo clientDataInfo = new ByteBufferDataInfo(serverDataInfo.asByteBuffer(false), serverDataInfo.isClose())
{
@@ -293,7 +297,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
@Override
public StreamFrameListener onPush(Stream senderStream, PushInfo pushInfo)
{
- LOG.debug("S -> P {} on {}");
+ if (LOG.isDebugEnabled())
+ LOG.debug("S -> P {} on {}");
PushInfo newPushInfo = convertPushInfo(pushInfo, senderStream, receiverStream);
PushStreamPromise pushStreamPromise = new PushStreamPromise(senderStream, newPushInfo);
receiverStream.push(newPushInfo, pushStreamPromise);
@@ -303,7 +308,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
@Override
public void onReply(final Stream stream, ReplyInfo replyInfo)
{
- LOG.debug("S -> P {} on {}", replyInfo, stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("S -> P {} on {}", replyInfo, stream);
final ReplyInfo clientReplyInfo = new ReplyInfo(convertHeaders(stream, receiverStream, replyInfo.getHeaders()),
replyInfo.isClose());
reply(stream, clientReplyInfo);
@@ -316,7 +322,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
@Override
public void succeeded()
{
- LOG.debug("P -> C {} from {} to {}", clientReplyInfo, stream, receiverStream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("P -> C {} from {} to {}", clientReplyInfo, stream, receiverStream);
}
@Override
@@ -338,7 +345,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
@Override
public void onData(final Stream stream, final DataInfo dataInfo)
{
- LOG.debug("S -> P {} on {}", dataInfo, stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("S -> P {} on {}", dataInfo, stream);
data(stream, dataInfo);
}
@@ -359,7 +367,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
@Override
public void succeeded()
{
- LOG.debug("P -> C {} from {} to {}", clientDataInfo, stream, receiverStream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("P -> C {} from {} to {}", clientDataInfo, stream, receiverStream);
}
@Override
@@ -396,7 +405,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
@Override
public void succeeded(Stream stream)
{
- LOG.debug("P -> S {} from {} to {}", info, senderStream, stream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("P -> S {} from {} to {}", info, senderStream, stream);
stream.setAttribute(CLIENT_STREAM_ATTRIBUTE, senderStream);
@@ -409,18 +419,21 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
{
if (dataInfoCallback.flushing)
{
- LOG.debug("SYN completed, flushing {}, queue size {}", dataInfoCallback.dataInfo, queue.size());
+ if (LOG.isDebugEnabled())
+ LOG.debug("SYN completed, flushing {}, queue size {}", dataInfoCallback.dataInfo, queue.size());
dataInfoCallback = null;
}
else
{
dataInfoCallback.flushing = true;
- LOG.debug("SYN completed, queue size {}", queue.size());
+ if (LOG.isDebugEnabled())
+ LOG.debug("SYN completed, queue size {}", queue.size());
}
}
else
{
- LOG.debug("SYN completed, queue empty");
+ if (LOG.isDebugEnabled())
+ LOG.debug("SYN completed, queue empty");
}
}
if (dataInfoCallback != null)
@@ -448,18 +461,21 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
dataInfoCallbackToFlush = queue.peek();
if (dataInfoCallbackToFlush.flushing)
{
- LOG.debug("Queued {}, flushing {}, queue size {}", dataInfo, dataInfoCallbackToFlush.dataInfo, queue.size());
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queued {}, flushing {}, queue size {}", dataInfo, dataInfoCallbackToFlush.dataInfo, queue.size());
receiverStream = null;
}
else
{
dataInfoCallbackToFlush.flushing = true;
- LOG.debug("Queued {}, queue size {}", dataInfo, queue.size());
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queued {}, queue size {}", dataInfo, queue.size());
}
}
else
{
- LOG.debug("Queued {}, SYN incomplete, queue size {}", dataInfo, queue.size());
+ if (LOG.isDebugEnabled())
+ LOG.debug("Queued {}, SYN incomplete, queue size {}", dataInfo, queue.size());
}
}
if (receiverStream != null)
@@ -468,7 +484,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
private void flush(Stream receiverStream, DataInfoCallback dataInfoCallback)
{
- LOG.debug("P -> S {} on {}", dataInfoCallback.dataInfo, receiverStream);
+ if (LOG.isDebugEnabled())
+ LOG.debug("P -> S {} on {}", dataInfoCallback.dataInfo, receiverStream);
receiverStream.data(dataInfoCallback.dataInfo, dataInfoCallback); //TODO: timeout???
}
@@ -498,11 +515,13 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
{
assert !dataInfoCallback.flushing;
dataInfoCallback.flushing = true;
- LOG.debug("Completed {}, queue size {}", dataInfo, queue.size());
+ if (LOG.isDebugEnabled())
+ LOG.debug("Completed {}, queue size {}", dataInfo, queue.size());
}
else
{
- LOG.debug("Completed {}, queue empty", dataInfo);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Completed {}, queue empty", dataInfo);
}
}
if (dataInfoCallback != null)
@@ -550,7 +569,8 @@ public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
{
super.succeeded(receiverStream);
- LOG.debug("P -> C PushStreamPromise.succeeded() called with pushStreamPromise: {}", pushStreamPromise);
+ if (LOG.isDebugEnabled())
+ LOG.debug("P -> C PushStreamPromise.succeeded() called with pushStreamPromise: {}", pushStreamPromise);
PushStreamPromise promise = pushStreamPromise;
if (promise != null)
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java
index b0bbf73a705..43c028a0980 100644
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java
+++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java
@@ -18,16 +18,6 @@
package org.eclipse.jetty.spdy.server.http;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.core.IsInstanceOf.instanceOf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -40,15 +30,15 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
-
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.eclipse.jetty.continuation.Continuation;
-import org.eclipse.jetty.continuation.ContinuationSupport;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.Request;
@@ -63,15 +53,23 @@ import org.eclipse.jetty.spdy.api.StringDataInfo;
import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.log.StdErrLog;
import org.junit.Assert;
import org.junit.Test;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
{
- private static final Logger LOG = Log.getLogger(ServerHTTPSPDYTest.class);
+ public static final String SUSPENDED_ATTRIBUTE = ServerHTTPSPDYTest.class.getName() + ".SUSPENDED";
public ServerHTTPSPDYTest(short version)
{
@@ -1160,10 +1158,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
throws IOException, ServletException
{
request.setHandled(true);
-
- final Continuation continuation = ContinuationSupport.getContinuation(request);
- continuation.suspend();
-
+ final AsyncContext asyncContext = request.startAsync();
new Thread()
{
@Override
@@ -1172,7 +1167,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
try
{
readRequestData(request, data.length);
- continuation.complete();
+ asyncContext.complete();
latch.countDown();
}
catch (IOException x)
@@ -1213,17 +1208,17 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
throws IOException, ServletException
{
request.setHandled(true);
- final Continuation continuation = ContinuationSupport.getContinuation(request);
- if (continuation.isInitial())
- {
- continuation.setTimeout(1000);
- continuation.suspend();
- }
- else
+ if (request.getAttribute(SUSPENDED_ATTRIBUTE) == Boolean.TRUE)
{
dispatchedAgainAfterExpire.countDown();
}
-
+ else
+ {
+ AsyncContext asyncContext = request.startAsync();
+ asyncContext.setTimeout(1000);
+ asyncContext.addListener(new AsyncListenerAdapter());
+ request.setAttribute(SUSPENDED_ATTRIBUTE, Boolean.TRUE);
+ }
}
}, 30000), null);
@@ -1257,18 +1252,18 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
throws IOException, ServletException
{
request.setHandled(true);
- final Continuation continuation = ContinuationSupport.getContinuation(request);
- if (continuation.isInitial())
- {
- readRequestData(request, data.length);
- continuation.setTimeout(1000);
- continuation.suspend();
- }
- else
+ if (request.getAttribute(SUSPENDED_ATTRIBUTE) == Boolean.TRUE)
{
dispatchedAgainAfterExpire.countDown();
}
-
+ else
+ {
+ readRequestData(request, data.length);
+ AsyncContext asyncContext = request.startAsync();
+ asyncContext.setTimeout(1000);
+ asyncContext.addListener(new AsyncListenerAdapter());
+ request.setAttribute(SUSPENDED_ATTRIBUTE, Boolean.TRUE);
+ }
}
}, 30000), null);
@@ -1312,10 +1307,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
throws IOException, ServletException
{
request.setHandled(true);
-
- final Continuation continuation = ContinuationSupport.getContinuation(request);
- continuation.suspend();
-
+ final AsyncContext asyncContext = request.startAsync();
new Thread()
{
@Override
@@ -1328,7 +1320,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
int read = 0;
while (read < 2 * data.length)
read += input.read(buffer);
- continuation.complete();
+ asyncContext.complete();
latch.countDown();
}
catch (IOException x)
@@ -1371,17 +1363,20 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
throws IOException, ServletException
{
request.setHandled(true);
-
- final Continuation continuation = ContinuationSupport.getContinuation(request);
-
- if (continuation.isInitial())
+ if (request.getAttribute(SUSPENDED_ATTRIBUTE) == Boolean.TRUE)
{
+ OutputStream output = httpResponse.getOutputStream();
+ output.write(data);
+ }
+ else
+ {
+ final AsyncContext asyncContext = request.startAsync();
+ request.setAttribute(SUSPENDED_ATTRIBUTE, Boolean.TRUE);
InputStream input = request.getInputStream();
byte[] buffer = new byte[256];
int read = 0;
while (read < data.length)
read += input.read(buffer);
- continuation.suspend();
new Thread()
{
@Override
@@ -1390,7 +1385,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
try
{
TimeUnit.SECONDS.sleep(1);
- continuation.resume();
+ asyncContext.dispatch();
latch.countDown();
}
catch (InterruptedException x)
@@ -1400,11 +1395,6 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}
}.start();
}
- else
- {
- OutputStream output = httpResponse.getOutputStream();
- output.write(data);
- }
}
}, 30000), null);
@@ -1532,7 +1522,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
}, idleTimeout), null);
Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/");
- Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0),
+ session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0),
new StreamFrameListener.Adapter()
{
@Override
@@ -1609,4 +1599,27 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
});
}
+ private class AsyncListenerAdapter implements AsyncListener
+ {
+ @Override
+ public void onStartAsync(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onComplete(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onTimeout(AsyncEvent event) throws IOException
+ {
+ event.getAsyncContext().dispatch();
+ }
+
+ @Override
+ public void onError(AsyncEvent event) throws IOException
+ {
+ }
+ }
}
diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java
index 1a9e291e0a6..58de4d3e2c7 100644
--- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java
+++ b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java
@@ -53,7 +53,8 @@ public class NPNServerConnection extends NegotiatingServerConnection implements
@Override
public void protocolSelected(String protocol)
{
- LOG.debug("{} protocol selected {}", this, protocol);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} protocol selected {}", this, protocol);
setProtocol(protocol != null ? protocol : getDefaultProtocol());
NextProtoNego.remove(getSSLEngine());
}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYClientFactoryTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYClientFactoryTest.java
index bba6166b181..844737026b0 100644
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYClientFactoryTest.java
+++ b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYClientFactoryTest.java
@@ -61,10 +61,15 @@ public class SPDYClientFactoryTest extends AbstractTest
session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
- // Sleep a while to allow the factory to remove the session
- // since it is done asynchronously by the selector thread
- TimeUnit.SECONDS.sleep(1);
+ for (int i=0;i<10;i++)
+ {
+ // Sleep a while to allow the factory to remove the session
+ // since it is done asynchronously by the selector thread
+ TimeUnit.SECONDS.sleep(1);
+ if (clientFactory.getSessions().isEmpty())
+ return;
+ }
- Assert.assertTrue(clientFactory.getSessions().isEmpty());
+ Assert.fail(clientFactory.getSessions().toString());
}
}
diff --git a/jetty-spring/pom.xml b/jetty-spring/pom.xml
index 407b78bd5d6..637f50523dd 100644
--- a/jetty-spring/pom.xml
+++ b/jetty-spring/pom.xml
@@ -9,7 +9,7 @@
Example :: Jetty Spring
- 3.1.3.RELEASE
+ 3.2.8.RELEASEtarget/dependencies
diff --git a/jetty-spring/src/main/config/modules/spring.mod b/jetty-spring/src/main/config/modules/spring.mod
new file mode 100644
index 00000000000..444afb2f93a
--- /dev/null
+++ b/jetty-spring/src/main/config/modules/spring.mod
@@ -0,0 +1,16 @@
+#
+# Spring
+#
+[name]
+spring
+
+[depend]
+server
+
+[lib]
+lib/spring/*.jar
+
+[ini-template]
+## See http://www.eclipse.org/jetty/documentation/current/frameworks.html#framework-jetty-spring
+## for information on how to complete spring configuration
+
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java
index 8859cff7d2e..965333b9d65 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java
@@ -136,6 +136,7 @@ public class Main
}
private BaseHome baseHome;
+ private StartArgs startupArgs;
public Main() throws IOException
{
@@ -389,10 +390,10 @@ public class Main
}
boolean transitive = module.isEnabled() && (module.getSources().size() == 0);
- boolean has_ini_lines = module.getInitialise().size() > 0;
+ boolean hasDefinedDefaults = module.getDefaultConfig().size() > 0;
// If it is not enabled or is transitive with ini template lines or toplevel and doesn't exist
- if (!module.isEnabled() || (transitive && has_ini_lines) || (topLevel && !FS.exists(startd_ini) && !appendStartIni))
+ if (!module.isEnabled() || (transitive && hasDefinedDefaults) || (topLevel && !FS.exists(startd_ini) && !appendStartIni))
{
// File BufferedWriter
BufferedWriter writer = null;
@@ -430,7 +431,7 @@ public class Main
out.println("--module=" + name);
args.parse("--module=" + name,source);
modules.enable(name,Collections.singletonList(source));
- for (String line : module.getInitialise())
+ for (String line : module.getDefaultConfig())
{
out.println(line);
args.parse(line,source);
@@ -490,10 +491,9 @@ public class Main
// Process dependencies
module.expandProperties(args.getProperties());
- modules.registerParentsIfMissing(baseHome,args,module);
+ modules.registerParentsIfMissing(module);
modules.buildGraph();
-
// process new ini modules
if (topLevel)
{
@@ -573,9 +573,9 @@ public class Main
// ------------------------------------------------------------
// 3) Module Registration
- Modules modules = new Modules();
+ Modules modules = new Modules(baseHome,args);
StartLog.debug("Registering all modules");
- modules.registerAll(baseHome, args);
+ modules.registerAll();
// ------------------------------------------------------------
// 4) Active Module Resolution
@@ -584,7 +584,7 @@ public class Main
List msources = args.getSources(enabledModule);
modules.enable(enabledModule,msources);
}
-
+
StartLog.debug("Building Module Graph");
modules.buildGraph();
@@ -600,6 +600,7 @@ public class Main
// 6) Resolve Extra XMLs
args.resolveExtraXmls(baseHome);
+ // ------------------------------------------------------------
// 9) Resolve Property Files
args.resolvePropertyFiles(baseHome);
@@ -658,19 +659,7 @@ public class Main
if (args.isStopCommand())
{
- int stopPort = Integer.parseInt(args.getProperties().getString("STOP.PORT"));
- String stopKey = args.getProperties().getString("STOP.KEY");
-
- if (args.getProperties().getString("STOP.WAIT") != null)
- {
- int stopWait = Integer.parseInt(args.getProperties().getString("STOP.PORT"));
-
- stop(stopPort,stopKey,stopWait);
- }
- else
- {
- stop(stopPort,stopKey);
- }
+ doStop(args);
}
// Initialize start.ini
@@ -760,6 +749,22 @@ public class Main
}
}
+ private void doStop(StartArgs args) {
+ int stopPort = Integer.parseInt(args.getProperties().getString("STOP.PORT"));
+ String stopKey = args.getProperties().getString("STOP.KEY");
+
+ if (args.getProperties().getString("STOP.WAIT") != null)
+ {
+ int stopWait = Integer.parseInt(args.getProperties().getString("STOP.PORT"));
+
+ stop(stopPort,stopKey,stopWait);
+ }
+ else
+ {
+ stop(stopPort,stopKey);
+ }
+ }
+
/**
* Stop a running jetty instance.
*/
@@ -867,4 +872,37 @@ public class Main
System.exit(EXIT_USAGE);
}
}
+
+ // ------------------------------------------------------------
+ // implement Apache commons daemon (jsvc) lifecycle methods (init, start, stop, destroy)
+ public void init(String[] args) throws Exception
+ {
+ try
+ {
+ startupArgs = processCommandLine(args);
+ }
+ catch (UsageException e)
+ {
+ System.err.println(e.getMessage());
+ usageExit(e.getCause(),e.getExitCode());
+ }
+ catch (Throwable e)
+ {
+ usageExit(e,UsageException.ERR_UNKNOWN);
+ }
+ }
+
+ public void start() throws Exception
+ {
+ start(startupArgs);
+ }
+
+ public void stop() throws Exception
+ {
+ doStop(startupArgs);
+ }
+
+ public void destroy()
+ {
+ }
}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java
index 2df1b05e64b..dc0de1ced59 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java
@@ -96,7 +96,7 @@ public class Module
/** List of xml configurations for this Module */
private List xmls;
/** List of ini template lines */
- private List initialise;
+ private List defaultConfig;
/** List of library options for this Module */
private List libs;
/** List of files for this Module */
@@ -213,9 +213,14 @@ public class Module
return fileRef;
}
- public List getInitialise()
+ public List getDefaultConfig()
{
- return initialise;
+ return defaultConfig;
+ }
+
+ public boolean hasDefaultConfig()
+ {
+ return (defaultConfig != null) && (defaultConfig.size() > 0);
}
public List getLibs()
@@ -274,7 +279,7 @@ public class Module
parentEdges = new HashSet<>();
childEdges = new HashSet<>();
xmls = new ArrayList<>();
- initialise = new ArrayList<>();
+ defaultConfig = new ArrayList<>();
libs = new ArrayList<>();
files = new ArrayList<>();
jvmArgs = new ArrayList<>();
@@ -328,7 +333,7 @@ public class Module
{
if ("INI-TEMPLATE".equals(sectionType))
{
- initialise.add(line);
+ defaultConfig.add(line);
}
}
else
@@ -344,8 +349,9 @@ public class Module
case "FILES":
files.add(line);
break;
+ case "DEFAULTS":
case "INI-TEMPLATE":
- initialise.add(line);
+ defaultConfig.add(line);
break;
case "LIB":
libs.add(line);
@@ -396,7 +402,10 @@ public class Module
{
StringBuilder str = new StringBuilder();
str.append("Module[").append(logicalName);
- str.append(",").append(fileRef);
+ if (!logicalName.equals(fileRef))
+ {
+ str.append(",file=").append(fileRef);
+ }
if (enabled)
{
str.append(",enabled");
@@ -404,4 +413,5 @@ public class Module
str.append(']');
return str.toString();
}
+
}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/ModuleGraphWriter.java b/jetty-start/src/main/java/org/eclipse/jetty/start/ModuleGraphWriter.java
index 7c612a71400..2d207727acd 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/ModuleGraphWriter.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/ModuleGraphWriter.java
@@ -212,9 +212,9 @@ public class ModuleGraphWriter
}
}
- if (!module.getInitialise().isEmpty())
+ if (!module.getDefaultConfig().isEmpty())
{
- List inis = module.getInitialise();
+ List inis = module.getDefaultConfig();
writeModuleDetailHeader(out,"INI Template",inis.size());
}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java
index 61330ac7546..804d63ae325 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java
@@ -38,6 +38,9 @@ import java.util.regex.Pattern;
*/
public class Modules implements Iterable
{
+ private final BaseHome baseHome;
+ private final StartArgs args;
+
private Map modules = new HashMap<>();
/*
* modules that may appear in the resolved graph but are undefined in the module system
@@ -47,6 +50,12 @@ public class Modules implements Iterable
private Set missingModules = new HashSet();
private int maxDepth = -1;
+
+ public Modules(BaseHome basehome, StartArgs args)
+ {
+ this.baseHome = basehome;
+ this.args = args;
+ }
private Set asNameSet(Set moduleSet)
{
@@ -106,8 +115,10 @@ public class Modules implements Iterable
/**
* Using the provided dependencies, build the module graph
*/
- public void buildGraph()
+ public void buildGraph() throws FileNotFoundException, IOException
{
+ normalizeDependencies();
+
// Connect edges
for (Module module : modules.values())
{
@@ -118,9 +129,13 @@ public class Modules implements Iterable
if (parent == null)
{
if (parentName.contains("${"))
+ {
StartLog.debug("module not found [%s]%n",parentName);
+ }
else
+ {
StartLog.warn("module not found [%s]%n",parentName);
+ }
}
else
{
@@ -250,19 +265,36 @@ public class Modules implements Iterable
}
}
- public void enable(String name, List sources)
+ public void enable(String name, List sources) throws IOException
{
if (name.contains("*"))
{
// A regex!
Pattern pat = Pattern.compile(name);
- for (Map.Entry entry : modules.entrySet())
+ List matching = new ArrayList<>();
+ do
{
- if (pat.matcher(entry.getKey()).matches())
+ matching.clear();
+
+ // find matching entries that are not enabled
+ for (Map.Entry entry : modules.entrySet())
{
- enableModule(entry.getValue(),sources);
+ if (pat.matcher(entry.getKey()).matches())
+ {
+ if (!entry.getValue().isEnabled())
+ {
+ matching.add(entry.getValue());
+ }
+ }
+ }
+
+ // enable them
+ for (Module module : matching)
+ {
+ enableModule(module,sources);
}
}
+ while (!matching.isEmpty());
}
else
{
@@ -276,16 +308,51 @@ public class Modules implements Iterable
}
}
- private void enableModule(Module module, List sources)
+ private void enableModule(Module module, List sources) throws IOException
{
+ if (module.isEnabled())
+ {
+ // already enabled, skip
+ return;
+ }
+
StartLog.debug("Enabling module: %s (via %s)",module.getName(),Main.join(sources,", "));
module.setEnabled(true);
+ args.parseModule(module);
+ module.expandProperties(args.getProperties());
if (sources != null)
{
module.addSources(sources);
}
+
+ // enable any parents that haven't been enabled (yet)
+ Set parentNames = new HashSet<>();
+ parentNames.addAll(module.getParentNames());
+ for(String name: parentNames)
+ {
+ Module parent = modules.get(name);
+ if (parent == null)
+ {
+ // parent module doesn't exist, yet
+ Path file = baseHome.getPath("modules/" + name + ".mod");
+ if (FS.canReadFile(file))
+ {
+ parent = registerModule(file);
+ updateParentReferencesTo(parent);
+ }
+ else
+ {
+ StartLog.debug("Missing module definition: [ Mod: %s | File: %s ]",name,file);
+ missingModules.add(name);
+ }
+ }
+ if (parent != null)
+ {
+ enableModule(parent,sources);
+ }
+ }
}
-
+
private void findChildren(Module module, Set ret)
{
ret.add(module);
@@ -372,32 +439,35 @@ public class Modules implements Iterable
return module;
}
- public void registerParentsIfMissing(BaseHome basehome, StartArgs args, Module module) throws IOException
+ public void registerParentsIfMissing(Module module) throws IOException
{
Set parents = new HashSet<>(module.getParentNames());
for (String name : parents)
{
if (!modules.containsKey(name))
{
- Path file = basehome.getPath("modules/" + name + ".mod");
+ Path file = baseHome.getPath("modules/" + name + ".mod");
if (FS.canReadFile(file))
{
- Module parent = registerModule(basehome,args,file);
+ Module parent = registerModule(file);
updateParentReferencesTo(parent);
- registerParentsIfMissing(basehome, args, parent);
+ registerParentsIfMissing(parent);
}
}
}
}
- public void registerAll(BaseHome basehome, StartArgs args) throws IOException
+ public void registerAll() throws IOException
{
- for (Path path : basehome.getPaths("modules/*.mod"))
+ for (Path path : baseHome.getPaths("modules/*.mod"))
{
- registerModule(basehome,args,path);
+ registerModule(path);
}
-
- // load missing post-expanded dependent modules
+ }
+
+ // load missing post-expanded dependent modules
+ private void normalizeDependencies() throws FileNotFoundException, IOException
+ {
boolean done = false;
while (!done)
{
@@ -419,30 +489,29 @@ public class Modules implements Iterable
for (String missingParent : missingParents)
{
- Path file = basehome.getPath("modules/" + missingParent + ".mod");
+ Path file = baseHome.getPath("modules/" + missingParent + ".mod");
if (FS.canReadFile(file))
{
- Module module = registerModule(basehome,args,file);
+ Module module = registerModule(file);
updateParentReferencesTo(module);
}
else
{
- StartLog.debug("Missing module definition: [ Mod: %s | File: %s]",missingParent,file);
+ StartLog.debug("Missing module definition: [ Mod: %s | File: %s ]",missingParent,file);
missingModules.add(missingParent);
}
}
}
}
- private Module registerModule(BaseHome basehome, StartArgs args, Path file) throws FileNotFoundException, IOException
+ private Module registerModule(Path file) throws FileNotFoundException, IOException
{
if (!FS.canReadFile(file))
{
throw new IOException("Cannot read file: " + file);
}
- StartLog.debug("Registering Module: %s",basehome.toShortForm(file));
- Module module = new Module(basehome,file);
- module.expandProperties(args.getProperties());
+ StartLog.debug("Registering Module: %s",baseHome.toShortForm(file));
+ Module module = new Module(baseHome,file);
return register(module);
}
@@ -485,7 +554,7 @@ public class Modules implements Iterable
StartLog.warn("** Unable to continue, required dependency missing. [%s]",missing);
StartLog.warn("** As configured, Jetty is unable to start due to a missing enabled module dependency.");
StartLog.warn("** This may be due to a transitive dependency akin to spdy on npn, which resolves based on the JDK in use.");
- return Collections.emptyList();
+ throw new UsageException(UsageException.ERR_BAD_ARG, "Missing referenced dependency: " + missing);
}
}
}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/PathMatchers.java b/jetty-start/src/main/java/org/eclipse/jetty/start/PathMatchers.java
index 05e08f95ed1..c7e2e7883a7 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/PathMatchers.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/PathMatchers.java
@@ -96,15 +96,11 @@ public class PathMatchers
// If the pattern starts with a root path then its assumed to
// be a full system path
- for (Path root : fs.getRootDirectories())
+ if (isAbsolute(pattern))
{
- StartLog.debug("root: " + root);
- if (pattern.startsWith(root.toString()))
- {
- String pat = "glob:" + pattern;
- StartLog.debug("Using absolute path pattern: " + pat);
- return fs.getPathMatcher(pat);
- }
+ String pat = "glob:" + pattern;
+ StartLog.debug("Using absolute path pattern: " + pat);
+ return fs.getPathMatcher(pat);
}
// Doesn't start with filesystem root, then assume the pattern
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java
index 7d35aaaf4c8..3875a4de9f4 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java
@@ -61,6 +61,22 @@ public final class Props implements Iterable
this(key,value,origin);
this.overrides = overrides;
}
+
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Prop [key=");
+ builder.append(key);
+ builder.append(", value=");
+ builder.append(value);
+ builder.append(", origin=");
+ builder.append(origin);
+ builder.append(", overrides=");
+ builder.append(overrides);
+ builder.append("]");
+ return builder.toString();
+ }
}
public static final String ORIGIN_SYSPROP = "";
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
index 43df38122a6..4aff293052b 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
@@ -647,11 +647,25 @@ public class StartArgs
}
public void parse(final String rawarg, String source)
+ {
+ parse(rawarg,source,true);
+ }
+
+ /**
+ * Parse a single line of argument.
+ *
+ * @param rawarg the raw argument to parse
+ * @param source the origin of this line of argument
+ * @param replaceProps true if properties in this parse replace previous ones, false to not replace.
+ */
+ private void parse(final String rawarg, String source, boolean replaceProps)
{
if (rawarg == null)
{
return;
}
+
+ StartLog.debug("parse(\"%s\", \"%s\", %b)",rawarg,source,replaceProps);
final String arg = rawarg.trim();
@@ -810,11 +824,11 @@ public class StartArgs
{
case 2:
System.setProperty(assign[0],assign[1]);
- setProperty(assign[0],assign[1],source);
+ setProperty(assign[0],assign[1],source,replaceProps);
break;
case 1:
System.setProperty(assign[0],"");
- setProperty(assign[0],"",source);
+ setProperty(assign[0],"",source,replaceProps);
break;
default:
break;
@@ -840,11 +854,14 @@ public class StartArgs
String key = arg.substring(0,idx);
String value = arg.substring(idx + 1);
- if (propertySource.containsKey(key))
+ if (replaceProps)
{
- StartLog.warn("Property %s in %s already set in %s",key,source,propertySource.get(key));
+ if (propertySource.containsKey(key))
+ {
+ StartLog.warn("Property %s in %s already set in %s",key,source,propertySource.get(key));
+ }
+ propertySource.put(key,source);
}
- propertySource.put(key,source);
if ("OPTION".equals(key) || "OPTIONS".equals(key))
{
@@ -857,7 +874,7 @@ public class StartArgs
StartLog.warn(warn.toString());
}
- setProperty(key,value,source);
+ setProperty(key,value,source,replaceProps);
return;
}
@@ -877,15 +894,26 @@ public class StartArgs
// only add non-duplicates
if (!propertyFileRefs.contains(arg))
{
- propertyFileRefs.add(arg);
+ propertyFileRefs.add(arg);
}
- return;
+ return;
}
// Anything else is unrecognized
throw new UsageException(ERR_BAD_ARG,"Unrecognized argument: \"%s\" in %s",arg,source);
}
+ public void parseModule(Module module)
+ {
+ if(module.hasDefaultConfig())
+ {
+ for(String line: module.getDefaultConfig())
+ {
+ parse(line,module.getFilesystemRef(),false);
+ }
+ }
+ }
+
public void resolveExtraXmls(BaseHome baseHome) throws IOException
{
// Find and Expand XML files
@@ -910,7 +938,7 @@ public class StartArgs
Path propertyFile = baseHome.getPath(propertyFileRef);
if (!FS.exists(propertyFile))
{
- propertyFile = baseHome.getPath("etc/" + propertyFileRef);
+ propertyFile = baseHome.getPath("etc/" + propertyFileRef);
}
addUniquePropertyFile(propertyFileRef,propertyFile);
}
@@ -921,7 +949,7 @@ public class StartArgs
this.allModules = allModules;
}
- private void setProperty(String key, String value, String source)
+ private void setProperty(String key, String value, String source, boolean replaceProp)
{
// Special / Prevent override from start.ini's
if (key.equals("jetty.home"))
@@ -938,7 +966,19 @@ public class StartArgs
}
// Normal
- properties.setProperty(key,value,source);
+ if (replaceProp)
+ {
+ // always override
+ properties.setProperty(key,value,source);
+ }
+ else
+ {
+ // only set if unset
+ if (!properties.containsKey(key))
+ {
+ properties.setProperty(key,value,source);
+ }
+ }
}
public void setRun(boolean run)
@@ -961,4 +1001,5 @@ public class StartArgs
builder.append("]");
return builder.toString();
}
+
}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java
index 1d2e8ba1d01..4baacb4af09 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java
@@ -51,7 +51,7 @@ public class ConfigurationAssert
*/
public static void assertConfiguration(BaseHome baseHome, StartArgs args, String filename) throws FileNotFoundException, IOException
{
- File testResourcesDir = MavenTestingUtils.getTestResourcesDir();
+ Path testResourcesDir = MavenTestingUtils.getTestResourcesDir().toPath().toAbsolutePath();
File file = MavenTestingUtils.getTestResourceFile(filename);
TextFile textFile = new TextFile(file.toPath());
@@ -149,18 +149,23 @@ public class ConfigurationAssert
assertContainsUnordered("Files/Dirs",expectedFiles,actualFiles);
}
- private static String shorten(BaseHome baseHome, Path path, File testResourcesDir)
+ private static String shorten(BaseHome baseHome, Path path, Path testResourcesDir)
{
String value = baseHome.toShortForm(path);
- if (value.startsWith(testResourcesDir.getAbsolutePath()))
+ if (value.startsWith("${"))
{
- int len = testResourcesDir.getAbsolutePath().length();
+ return value;
+ }
+
+ if (path.startsWith(testResourcesDir))
+ {
+ int len = testResourcesDir.toString().length();
value = "${maven-test-resources}" + value.substring(len);
}
return value;
}
-
- private static void assertContainsUnordered(String msg, Collection expectedSet, Collection actualSet)
+
+ public static void assertContainsUnordered(String msg, Collection expectedSet, Collection actualSet)
{
// same size?
boolean mismatch = expectedSet.size() != actualSet.size();
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java
index 2043d6b5ae9..54cb773c509 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java
@@ -18,20 +18,27 @@
package org.eclipse.jetty.start;
-import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
-import org.junit.Assert;
+import org.eclipse.jetty.toolchain.test.TestTracker;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
public class MainTest
{
+ @Rule
+ public TestTracker ttracker = new TestTracker();
+
@Before
public void clearSystemProperties()
{
@@ -70,9 +77,9 @@ public class MainTest
System.err.println(args);
// Assert.assertEquals("--stop should not build module tree", 0, args.getEnabledModules().size());
- Assert.assertEquals("--stop missing port","10000",args.getProperties().getString("STOP.PORT"));
- Assert.assertEquals("--stop missing key","foo",args.getProperties().getString("STOP.KEY"));
- Assert.assertEquals("--stop missing wait","300",args.getProperties().getString("STOP.WAIT"));
+ assertEquals("--stop missing port","10000",args.getProperties().getString("STOP.PORT"));
+ assertEquals("--stop missing key","foo",args.getProperties().getString("STOP.KEY"));
+ assertEquals("--stop missing wait","300",args.getProperties().getString("STOP.WAIT"));
}
@Test
@@ -114,9 +121,22 @@ public class MainTest
cmdLineArgs.add("-Xmx1024m");
// Arbitrary Libs
- File extraJar = MavenTestingUtils.getTestResourceFile("extra-libs/example.jar");
- File extraDir = MavenTestingUtils.getTestResourceDir("extra-resources");
- cmdLineArgs.add(String.format("--lib=%s%s%s",extraJar.getAbsolutePath(),File.pathSeparatorChar,extraDir.getAbsolutePath()));
+ Path extraJar = MavenTestingUtils.getTestResourceFile("extra-libs/example.jar").toPath().normalize();
+ Path extraDir = MavenTestingUtils.getTestResourceDir("extra-resources").toPath().normalize();
+
+ extraJar = extraJar.toAbsolutePath();
+ extraDir = extraDir.toAbsolutePath();
+
+ assertThat("Extra Jar exists: " + extraJar,Files.exists(extraJar),is(true));
+ assertThat("Extra Dir exists: " + extraDir,Files.exists(extraDir),is(true));
+
+ StringBuilder lib = new StringBuilder();
+ lib.append("--lib=");
+ lib.append(extraJar.toString());
+ lib.append(File.pathSeparator);
+ lib.append(extraDir.toString());
+
+ cmdLineArgs.add(lib.toString());
// Arbitrary XMLs
cmdLineArgs.add("jetty.xml");
@@ -128,11 +148,37 @@ public class MainTest
StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
BaseHome baseHome = main.getBaseHome();
- Assert.assertThat("jetty.home",baseHome.getHome(),is(homePath.getAbsolutePath()));
- Assert.assertThat("jetty.base",baseHome.getBase(),is(homePath.getAbsolutePath()));
+ assertThat("jetty.home",baseHome.getHome(),is(homePath.getAbsolutePath()));
+ assertThat("jetty.base",baseHome.getBase(),is(homePath.getAbsolutePath()));
ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-jvm.txt");
}
+
+ @Test
+ public void testWithSpdy() throws Exception
+ {
+ List cmdLineArgs = new ArrayList<>();
+
+ File homePath = MavenTestingUtils.getTestResourceDir("usecases/home").getAbsoluteFile();
+ cmdLineArgs.add("jetty.home=" + homePath);
+ cmdLineArgs.add("user.dir=" + homePath);
+ cmdLineArgs.add("java.version=1.7.0_60");
+
+ // Modules
+ cmdLineArgs.add("--module=server");
+ cmdLineArgs.add("--module=deploy");
+ cmdLineArgs.add("--module=spdy");
+
+ Main main = new Main();
+
+ StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
+ BaseHome baseHome = main.getBaseHome();
+
+ assertThat("jetty.home",baseHome.getHome(),is(homePath.getAbsolutePath()));
+ assertThat("jetty.base",baseHome.getBase(),is(homePath.getAbsolutePath()));
+
+ ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-spdy.txt");
+ }
@Test
public void testJettyHomeWithSpaces() throws Exception
@@ -147,8 +193,8 @@ public class MainTest
StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
BaseHome baseHome = main.getBaseHome();
- Assert.assertThat("jetty.home",baseHome.getHome(),is(homePath.getAbsolutePath()));
- Assert.assertThat("jetty.base",baseHome.getBase(),is(homePath.getAbsolutePath()));
+ assertThat("jetty.home",baseHome.getHome(),is(homePath.getAbsolutePath()));
+ assertThat("jetty.base",baseHome.getBase(),is(homePath.getAbsolutePath()));
ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-spaces.txt");
}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleGraphWriterTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleGraphWriterTest.java
index 82db04cf9cb..13b43cc25ee 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleGraphWriterTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleGraphWriterTest.java
@@ -60,8 +60,8 @@ public class ModuleGraphWriterTest
StartArgs args = new StartArgs();
args.parse(config);
- Modules modules = new Modules();
- modules.registerAll(basehome, args);
+ Modules modules = new Modules(basehome, args);
+ modules.registerAll();
modules.buildGraph();
Path outputFile = basehome.getBasePath("graph.dot");
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java
index fff9e4df2ec..506ad932ce0 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java
@@ -19,7 +19,6 @@
package org.eclipse.jetty.start;
import static org.hamcrest.Matchers.contains;
-import static org.hamcrest.Matchers.is;
import java.io.File;
import java.io.IOException;
@@ -66,8 +65,8 @@ public class ModulesTest
args.parse(config);
// Test Modules
- Modules modules = new Modules();
- modules.registerAll(basehome,args);
+ Modules modules = new Modules(basehome,args);
+ modules.registerAll();
List moduleNames = new ArrayList<>();
for (Module mod : modules)
@@ -80,11 +79,42 @@ public class ModulesTest
moduleNames.add(mod.getName());
}
- String expected[] = { "jmx", "client", "stats", "spdy", "deploy", "debug", "security", "npn", "ext", "websocket", "rewrite", "ipaccess", "xinetd",
- "proxy", "webapp", "jndi", "lowresources", "https", "plus", "requestlog", "jsp", "monitor", "xml", "servlet", "jaas", "http", "base", "server",
- "annotations", "resources", "loggging" };
-
- Assert.assertThat("Module count: " + moduleNames,moduleNames.size(),is(expected.length));
+ List expected = new ArrayList<>();
+ expected.add("jmx");
+ expected.add("client");
+ expected.add("stats");
+ expected.add("spdy");
+ expected.add("deploy");
+ expected.add("debug");
+ expected.add("security");
+ expected.add("ext");
+ expected.add("websocket");
+ expected.add("rewrite");
+ expected.add("ipaccess");
+ expected.add("xinetd");
+ expected.add("proxy");
+ expected.add("webapp");
+ expected.add("jndi");
+ expected.add("lowresources");
+ expected.add("https");
+ expected.add("plus");
+ expected.add("requestlog");
+ expected.add("jsp");
+ // (only present if enabled) expected.add("jsp-impl");
+ expected.add("monitor");
+ expected.add("xml");
+ expected.add("ssl");
+ expected.add("protonego");
+ expected.add("servlet");
+ expected.add("jaas");
+ expected.add("http");
+ expected.add("base");
+ expected.add("server");
+ expected.add("annotations");
+ expected.add("resources");
+ expected.add("logging");
+
+ ConfigurationAssert.assertContainsUnordered("All Modules",expected,moduleNames);
}
@Test
@@ -93,7 +123,7 @@ public class ModulesTest
// Test Env
File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
File baseDir = testdir.getEmptyDir();
- String cmdLine[] = new String[] {"jetty.version=TEST"};
+ String cmdLine[] = new String[] {"jetty.version=TEST", "java.version=1.7.0_60"};
// Configuration
CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine);
@@ -109,13 +139,37 @@ public class ModulesTest
args.parse(config);
// Test Modules
- Modules modules = new Modules();
- modules.registerAll(basehome,args);
+ Modules modules = new Modules(basehome,args);
+ modules.registerAll();
modules.enable("[sj]{1}.*",TEST_SOURCE);
+ modules.buildGraph();
- String expected[] = { "jmx", "stats", "spdy", "security", "jndi", "jsp", "servlet", "jaas", "server" };
+ List expected = new ArrayList<>();
+ expected.add("jmx");
+ expected.add("stats");
+ expected.add("spdy");
+ expected.add("security");
+ expected.add("jndi");
+ expected.add("jsp");
+ expected.add("servlet");
+ expected.add("jaas");
+ expected.add("server");
+ // transitive
+ expected.add("base");
+ expected.add("ssl");
+ expected.add("protonego");
+ expected.add("protonego-boot");
+ expected.add("protonego-impl");
+ expected.add("xml");
+ expected.add("jsp-impl");
+
+ List resolved = new ArrayList<>();
+ for (Module module : modules.resolveEnabled())
+ {
+ resolved.add(module.getName());
+ }
- Assert.assertThat("Enabled Module count",modules.resolveEnabled().size(),is(expected.length));
+ ConfigurationAssert.assertContainsUnordered("Enabled Modules",expected,resolved);
}
@Test
@@ -140,14 +194,15 @@ public class ModulesTest
args.parse(config);
// Test Modules
- Modules modules = new Modules();
- modules.registerAll(basehome,args);
- modules.buildGraph();
+ Modules modules = new Modules(basehome, args);
+ modules.registerAll();
// Enable 2 modules
modules.enable("server",TEST_SOURCE);
modules.enable("http",TEST_SOURCE);
+ modules.buildGraph();
+
// Collect active module list
List active = modules.resolveEnabled();
@@ -211,15 +266,16 @@ public class ModulesTest
args.parse(config);
// Test Modules
- Modules modules = new Modules();
- modules.registerAll(basehome,args);
- modules.buildGraph();
- // modules.dump();
+ Modules modules = new Modules(basehome,args);
+ modules.registerAll();
// Enable 2 modules
modules.enable("websocket",TEST_SOURCE);
modules.enable("http",TEST_SOURCE);
+ modules.buildGraph();
+ // modules.dump();
+
// Collect active module list
List active = modules.resolveEnabled();
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/TestBadUseCases.java b/jetty-start/src/test/java/org/eclipse/jetty/start/TestBadUseCases.java
new file mode 100644
index 00000000000..9280cdab156
--- /dev/null
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/TestBadUseCases.java
@@ -0,0 +1,85 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.start;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.junit.Test;
+
+/**
+ * Test bad configuration scenarios.
+ */
+public class TestBadUseCases
+{
+ private void assertBadConfig(String homeName, String baseName, String expectedErrorMessage, String... cmdLineArgs) throws Exception
+ {
+ File homeDir = MavenTestingUtils.getTestResourceDir("usecases/" + homeName);
+ File baseDir = MavenTestingUtils.getTestResourceDir("usecases/" + baseName);
+
+ Main main = new Main();
+ List cmdLine = new ArrayList<>();
+ cmdLine.add("jetty.home=" + homeDir.getAbsolutePath());
+ cmdLine.add("jetty.base=" + baseDir.getAbsolutePath());
+ // cmdLine.add("--debug");
+ for (String arg : cmdLineArgs)
+ {
+ cmdLine.add(arg);
+ }
+
+ try
+ {
+ main.processCommandLine(cmdLine);
+ fail("Expected " + UsageException.class.getName());
+ }
+ catch (UsageException e)
+ {
+ assertThat("Usage error",e.getMessage(),containsString(expectedErrorMessage));
+ }
+ }
+
+ @Test
+ public void testBadJspCommandLine() throws Exception
+ {
+ assertBadConfig("home","base.with.jsp.default",
+ "Missing referenced dependency: jsp-impl/bad-jsp","jsp-impl=bad");
+ }
+
+ @Test
+ public void testBadJspImplName() throws Exception
+ {
+ assertBadConfig("home","base.with.jsp.bad",
+ "Missing referenced dependency: jsp-impl/bogus-jsp");
+ }
+
+ @Test
+ public void testWithSpdyBadNpnVersion() throws Exception
+ {
+ assertBadConfig("home","base.enable.spdy.bad.npn.version",
+ "Missing referenced dependency: protonego-impl/npn-1.7.0_01",
+ "java.version=1.7.0_01", "protonego=npn");
+ }
+
+
+}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java b/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java
index aef3da70691..bf77b48141d 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java
@@ -73,6 +73,30 @@ public class TestUseCases
assertUseCase("home","base.with.include.jetty.dirs","assert-include-jetty-dir-logging.txt");
}
+ @Test
+ public void testWithJspDefault() throws Exception
+ {
+ assertUseCase("home","base.with.jsp.default","assert-jsp-apache.txt");
+ }
+
+ @Test
+ public void testWithJspApache() throws Exception
+ {
+ assertUseCase("home","base.with.jsp.apache","assert-jsp-apache.txt");
+ }
+
+ @Test
+ public void testWithJspGlassfish() throws Exception
+ {
+ assertUseCase("home","base.with.jsp.glassfish","assert-jsp-glassfish.txt");
+ }
+
+ @Test
+ public void testWithJspGlassfishCmdLine() throws Exception
+ {
+ assertUseCase("home","base.with.jsp.default","assert-jsp-glassfish.txt","jsp-impl=glassfish");
+ }
+
@Test
public void testWithMissingNpnVersion() throws Exception
{
@@ -82,15 +106,9 @@ public class TestUseCases
@Test
public void testWithSpdy() throws Exception
{
- assertUseCase("home","base.enable.spdy","assert-enable-spdy.txt","java.version=1.7.0_21");
+ assertUseCase("home","base.enable.spdy","assert-enable-spdy.txt","java.version=1.7.0_60");
}
- @Test
- public void testWithSpdyBadNpnVersion() throws Exception
- {
- assertUseCase("home","base.enable.spdy.bad.npn.version","assert-enable-spdy-bad-npn-version.txt","java.version=1.7.0_01");
- }
-
@Test
public void testWithDatabase() throws Exception
{
diff --git a/jetty-start/src/test/resources/assert-home-with-spdy.txt b/jetty-start/src/test/resources/assert-home-with-spdy.txt
new file mode 100644
index 00000000000..9069c2bf79c
--- /dev/null
+++ b/jetty-start/src/test/resources/assert-home-with-spdy.txt
@@ -0,0 +1,72 @@
+# The XMLs we expect (order is important)
+XML|${jetty.base}/etc/jetty-jmx.xml
+XML|${jetty.base}/etc/protonego-alpn.xml
+XML|${jetty.base}/etc/jetty.xml
+XML|${jetty.base}/etc/jetty-http.xml
+XML|${jetty.base}/etc/jetty-ssl.xml
+XML|${jetty.base}/etc/jetty-plus.xml
+XML|${jetty.base}/etc/jetty-spdy.xml
+XML|${jetty.base}/etc/jetty-annotations.xml
+XML|${jetty.base}/etc/jetty-deploy.xml
+XML|${jetty.base}/etc/jetty-websockets.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.base}/lib/annotations/javax.annotation-api-1.2.jar
+LIB|${jetty.base}/lib/annotations/org.objectweb.asm-TEST.jar
+LIB|${jetty.base}/lib/jetty-annotations-TEST.jar
+LIB|${jetty.base}/lib/jetty-continuation-TEST.jar
+LIB|${jetty.base}/lib/jetty-http-TEST.jar
+LIB|${jetty.base}/lib/jetty-io-TEST.jar
+LIB|${jetty.base}/lib/jetty-deploy-TEST.jar
+LIB|${jetty.base}/lib/jetty-jmx-TEST.jar
+LIB|${jetty.base}/lib/jetty-jndi-TEST.jar
+LIB|${jetty.base}/lib/jetty-plus-TEST.jar
+LIB|${jetty.base}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.base}/lib/jetty-security-TEST.jar
+LIB|${jetty.base}/lib/jetty-server-TEST.jar
+LIB|${jetty.base}/lib/jetty-servlet-TEST.jar
+LIB|${jetty.base}/lib/jetty-util-TEST.jar
+LIB|${jetty.base}/lib/jetty-webapp-TEST.jar
+LIB|${jetty.base}/lib/jetty-xml-TEST.jar
+LIB|${jetty.base}/lib/spdy/spdy-client-TEST.jar
+LIB|${jetty.base}/lib/spdy/spdy-core-TEST.jar
+LIB|${jetty.base}/lib/spdy/spdy-http-common-TEST.jar
+LIB|${jetty.base}/lib/spdy/spdy-http-server-TEST.jar
+LIB|${jetty.base}/lib/spdy/spdy-server-TEST.jar
+LIB|${jetty.base}/lib/jndi/javax.activation-1.1.jar
+LIB|${jetty.base}/lib/jndi/javax.transaction-api-1.2.jar
+LIB|${jetty.base}/lib/servlet-api-3.1.jar
+LIB|${jetty.base}/lib/websocket/javax.websocket-api-1.0.jar
+LIB|${jetty.base}/lib/websocket/javax-websocket-client-impl-TEST.jar
+LIB|${jetty.base}/lib/websocket/javax-websocket-server-impl-TEST.jar
+LIB|${jetty.base}/lib/websocket/websocket-api-TEST.jar
+LIB|${jetty.base}/lib/websocket/websocket-client-TEST.jar
+LIB|${jetty.base}/lib/websocket/websocket-common-TEST.jar
+LIB|${jetty.base}/lib/websocket/websocket-server-TEST.jar
+LIB|${jetty.base}/lib/websocket/websocket-servlet-TEST.jar
+
+# The Properties we expect (order is irrelevant)
+PROP|java.version=1.7.0_60
+PROP|jetty.keymanager.password=OBF:1u2u1wml1z7s1z7a1wnl1u2g
+PROP|jetty.keystore=etc/keystore
+PROP|jetty.keystore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
+PROP|jetty.secure.port=8443
+PROP|jetty.truststore=etc/keystore
+PROP|jetty.truststore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
+PROP|protonego=alpn
+PROP|spdy.port=8443
+PROP|spdy.timeout=30000
+
+# JVM Args
+JVM|-Xms1024m
+JVM|-Xmx1024m
+
+# Downloads
+DOWNLOAD|http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar
+DOWNLOAD|http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/main/config/etc/keystore|etc/keystore
+
+# Files
+FILE|lib/
+FILE|lib/alpn/
+
+
diff --git a/jetty-start/src/test/resources/usecases/assert-enable-spdy.txt b/jetty-start/src/test/resources/usecases/assert-enable-spdy.txt
index b097f5d12f4..40577a7ed30 100644
--- a/jetty-start/src/test/resources/usecases/assert-enable-spdy.txt
+++ b/jetty-start/src/test/resources/usecases/assert-enable-spdy.txt
@@ -1,10 +1,12 @@
# The XMLs we expect (order is important)
XML|${jetty.home}/etc/jetty-jmx.xml
+XML|${jetty.home}/etc/protonego-alpn.xml
XML|${jetty.home}/etc/jetty.xml
XML|${jetty.home}/etc/jetty-http.xml
XML|${jetty.home}/etc/jetty-ssl.xml
XML|${jetty.home}/etc/jetty-spdy.xml
+
# The LIBs we expect (order is irrelevant)
LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
LIB|${jetty.home}/lib/jetty-http-TEST.jar
@@ -23,15 +25,25 @@ LIB|${jetty.home}/lib/spdy/spdy-core-TEST.jar
# The Properties we expect (order is irrelevant)
PROP|jetty.port=9090
+PROP|jetty.secure.port=8443
PROP|jetty.keystore=etc/keystore
PROP|jetty.keystore.password=friendly
PROP|jetty.keymanager.password=icecream
PROP|jetty.truststore=etc/keystore
PROP|jetty.truststore.password=sundae
-PROP|java.version=1.7.0_21
+PROP|java.version=1.7.0_60
+PROP|protonego=alpn
+PROP|spdy.port=8443
+PROP|spdy.timeout=30000
# The Downloads
-DOWNLOAD|http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
+DOWNLOAD|http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar
+DOWNLOAD|http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/main/config/etc/keystore|etc/keystore
# The Bootlib
-BOOTLIB|-Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
+BOOTLIB|-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar
+
+# The Files
+FILE|lib/
+FILE|lib/alpn/
+
diff --git a/jetty-start/src/test/resources/usecases/assert-jsp-apache.txt b/jetty-start/src/test/resources/usecases/assert-jsp-apache.txt
new file mode 100644
index 00000000000..fe3d51ce8aa
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/assert-jsp-apache.txt
@@ -0,0 +1,26 @@
+# The XMLs we expect (order is important)
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
+LIB|${jetty.home}/lib/jetty-http-TEST.jar
+LIB|${jetty.home}/lib/jetty-io-TEST.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-server-TEST.jar
+LIB|${jetty.home}/lib/jetty-servlet-TEST.jar
+LIB|${jetty.home}/lib/jetty-util-TEST.jar
+LIB|${jetty.home}/lib/jetty-xml-TEST.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+LIB|${jetty.home}/lib/apache-jsp/javax.servlet.jsp.javax.servlet.jsp-api-TEST.jar
+LIB|${jetty.home}/lib/apache-jsp/org.eclipse.jetty.apache-jsp-TEST.jar
+LIB|${jetty.home}/lib/apache-jsp/org.eclipse.jetty.orbit.org.eclipse.jdt.core-TEST.jar
+LIB|${jetty.home}/lib/apache-jsp/org.mortbay.jasper.apache-el-TEST.jar
+LIB|${jetty.home}/lib/apache-jsp/org.mortbay.jasper.apache-jsp-TEST.jar
+
+# The Properties we expect (order is irrelevant)
+PROP|jetty.port=9090
+PROP|jsp-impl=apache
+
+# Files / Directories to create
+# FILE|lib/
diff --git a/jetty-start/src/test/resources/usecases/assert-jsp-glassfish.txt b/jetty-start/src/test/resources/usecases/assert-jsp-glassfish.txt
new file mode 100644
index 00000000000..9c17c56fb27
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/assert-jsp-glassfish.txt
@@ -0,0 +1,28 @@
+# The XMLs we expect (order is important)
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
+LIB|${jetty.home}/lib/jetty-http-TEST.jar
+LIB|${jetty.home}/lib/jetty-io-TEST.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-server-TEST.jar
+LIB|${jetty.home}/lib/jetty-servlet-TEST.jar
+LIB|${jetty.home}/lib/jetty-util-TEST.jar
+LIB|${jetty.home}/lib/jetty-xml-TEST.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+LIB|${jetty.home}/lib/jsp/javax.el-TEST.jar
+LIB|${jetty.home}/lib/jsp/javax.servlet.jsp.jstl-TEST.jar
+LIB|${jetty.home}/lib/jsp/javax.servlet.jsp-api-TEST.jar
+LIB|${jetty.home}/lib/jsp/javax.servlet.jsp-TEST.jar
+LIB|${jetty.home}/lib/jsp/jetty-jsp-jdt-TEST.jar
+LIB|${jetty.home}/lib/jsp/org.eclipse.jdt.core-TEST.jar
+LIB|${jetty.home}/lib/jsp/org.eclipse.jetty.orbit.javax.servlet.jsp.jstl-TEST.jar
+
+# The Properties we expect (order is irrelevant)
+PROP|jetty.port=9090
+PROP|jsp-impl=glassfish
+
+# Files / Directories to create
+# FILE|lib/
diff --git a/jetty-start/src/test/resources/usecases/base.with.jsp.apache/start.ini b/jetty-start/src/test/resources/usecases/base.with.jsp.apache/start.ini
new file mode 100644
index 00000000000..fcdea021bd8
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/base.with.jsp.apache/start.ini
@@ -0,0 +1,7 @@
+
+--module=server
+--module=http
+--module=jsp
+jsp-impl=apache
+
+jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.with.jsp.bad/start.ini b/jetty-start/src/test/resources/usecases/base.with.jsp.bad/start.ini
new file mode 100644
index 00000000000..96e495acaff
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/base.with.jsp.bad/start.ini
@@ -0,0 +1,7 @@
+
+--module=server
+--module=http
+--module=jsp
+jsp-impl=bogus
+
+jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.with.jsp.default/start.ini b/jetty-start/src/test/resources/usecases/base.with.jsp.default/start.ini
new file mode 100644
index 00000000000..bf58fa82d77
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/base.with.jsp.default/start.ini
@@ -0,0 +1,6 @@
+
+--module=server
+--module=http
+--module=jsp
+
+jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.with.jsp.glassfish/start.ini b/jetty-start/src/test/resources/usecases/base.with.jsp.glassfish/start.ini
new file mode 100644
index 00000000000..7107adec968
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/base.with.jsp.glassfish/start.ini
@@ -0,0 +1,7 @@
+
+--module=server
+--module=http
+--module=jsp
+jsp-impl=glassfish
+
+jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.el-3.0.0.jar b/jetty-start/src/test/resources/usecases/home/etc/protonego-alpn.xml
similarity index 100%
rename from jetty-start/src/test/resources/usecases/home/lib/jsp/javax.el-3.0.0.jar
rename to jetty-start/src/test/resources/usecases/home/etc/protonego-alpn.xml
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-2.3.2.jar b/jetty-start/src/test/resources/usecases/home/etc/protonego-npn.xml
similarity index 100%
rename from jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-2.3.2.jar
rename to jetty-start/src/test/resources/usecases/home/etc/protonego-npn.xml
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-api-2.3.1.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/javax.servlet.jsp.javax.servlet.jsp-api-TEST.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-api-2.3.1.jar
rename to jetty-start/src/test/resources/usecases/home/lib/apache-jsp/javax.servlet.jsp.javax.servlet.jsp-api-TEST.jar
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp.jstl-1.2.0.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.eclipse.jetty.apache-jsp-TEST.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp.jstl-1.2.0.jar
rename to jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.eclipse.jetty.apache-jsp-TEST.jar
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/org.apache.taglibs.standard.glassfish-1.2.0.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.eclipse.jetty.orbit.org.eclipse.jdt.core-TEST.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/home/lib/jsp/org.apache.taglibs.standard.glassfish-1.2.0.jar
rename to jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.eclipse.jetty.orbit.org.eclipse.jdt.core-TEST.jar
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/org.eclipse.jdt.core-3.8.2.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.mortbay.jasper.apache-el-TEST.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/home/lib/jsp/org.eclipse.jdt.core-3.8.2.jar
rename to jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.mortbay.jasper.apache-el-TEST.jar
diff --git a/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.mortbay.jasper.apache-jsp-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.mortbay.jasper.apache-jsp-TEST.jar
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/jetty-start/src/test/resources/usecases/home/lib/apache-jstl/org.apache.taglibs.taglibs-standard-impl-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jstl/org.apache.taglibs.taglibs-standard-impl-TEST.jar
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/jetty-start/src/test/resources/usecases/home/lib/apache-jstl/org.apache.taglibs.taglibs-standard-spec-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jstl/org.apache.taglibs.taglibs-standard-spec-TEST.jar
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.el-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.el-TEST.jar
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-TEST.jar
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-api-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-api-TEST.jar
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp.jstl-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp.jstl-TEST.jar
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/jetty-jsp-jdt-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/jetty-jsp-jdt-TEST.jar
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/org.eclipse.jdt.core-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/org.eclipse.jdt.core-TEST.jar
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/org.eclipse.jetty.orbit.javax.servlet.jsp.jstl-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/org.eclipse.jetty.orbit.javax.servlet.jsp.jstl-TEST.jar
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/jetty-start/src/test/resources/usecases/home/modules/jsp-impl/apache-jsp.mod b/jetty-start/src/test/resources/usecases/home/modules/jsp-impl/apache-jsp.mod
new file mode 100644
index 00000000000..aed547c851f
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/jsp-impl/apache-jsp.mod
@@ -0,0 +1,10 @@
+#
+# Apache JSP Module
+#
+
+[name]
+jsp-impl
+
+[lib]
+lib/apache-jsp/*.jar
+
diff --git a/jetty-start/src/test/resources/usecases/home/modules/jsp-impl/glassfish-jsp.mod b/jetty-start/src/test/resources/usecases/home/modules/jsp-impl/glassfish-jsp.mod
new file mode 100644
index 00000000000..130d2b371f4
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/jsp-impl/glassfish-jsp.mod
@@ -0,0 +1,8 @@
+#
+# Glassfish JSP Module
+#
+[name]
+jsp-impl
+
+[lib]
+lib/jsp/*.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/jsp.mod b/jetty-start/src/test/resources/usecases/home/modules/jsp.mod
index f85530d3c8a..fa5b9fdfa95 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/jsp.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/jsp.mod
@@ -1,10 +1,20 @@
#
-# Jetty Servlet Module
+# Jetty JSP Module
#
[depend]
servlet
+jsp-impl/${jsp-impl}-jsp
-[lib]
-lib/jsp/*.jar
+[ini-template]
+# JSP Configuration
+# Select JSP implementation, choices are
+# glassfish : The reference implementation
+# default in jetty <= 9.1
+# apache : The apache version
+# default jetty >= 9.2
+jsp-impl=apache
+
+# To use a non-jdk compiler for JSP compilation when using glassfish uncomment next line
+# -Dorg.apache.jasper.compiler.disablejsr199=true
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn.mod b/jetty-start/src/test/resources/usecases/home/modules/npn.mod
deleted file mode 100644
index 9c9d4bcd1d3..00000000000
--- a/jetty-start/src/test/resources/usecases/home/modules/npn.mod
+++ /dev/null
@@ -1,4 +0,0 @@
-
-[depend]
-npn/npn-${java.version}
-
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_40.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_40.mod
new file mode 100644
index 00000000000..45bbad75c9f
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_40.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_45.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_45.mod
new file mode 100644
index 00000000000..45bbad75c9f
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_45.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_51.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_51.mod
new file mode 100644
index 00000000000..45bbad75c9f
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_51.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_55.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_55.mod
new file mode 100644
index 00000000000..45bbad75c9f
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_55.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_60.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_60.mod
new file mode 100644
index 00000000000..45bbad75c9f
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_60.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0.mod
new file mode 100644
index 00000000000..65e6cb3c4db
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.0.0.v20140317/alpn-boot-8.0.0.v20140317.jar|lib/alpn/alpn-boot-8.0.0.v20140317.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.0.0.v20140317.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0_05.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0_05.mod
new file mode 100644
index 00000000000..65e6cb3c4db
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0_05.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.0.0.v20140317/alpn-boot-8.0.0.v20140317.jar|lib/alpn/alpn-boot-8.0.0.v20140317.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.0.0.v20140317.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn.mod
new file mode 100644
index 00000000000..0e399f05cb1
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn.mod
@@ -0,0 +1,36 @@
+# ALPN is provided via a -Xbootclasspath that modifies the secure connections
+# in java to support the ALPN layer needed for SPDY (and eventually HTTP/2)
+#
+# This modification has a tight dependency on specific recent updates of
+# Java 1.7 and Java 1.8
+# (Java versions prior to 1.7u40 are not supported)
+#
+# The alpn protonego module will use an appropriate alpn-boot jar for your
+# specific version of Java.
+#
+# IMPORTANT: Versions of Java that exist after this module was created are
+# not guaranteed to work with existing alpn-boot jars, and might
+# need a new alpn-boot to be created / tested / deployed by the
+# Jetty project in order to provide support for these future
+# Java versions.
+#
+# All versions of alpn-boot can be found at
+# http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/
+
+[name]
+protonego-impl
+
+[depend]
+protonego-impl/alpn-${java.version}
+
+[lib]
+lib/jetty-alpn-client-${jetty.version}.jar
+lib/jetty-alpn-server-${jetty.version}.jar
+
+[xml]
+etc/protonego-alpn.xml
+
+[files]
+lib/
+lib/alpn/
+
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_04.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_04.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_04.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_04.mod
index a6778222464..007570b6757 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_04.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_04.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar|lib/npn/npn-boot-1.1.0.v20120525.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_05.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_05.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_05.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_05.mod
index a6778222464..007570b6757 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_05.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_05.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar|lib/npn/npn-boot-1.1.0.v20120525.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_06.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_06.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_06.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_06.mod
index bb6b64bf1f1..868a7a77fcb 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_06.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_06.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar|lib/npn/npn-boot-1.1.1.v20121030.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_07.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_07.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_07.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_07.mod
index bb6b64bf1f1..868a7a77fcb 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_07.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_07.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar|lib/npn/npn-boot-1.1.1.v20121030.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_09.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_09.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_09.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_09.mod
index c488457f14e..20c1db27bd5 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_09.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_09.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_10.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_10.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_10.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_10.mod
index c488457f14e..20c1db27bd5 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_10.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_10.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_11.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_11.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_11.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_11.mod
index c488457f14e..20c1db27bd5 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_11.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_11.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_13.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_13.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_13.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_13.mod
index 0264d724869..1645a52dba0 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_13.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_13.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.4.v20130313/npn-boot-1.1.4.v20130313.jar|lib/npn/npn-boot-1.1.4.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_15.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_15.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_15.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_15.mod
index d2d09ea2d68..73bc09007eb 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_15.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_15.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_17.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_17.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_17.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_17.mod
index d2d09ea2d68..73bc09007eb 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_17.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_17.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_21.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_21.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_21.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_21.mod
index d2d09ea2d68..73bc09007eb 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_21.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_21.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_25.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_25.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_25.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_25.mod
index d2d09ea2d68..73bc09007eb 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_25.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_25.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_40.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_40.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_40.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_40.mod
index 909bebf5f70..465e6f034b6 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_40.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_40.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_45.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_45.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_45.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_45.mod
index 909bebf5f70..465e6f034b6 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_45.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_45.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_51.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_51.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_51.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_51.mod
index 909bebf5f70..465e6f034b6 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_51.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_51.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_55.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_55.mod
similarity index 93%
rename from jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_55.mod
rename to jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_55.mod
index 6f6b4250803..639c70e3ffd 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/npn/npn-1.7.0_55.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_55.mod
@@ -1,5 +1,5 @@
[name]
-npn-boot
+protonego-boot
[files]
http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.7.v20140316/npn-boot-1.1.7.v20140316.jar|lib/npn/npn-boot-1.1.7.v20140316.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_60.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_60.mod
new file mode 100644
index 00000000000..639c70e3ffd
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_60.mod
@@ -0,0 +1,8 @@
+[name]
+protonego-boot
+
+[files]
+http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.7.v20140316/npn-boot-1.1.7.v20140316.jar|lib/npn/npn-boot-1.1.7.v20140316.jar
+
+[exec]
+-Xbootclasspath/p:lib/npn/npn-boot-1.1.7.v20140316.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn.mod
new file mode 100644
index 00000000000..040aad10197
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn.mod
@@ -0,0 +1,31 @@
+# NPN is provided via a -Xbootclasspath that modifies the secure connections
+# in java to support the NPN layer needed for SPDY.
+#
+# This modification has a tight dependency on specific updates of Java 1.7.
+# (No support for Java 8 exists for npn / npn-boot, use alpn instead)
+#
+# The npn module will use an appropriate npn-boot jar for your specific
+# version of Java.
+#
+# IMPORTANT: Versions of Java that exist after this module was created are
+# not guaranteed to work with existing npn-boot jars, and might
+# need a new npn-boot to be created / tested / deployed by the
+# Jetty project in order to provide support for these future
+# Java versions.
+#
+# All versions of npn-boot can be found at
+# http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/
+
+
+[name]
+protonego-impl
+
+[depend]
+protonego-impl/npn-${java.version}
+
+[xml]
+etc/protonego-npn.xml
+
+[files]
+lib/
+lib/npn/
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego.mod
new file mode 100644
index 00000000000..d7bba9fbeca
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/protonego.mod
@@ -0,0 +1,15 @@
+#
+# Protocol Negotiatin Selection Module
+#
+
+[depend]
+protonego-impl/${protonego}
+
+[ini-template]
+# Protocol Negotiation Implementation Selection
+# choices are:
+# 'npn' : original implementation for SPDY (now deprecated)
+# 'alpn' : replacement for NPN, in use by current SPDY implementations
+# and the future HTTP/2 spec
+# Note: java 1.8+ are ALPN only.
+protonego=alpn
diff --git a/jetty-start/src/test/resources/usecases/home/modules/spdy.mod b/jetty-start/src/test/resources/usecases/home/modules/spdy.mod
index 92e31a2b231..cf79dfa0f20 100644
--- a/jetty-start/src/test/resources/usecases/home/modules/spdy.mod
+++ b/jetty-start/src/test/resources/usecases/home/modules/spdy.mod
@@ -1,7 +1,10 @@
+#
+# SPDY Support Module
+#
[depend]
-server
-npn
+ssl
+protonego
[lib]
lib/spdy/*.jar
@@ -9,3 +12,15 @@ lib/spdy/*.jar
[xml]
etc/jetty-ssl.xml
etc/jetty-spdy.xml
+
+[ini-template]
+## SPDY Configuration
+
+# Port for SPDY connections
+spdy.port=8443
+
+# SPDY idle timeout in milliseconds
+spdy.timeout=30000
+
+# Initial Window Size for SPDY
+#spdy.initialWindowSize=65536
diff --git a/jetty-start/src/test/resources/usecases/home/modules/ssl.mod b/jetty-start/src/test/resources/usecases/home/modules/ssl.mod
new file mode 100644
index 00000000000..449f58104fb
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/home/modules/ssl.mod
@@ -0,0 +1,35 @@
+#
+# SSL Keystore module
+#
+
+[depend]
+server
+
+[xml]
+etc/jetty-ssl.xml
+
+[files]
+http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/main/config/etc/keystore|etc/keystore
+
+[ini-template]
+## SSL Keystore Configuration
+# define the port to use for secure redirection
+jetty.secure.port=8443
+
+# Setup a demonstration keystore and truststore
+jetty.keystore=etc/keystore
+jetty.truststore=etc/keystore
+
+# Set the demonstration passwords.
+# Note that OBF passwords are not secure, just protected from casual observation
+# See http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
+jetty.keystore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
+jetty.keymanager.password=OBF:1u2u1wml1z7s1z7a1wnl1u2g
+jetty.truststore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
+
+# Set the client auth behavior
+# Set to true if client certificate authentication is required
+# jetty.ssl.needClientAuth=true
+# Set to true if client certificate authentication is desired
+# jetty.ssl.wantClientAuth=true
+
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java
index fdca4ce1350..2cd345ae6de 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java
@@ -71,7 +71,7 @@ public class ArrayTernaryTrie extends AbstractTrie
* The value (if any) for a Trie row.
* A row may be a leaf, a node or both in the Trie tree.
*/
- private final Object[] _value;
+ private final V[] _value;
/**
* The number of rows allocated
@@ -96,7 +96,7 @@ public class ArrayTernaryTrie extends AbstractTrie
public ArrayTernaryTrie(boolean insensitive, int capacityInNodes)
{
super(insensitive);
- _value=new Object[capacityInNodes];
+ _value=(V[])new Object[capacityInNodes];
_tree=new char[capacityInNodes*ROW_SIZE];
_key=new String[capacityInNodes];
}
@@ -216,7 +216,7 @@ public class ArrayTernaryTrie extends AbstractTrie
}
}
- return (V)_value[t];
+ return _value[t];
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java
index 73ccc424fd0..9d8013cacd8 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java
@@ -79,7 +79,7 @@ public class ArrayTrie extends AbstractTrie
* The value (if any) for a Trie row.
* A row may be a leaf, a node or both in the Trie tree.
*/
- private final Object[] _value;
+ private final V[] _value;
/**
* A big index for each row.
@@ -102,7 +102,7 @@ public class ArrayTrie extends AbstractTrie
public ArrayTrie(int capacityInNodes)
{
super(true);
- _value=new Object[capacityInNodes];
+ _value=(V[])new Object[capacityInNodes];
_rowIndex=new char[capacityInNodes*32];
_key=new String[capacityInNodes];
}
@@ -183,7 +183,7 @@ public class ArrayTrie extends AbstractTrie
return null;
}
}
- return (V)_value[t];
+ return _value[t];
}
/* ------------------------------------------------------------ */
@@ -374,7 +374,7 @@ public class ArrayTrie extends AbstractTrie
}
- private void toString(Appendable out, int t)
+ private void toString(Appendable out, int t)
{
if (_value[t]!=null)
{
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java b/jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java
index 7fbbb187d32..0560ffc5361 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java
@@ -22,7 +22,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
-import java.nio.charset.UnsupportedCharsetException;
/** Fast B64 Encoder/Decoder as described in RFC 1421.
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java
index bd7cb06ecd1..53d24db9669 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java
@@ -23,7 +23,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
-import java.nio.Buffer;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
@@ -930,7 +929,7 @@ public class BufferUtil
buf.append(buffer.getClass().getSimpleName());
buf.append("@");
if (buffer.hasArray())
- buf.append(Integer.toHexString(((Object)buffer.array()).hashCode()));
+ buf.append(Integer.toHexString(Arrays.hashCode(buffer.array())));
else
buf.append(Integer.toHexString(buf.hashCode()));
buf.append("[p=");
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ClassLoadingObjectInputStream.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ClassLoadingObjectInputStream.java
index 5b734db7f4f..58f6df411a4 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ClassLoadingObjectInputStream.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ClassLoadingObjectInputStream.java
@@ -71,10 +71,10 @@ public class ClassLoadingObjectInputStream extends ObjectInputStream
boolean hasNonPublicInterface = false;
// define proxy in class loader of non-public interface(s), if any
- Class[] classObjs = new Class[interfaces.length];
+ Class>[] classObjs = new Class[interfaces.length];
for (int i = 0; i < interfaces.length; i++)
{
- Class cl = Class.forName(interfaces[i], false, loader);
+ Class> cl = Class.forName(interfaces[i], false, loader);
if ((cl.getModifiers() & Modifier.PUBLIC) == 0)
{
if (hasNonPublicInterface)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentArrayQueue.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentArrayQueue.java
index fc1326d63a6..c7aa96e3cb7 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentArrayQueue.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentArrayQueue.java
@@ -25,8 +25,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;
@@ -168,6 +166,7 @@ public class ConcurrentArrayQueue extends AbstractQueue
return _blocks.compareAndSet(TAIL_OFFSET,current,update);
}
+ @SuppressWarnings("unchecked")
@Override
public T poll()
{
@@ -276,7 +275,7 @@ public class ConcurrentArrayQueue extends AbstractQueue
}
else
{
- Object element = currentHeadBlock.peek(head);
+ T element = currentHeadBlock.peek(head);
if (element == REMOVED_ELEMENT)
{
// Already removed, try next index
@@ -284,7 +283,7 @@ public class ConcurrentArrayQueue extends AbstractQueue
}
else
{
- return (T)element;
+ return element;
}
}
}
@@ -421,8 +420,11 @@ public class ConcurrentArrayQueue extends AbstractQueue
advance();
- if (element != REMOVED_ELEMENT)
- return (T)element;
+ if (element != REMOVED_ELEMENT) {
+ @SuppressWarnings("unchecked")
+ T e = (T)element;
+ return e;
+ }
}
}
@@ -518,9 +520,10 @@ public class ConcurrentArrayQueue extends AbstractQueue
elements = new AtomicReferenceArray<>(blockSize);
}
- public Object peek(int index)
+ @SuppressWarnings("unchecked")
+ public E peek(int index)
{
- return elements.get(index);
+ return (E)elements.get(index);
}
public boolean store(int index, E item)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ForkInvoker.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ForkInvoker.java
deleted file mode 100644
index c15b313b0d9..00000000000
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ForkInvoker.java
+++ /dev/null
@@ -1,135 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
-// ------------------------------------------------------------------------
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the Eclipse Public License v1.0
-// and Apache License v2.0 which accompanies this distribution.
-//
-// The Eclipse Public License is available at
-// http://www.eclipse.org/legal/epl-v10.html
-//
-// The Apache License v2.0 is available at
-// http://www.opensource.org/licenses/apache2.0.php
-//
-// You may elect to redistribute this code under either of these licenses.
-// ========================================================================
-//
-
-package org.eclipse.jetty.util;
-
-/**
- * Utility class that splits calls to {@link #invoke(Object)} into calls to {@link #fork(Object)} or {@link #call(Object)}
- * depending on the max number of reentrant calls to {@link #invoke(Object)}.
- *
- * This class prevents {@link StackOverflowError}s in case of methods that end up invoking themselves,
- * such is common for {@link Callback#succeeded()}.
- *
- * Typical use case is:
- *
- * Calculating {@code tooManyReenters} usually involves using a {@link ThreadLocal} and algebra on the
- * number of reentrant invocations, which is factored out in this class for convenience.
- *
- * The same code using this class becomes:
- *
- *
- */
-public abstract class ForkInvoker
-{
- private static final ThreadLocal __invocations = new ThreadLocal()
- {
- @Override
- protected Integer initialValue()
- {
- return 0;
- }
- };
- private final int _maxInvocations;
-
- /**
- * Creates an instance with the given max number of reentrant calls to {@link #invoke(Object)}
- *
- * If {@code maxInvocations} is zero or negative, it is interpreted
- * as if the max number of reentrant calls is infinite.
- *
- * @param maxInvocations the max number of reentrant calls to {@link #invoke(Object)}
- */
- public ForkInvoker(int maxInvocations)
- {
- _maxInvocations = maxInvocations;
- }
-
- /**
- * Invokes either {@link #fork(Object)} or {@link #call(Object)}.
- * If {@link #condition()} returns true, {@link #fork(Object)} is invoked.
- * Otherwise, if the max number of reentrant calls is positive and the
- * actual number of reentrant invocations exceeds it, {@link #fork(Object)} is invoked.
- * Otherwise, {@link #call(Object)} is invoked.
- * @param arg TODO
- *
- * @return true if {@link #fork(Object)} has been called, false otherwise
- */
- public boolean invoke(T arg)
- {
- boolean countInvocations = _maxInvocations > 0;
- int invocations = __invocations.get();
- if (condition() || countInvocations && invocations > _maxInvocations)
- {
- fork(arg);
- return true;
- }
- else
- {
- if (countInvocations)
- __invocations.set(invocations + 1);
- try
- {
- call(arg);
- return false;
- }
- finally
- {
- if (countInvocations)
- __invocations.set(invocations);
- }
- }
- }
-
- /**
- * Subclasses should override this method returning true if they want
- * {@link #invoke(Object)} to call {@link #fork(Object)}.
- *
- * @return true if {@link #invoke(Object)} should call {@link #fork(Object)}, false otherwise
- */
- protected boolean condition()
- {
- return false;
- }
-
- /**
- * Executes the forked invocation
- * @param arg TODO
- */
- public abstract void fork(T arg);
-
- /**
- * Executes the direct, non-forked, invocation
- * @param arg TODO
- */
- public abstract void call(T arg);
-}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/FutureCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/FutureCallback.java
index 5bad6b2e111..27403be261d 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/FutureCallback.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/FutureCallback.java
@@ -151,7 +151,7 @@ public class FutureCallback implements Future,Callback
@Override
public String toString()
{
- return String.format("FutureCallback@%x{%b,%b}",hashCode(),_done,_cause==COMPLETED);
+ return String.format("FutureCallback@%x{%b,%b}",hashCode(),_done.get(),_cause==COMPLETED);
}
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java b/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java
index f781c85004d..edba7662b62 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java
@@ -153,7 +153,7 @@ public class FuturePromise implements Future,Promise
@Override
public String toString()
{
- return String.format("FutureCallback@%x{%b,%b,%s}",hashCode(),_done,_cause==COMPLETED,_result);
+ return String.format("FutureCallback@%x{%b,%b,%s}",hashCode(),_done.get(),_cause==COMPLETED,_result);
}
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java
index 1c74d5eaf65..2791803ba69 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java
@@ -50,6 +50,46 @@ import java.util.concurrent.atomic.AtomicReference;
*/
public abstract class IteratingCallback implements Callback
{
+ /**
+ * The internal states of this callback
+ */
+ private enum State
+ {
+ /**
+ * This callback is inactive, ready to iterate.
+ */
+ INACTIVE,
+ /**
+ * This callback is iterating and {@link #process()} has scheduled an
+ * asynchronous operation by returning {@link Action#SCHEDULED}, but
+ * the operation is still undergoing.
+ */
+ ACTIVE,
+ /**
+ * This callback is iterating and {@link #process()} has been called
+ * but not returned yet.
+ */
+ ITERATING,
+ /**
+ * While this callback was iterating, another request for iteration
+ * has been issued, so the iteration must continue even if a previous
+ * call to {@link #process()} returned {@link Action#IDLE}.
+ */
+ ITERATE_AGAIN,
+ /**
+ * The overall job has succeeded.
+ */
+ SUCCEEDED,
+ /**
+ * The overall job has failed.
+ */
+ FAILED,
+ /**
+ * This callback has been closed and cannot be reset.
+ */
+ CLOSED
+ }
+
/**
* The indication of the overall progress of the overall job that
* implementations of {@link #process()} must return.
@@ -71,15 +111,21 @@ public abstract class IteratingCallback implements Callback
/**
* Indicates that {@link #process()} has completed the overall job.
*/
- SUCCEEDED,
- /**
- * Indicates that {@link #process()} has failed the overall job.
- */
- FAILED
+ SUCCEEDED
}
- private final AtomicReference _state = new AtomicReference<>(State.INACTIVE);
-
+ private final AtomicReference _state;
+
+ protected IteratingCallback()
+ {
+ _state = new AtomicReference<>(State.INACTIVE);
+ }
+
+ protected IteratingCallback(boolean needReset)
+ {
+ _state = new AtomicReference<>(needReset ? State.SUCCEEDED : State.INACTIVE);
+ }
+
/**
* Method called by {@link #iterate()} to process the sub task.
*
@@ -91,7 +137,6 @@ public abstract class IteratingCallback implements Callback
*
{@link Action#SCHEDULED} when the sub task asynchronous execution
* has been started
*
{@link Action#SUCCEEDED} when the overall job is completed
- *
{@link Action#FAILED} when the overall job cannot be completed
*
*
* @throws Exception if the sub task processing throws
@@ -99,9 +144,31 @@ public abstract class IteratingCallback implements Callback
protected abstract Action process() throws Exception;
/**
- * Invoked when the overall task has completed successfully.
+ * @deprecated Use {@link #onCompleteSuccess()} instead.
*/
- protected abstract void completed();
+ @Deprecated
+ protected void completed()
+ {
+ }
+
+ /**
+ * Invoked when the overall task has completed successfully.
+ *
+ * @see #onCompleteFailure(Throwable)
+ */
+ protected void onCompleteSuccess()
+ {
+ completed();
+ }
+
+ /**
+ * Invoked when the overall task has completed with a failure.
+ *
+ * @see #onCompleteSuccess()
+ */
+ protected void onCompleteFailure(Throwable x)
+ {
+ }
/**
* This method must be invoked by applications to start the processing
@@ -196,14 +263,25 @@ public abstract class IteratingCallback implements Callback
case SUCCEEDED:
{
// The overall job has completed.
- if (completeSuccess())
- completed();
- return true;
- }
- case FAILED:
- {
- completeFailure();
- return true;
+ while (true)
+ {
+ State current = _state.get();
+ switch(current)
+ {
+ case SUCCEEDED:
+ case FAILED:
+ // Already complete!.
+ return true;
+ case CLOSED:
+ throw new IllegalStateException();
+ default:
+ if (_state.compareAndSet(current, State.SUCCEEDED))
+ {
+ onCompleteSuccess();
+ return true;
+ }
+ }
+ }
}
default:
{
@@ -251,6 +329,11 @@ public abstract class IteratingCallback implements Callback
iterate();
return;
}
+ case CLOSED:
+ {
+ // Too late!
+ return;
+ }
default:
{
throw new IllegalStateException(toString());
@@ -266,54 +349,73 @@ public abstract class IteratingCallback implements Callback
*/
@Override
public void failed(Throwable x)
- {
- completeFailure();
- }
-
- private boolean completeSuccess()
{
while (true)
{
State current = _state.get();
- if (current == State.FAILED)
+ switch (current)
{
- // Success arrived too late, sorry.
- return false;
- }
- else
- {
- if (_state.compareAndSet(current, State.SUCCEEDED))
- return true;
+ case SUCCEEDED:
+ case FAILED:
+ case INACTIVE:
+ case CLOSED:
+ {
+ // Already complete!.
+ return;
+ }
+ default:
+ {
+ if (_state.compareAndSet(current, State.FAILED))
+ {
+ onCompleteFailure(x);
+ return;
+ }
+ }
}
}
}
- private void completeFailure()
+ public void close()
{
while (true)
{
State current = _state.get();
- if (current == State.SUCCEEDED)
+ switch (current)
{
- // Failed arrived too late, sorry.
- return;
- }
- else
- {
- if (_state.compareAndSet(current, State.FAILED))
+ case INACTIVE:
+ case SUCCEEDED:
+ case FAILED:
+ {
+ if (_state.compareAndSet(current, State.CLOSED))
+ return;
break;
+ }
+ default:
+ {
+ if (_state.compareAndSet(current, State.CLOSED))
+ {
+ onCompleteFailure(new IllegalStateException("Closed with pending callback " + this));
+ return;
+ }
+ }
}
}
}
- /**
+ /*
+ * only for testing
* @return whether this callback is idle and {@link #iterate()} needs to be called
*/
- public boolean isIdle()
+ boolean isIdle()
{
return _state.get() == State.INACTIVE;
}
+ public boolean isClosed()
+ {
+ return _state.get() == State.CLOSED;
+ }
+
/**
* @return whether this callback has failed
*/
@@ -330,45 +432,42 @@ public abstract class IteratingCallback implements Callback
return _state.get() == State.SUCCEEDED;
}
+ /**
+ * Resets this callback.
+ *
+ * A callback can only be reset to INACTIVE from the
+ * SUCCEEDED or FAILED states or if it is already INACTIVE.
+ *
+ * @return true if the reset was successful
+ */
+ public boolean reset()
+ {
+ while (true)
+ {
+ switch(_state.get())
+ {
+ case INACTIVE:
+ return true;
+
+ case SUCCEEDED:
+ if (_state.compareAndSet(State.SUCCEEDED, State.INACTIVE))
+ return true;
+ break;
+
+ case FAILED:
+ if (_state.compareAndSet(State.FAILED, State.INACTIVE))
+ return true;
+ break;
+
+ default:
+ return false;
+ }
+ }
+ }
+
@Override
public String toString()
{
return String.format("%s[%s]", super.toString(), _state);
}
-
- /**
- * The internal states of this callback
- */
- private enum State
- {
- /**
- * This callback is inactive, ready to iterate.
- */
- INACTIVE,
- /**
- * This callback is iterating and {@link #process()} has scheduled an
- * asynchronous operation by returning {@link Action#SCHEDULED}, but
- * the operation is still undergoing.
- */
- ACTIVE,
- /**
- * This callback is iterating and {@link #process()} has been called
- * but not returned yet.
- */
- ITERATING,
- /**
- * While this callback was iterating, another request for iteration
- * has been issued, so the iteration must continue even if a previous
- * call to {@link #process()} returned {@link Action#IDLE}.
- */
- ITERATE_AGAIN,
- /**
- * The overall job has succeeded.
- */
- SUCCEEDED,
- /**
- * The overall job has failed.
- */
- FAILED
- }
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingNestedCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingNestedCallback.java
index e018f43a484..dd05ded9789 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingNestedCallback.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingNestedCallback.java
@@ -48,15 +48,14 @@ public abstract class IteratingNestedCallback extends IteratingCallback
}
@Override
- protected void completed()
+ protected void onCompleteSuccess()
{
_callback.succeeded();
}
-
+
@Override
- public void failed(Throwable x)
+ protected void onCompleteFailure(Throwable x)
{
- super.failed(x);
_callback.failed(x);
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/LeakDetector.java b/jetty-util/src/main/java/org/eclipse/jetty/util/LeakDetector.java
index b0ac94e9b4d..55aab63fa5b 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/LeakDetector.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/LeakDetector.java
@@ -20,7 +20,6 @@ package org.eclipse.jetty.util;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
-import java.lang.ref.WeakReference;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -138,7 +137,8 @@ public class LeakDetector extends AbstractLifeCycle implements Runnable
{
@SuppressWarnings("unchecked")
LeakInfo leakInfo = (LeakInfo)queue.remove();
- LOG.debug("Resource GC'ed: {}", leakInfo);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Resource GC'ed: {}", leakInfo);
if (resources.remove(leakInfo.id) != null)
leaked(leakInfo);
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiException.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiException.java
index 2e71f3c58cc..f5aa27df7ec 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiException.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiException.java
@@ -43,10 +43,11 @@ public class MultiException extends Exception
/* ------------------------------------------------------------ */
public void add(Throwable e)
{
+ if (e==null)
+ throw new IllegalArgumentException();
+
if(nested == null)
- {
nested = new ArrayList<>();
- }
if (e instanceof MultiException)
{
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java
index 441d648ea52..026856f46dd 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java
@@ -57,7 +57,7 @@ public class MultiPartInputStreamParser
protected InputStream _in;
protected MultipartConfigElement _config;
protected String _contentType;
- protected MultiMap _parts;
+ protected MultiMap _parts;
protected File _tmpDir;
protected File _contextTmpDir;
protected boolean _deleteOnExit;
@@ -72,7 +72,7 @@ public class MultiPartInputStreamParser
protected OutputStream _out;
protected ByteArrayOutputStream2 _bout;
protected String _contentType;
- protected MultiMap _headers;
+ protected MultiMap _headers;
protected long _size = 0;
protected boolean _temporary = true;
@@ -161,7 +161,7 @@ public class MultiPartInputStreamParser
- protected void setHeaders(MultiMap headers)
+ protected void setHeaders(MultiMap headers)
{
_headers = headers;
}
@@ -359,9 +359,9 @@ public class MultiPartInputStreamParser
if (_parts == null)
return Collections.emptyList();
- Collection values = _parts.values();
+ Collection> values = _parts.values();
List parts = new ArrayList();
- for (Object o: values)
+ for (List o: values)
{
List asList = LazyList.getList(o, false);
parts.addAll(asList);
@@ -406,9 +406,9 @@ public class MultiPartInputStreamParser
throws IOException, ServletException
{
parse();
- Collection values = _parts.values();
+ Collection> values = _parts.values();
List parts = new ArrayList();
- for (Object o: values)
+ for (List o: values)
{
List asList = LazyList.getList(o, false);
parts.addAll(asList);
@@ -447,7 +447,7 @@ public class MultiPartInputStreamParser
//initialize
long total = 0; //keep running total of size of bytes read from input and throw an exception if exceeds MultipartConfigElement._maxRequestSize
- _parts = new MultiMap();
+ _parts = new MultiMap();
//if its not a multipart request, don't parse it
if (_contentType == null || !_contentType.startsWith("multipart/form-data"))
@@ -523,7 +523,7 @@ public class MultiPartInputStreamParser
String contentType=null;
String contentTransferEncoding=null;
- MultiMap headers = new MultiMap();
+ MultiMap headers = new MultiMap();
while(true)
{
line=((ReadLineInputStream)_in).readLine();
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java
index f29db3daac4..f2068bb43d2 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java
@@ -557,12 +557,16 @@ public class Scanner extends AbstractLifeCycle
{
if ((_filter == null) || ((_filter != null) && _filter.accept(f.getParentFile(), f.getName())))
{
- LOG.debug("scan accepted {}",f);
+ if (LOG.isDebugEnabled())
+ LOG.debug("scan accepted {}",f);
String name = f.getCanonicalPath();
scanInfoMap.put(name, new TimeNSize(f.lastModified(),f.length()));
}
else
- LOG.debug("scan rejected {}",f);
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("scan rejected {}",f);
+ }
}
// If it is a directory, scan if it is a known directory or the depth is OK.
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java
index 3085a68735d..07b08368960 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java
@@ -23,7 +23,6 @@ import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -159,14 +158,11 @@ public class SharedBlockingCallback
{
if (_state == null)
{
- // TODO remove when feedback received on 435322
- if (cause==null)
- LOG.warn("null failed cause (please report stack trace) ",new Throwable());
_state = cause==null?FAILED:cause;
_complete.signalAll();
}
else if (_state == IDLE)
- throw new IllegalStateException("IDLE");
+ throw new IllegalStateException("IDLE",cause);
}
finally
{
@@ -249,9 +245,15 @@ public class SharedBlockingCallback
}
finally
{
- _state = IDLE;
- _idle.signalAll();
- _lock.unlock();
+ try
+ {
+ _state = IDLE;
+ _idle.signalAll();
+ }
+ finally
+ {
+ _lock.unlock();
+ }
}
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SocketAddressResolver.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SocketAddressResolver.java
index e75abfc064f..b7916f3d2f7 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/SocketAddressResolver.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SocketAddressResolver.java
@@ -148,7 +148,8 @@ public class SocketAddressResolver
long start = System.nanoTime();
InetSocketAddress result = new InetSocketAddress(host, port);
long elapsed = System.nanoTime() - start;
- LOG.debug("Resolved {} in {} ms", host, TimeUnit.NANOSECONDS.toMillis(elapsed));
+ if (LOG.isDebugEnabled())
+ LOG.debug("Resolved {} in {} ms", host, TimeUnit.NANOSECONDS.toMillis(elapsed));
if (complete.compareAndSet(false, true))
{
if (result.isUnresolved())
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java
index b96a520c110..d30ad320f9b 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java
@@ -569,8 +569,9 @@ public class TypeUtil
// target has no annotations
if ( parameterAnnotations == null || parameterAnnotations.length == 0 )
- {
- LOG.debug("Target has no parameter annotations");
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("Target has no parameter annotations");
return constructor.newInstance(arguments);
}
else
@@ -588,19 +589,22 @@ public class TypeUtil
if (namedArgMap.containsKey(param.value()))
{
- LOG.debug("placing named {} in position {}", param.value(), count);
+ if (LOG.isDebugEnabled())
+ LOG.debug("placing named {} in position {}", param.value(), count);
swizzled[count] = namedArgMap.get(param.value());
}
else
{
- LOG.debug("placing {} in position {}", arguments[count], count);
+ if (LOG.isDebugEnabled())
+ LOG.debug("placing {} in position {}", arguments[count], count);
swizzled[count] = arguments[count];
}
++count;
}
else
{
- LOG.debug("passing on annotation {}", annotation);
+ if (LOG.isDebugEnabled())
+ LOG.debug("passing on annotation {}", annotation);
}
}
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
index f333fc3b5f2..ca2013830c2 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
@@ -663,7 +663,49 @@ public class URIUtil
}
return false;
}
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Create a new URI from the arguments, handling IPv6 host encoding and default ports
+ * @param scheme
+ * @param server
+ * @param port
+ * @param path
+ * @param query
+ * @return A String URI
+ */
+ public static String newURI(String scheme,String server, int port,String path,String query)
+ {
+ StringBuilder builder = newURIBuilder(scheme, server, port);
+ builder.append(path);
+ if (query!=null && query.length()>0)
+ builder.append('?').append(query);
+ return builder.toString();
+ }
+ /* ------------------------------------------------------------ */
+ /**
+ * Create a new URI StringBuilder from the arguments, handling IPv6 host encoding and default ports
+ * @param scheme
+ * @param server
+ * @param port
+ * @return a StringBuilder containing URI prefix
+ */
+ public static StringBuilder newURIBuilder(String scheme,String server, int port)
+ {
+ StringBuilder builder = new StringBuilder();
+ appendSchemeHostPort(builder, scheme, server, port);
+ return builder;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Append scheme, host and port URI prefix, handling IPv6 address encoding and default ports
+ * @param url StringBuilder to append to
+ * @param scheme
+ * @param server
+ * @param port
+ */
public static void appendSchemeHostPort(StringBuilder url,String scheme,String server, int port)
{
if (server.indexOf(':')>=0&&server.charAt(0)!='[')
@@ -671,10 +713,34 @@ public class URIUtil
else
url.append(scheme).append("://").append(server);
- if (port > 0 && (("http".equalsIgnoreCase(scheme) && port != 80) || ("https".equalsIgnoreCase(scheme) && port != 443)))
- url.append(':').append(port);
+ if (port > 0)
+ {
+ switch(scheme)
+ {
+ case "http":
+ if (port!=80)
+ url.append(':').append(port);
+ break;
+
+ case "https":
+ if (port!=443)
+ url.append(':').append(port);
+ break;
+
+ default:
+ url.append(':').append(port);
+ }
+ }
}
+ /* ------------------------------------------------------------ */
+ /**
+ * Append scheme, host and port URI prefix, handling IPv6 address encoding and default ports
+ * @param url StringBuffer to append to
+ * @param scheme
+ * @param server
+ * @param port
+ */
public static void appendSchemeHostPort(StringBuffer url,String scheme,String server, int port)
{
synchronized (url)
@@ -684,10 +750,55 @@ public class URIUtil
else
url.append(scheme).append("://").append(server);
- if (port > 0 && (("http".equalsIgnoreCase(scheme) && port != 80) || ("https".equalsIgnoreCase(scheme) && port != 443)))
- url.append(':').append(port);
+ if (port > 0)
+ {
+ switch(scheme)
+ {
+ case "http":
+ if (port!=80)
+ url.append(':').append(port);
+ break;
+
+ case "https":
+ if (port!=443)
+ url.append(':').append(port);
+ break;
+
+ default:
+ url.append(':').append(port);
+ }
+ }
}
}
+
+ public static boolean equalsIgnoreEncodings(String uriA, String uriB)
+ {
+ int lenA=uriA.length();
+ int lenB=uriB.length();
+ int a=0;
+ int b=0;
+
+ while (a implements Cloneable
int c;
int totalLength = 0;
- ByteArrayOutputStream2 output = new ByteArrayOutputStream2();
- int size=0;
-
- while ((c=in.read())>0)
+ try(ByteArrayOutputStream2 output = new ByteArrayOutputStream2();)
{
- switch ((char) c)
+ int size=0;
+
+ while ((c=in.read())>0)
{
- case '&':
- size=output.size();
- value = size==0?"":output.toString(charset);
- output.setCount(0);
- if (key != null)
- {
- map.add(key,value);
- }
- else if (value!=null&&value.length()>0)
- {
- map.add(value,"");
- }
- key = null;
- value=null;
- if (maxKeys>0 && map.size()>maxKeys)
- throw new IllegalStateException("Form too many keys");
- break;
- case '=':
- if (key!=null)
- {
+ switch ((char) c)
+ {
+ case '&':
+ size=output.size();
+ value = size==0?"":output.toString(charset);
+ output.setCount(0);
+ if (key != null)
+ {
+ map.add(key,value);
+ }
+ else if (value!=null&&value.length()>0)
+ {
+ map.add(value,"");
+ }
+ key = null;
+ value=null;
+ if (maxKeys>0 && map.size()>maxKeys)
+ throw new IllegalStateException("Form too many keys");
+ break;
+ case '=':
+ if (key!=null)
+ {
+ output.write(c);
+ break;
+ }
+ size=output.size();
+ key = size==0?"":output.toString(charset);
+ output.setCount(0);
+ break;
+ case '+':
+ output.write(' ');
+ break;
+ case '%':
+ int code0=in.read();
+ if ('u'==code0)
+ {
+ int code1=in.read();
+ if (code1>=0)
+ {
+ int code2=in.read();
+ if (code2>=0)
+ {
+ int code3=in.read();
+ if (code3>=0)
+ output.write(new String(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3))).getBytes(charset));
+ }
+ }
+
+ }
+ else if (code0>=0)
+ {
+ int code1=in.read();
+ if (code1>=0)
+ output.write((convertHexDigit(code0)<<4)+convertHexDigit(code1));
+ }
+ break;
+ default:
output.write(c);
break;
- }
- size=output.size();
- key = size==0?"":output.toString(charset);
- output.setCount(0);
- break;
- case '+':
- output.write(' ');
- break;
- case '%':
- int code0=in.read();
- if ('u'==code0)
- {
- int code1=in.read();
- if (code1>=0)
- {
- int code2=in.read();
- if (code2>=0)
- {
- int code3=in.read();
- if (code3>=0)
- output.write(new String(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3))).getBytes(charset));
- }
- }
-
- }
- else if (code0>=0)
- {
- int code1=in.read();
- if (code1>=0)
- output.write((convertHexDigit(code0)<<4)+convertHexDigit(code1));
- }
- break;
- default:
- output.write(c);
- break;
- }
-
- totalLength++;
- if (maxLength>=0 && totalLength > maxLength)
- throw new IllegalStateException("Form too large");
- }
+ }
- size=output.size();
- if (key != null)
- {
- value = size==0?"":output.toString(charset);
- output.setCount(0);
- map.add(key,value);
+ totalLength++;
+ if (maxLength>=0 && totalLength > maxLength)
+ throw new IllegalStateException("Form too large");
+ }
+
+ size=output.size();
+ if (key != null)
+ {
+ value = size==0?"":output.toString(charset);
+ output.setCount(0);
+ map.add(key,value);
+ }
+ else if (size>0)
+ map.add(output.toString(charset),"");
}
- else if (size>0)
- map.add(output.toString(charset),"");
}
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8LineParser.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8LineParser.java
index b54cf419391..e9e2159444c 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8LineParser.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8LineParser.java
@@ -20,8 +20,6 @@ package org.eclipse.jetty.util;
import java.nio.ByteBuffer;
-import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
-
/**
* Stateful parser for lines of UTF8 formatted text, looking for "\n" as a line termination character.
*
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java
index 8f2d9dc7ab0..1b0d7366ebc 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java
@@ -174,15 +174,15 @@ public abstract class AbstractLifeCycle implements LifeCycle
{
_state = __STARTED;
if (LOG.isDebugEnabled())
-
- LOG.debug(STARTED+" @{}ms {}",ManagementFactory.getRuntimeMXBean().getUptime(),this);
+ LOG.debug(STARTED+" @{}ms {}",ManagementFactory.getRuntimeMXBean().getUptime(),this);
for (Listener listener : _listeners)
listener.lifeCycleStarted(this);
}
private void setStarting()
{
- LOG.debug("starting {}",this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("starting {}",this);
_state = __STARTING;
for (Listener listener : _listeners)
listener.lifeCycleStarting(this);
@@ -190,7 +190,8 @@ public abstract class AbstractLifeCycle implements LifeCycle
private void setStopping()
{
- LOG.debug("stopping {}",this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("stopping {}",this);
_state = __STOPPING;
for (Listener listener : _listeners)
listener.lifeCycleStopping(this);
@@ -199,7 +200,8 @@ public abstract class AbstractLifeCycle implements LifeCycle
private void setStopped()
{
_state = __STOPPED;
- LOG.debug("{} {}",STOPPED,this);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} {}",STOPPED,this);
for (Listener listener : _listeners)
listener.lifeCycleStopped(this);
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java
index 464c0f7e4a8..28c45664bf7 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java
@@ -320,7 +320,8 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
throw new RuntimeException(e);
}
- LOG.debug("{} added {}",this,new_bean);
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} added {}",this,new_bean);
return true;
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/FileDestroyable.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/FileDestroyable.java
index 94936452bd3..29c54b31009 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/FileDestroyable.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/FileDestroyable.java
@@ -86,7 +86,8 @@ public class FileDestroyable implements Destroyable
{
if (file.exists())
{
- LOG.debug("Destroy {}",file);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Destroy {}",file);
IO.delete(file);
}
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/AbstractLogger.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/AbstractLogger.java
index 66453768a22..36d19780f03 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/AbstractLogger.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/AbstractLogger.java
@@ -79,6 +79,8 @@ public abstract class AbstractLogger implements Logger
public void debug(String msg, long arg)
{
if (isDebugEnabled())
- debug(msg,new Long(arg));
+ {
+ debug(msg,new Object[] { new Long(arg) });
+ }
}
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java
index fda1c722b5b..80622c05b63 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java
@@ -239,6 +239,12 @@ public class StdErrLog extends AbstractLogger
*/
public static int getLoggingLevel(Properties props, final String name)
{
+ if ((props == null) || (props.isEmpty()))
+ {
+ // Default Logging Level
+ return getLevelId("log.LEVEL","INFO");
+ }
+
// Calculate the level this named logger should operate under.
// Checking with FQCN first, then each package segment from longest to shortest.
String nameSegment = name;
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/AWTLeakPreventer.java b/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/AWTLeakPreventer.java
index 0f6caf9b072..39064e378d1 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/AWTLeakPreventer.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/AWTLeakPreventer.java
@@ -40,7 +40,8 @@ public class AWTLeakPreventer extends AbstractLeakPreventer
@Override
public void prevent(ClassLoader loader)
{
- LOG.debug("Pinning classloader for java.awt.EventQueue using "+loader);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Pinning classloader for java.awt.EventQueue using "+loader);
Toolkit.getDefaultToolkit();
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/AppContextLeakPreventer.java b/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/AppContextLeakPreventer.java
index 0cfd3c9553d..1ca99601d26 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/AppContextLeakPreventer.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/AppContextLeakPreventer.java
@@ -34,7 +34,8 @@ public class AppContextLeakPreventer extends AbstractLeakPreventer
@Override
public void prevent(ClassLoader loader)
{
- LOG.debug("Pinning classloader for AppContext.getContext() with "+loader);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Pinning classloader for AppContext.getContext() with "+loader);
ImageIO.getUseCache();
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/DriverManagerLeakPreventer.java b/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/DriverManagerLeakPreventer.java
index d229ba740aa..a8d211bdda6 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/DriverManagerLeakPreventer.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/DriverManagerLeakPreventer.java
@@ -35,7 +35,8 @@ public class DriverManagerLeakPreventer extends AbstractLeakPreventer
@Override
public void prevent(ClassLoader loader)
{
- LOG.debug("Pinning DriverManager classloader with "+loader);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Pinning DriverManager classloader with "+loader);
DriverManager.getDrivers();
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/GCThreadLeakPreventer.java b/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/GCThreadLeakPreventer.java
index 6ea4de2e16d..e1b999556eb 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/GCThreadLeakPreventer.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/preventers/GCThreadLeakPreventer.java
@@ -47,7 +47,7 @@ public class GCThreadLeakPreventer extends AbstractLeakPreventer
{
try
{
- Class clazz = Class.forName("sun.misc.GC");
+ Class> clazz = Class.forName("sun.misc.GC");
Method requestLatency = clazz.getMethod("requestLatency", new Class[] {long.class});
requestLatency.invoke(null, Long.valueOf(Long.MAX_VALUE-1));
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java
index 449884241b6..47776f4643a 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java
@@ -98,7 +98,7 @@ public class FileResource extends Resource
_file=file;
_uri=normalizeURI(_file,url.toURI());
- _alias=checkAlias(_file);
+ _alias=checkFileAlias(_file);
}
/* -------------------------------------------------------- */
@@ -108,17 +108,12 @@ public class FileResource extends Resource
_file=file;
URI file_uri=_file.toURI();
_uri=normalizeURI(_file,uri);
-
- if (!_uri.equals(file_uri.toString()))
- {
- // URI and File URI are different. Is it just an encoding difference?
- if (!file_uri.toString().equals(URIUtil.decodePath(uri.toString())))
- _alias=_file.toURI();
- else
- _alias=checkAlias(_file);
- }
+
+ // Is it a URI alias?
+ if (!URIUtil.equalsIgnoreEncodings(_uri,file_uri.toString()))
+ _alias=_file.toURI();
else
- _alias=checkAlias(_file);
+ _alias=checkFileAlias(_file);
}
/* -------------------------------------------------------- */
@@ -126,7 +121,7 @@ public class FileResource extends Resource
{
_file=file;
_uri=normalizeURI(_file,_file.toURI());
- _alias=checkAlias(_file);
+ _alias=checkFileAlias(_file);
}
/* -------------------------------------------------------- */
@@ -144,7 +139,7 @@ public class FileResource extends Resource
}
/* -------------------------------------------------------- */
- private static URI checkAlias(File file)
+ private static URI checkFileAlias(File file)
{
try
{
@@ -153,7 +148,8 @@ public class FileResource extends Resource
if (!abs.equals(can))
{
- LOG.debug("ALIAS abs={} can={}",abs,can);
+ if (LOG.isDebugEnabled())
+ LOG.debug("ALIAS abs={} can={}",abs,can);
URI alias=new File(can).toURI();
// Have to encode the path as File.toURI does not!
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java
index 434aa887565..9d3b932b665 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java
@@ -73,7 +73,8 @@ class JarFileResource extends JarResource
{
try
{
- LOG.debug("Closing JarFile "+_jarFile.getName());
+ if (LOG.isDebugEnabled())
+ LOG.debug("Closing JarFile "+_jarFile.getName());
_jarFile.close();
}
catch ( IOException ioe )
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java
new file mode 100644
index 00000000000..824e5c59fee
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java
@@ -0,0 +1,354 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.util.resource;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.FileTime;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * Java NIO Path equivalent of FileResource.
+ */
+public class PathResource extends Resource
+{
+ private static final Logger LOG = Log.getLogger(PathResource.class);
+
+ private final Path path;
+ private final URI uri;
+ private LinkOption linkOptions[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+
+ public PathResource(File file)
+ {
+ this(file.toPath());
+ }
+
+ public PathResource(Path path)
+ {
+ this.path = path;
+ this.uri = this.path.toUri();
+ }
+
+ public PathResource(URI uri) throws IOException
+ {
+ if (!uri.isAbsolute())
+ {
+ throw new IllegalArgumentException("not an absolute uri");
+ }
+
+ if (!uri.getScheme().equalsIgnoreCase("file"))
+ {
+ throw new IllegalArgumentException("not file: scheme");
+ }
+
+ Path path;
+ try
+ {
+ path = new File(uri).toPath();
+ }
+ catch (InvalidPathException e)
+ {
+ throw e;
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ LOG.ignore(e);
+ throw new IOException("Unable to build Path from: " + uri,e);
+ }
+
+ this.path = path;
+ this.uri = path.toUri();
+ }
+
+ public PathResource(URL url) throws IOException, URISyntaxException
+ {
+ this(url.toURI());
+ }
+
+ @Override
+ public Resource addPath(String apath) throws IOException, MalformedURLException
+ {
+ return new PathResource(this.path.resolve(apath));
+ }
+
+ @Override
+ public void close()
+ {
+ // not applicable for FileSytem / Path
+ }
+
+ @Override
+ public boolean delete() throws SecurityException
+ {
+ try
+ {
+ return Files.deleteIfExists(path);
+ }
+ catch (IOException e)
+ {
+ LOG.ignore(e);
+ return false;
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ PathResource other = (PathResource)obj;
+ if (path == null)
+ {
+ if (other.path != null)
+ {
+ return false;
+ }
+ }
+ else if (!path.equals(other.path))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean exists()
+ {
+ return Files.exists(path,linkOptions);
+ }
+
+ @Override
+ public File getFile() throws IOException
+ {
+ return path.toFile();
+ }
+
+ public boolean getFollowLinks()
+ {
+ return (linkOptions != null) && (linkOptions.length > 0) && (linkOptions[0] == LinkOption.NOFOLLOW_LINKS);
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException
+ {
+ return Files.newInputStream(path,StandardOpenOption.READ);
+ }
+
+ @Override
+ public String getName()
+ {
+ return path.toAbsolutePath().toString();
+ }
+
+ @Override
+ public ReadableByteChannel getReadableByteChannel() throws IOException
+ {
+ return FileChannel.open(path,StandardOpenOption.READ);
+ }
+
+ @Override
+ public URI getURI()
+ {
+ return this.uri;
+ }
+
+ @Override
+ public URL getURL()
+ {
+ try
+ {
+ return path.toUri().toURL();
+ }
+ catch (MalformedURLException e)
+ {
+ return null;
+ }
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + ((path == null)?0:path.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean isContainedIn(Resource r) throws MalformedURLException
+ {
+ // not applicable for FileSystem / path
+ return false;
+ }
+
+ @Override
+ public boolean isDirectory()
+ {
+ return Files.isDirectory(path,linkOptions);
+ }
+
+ @Override
+ public long lastModified()
+ {
+ try
+ {
+ FileTime ft = Files.getLastModifiedTime(path,linkOptions);
+ return ft.toMillis();
+ }
+ catch (IOException e)
+ {
+ LOG.ignore(e);
+ return 0;
+ }
+ }
+
+ @Override
+ public long length()
+ {
+ try
+ {
+ return Files.size(path);
+ }
+ catch (IOException e)
+ {
+ // in case of error, use File.length logic of 0L
+ return 0L;
+ }
+ }
+
+ @Override
+ public URI getAlias()
+ {
+ if (Files.isSymbolicLink(path))
+ {
+ try
+ {
+ return path.toRealPath().toUri();
+ }
+ catch (IOException e)
+ {
+ LOG.debug(e);
+ return null;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ @Override
+ public String[] list()
+ {
+ try (DirectoryStream dir = Files.newDirectoryStream(path))
+ {
+ List entries = new ArrayList<>();
+ for (Path entry : dir)
+ {
+ String name = entry.getFileName().toString();
+
+ if (Files.isDirectory(entry))
+ {
+ name += "/";
+ }
+
+ entries.add(name);
+ }
+ int size = entries.size();
+ return entries.toArray(new String[size]);
+ }
+ catch (DirectoryIteratorException e)
+ {
+ LOG.debug(e);
+ }
+ catch (IOException e)
+ {
+ LOG.debug(e);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean renameTo(Resource dest) throws SecurityException
+ {
+ if (dest instanceof PathResource)
+ {
+ PathResource destRes = (PathResource)dest;
+ try
+ {
+ Path result = Files.move(path,destRes.path,StandardCopyOption.ATOMIC_MOVE);
+ return Files.exists(result,linkOptions);
+ }
+ catch (IOException e)
+ {
+ LOG.ignore(e);
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public void setFollowLinks(boolean followLinks)
+ {
+ if (followLinks)
+ {
+ linkOptions = new LinkOption[0];
+ }
+ else
+ {
+ linkOptions = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+ }
+ }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
index b36a9355823..426b46ea42e 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
@@ -352,6 +352,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/**
* Returns an URL representing the given resource
*/
+ // TODO: should deprecate this one and only use getURI()
public abstract URL getURL();
/* ------------------------------------------------------------ */
@@ -405,6 +406,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/**
* Deletes the given resource
*/
+ // TODO: can throw IOException
public abstract boolean delete()
throws SecurityException;
@@ -412,6 +414,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/**
* Rename the given resource
*/
+ // TODO: can throw IOException
public abstract boolean renameTo( Resource dest)
throws SecurityException;
@@ -420,6 +423,7 @@ public abstract class Resource implements ResourceFactory, Closeable
* Returns a list of resource names contained in the given resource
* The resource names are not URL encoded.
*/
+ // TODO: can throw IOException
public abstract String[] list();
/* ------------------------------------------------------------ */
@@ -545,7 +549,7 @@ public abstract class Resource implements ResourceFactory, Closeable
buf.append("");
}
buf.append("\n");
- buf.append("