Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Wilkins2016-02-04 01:00:13 -0500
committerGreg Wilkins2016-02-04 01:00:13 -0500
commitdf79ad689a38592472d3696e15bf0252e617b8e7 (patch)
treec2fedd48685d4f06c044821f01b3a7c12a455b71
parent459ba4ae5aa7f9a29d18b4e08848ff6e1cec0e4a (diff)
parent009fde2400a746b1ce24ba04bd4fcd001378516b (diff)
downloadorg.eclipse.jetty.project-df79ad689a38592472d3696e15bf0252e617b8e7.tar.gz
org.eclipse.jetty.project-df79ad689a38592472d3696e15bf0252e617b8e7.tar.xz
org.eclipse.jetty.project-df79ad689a38592472d3696e15bf0252e617b8e7.zip
Merge remote-tracking branch 'origin/jetty-9.3.x'
-rw-r--r--apache-jstl/src/test/java/org/eclipse/jetty/jstl/JstlTest.java15
-rw-r--r--apache-jstl/src/test/resources/jetty-logging.properties3
-rw-r--r--jetty-distribution/src/main/resources/demo-base/webapps/ROOT/index.html2
-rw-r--r--jetty-distribution/src/main/resources/etc/jamon.xml14
-rw-r--r--jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java19
-rw-r--r--jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java10
-rw-r--r--jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java28
-rw-r--r--jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java19
-rw-r--r--jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointTest.java154
-rw-r--r--jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/AttributeNormalizer.java304
-rw-r--r--jetty-rewrite/src/main/config/etc/jetty-rewrite.xml66
-rw-r--r--jetty-server/src/main/config/etc/jetty-debuglog.xml32
-rw-r--r--jetty-server/src/main/config/etc/jetty-gzip.xml94
-rw-r--r--jetty-server/src/main/config/etc/jetty-ipaccess.xml41
-rw-r--r--jetty-server/src/main/config/etc/jetty-ssl-context.xml14
-rw-r--r--jetty-server/src/main/config/etc/jetty-stats.xml12
-rw-r--r--jetty-server/src/main/config/modules/ssl.mod3
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/Server.java6
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java2
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java5
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java10
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java19
-rw-r--r--jetty-server/src/test/java/org/eclipse/jetty/server/handler/HandlerTest.java342
-rw-r--r--jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLSelectChannelConnectorLoadTest.java13
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java51
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java92
-rw-r--r--jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java2
-rw-r--r--jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestGetPartsTest.java145
-rw-r--r--jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java2
-rw-r--r--jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java3
-rw-r--r--jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/IncludedGzipTest.java3
-rw-r--r--jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java262
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java26
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java10
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsume.java39
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ProduceExecuteConsume.java22
-rw-r--r--jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java32
-rw-r--r--jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/BinaryFrame.java2
-rw-r--r--jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/TextFrame.java2
-rw-r--r--tests/test-integration/src/test/resources/DefaultHandler.xml4
-rw-r--r--tests/test-integration/src/test/resources/RFC2616Base.xml12
-rw-r--r--tests/test-integration/src/test/resources/RFC2616_Redirects.xml80
-rw-r--r--tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java13
-rw-r--r--tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/AttributeNormalizerTest.java87
-rw-r--r--tests/test-webapps/test-jetty-webapp/src/main/assembly/embedded-jetty-web-for-webbundle.xml1
45 files changed, 1732 insertions, 385 deletions
diff --git a/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JstlTest.java b/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JstlTest.java
index f1c4dd32fd..5642ef44ae 100644
--- a/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JstlTest.java
+++ b/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JstlTest.java
@@ -18,8 +18,9 @@
package org.eclipse.jetty.jstl;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
import java.io.File;
import java.io.IOException;
@@ -75,6 +76,16 @@ public class JstlTest
WebAppContext context = new WebAppContext();
context.setContextPath("/");
+ /* TODO: Bug #486530 - sub-handler on WebAppContext prevents startup
+ context.setHandler(new AbstractHandler()
+ {
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ }
+ });
+ */
+
File scratchDir = MavenTestingUtils.getTargetFile("tests/" + JstlTest.class.getSimpleName() + "-scratch");
FS.ensureEmpty(scratchDir);
JspConfig.init(context,testWebAppDir.toURI(),scratchDir);
diff --git a/apache-jstl/src/test/resources/jetty-logging.properties b/apache-jstl/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000000..08befa5ce9
--- /dev/null
+++ b/apache-jstl/src/test/resources/jetty-logging.properties
@@ -0,0 +1,3 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+# org.eclipse.jetty.LEVEL=INFO
+# org.eclipse.jetty.util.LEVEL=DEBUG
diff --git a/jetty-distribution/src/main/resources/demo-base/webapps/ROOT/index.html b/jetty-distribution/src/main/resources/demo-base/webapps/ROOT/index.html
index 4d5a13f24d..30368ba8c5 100644
--- a/jetty-distribution/src/main/resources/demo-base/webapps/ROOT/index.html
+++ b/jetty-distribution/src/main/resources/demo-base/webapps/ROOT/index.html
@@ -66,7 +66,7 @@
<div id='blog'>
<h1>Jetty Blog</h1>
- <iframe src="http://www.webtide.com/blog.jsp" />
+ <iframe src="https://webtide.com/blog.jsp" />
</div>
</body>
</html>
diff --git a/jetty-distribution/src/main/resources/etc/jamon.xml b/jetty-distribution/src/main/resources/etc/jamon.xml
index ec1d3f509b..2ec2d89db4 100644
--- a/jetty-distribution/src/main/resources/etc/jamon.xml
+++ b/jetty-distribution/src/main/resources/etc/jamon.xml
@@ -7,13 +7,13 @@
<Configure id="Server" class="org.eclipse.jetty.server.Server">
- <Get id="oldhandler" name="handler" />
- <Set name="handler">
- <New id="JamonHandler" class="com.jamonapi.http.JAMonJettyHandlerNew">
- <Set name="handler"><Ref refid="oldhandler" /></Set>
- <Set name="summaryLabels"><Property name="jamon.summaryLabels" /></Set>
- </New>
- </Set>
+ <Call name="insertHandler">
+ <Arg>
+ <New id="JamonHandler" class="com.jamonapi.http.JAMonJettyHandlerNew">
+ <Set name="summaryLabels"><Property name="jamon.summaryLabels" /></Set>
+ </New>
+ </Arg>
+ </Call>
<Ref refid="Contexts">
<Call name="addHandler">
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
index f0e271117b..6b0a39a2d6 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
@@ -334,6 +334,8 @@ public class HttpURI
state=State.PORT;
break;
case '@':
+ if (_user!=null)
+ throw new IllegalArgumentException("Bad authority");
_user=uri.substring(mark,i);
mark=i+1;
break;
@@ -372,7 +374,16 @@ public class HttpURI
case PORT:
{
- if (c=='/')
+ if (c=='@')
+ {
+ if (_user!=null)
+ throw new IllegalArgumentException("Bad authority");
+ // It wasn't a port, but a password!
+ _user=_host+":"+uri.substring(mark,i);
+ mark=i+1;
+ state=State.HOST;
+ }
+ else if (c=='/')
{
_port=TypeUtil.parseInt(uri,mark,i-mark,10);
path_mark=mark=i;
@@ -745,6 +756,12 @@ public class HttpURI
return _host+":"+_port;
return _host;
}
+
+ /* ------------------------------------------------------------ */
+ public String getUser()
+ {
+ return _user;
+ }
}
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java
index d308cde3b5..74c6feedde 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java
@@ -22,6 +22,7 @@ package org.eclipse.jetty.http;
import static org.junit.Assert.*;
import java.io.UnsupportedEncodingException;
+import java.net.URI;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@@ -193,4 +194,13 @@ public class HttpURITest
assertEquals("http:/path/info",uri.toString());
}
+
+ @Test
+ public void testBasicAuthCredentials() throws Exception
+ {
+ HttpURI uri = new HttpURI("http://user:password@example.com:8888/blah");
+ assertEquals("http://user:password@example.com:8888/blah", uri.toString());
+ assertEquals(uri.getAuthority(), "example.com:8888");
+ assertEquals(uri.getUser(), "user:password");
+ }
}
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 a0257efa4c..6e5688fa63 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
@@ -28,6 +28,7 @@ import java.nio.channels.SelectionKey;
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.ExecutionStrategy.Rejectable;
import org.eclipse.jetty.util.thread.Locker;
import org.eclipse.jetty.util.thread.Scheduler;
@@ -73,6 +74,27 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage
}
}
+ private abstract class RejectableRunnable extends RunnableTask implements Rejectable
+ {
+ RejectableRunnable(String op)
+ {
+ super(op);
+ }
+
+ @Override
+ public void reject()
+ {
+ try
+ {
+ close();
+ }
+ catch (Throwable x)
+ {
+ LOG.warn(x);
+ }
+ }
+ }
+
private final Runnable _runUpdateKey = new RunnableTask("runUpdateKey")
{
@Override
@@ -82,7 +104,7 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage
}
};
- private final Runnable _runFillable = new RunnableTask("runFillable")
+ private final Runnable _runFillable = new RejectableRunnable("runFillable")
{
@Override
public void run()
@@ -91,7 +113,7 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage
}
};
- private final Runnable _runCompleteWrite = new RunnableTask("runCompleteWrite")
+ private final Runnable _runCompleteWrite = new RejectableRunnable("runCompleteWrite")
{
@Override
public void run()
@@ -100,7 +122,7 @@ public abstract class ChannelEndPoint extends AbstractEndPoint implements Manage
}
};
- private final Runnable _runFillableCompleteWrite = new RunnableTask("runFillableCompleteWrite")
+ private final Runnable _runFillableCompleteWrite = new RejectableRunnable("runFillableCompleteWrite")
{
@Override
public void run()
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java
index 35c6d51225..40d5a01a51 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java
@@ -43,6 +43,7 @@ import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.ExecutionStrategy;
+import org.eclipse.jetty.util.thread.ExecutionStrategy.Rejectable;
import org.eclipse.jetty.util.thread.Locker;
import org.eclipse.jetty.util.thread.Scheduler;
@@ -536,7 +537,7 @@ public class ManagedSelector extends AbstractLifeCycle implements Runnable, Dump
}
}
- class Accept implements Runnable
+ class Accept implements Runnable, Rejectable
{
private final SelectableChannel channel;
private final Object attachment;
@@ -548,6 +549,13 @@ public class ManagedSelector extends AbstractLifeCycle implements Runnable, Dump
}
@Override
+ public void reject()
+ {
+ LOG.debug("rejected accept {}",channel);
+ closeNoExceptions(channel);
+ }
+
+ @Override
public void run()
{
try
@@ -563,7 +571,7 @@ public class ManagedSelector extends AbstractLifeCycle implements Runnable, Dump
}
}
- private class CreateEndPoint implements Product
+ private class CreateEndPoint implements Product, Rejectable
{
private final SelectableChannel channel;
private final SelectionKey key;
@@ -588,6 +596,13 @@ public class ManagedSelector extends AbstractLifeCycle implements Runnable, Dump
}
}
+ @Override
+ public void reject()
+ {
+ LOG.debug("rejected create {}",channel);
+ closeNoExceptions(channel);
+ }
+
protected void failed(Throwable failure)
{
closeNoExceptions(channel);
diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointTest.java
index 0e26326ad9..99632febb0 100644
--- a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointTest.java
+++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointTest.java
@@ -37,9 +37,12 @@ import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
@@ -49,9 +52,11 @@ import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.Scheduler;
import org.eclipse.jetty.util.thread.TimerScheduler;
+import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
public class SelectChannelEndPointTest
@@ -124,10 +129,18 @@ public class SelectChannelEndPointTest
ByteBuffer _in = BufferUtil.allocate(32 * 1024);
ByteBuffer _out = BufferUtil.allocate(32 * 1024);
long _last = -1;
+ final CountDownLatch _latch;
public TestConnection(EndPoint endp)
{
super(endp, _threadPool);
+ _latch=null;
+ }
+
+ public TestConnection(EndPoint endp,CountDownLatch latch)
+ {
+ super(endp, _threadPool);
+ _latch=latch;
}
@Override
@@ -153,6 +166,18 @@ public class SelectChannelEndPointTest
@Override
public void onFillable()
{
+ if (_latch!=null)
+ {
+ try
+ {
+ _latch.await();
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
Callback blocking = _blockingRead;
if (blocking!=null)
{
@@ -671,4 +696,133 @@ public class SelectChannelEndPointTest
}
assertFalse(server.isOpen());
}
+
+
+ // TODO make this test reliable
+ @Test
+ @Ignore
+ public void testRejectedExecution() throws Exception
+ {
+ _manager.stop();
+ _threadPool.stop();
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ BlockingQueue<Runnable> q = new ArrayBlockingQueue<>(4);
+ _threadPool = new QueuedThreadPool(4,4,60000,q);
+ _manager = new SelectorManager(_threadPool, _scheduler, 1)
+ {
+
+ @Override
+ protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey selectionKey) throws IOException
+ {
+ SocketChannelEndPoint endp = new SocketChannelEndPoint(channel,selector,selectionKey,getScheduler());
+ _lastEndPoint = endp;
+ _lastEndPointLatch.countDown();
+ return endp;
+ }
+
+ @Override
+ public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment) throws IOException
+ {
+ return new TestConnection(endpoint,latch);
+ }
+ };
+
+ _threadPool.start();
+ _manager.start();
+
+ AtomicInteger timeout = new AtomicInteger();
+ AtomicInteger rejections = new AtomicInteger();
+ AtomicInteger echoed = new AtomicInteger();
+
+ CountDownLatch closed = new CountDownLatch(20);
+ for (int i=0;i<20;i++)
+ {
+ new Thread()
+ {
+ public void run()
+ {
+ try(Socket client = newClient();)
+ {
+ client.setSoTimeout(5000);
+
+ SocketChannel server = _connector.accept();
+ server.configureBlocking(false);
+
+ _manager.accept(server);
+
+ // Write client to server
+ client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8));
+ client.getOutputStream().flush();
+ client.shutdownOutput();
+
+ // Verify echo server to client
+ for (char c : "HelloWorld".toCharArray())
+ {
+ int b = client.getInputStream().read();
+ assertTrue(b > 0);
+ assertEquals(c, (char)b);
+ }
+ assertEquals(-1,client.getInputStream().read());
+ echoed.incrementAndGet();
+ }
+ catch(SocketTimeoutException x)
+ {
+ x.printStackTrace();
+ timeout.incrementAndGet();
+ }
+ catch(Throwable x)
+ {
+ rejections.incrementAndGet();
+ }
+ finally
+ {
+ closed.countDown();
+ }
+ }
+ }.start();
+ }
+
+ // unblock the handling
+ latch.countDown();
+
+ // wait for all clients to complete or fail
+ closed.await();
+
+ // assert some clients must have been rejected
+ Assert.assertThat(rejections.get(),Matchers.greaterThan(0));
+ // but not all of them
+ Assert.assertThat(rejections.get(),Matchers.lessThan(20));
+ // none should have timed out
+ Assert.assertThat(timeout.get(),Matchers.equalTo(0));
+ // and the rest should have worked
+ Assert.assertThat(echoed.get(),Matchers.equalTo(20-rejections.get()));
+
+ // and the selector is still working for new requests
+ try(Socket client = newClient();)
+ {
+ client.setSoTimeout(5000);
+
+ SocketChannel server = _connector.accept();
+ server.configureBlocking(false);
+
+ _manager.accept(server);
+
+ // Write client to server
+ client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8));
+ client.getOutputStream().flush();
+ client.shutdownOutput();
+
+ // Verify echo server to client
+ for (char c : "HelloWorld".toCharArray())
+ {
+ int b = client.getInputStream().read();
+ assertTrue(b > 0);
+ assertEquals(c, (char)b);
+ }
+ assertEquals(-1,client.getInputStream().read());
+ }
+
+ }
}
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/AttributeNormalizer.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/AttributeNormalizer.java
index 8494386324..aae4361f6f 100644
--- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/AttributeNormalizer.java
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/AttributeNormalizer.java
@@ -19,9 +19,19 @@
package org.eclipse.jetty.quickstart;
import java.io.File;
+import java.io.IOException;
import java.net.URI;
import java.net.URL;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Stack;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
@@ -30,7 +40,8 @@ import org.eclipse.jetty.util.resource.Resource;
/**
* Normalize Attribute to String.
- * <p>Replaces and expands:
+ * <p>
+ * Replaces and expands:
* <ul>
* <li>${WAR}</li>
* <li>${jetty.base}</li>
@@ -42,116 +53,269 @@ import org.eclipse.jetty.util.resource.Resource;
public class AttributeNormalizer
{
private static final Logger LOG = Log.getLogger(AttributeNormalizer.class);
- private final Path _warPath;
- private final Path _jettyBasePath;
- private final Path _jettyHomePath;
- private final Path _userHomePath;
- private final Path _userDirPath;
-
-
+ private static final Pattern __propertyPattern = Pattern.compile("(?<=[^$]|^)\\$\\{([^}]*)\\}");
+
+ private static class PathAttribute
+ {
+ public final Path path;
+ public final String key;
+ private int weight = -1;
+
+ public PathAttribute(String key, Path path) throws IOException
+ {
+ this.key = key;
+ this.path = toCanonicalPath(path);
+ // TODO: Don't allow non-directory paths? (but what if the path doesn't exist?)
+ }
+
+ public PathAttribute(String key, String systemPropertyKey) throws IOException
+ {
+ this(key, toCanonicalPath(System.getProperty(systemPropertyKey)));
+ }
+
+ private static Path toCanonicalPath(String path) throws IOException
+ {
+ if (path == null)
+ {
+ return null;
+ }
+ return toCanonicalPath(FileSystems.getDefault().getPath(path));
+ }
+
+ private static Path toCanonicalPath(Path path) throws IOException
+ {
+ if (path == null)
+ {
+ return null;
+ }
+ if (Files.exists(path))
+ {
+ return path.toRealPath();
+ }
+ return path.toAbsolutePath();
+ }
+
+ public PathAttribute weight(int newweight)
+ {
+ this.weight = newweight;
+ return this;
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("PathAttribute[%s=>%s,%d]",key,path,weight);
+ }
+ }
+
+ private static class PathAttributeComparator implements Comparator<PathAttribute>
+ {
+ @Override
+ public int compare(PathAttribute o1, PathAttribute o2)
+ {
+ if( (o1.path == null) && (o2.path != null) )
+ {
+ return -1;
+ }
+
+ if( (o1.path != null) && (o2.path == null) )
+ {
+ return 1;
+ }
+
+ // Different lengths?
+ int diff = o2.path.getNameCount() - o1.path.getNameCount();
+ if(diff != 0)
+ {
+ return diff;
+ }
+
+ // Different names?
+ diff = o2.path.compareTo(o1.path);
+ if(diff != 0)
+ {
+ return diff;
+ }
+
+ // The paths are the same, base now on weight
+ return o2.weight - o1.weight;
+ }
+ }
+
+ private List<PathAttribute> attributes = new ArrayList<>();
+
public AttributeNormalizer(Resource baseResource)
{
try
{
- _warPath=baseResource==null?null:baseResource.getFile().toPath();
- _jettyBasePath=systemPath("jetty.base");
- _jettyHomePath=systemPath("jetty.home");
- _userHomePath=systemPath("user.home");
- _userDirPath=systemPath("user.dir");
+ // Track path attributes for expansion
+ attributes.add(new PathAttribute("WAR", baseResource == null ? null : baseResource.getFile().toPath()).weight(10));
+ attributes.add(new PathAttribute("jetty.base", "jetty.base").weight(9));
+ attributes.add(new PathAttribute("jetty.home", "jetty.home").weight(8));
+ attributes.add(new PathAttribute("user.home", "user.home").weight(7));
+ attributes.add(new PathAttribute("user.dir", "user.dir").weight(6));
+
+ Collections.sort(attributes, new PathAttributeComparator());
}
- catch(Exception e)
+ catch (Exception e)
{
throw new IllegalArgumentException(e);
}
}
-
- private static Path systemPath(String property) throws Exception
- {
- String p=System.getProperty(property);
- if (p!=null)
- return new File(p).getAbsoluteFile().getCanonicalFile().toPath();
- return null;
- }
-
+
public String normalize(Object o)
{
try
{
// Find a URI
- URI uri=null;
+ URI uri = null;
if (o instanceof URI)
- uri=(URI)o;
+ uri = (URI)o;
else if (o instanceof URL)
uri = ((URL)o).toURI();
else if (o instanceof File)
uri = ((File)o).toURI();
else
{
- String s=o.toString();
- uri=new URI(s);
- if (uri.getScheme()==null)
+ String s = o.toString();
+ uri = new URI(s);
+ if (uri.getScheme() == null)
return s;
}
-
+
if ("jar".equalsIgnoreCase(uri.getScheme()))
{
String raw = uri.getRawSchemeSpecificPart();
- int bang=raw.indexOf("!/");
- String normal=normalize(raw.substring(0,bang));
- String suffix=raw.substring(bang);
- return "jar:"+normal+suffix;
+ int bang = raw.indexOf("!/");
+ String normal = normalize(raw.substring(0,bang));
+ String suffix = raw.substring(bang);
+ return "jar:" + normal + suffix;
}
else if ("file".equalsIgnoreCase(uri.getScheme()))
{
- return "file:"+normalizePath(new File(uri).toPath());
+ return "file:" + normalizePath(new File(uri).toPath());
}
-
+
}
- catch(Exception e)
+ catch (Exception e)
{
LOG.warn(e);
}
return String.valueOf(o);
}
-
+
public String normalizePath(Path path)
{
- if (_warPath!=null && path.startsWith(_warPath))
- return URIUtil.addPaths("${WAR}",_warPath.relativize(path).toString());
- if (_jettyBasePath!=null && path.startsWith(_jettyBasePath))
- return URIUtil.addPaths("${jetty.base}",_jettyBasePath.relativize(path).toString());
- if (_jettyHomePath!=null && path.startsWith(_jettyHomePath))
- return URIUtil.addPaths("${jetty.home}",_jettyHomePath.relativize(path).toString());
- if (_userHomePath!=null && path.startsWith(_userHomePath))
- return URIUtil.addPaths("${user.home}",_userHomePath.relativize(path).toString());
- if (_userDirPath!=null && path.startsWith(_userDirPath))
- return URIUtil.addPaths("${user.dir}",_userDirPath.relativize(path).toString());
-
+ for (PathAttribute attr : attributes)
+ {
+ if (attr.path == null)
+ continue;
+
+ try
+ {
+ if (path.startsWith(attr.path) || path.equals(attr.path) || Files.isSameFile(path,attr.path))
+ {
+ return URIUtil.addPaths("${" + attr.key + "}",attr.path.relativize(path).toString());
+ }
+ }
+ catch (IOException ignore)
+ {
+ LOG.ignore(ignore);
+ }
+ }
+
return path.toString();
}
-
-
- public String expand(String s)
+
+ public String expand(String str)
+ {
+ return expand(str,new Stack<String>());
+ }
+
+ public String expand(String str, Stack<String> seenStack)
{
- int i=s.indexOf("${");
- if (i<0)
- return s;
- int e=s.indexOf('}',i+3);
- String prop=s.substring(i+2,e);
- switch(prop)
- {
- case "WAR":
- return s.substring(0,i)+_warPath+expand(s.substring(e+1));
- case "jetty.base":
- return s.substring(0,i)+_jettyBasePath+expand(s.substring(e+1));
- case "jetty.home":
- return s.substring(0,i)+_jettyHomePath+expand(s.substring(e+1));
- case "user.home":
- return s.substring(0,i)+_userHomePath+expand(s.substring(e+1));
- case "user.dir":
- return s.substring(0,i)+_userDirPath+expand(s.substring(e+1));
- default:
- return s;
+ if (str == null)
+ {
+ return str;
}
+
+ if (str.indexOf("${") < 0)
+ {
+ // Contains no potential expressions.
+ return str;
+ }
+
+ Matcher mat = __propertyPattern.matcher(str);
+ StringBuilder expanded = new StringBuilder();
+ int offset = 0;
+ String property;
+ String value;
+
+ while (mat.find(offset))
+ {
+ property = mat.group(1);
+
+ // Loop detection
+ if (seenStack.contains(property))
+ {
+ StringBuilder err = new StringBuilder();
+ err.append("Property expansion loop detected: ");
+ int idx = seenStack.lastIndexOf(property);
+ for (int i = idx; i < seenStack.size(); i++)
+ {
+ err.append(seenStack.get(i));
+ err.append(" -> ");
+ }
+ err.append(property);
+ throw new RuntimeException(err.toString());
+ }
+
+ seenStack.push(property);
+
+ // find property name
+ expanded.append(str.subSequence(offset,mat.start()));
+ // get property value
+ value = getString(property);
+ if (value == null)
+ {
+ if(LOG.isDebugEnabled())
+ LOG.debug("Unable to expand: {}",property);
+ expanded.append(mat.group());
+ }
+ else
+ {
+ // recursively expand
+ value = expand(value,seenStack);
+ expanded.append(value);
+ }
+ // update offset
+ offset = mat.end();
+ }
+
+ // leftover
+ expanded.append(str.substring(offset));
+
+ // special case for "$$"
+ if (expanded.indexOf("$$") >= 0)
+ {
+ return expanded.toString().replaceAll("\\$\\$","\\$");
+ }
+
+ return expanded.toString();
+ }
+
+ private String getString(String property)
+ {
+ // Use known attributes first
+ for (PathAttribute attr : attributes)
+ {
+ if (attr.key.equalsIgnoreCase(property))
+ {
+ return attr.path.toString();
+ }
+ }
+
+ // Use system properties next
+ return System.getProperty(property);
}
}
diff --git a/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml b/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml
index 65a5dea44a..0f37c7c5bb 100644
--- a/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml
+++ b/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml
@@ -1,47 +1,41 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
-<!-- =============================================================== -->
-<!-- Mixin the RewriteHandler -->
-<!-- =============================================================== -->
-
-
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- configure rewrite handler -->
<!-- =========================================================== -->
- <Get id="oldhandler" name="handler"/>
-
- <Set name="handler">
- <New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
- <Set name="handler"><Ref refid="oldhandler"/></Set>
- <Set name="rewriteRequestURI"><Property name="jetty.rewrite.rewriteRequestURI" deprecated="rewrite.rewriteRequestURI" default="true"/></Set>
- <Set name="rewritePathInfo"><Property name="jetty.rewrite.rewritePathInfo" deprecated="rewrite.rewritePathInfo" default="false"/></Set>
- <Set name="originalPathAttribute"><Property name="jetty.rewrite.originalPathAttribute" deprecated="rewrite.originalPathAttribute" default="requestedPath"/></Set>
-
- <!-- Set DispatcherTypes -->
- <Set name="dispatcherTypes">
- <Array type="javax.servlet.DispatcherType">
- <Item><Call class="javax.servlet.DispatcherType" name="valueOf"><Arg>REQUEST</Arg></Call></Item>
- <Item><Call class="javax.servlet.DispatcherType" name="valueOf"><Arg>ASYNC</Arg></Call></Item>
- </Array>
- </Set>
+ <Call name="insertHandler">
+ <Arg>
+ <New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
+ <Set name="rewriteRequestURI"><Property name="jetty.rewrite.rewriteRequestURI" deprecated="rewrite.rewriteRequestURI" default="true"/></Set>
+ <Set name="rewritePathInfo"><Property name="jetty.rewrite.rewritePathInfo" deprecated="rewrite.rewritePathInfo" default="false"/></Set>
+ <Set name="originalPathAttribute"><Property name="jetty.rewrite.originalPathAttribute" deprecated="rewrite.originalPathAttribute" default="requestedPath"/></Set>
+
+ <!-- Set DispatcherTypes -->
+ <Set name="dispatcherTypes">
+ <Array type="javax.servlet.DispatcherType">
+ <Item><Call class="javax.servlet.DispatcherType" name="valueOf"><Arg>REQUEST</Arg></Call></Item>
+ <Item><Call class="javax.servlet.DispatcherType" name="valueOf"><Arg>ASYNC</Arg></Call></Item>
+ </Array>
+ </Set>
- <!-- example rule -->
- <!--
- <Call name="addRule">
- <Arg>
- <New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
- <Set name="pattern">/favicon.ico</Set>
- <Set name="name">Cache-Control</Set>
- <Set name="value">Max-Age=3600,public</Set>
- <Set name="terminating">true</Set>
- </New>
- </Arg>
- </Call>
- -->
+ <!-- example rule -->
+ <!--
+ <Call name="addRule">
+ <Arg>
+ <New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
+ <Set name="pattern">/favicon.ico</Set>
+ <Set name="name">Cache-Control</Set>
+ <Set name="value">Max-Age=3600,public</Set>
+ <Set name="terminating">true</Set>
+ </New>
+ </Arg>
+ </Call>
+ -->
- </New>
- </Set>
+ </New>
+ </Arg>
+ </Call>
</Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-debuglog.xml b/jetty-server/src/main/config/etc/jetty-debuglog.xml
index adbb10a5d4..0a082ce11f 100644
--- a/jetty-server/src/main/config/etc/jetty-debuglog.xml
+++ b/jetty-server/src/main/config/etc/jetty-debuglog.xml
@@ -6,20 +6,20 @@
<!-- =============================================================== -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
- <Get id="oldhandler" name="handler"/>
- <Set name="handler">
- <New id="DebugHandler" class="org.eclipse.jetty.server.handler.DebugHandler">
- <Set name="handler"><Ref refid="oldhandler"/></Set>
- <Set name="outputStream">
- <New class="org.eclipse.jetty.util.RolloverFileOutputStream">
- <Arg type="String"><Property name="jetty.debuglog.dir" deprecated="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg>
- <Arg type="boolean"><Property name="jetty.debuglog.append" default="true"/></Arg>
- <Arg type="int"><Property name="jetty.debuglog.retainDays" default="90"/></Arg>
- <Arg>
- <Call class="java.util.TimeZone" name="getTimeZone"><Arg><Property name="jetty.debuglog.timezone" default="GMT"/></Arg></Call>
- </Arg>
- </New>
- </Set>
- </New>
- </Set>
+ <Call name="insertHandler">
+ <Arg>
+ <New id="DebugHandler" class="org.eclipse.jetty.server.handler.DebugHandler">
+ <Set name="outputStream">
+ <New class="org.eclipse.jetty.util.RolloverFileOutputStream">
+ <Arg type="String"><Property name="jetty.debuglog.dir" deprecated="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg>
+ <Arg type="boolean"><Property name="jetty.debuglog.append" default="true"/></Arg>
+ <Arg type="int"><Property name="jetty.debuglog.retainDays" default="90"/></Arg>
+ <Arg>
+ <Call class="java.util.TimeZone" name="getTimeZone"><Arg><Property name="jetty.debuglog.timezone" default="GMT"/></Arg></Call>
+ </Arg>
+ </New>
+ </Set>
+ </New>
+ </Arg>
+ </Call>
</Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-gzip.xml b/jetty-server/src/main/config/etc/jetty-gzip.xml
index f26ef0b5a1..93b41fd639 100644
--- a/jetty-server/src/main/config/etc/jetty-gzip.xml
+++ b/jetty-server/src/main/config/etc/jetty-gzip.xml
@@ -9,59 +9,59 @@
<!-- =============================================================== -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
- <Get id="next" name="handler" />
- <Set name="handler">
- <New id="GzipHandler" class="org.eclipse.jetty.server.handler.gzip.GzipHandler">
- <Set name="handler"><Ref refid="next" /></Set>
- <Set name="minGzipSize"><Property name="jetty.gzip.minGzipSize" deprecated="gzip.minGzipSize" default="2048"/></Set>
- <Set name="checkGzExists"><Property name="jetty.gzip.checkGzExists" deprecated="gzip.checkGzExists" default="false"/></Set>
- <Set name="compressionLevel"><Property name="jetty.gzip.compressionLevel" deprecated="gzip.compressionLevel" default="-1"/></Set>
- <Set name="excludedAgentPatterns">
- <Array type="String">
- <Item><Property name="jetty.gzip.excludedUserAgent" deprecated="gzip.excludedUserAgent" default=".*MSIE.6\.0.*"/></Item>
- </Array>
- </Set>
+ <Call name="insertHandler">
+ <Arg>
+ <New id="GzipHandler" class="org.eclipse.jetty.server.handler.gzip.GzipHandler">
+ <Set name="minGzipSize"><Property name="jetty.gzip.minGzipSize" deprecated="gzip.minGzipSize" default="2048"/></Set>
+ <Set name="checkGzExists"><Property name="jetty.gzip.checkGzExists" deprecated="gzip.checkGzExists" default="false"/></Set>
+ <Set name="compressionLevel"><Property name="jetty.gzip.compressionLevel" deprecated="gzip.compressionLevel" default="-1"/></Set>
+ <Set name="excludedAgentPatterns">
+ <Array type="String">
+ <Item><Property name="jetty.gzip.excludedUserAgent" deprecated="gzip.excludedUserAgent" default=".*MSIE.6\.0.*"/></Item>
+ </Array>
+ </Set>
- <Set name="includedMethods">
- <Array type="String">
- <Item>GET</Item>
- </Array>
- </Set>
+ <Set name="includedMethods">
+ <Array type="String">
+ <Item>GET</Item>
+ </Array>
+ </Set>
- <!--
- <Set name="includedPaths">
- <Array type="String">
- <Item>/*</Item>
- </Array>
- </Set>
- -->
+ <!--
+ <Set name="includedPaths">
+ <Array type="String">
+ <Item>/*</Item>
+ </Array>
+ </Set>
+ -->
- <!--
- <Set name="excludedPaths">
- <Array type="String">
- <Item>*.gz</Item>
- </Array>
- </Set>
- -->
+ <!--
+ <Set name="excludedPaths">
+ <Array type="String">
+ <Item>*.gz</Item>
+ </Array>
+ </Set>
+ -->
- <!--
- <Call name="addIncludedMimeTypes">
- <Arg><Array type="String">
- <Item>some/type</Item>
- </Array></Arg>
- </Call>
- -->
+ <!--
+ <Call name="addIncludedMimeTypes">
+ <Arg><Array type="String">
+ <Item>some/type</Item>
+ </Array></Arg>
+ </Call>
+ -->
- <!--
- <Call name="addExcludedMimeTypes">
- <Arg><Array type="String">
- <Item>some/type</Item>
- </Array></Arg>
- </Call>
- -->
+ <!--
+ <Call name="addExcludedMimeTypes">
+ <Arg><Array type="String">
+ <Item>some/type</Item>
+ </Array></Arg>
+ </Call>
+ -->
- </New>
- </Set>
+ </New>
+ </Arg>
+ </Call>
</Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-ipaccess.xml b/jetty-server/src/main/config/etc/jetty-ipaccess.xml
index d8236a99a0..832565c5ad 100644
--- a/jetty-server/src/main/config/etc/jetty-ipaccess.xml
+++ b/jetty-server/src/main/config/etc/jetty-ipaccess.xml
@@ -6,26 +6,23 @@
<!-- =============================================================== -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
-
- <Get id="oldhandler" name="handler"/>
-
- <Set name="handler">
- <New id="IPAccessHandler" class="org.eclipse.jetty.server.handler.IPAccessHandler">
- <Set name="handler"><Ref refid="oldhandler"/></Set>
- <Set name="white">
- <Array type="String">
- <Item>127.0.0.1</Item>
- <Item>127.0.0.2/*.html</Item>
- </Array>
- </Set>
- <Set name="black">
- <Array type="String">
- <Item>127.0.0.1/blacklisted</Item>
- <Item>127.0.0.2/black.html</Item>
- </Array>
- </Set>
- <Set name="whiteListByPath">false</Set>
- </New>
- </Set>
-
+ <Call name="insertHandler">
+ <Arg>
+ <New id="IPAccessHandler" class="org.eclipse.jetty.server.handler.IPAccessHandler">
+ <Set name="white">
+ <Array type="String">
+ <Item>127.0.0.1</Item>
+ <Item>127.0.0.2/*.html</Item>
+ </Array>
+ </Set>
+ <Set name="black">
+ <Array type="String">
+ <Item>127.0.0.1/blacklisted</Item>
+ <Item>127.0.0.2/black.html</Item>
+ </Array>
+ </Set>
+ <Set name="whiteListByPath">false</Set>
+ </New>
+ </Arg>
+ </Call>
</Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-ssl-context.xml b/jetty-server/src/main/config/etc/jetty-ssl-context.xml
index 68b802c9c7..7af6e66c60 100644
--- a/jetty-server/src/main/config/etc/jetty-ssl-context.xml
+++ b/jetty-server/src/main/config/etc/jetty-ssl-context.xml
@@ -17,16 +17,8 @@
<Set name="EndpointIdentificationAlgorithm"></Set>
<Set name="NeedClientAuth"><Property name="jetty.sslContext.needClientAuth" deprecated="jetty.ssl.needClientAuth" default="false"/></Set>
<Set name="WantClientAuth"><Property name="jetty.sslContext.wantClientAuth" deprecated="jetty.ssl.wantClientAuth" default="false"/></Set>
- <Set name="ExcludeCipherSuites">
- <Array type="String">
- <Item>SSL_RSA_WITH_DES_CBC_SHA</Item>
- <Item>SSL_DHE_RSA_WITH_DES_CBC_SHA</Item>
- <Item>SSL_DHE_DSS_WITH_DES_CBC_SHA</Item>
- <Item>SSL_RSA_EXPORT_WITH_RC4_40_MD5</Item>
- <Item>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
- <Item>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
- <Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item>
- </Array>
- </Set>
+ <!-- To configure Includes / Excludes for Cipher Suites or Protocols see tweak-ssl.xml example at
+ https://www.eclipse.org/jetty/documentation/current/configuring-ssl.html#configuring-sslcontextfactory-cipherSuites
+ -->
<Set name="useCipherSuitesOrder"><Property name="jetty.sslContext.useCipherSuitesOrder" default="true"/></Set>
</Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-stats.xml b/jetty-server/src/main/config/etc/jetty-stats.xml
index 4e014906a5..445ae6a8a4 100644
--- a/jetty-server/src/main/config/etc/jetty-stats.xml
+++ b/jetty-server/src/main/config/etc/jetty-stats.xml
@@ -6,12 +6,12 @@
<!-- =============================================================== -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
- <Get id="oldhandler" name="handler" />
- <Set name="handler">
- <New id="StatsHandler" class="org.eclipse.jetty.server.handler.StatisticsHandler">
- <Set name="handler"><Ref refid="oldhandler" /></Set>
- </New>
- </Set>
+ <Call name="insertHandler">
+ <Arg>
+ <New id="StatsHandler" class="org.eclipse.jetty.server.handler.StatisticsHandler">
+ </New>
+ </Arg>
+ </Call>
<Call class="org.eclipse.jetty.server.ConnectorStatistics" name="addToAllConnectors">
<Arg><Ref refid="Server"/></Arg>
</Call>
diff --git a/jetty-server/src/main/config/modules/ssl.mod b/jetty-server/src/main/config/modules/ssl.mod
index d262842c32..2e6dc80447 100644
--- a/jetty-server/src/main/config/modules/ssl.mod
+++ b/jetty-server/src/main/config/modules/ssl.mod
@@ -88,3 +88,6 @@ http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/
## Whether cipher order is significant (since java 8 only)
# jetty.sslContext.useCipherSuitesOrder=true
+## To configure Includes / Excludes for Cipher Suites or Protocols see tweak-ssl.xml example at
+## https://www.eclipse.org/jetty/documentation/current/configuring-ssl.html#configuring-sslcontextfactory-cipherSuites
+
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java
index 1d81e6a615..51c145d606 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java
@@ -654,7 +654,6 @@ public class Server extends HandlerWrapper implements Attributes
/**
* @return The URI of the first {@link NetworkConnector} and first {@link ContextHandler}, or null
*/
- @SuppressWarnings("resource")
public URI getURI()
{
NetworkConnector connector=null;
@@ -674,7 +673,10 @@ public class Server extends HandlerWrapper implements Attributes
try
{
- String scheme=connector.getDefaultConnectionFactory().getProtocol().startsWith("SSL-")?"https":"http";
+ String protocol = connector.getDefaultConnectionFactory().getProtocol();
+ String scheme="http";
+ if (protocol.startsWith("SSL-") || protocol.equals("SSL"))
+ scheme = "https";
String host=connector.getHost();
if (context!=null && context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
index d0fbce55de..07c316c3c4 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
@@ -100,7 +100,7 @@ import org.eclipse.jetty.util.resource.Resource;
* The maximum size of a form that can be processed by this context is controlled by the system properties org.eclipse.jetty.server.Request.maxFormKeys
* and org.eclipse.jetty.server.Request.maxFormContentSize. These can also be configured with {@link #setMaxFormContentSize(int)} and {@link #setMaxFormKeys(int)}
* <p>
- * This servers executore is made available via a context attributed "org.eclipse.jetty.server.Executor".
+ * This servers executor is made available via a context attributed "org.eclipse.jetty.server.Executor".
* <p>
* By default, the context is created with alias checkers for {@link AllowSymLinkAliasChecker} (unix only) and {@link ApproveNonExistentDirectoryAliases}.
* If these alias checkers are not required, then {@link #clearAliasChecks()} or {@link #setAliasChecks(List)} should be called.
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
index 1b2867384c..1eacb7d64c 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
@@ -99,6 +99,11 @@ public class ErrorHandler extends AbstractHandler
throw new IOException(x);
}
}
+ } else {
+ if (LOG.isDebugEnabled())
+ {
+ LOG.debug("No Error Page mapping for request({} {}) (using default)",request.getMethod(),request.getRequestURI());
+ }
else
{
LOG.warn("Could not dispatch to error page: {}", error_page);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java
index 4a98f786bd..0a085ffa5b 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java
@@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HandlerContainer;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.ArrayUtil;
import org.eclipse.jetty.util.MultiException;
@@ -81,9 +82,18 @@ public class HandlerCollection extends AbstractHandlerContainer
throw new IllegalStateException(STARTED);
if (handlers!=null)
+ {
+ // check for loops
+ for (Handler handler:handlers)
+ if (handler == this || (handler instanceof HandlerContainer &&
+ Arrays.asList(((HandlerContainer)handler).getChildHandlers()).contains(this)))
+ throw new IllegalStateException("setHandler loop");
+
+ // Set server
for (Handler handler:handlers)
if (handler.getServer()!=getServer())
handler.setServer(getServer());
+ }
Handler[] old=_handlers;;
_handlers = handlers;
updateBeans(old, handlers);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java
index 5fc2d730f7..bafc4afad3 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java
@@ -19,6 +19,7 @@
package org.eclipse.jetty.server.handler;
import java.io.IOException;
+import java.util.Arrays;
import java.util.List;
import javax.servlet.ServletException;
@@ -26,6 +27,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HandlerContainer;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
@@ -80,6 +82,11 @@ public class HandlerWrapper extends AbstractHandlerContainer
if (isStarted())
throw new IllegalStateException(STARTED);
+ // check for loops
+ if (handler==this || (handler instanceof HandlerContainer &&
+ Arrays.asList(((HandlerContainer)handler).getChildHandlers()).contains(this)))
+ throw new IllegalStateException("setHandler loop");
+
if (handler!=null)
handler.setServer(getServer());
@@ -102,10 +109,18 @@ public class HandlerWrapper extends AbstractHandlerContainer
*/
public void insertHandler(HandlerWrapper wrapper)
{
- if (wrapper==null || wrapper.getHandler()!=null)
+ if (wrapper==null)
throw new IllegalArgumentException();
- wrapper.setHandler(getHandler());
+
+ HandlerWrapper tail = wrapper;
+ while(tail.getHandler() instanceof HandlerWrapper)
+ tail=(HandlerWrapper)tail.getHandler();
+ if (tail.getHandler()!=null)
+ throw new IllegalArgumentException("bad tail of inserted wrapper chain");
+
+ Handler next=getHandler();
setHandler(wrapper);
+ tail.setHandler(next);
}
/* ------------------------------------------------------------ */
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/HandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/HandlerTest.java
new file mode 100644
index 0000000000..c09e4037ba
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/HandlerTest.java
@@ -0,0 +1,342 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.server.handler;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+public class HandlerTest
+{
+
+ @Test
+ public void testWrapperSetServer()
+ {
+ Server s=new Server();
+ HandlerWrapper a = new HandlerWrapper();
+ HandlerWrapper b = new HandlerWrapper();
+ HandlerWrapper c = new HandlerWrapper();
+ a.setHandler(b);
+ b.setHandler(c);
+
+ a.setServer(s);
+ assertThat(b.getServer(),equalTo(s));
+ assertThat(c.getServer(),equalTo(s));
+ }
+
+ @Test
+ public void testWrapperServerSet()
+ {
+ Server s=new Server();
+ HandlerWrapper a = new HandlerWrapper();
+ HandlerWrapper b = new HandlerWrapper();
+ HandlerWrapper c = new HandlerWrapper();
+ a.setServer(s);
+ b.setHandler(c);
+ a.setHandler(b);
+
+ assertThat(b.getServer(),equalTo(s));
+ assertThat(c.getServer(),equalTo(s));
+ }
+
+ @Test
+ public void testWrapperThisLoop()
+ {
+ HandlerWrapper a = new HandlerWrapper();
+
+ try
+ {
+ a.setHandler(a);
+ fail();
+ }
+ catch(IllegalStateException e)
+ {
+ assertThat(e.getMessage(),containsString("loop"));
+ }
+ }
+
+ @Test
+ public void testWrapperSimpleLoop()
+ {
+ HandlerWrapper a = new HandlerWrapper();
+ HandlerWrapper b = new HandlerWrapper();
+
+ a.setHandler(b);
+
+ try
+ {
+ b.setHandler(a);
+ fail();
+ }
+ catch(IllegalStateException e)
+ {
+ assertThat(e.getMessage(),containsString("loop"));
+ }
+ }
+
+ @Test
+ public void testWrapperDeepLoop()
+ {
+ HandlerWrapper a = new HandlerWrapper();
+ HandlerWrapper b = new HandlerWrapper();
+ HandlerWrapper c = new HandlerWrapper();
+
+ a.setHandler(b);
+ b.setHandler(c);
+
+ try
+ {
+ c.setHandler(a);
+ fail();
+ }
+ catch(IllegalStateException e)
+ {
+ assertThat(e.getMessage(),containsString("loop"));
+ }
+ }
+
+ @Test
+ public void testWrapperChainLoop()
+ {
+ HandlerWrapper a = new HandlerWrapper();
+ HandlerWrapper b = new HandlerWrapper();
+ HandlerWrapper c = new HandlerWrapper();
+
+ a.setHandler(b);
+ c.setHandler(a);
+
+ try
+ {
+ b.setHandler(c);
+ fail();
+ }
+ catch(IllegalStateException e)
+ {
+ assertThat(e.getMessage(),containsString("loop"));
+ }
+ }
+
+
+ @Test
+ public void testCollectionSetServer()
+ {
+ Server s=new Server();
+ HandlerCollection a = new HandlerCollection();
+ HandlerCollection b = new HandlerCollection();
+ HandlerCollection b1 = new HandlerCollection();
+ HandlerCollection b2 = new HandlerCollection();
+ HandlerCollection c = new HandlerCollection();
+ HandlerCollection c1 = new HandlerCollection();
+ HandlerCollection c2 = new HandlerCollection();
+
+ a.addHandler(b);
+ a.addHandler(c);
+ b.setHandlers(new Handler[]{b1,b2});
+ c.setHandlers(new Handler[]{c1,c2});
+ a.setServer(s);
+
+ assertThat(b.getServer(),equalTo(s));
+ assertThat(c.getServer(),equalTo(s));
+ assertThat(b1.getServer(),equalTo(s));
+ assertThat(b2.getServer(),equalTo(s));
+ assertThat(c1.getServer(),equalTo(s));
+ assertThat(c2.getServer(),equalTo(s));
+ }
+
+ @Test
+ public void testCollectionServerSet()
+ {
+ Server s=new Server();
+ HandlerCollection a = new HandlerCollection();
+ HandlerCollection b = new HandlerCollection();
+ HandlerCollection b1 = new HandlerCollection();
+ HandlerCollection b2 = new HandlerCollection();
+ HandlerCollection c = new HandlerCollection();
+ HandlerCollection c1 = new HandlerCollection();
+ HandlerCollection c2 = new HandlerCollection();
+
+ a.setServer(s);
+ a.addHandler(b);
+ a.addHandler(c);
+ b.setHandlers(new Handler[]{b1,b2});
+ c.setHandlers(new Handler[]{c1,c2});
+
+ assertThat(b.getServer(),equalTo(s));
+ assertThat(c.getServer(),equalTo(s));
+ assertThat(b1.getServer(),equalTo(s));
+ assertThat(b2.getServer(),equalTo(s));
+ assertThat(c1.getServer(),equalTo(s));
+ assertThat(c2.getServer(),equalTo(s));
+ }
+
+ @Test
+ public void testCollectionThisLoop()
+ {
+ HandlerCollection a = new HandlerCollection();
+
+ try
+ {
+ a.addHandler(a);
+ fail();
+ }
+ catch(IllegalStateException e)
+ {
+ assertThat(e.getMessage(),containsString("loop"));
+ }
+ }
+
+ @Test
+ public void testCollectionDeepLoop()
+ {
+ HandlerCollection a = new HandlerCollection();
+ HandlerCollection b = new HandlerCollection();
+ HandlerCollection b1 = new HandlerCollection();
+ HandlerCollection b2 = new HandlerCollection();
+ HandlerCollection c = new HandlerCollection();
+ HandlerCollection c1 = new HandlerCollection();
+ HandlerCollection c2 = new HandlerCollection();
+
+ a.addHandler(b);
+ a.addHandler(c);
+ b.setHandlers(new Handler[]{b1,b2});
+ c.setHandlers(new Handler[]{c1,c2});
+
+ try
+ {
+ b2.addHandler(a);
+ fail();
+ }
+ catch(IllegalStateException e)
+ {
+ assertThat(e.getMessage(),containsString("loop"));
+ }
+ }
+
+ @Test
+ public void testCollectionChainLoop()
+ {
+ HandlerCollection a = new HandlerCollection();
+ HandlerCollection b = new HandlerCollection();
+ HandlerCollection b1 = new HandlerCollection();
+ HandlerCollection b2 = new HandlerCollection();
+ HandlerCollection c = new HandlerCollection();
+ HandlerCollection c1 = new HandlerCollection();
+ HandlerCollection c2 = new HandlerCollection();
+
+ a.addHandler(c);
+ b.setHandlers(new Handler[]{b1,b2});
+ c.setHandlers(new Handler[]{c1,c2});
+ b2.addHandler(a);
+
+ try
+ {
+ a.addHandler(b);
+ fail();
+ }
+ catch(IllegalStateException e)
+ {
+ assertThat(e.getMessage(),containsString("loop"));
+ }
+ }
+
+ @Test
+ public void testInsertWrapperTail()
+ {
+ HandlerWrapper a = new HandlerWrapper();
+ HandlerWrapper b = new HandlerWrapper();
+
+ a.insertHandler(b);
+ assertThat(a.getHandler(),equalTo(b));
+ assertThat(b.getHandler(),nullValue());
+ }
+
+ @Test
+ public void testInsertWrapper()
+ {
+ HandlerWrapper a = new HandlerWrapper();
+ HandlerWrapper b = new HandlerWrapper();
+ HandlerWrapper c = new HandlerWrapper();
+
+ a.insertHandler(c);
+ a.insertHandler(b);
+ assertThat(a.getHandler(),equalTo(b));
+ assertThat(b.getHandler(),equalTo(c));
+ assertThat(c.getHandler(),nullValue());
+ }
+
+ @Test
+ public void testInsertWrapperChain()
+ {
+ HandlerWrapper a = new HandlerWrapper();
+ HandlerWrapper b = new HandlerWrapper();
+ HandlerWrapper c = new HandlerWrapper();
+ HandlerWrapper d = new HandlerWrapper();
+
+ a.insertHandler(d);
+ b.insertHandler(c);
+ a.insertHandler(b);
+ assertThat(a.getHandler(),equalTo(b));
+ assertThat(b.getHandler(),equalTo(c));
+ assertThat(c.getHandler(),equalTo(d));
+ assertThat(d.getHandler(),nullValue());
+ }
+
+ @Test
+ public void testInsertWrapperBadChain()
+ {
+ HandlerWrapper a = new HandlerWrapper();
+ HandlerWrapper b = new HandlerWrapper();
+ HandlerWrapper c = new HandlerWrapper();
+ HandlerWrapper d = new HandlerWrapper();
+
+ a.insertHandler(d);
+ b.insertHandler(c);
+ c.setHandler(new AbstractHandler()
+ {
+ @Override
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ }
+ });
+
+ try
+ {
+ a.insertHandler(b);
+ fail();
+ }
+ catch(IllegalArgumentException e)
+ {
+ assertThat(e.getMessage(),containsString("bad tail"));
+ }
+ }
+}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLSelectChannelConnectorLoadTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLSelectChannelConnectorLoadTest.java
index b5fde36ef7..a6d8aedcc3 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLSelectChannelConnectorLoadTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLSelectChannelConnectorLoadTest.java
@@ -18,12 +18,16 @@
package org.eclipse.jetty.server.ssl;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
+import java.net.URI;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.Random;
@@ -91,6 +95,15 @@ public class SSLSelectChannelConnectorLoadTest
server.stop();
server.join();
}
+
+ @Test
+ public void testGetURI()
+ {
+ URI uri = server.getURI();
+ assertThat("Server.uri.scheme", uri.getScheme(), is("https"));
+ assertThat("Server.uri.port", uri.getPort(), is(connector.getLocalPort()));
+ assertThat("Server.uri.path", uri.getPath(), is("/"));
+ }
@Test
public void testLongLivedConnections() throws Exception
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java
index 4ef91fa921..3dffd4c3c1 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java
@@ -30,6 +30,8 @@ import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ErrorHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
/**
* An ErrorHandler that maps exceptions and status codes to URIs for dispatch using
@@ -38,6 +40,8 @@ import org.eclipse.jetty.server.handler.ErrorHandler;
public class ErrorPageErrorHandler extends ErrorHandler implements ErrorHandler.ErrorPageMapper
{
public final static String GLOBAL_ERROR_PAGE = "org.eclipse.jetty.server.error_page.global";
+ private static final Logger LOG = Log.getLogger(ErrorPageErrorHandler.class);
+ enum PageLookupTechnique{ THROWABLE, STATUS_CODE, GLOBAL }
protected ServletContext _servletContext;
private final Map<String,String> _errorPages= new HashMap<>(); // code or exception to URL
@@ -48,11 +52,15 @@ public class ErrorPageErrorHandler extends ErrorHandler implements ErrorHandler.
{
String error_page= null;
+ PageLookupTechnique pageSource = null;
+
Throwable th = (Throwable)request.getAttribute(Dispatcher.ERROR_EXCEPTION);
// Walk the cause hierarchy
while (error_page == null && th != null )
{
+ pageSource = PageLookupTechnique.THROWABLE;
+
Class<?> exClass=th.getClass();
error_page = _errorPages.get(exClass.getName());
@@ -68,13 +76,17 @@ public class ErrorPageErrorHandler extends ErrorHandler implements ErrorHandler.
th=(th instanceof ServletException)?((ServletException)th).getRootCause():null;
}
+ Integer errorStatusCode = null;
+
if (error_page == null)
{
+ pageSource = PageLookupTechnique.STATUS_CODE;
+
// look for an exact code match
- Integer code=(Integer)request.getAttribute(Dispatcher.ERROR_STATUS_CODE);
- if (code!=null)
+ errorStatusCode = (Integer)request.getAttribute(Dispatcher.ERROR_STATUS_CODE);
+ if (errorStatusCode!=null)
{
- error_page=_errorPages.get(Integer.toString(code));
+ error_page= (String)_errorPages.get(Integer.toString(errorStatusCode));
// if still not found
if ((error_page == null) && (_errorPageList != null))
@@ -83,7 +95,7 @@ public class ErrorPageErrorHandler extends ErrorHandler implements ErrorHandler.
for (int i = 0; i < _errorPageList.size(); i++)
{
ErrorCodeRange errCode = _errorPageList.get(i);
- if (errCode.isInRange(code))
+ if (errCode.isInRange(errorStatusCode))
{
error_page = errCode.getUri();
break;
@@ -95,7 +107,38 @@ public class ErrorPageErrorHandler extends ErrorHandler implements ErrorHandler.
// Try servlet 3.x global error page.
if (error_page == null)
+ {
+ pageSource = PageLookupTechnique.GLOBAL;
error_page = _errorPages.get(GLOBAL_ERROR_PAGE);
+ }
+
+ if (LOG.isDebugEnabled())
+ {
+ StringBuilder dbg = new StringBuilder();
+ dbg.append("getErrorPage(");
+ dbg.append(request.getMethod()).append(' ');
+ dbg.append(request.getRequestURI());
+ dbg.append(") => error_page=").append(error_page);
+ switch (pageSource)
+ {
+ case THROWABLE:
+ dbg.append(" (from Throwable ");
+ dbg.append(th.getClass().getName());
+ dbg.append(')');
+ LOG.debug(dbg.toString(),th);
+ break;
+ case STATUS_CODE:
+ dbg.append(" (from status code ");
+ dbg.append(errorStatusCode);
+ dbg.append(')');
+ LOG.debug(dbg.toString());
+ break;
+ case GLOBAL:
+ dbg.append(" (from global default)");
+ LOG.debug(dbg.toString());
+ break;
+ }
+ }
return error_page;
}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
index e1680a57ca..4d7a4139b0 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
@@ -66,6 +66,8 @@ import org.eclipse.jetty.util.DeprecationWarning;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.LifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
/**
* Servlet Context.
@@ -83,6 +85,8 @@ import org.eclipse.jetty.util.component.LifeCycle;
@ManagedObject("Servlet Context Handler")
public class ServletContextHandler extends ContextHandler
{
+ private static final Logger LOG = Log.getLogger(ServletContextHandler.class);
+
public final static int SESSIONS=1;
public final static int SECURITY=2;
public final static int GZIP=4;
@@ -169,7 +173,21 @@ public class ServletContextHandler extends ContextHandler
if (errorHandler!=null)
setErrorHandler(errorHandler);
+ }
+
+ @Override
+ public void setHandler(Handler handler)
+ {
+ LOG.warn("ServletContextHandler.setHandler should not be called directly. Use insertHandler or setSessionHandler etc.");
+ super.setHandler(handler);
+ }
+ private void doSetHandler(HandlerWrapper wrapper, Handler handler)
+ {
+ if (wrapper==this)
+ super.setHandler(handler);
+ else
+ wrapper.setHandler(handler);
}
/* ------------------------------------------------------------ */
@@ -189,12 +207,7 @@ public class ServletContextHandler extends ContextHandler
handler=(HandlerWrapper)handler.getHandler();
if (handler.getHandler()!=_sessionHandler)
- {
- if (handler== this)
- super.setHandler(_sessionHandler);
- else
- handler.setHandler(_sessionHandler);
- }
+ doSetHandler(handler,_sessionHandler);
handler=_sessionHandler;
}
@@ -208,12 +221,7 @@ public class ServletContextHandler extends ContextHandler
handler=(HandlerWrapper)handler.getHandler();
if (handler.getHandler()!=_securityHandler)
- {
- if (handler== this)
- super.setHandler(_securityHandler);
- else
- handler.setHandler(_securityHandler);
- }
+ doSetHandler(handler,_securityHandler);
handler=_securityHandler;
}
@@ -226,12 +234,7 @@ public class ServletContextHandler extends ContextHandler
handler=(HandlerWrapper)handler.getHandler();
if (handler.getHandler()!=_gzipHandler)
- {
- if (handler== this)
- super.setHandler(_gzipHandler);
- else
- handler.setHandler(_gzipHandler);
- }
+ doSetHandler(handler,_gzipHandler);
handler=_gzipHandler;
}
@@ -244,12 +247,7 @@ public class ServletContextHandler extends ContextHandler
handler=(HandlerWrapper)handler.getHandler();
if (handler.getHandler()!=_servletHandler)
- {
- if (handler== this)
- super.setHandler(_servletHandler);
- else
- handler.setHandler(_servletHandler);
- }
+ doSetHandler(handler,_servletHandler);
handler=_servletHandler;
}
@@ -554,7 +552,7 @@ public class ServletContextHandler extends ContextHandler
{
if (wrapper.getHandler()==handler)
{
- wrapper.setHandler(replace);
+ doSetHandler(wrapper,replace);
return true;
}
@@ -664,20 +662,38 @@ public class ServletContextHandler extends ContextHandler
*/
public void insertHandler(HandlerWrapper handler)
{
- HandlerWrapper h=this;
-
- // Skip any injected handlers
- while (h.getHandler() instanceof HandlerWrapper)
- {
- HandlerWrapper wrapper = (HandlerWrapper)h.getHandler();
- if (wrapper instanceof SessionHandler ||
- wrapper instanceof SecurityHandler ||
- wrapper instanceof ServletHandler)
- break;
- h=wrapper;
+ if (handler instanceof SessionHandler)
+ setSessionHandler((SessionHandler)handler);
+ else if (handler instanceof SecurityHandler)
+ setSecurityHandler((SecurityHandler)handler);
+ else if (handler instanceof GzipHandler)
+ setGzipHandler((GzipHandler)handler);
+ else if (handler instanceof ServletHandler)
+ setServletHandler((ServletHandler)handler);
+ else
+ {
+ HandlerWrapper tail = handler;
+ while(tail.getHandler() instanceof HandlerWrapper)
+ tail=(HandlerWrapper)tail.getHandler();
+ if (tail.getHandler()!=null)
+ throw new IllegalArgumentException("bad tail of inserted wrapper chain");
+
+ // Skip any injected handlers
+ HandlerWrapper h=this;
+ while (h.getHandler() instanceof HandlerWrapper)
+ {
+ HandlerWrapper wrapper = (HandlerWrapper)h.getHandler();
+ if (wrapper instanceof SessionHandler ||
+ wrapper instanceof SecurityHandler ||
+ wrapper instanceof ServletHandler)
+ break;
+ h=wrapper;
+ }
+
+ Handler next=h.getHandler();
+ doSetHandler(h,handler);
+ doSetHandler(tail,next);
}
-
- h.setHandler(handler);
relinkHandlers();
}
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java
index 4be7ff073c..99ca52f754 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java
@@ -81,7 +81,6 @@ public class GzipHandlerTest
_server.setHandler(gzipHandler);
gzipHandler.setHandler(context);
- context.setHandler(servlets);
servlets.addServletWithMapping(TestServlet.class,"/content");
servlets.addServletWithMapping(ForwardServlet.class,"/forward");
servlets.addServletWithMapping(IncludeServlet.class,"/include");
@@ -91,7 +90,6 @@ public class GzipHandlerTest
public static class TestServlet extends HttpServlet
{
-
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
{
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestGetPartsTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestGetPartsTest.java
new file mode 100644
index 0000000000..9cc62c6094
--- /dev/null
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestGetPartsTest.java
@@ -0,0 +1,145 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.servlet;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+
+import javax.servlet.MultipartConfigElement;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.Part;
+
+import org.eclipse.jetty.http.HttpTester;
+import org.eclipse.jetty.server.LocalConnector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.toolchain.test.FS;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class RequestGetPartsTest
+{
+ @SuppressWarnings("serial")
+ public static class DumpPartInfoServlet extends HttpServlet
+ {
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ resp.setContentType("text/plain");
+ PrintWriter out = resp.getWriter();
+
+ for(Part part: req.getParts())
+ {
+ out.printf("Got part: name=%s, size=%,d, filename=%s%n",part.getName(), part.getSize(), part.getSubmittedFileName());
+ }
+ }
+ }
+
+ private static Server server;
+ private static LocalConnector connector;
+ private static File locationDir;
+
+ @BeforeClass
+ public static void startServer() throws Exception
+ {
+ Path tmpDir = MavenTestingUtils.getTargetTestingPath("testrequest_getparts");
+ FS.ensureEmpty(tmpDir);
+
+ locationDir = tmpDir.toFile();
+
+ server = new Server();
+ connector = new LocalConnector(server);
+ server.addConnector(connector);
+
+ ServletContextHandler context = new ServletContextHandler();
+ context.setContextPath("/");
+ server.setHandler(context);
+
+ ServletHolder holder = context.addServlet(DumpPartInfoServlet.class,"/dump/*");
+ String location = locationDir.getAbsolutePath();
+ long maxFileSize = 1024*1024*5;
+ long maxRequestSize = 1024*1024*10;
+ int fileSizeThreshold = 1;
+ MultipartConfigElement multipartConfig = new MultipartConfigElement(location,maxFileSize,maxRequestSize,fileSizeThreshold);
+ ((ServletHolder.Registration) holder.getRegistration()).setMultipartConfig(multipartConfig);
+
+ server.start();
+ }
+
+ @AfterClass
+ public static void stopServer() throws Exception
+ {
+ server.stop();
+ }
+
+ @Test
+ public void testMultiFileUpload_SameName() throws Exception
+ {
+ // generated and parsed test
+ HttpTester.Request request = HttpTester.newRequest();
+ HttpTester.Response response;
+
+ // test GET
+ request.setMethod("POST");
+ request.setURI("/dump/");
+ request.setVersion("HTTP/1.1");
+ request.setHeader("Host","tester");
+ request.setHeader("Connection","close");
+
+ String boundary="XyXyXy";
+ request.setHeader("Content-Type","multipart/form-data; boundary=" + boundary);
+
+ String crocMsg = "See ya later, aligator.";
+ String aligMsg = "In a while, crocodile.";
+
+ StringBuilder content = new StringBuilder();
+ content.append("--").append(boundary).append("\r\n");
+ content.append("Content-Disposition: form-data; name=\"same\"; filename=\"crocodile.dat\"\r\n");
+ content.append("Content-Type: application/octet-stream\r\n");
+ content.append("\r\n");
+ content.append(crocMsg).append("\r\n");
+ content.append("--").append(boundary).append("\r\n");
+ content.append("Content-Disposition: form-data; name=\"same\"; filename=\"aligator.dat\"\r\n");
+ content.append("Content-Type: application/octet-stream\r\n");
+ content.append("\r\n");
+ content.append(aligMsg).append("\r\n");
+ content.append("--").append(boundary).append("--\r\n");
+ content.append("\r\n");
+
+ request.setContent(content.toString());
+
+ response = HttpTester.parseResponse(connector.getResponses(request.generate()));
+ assertThat("Response status", response.getStatus(), is(HttpServletResponse.SC_OK));
+ assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+
+ String responseContents = response.getContent();
+ assertThat("response.contents", responseContents, containsString(String.format("Got part: name=same, size=%d, filename=crocodile.dat",crocMsg.length())));
+ assertThat("response.contents", responseContents, containsString(String.format("Got part: name=same, size=%d, filename=aligator.dat",aligMsg.length())));
+ }
+}
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java
index f088ffd3fc..2b2c671f96 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java
@@ -26,6 +26,7 @@ import java.util.EnumSet;
import javax.servlet.DispatcherType;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.servlet.BaseHolder.Source;
import org.junit.Before;
import org.junit.Test;
@@ -428,5 +429,4 @@ public class ServletHandlerTest
}
-
}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java
index 623a0af6c0..4a5c483586 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java
@@ -104,6 +104,7 @@ public class MultiPartFilter implements Filter
private boolean _deleteFiles;
private ServletContext _context;
private int _fileOutputBuffer = 0;
+ private boolean _writeFilesWithFilenames = false;
private long _maxFileSize = -1L;
private long _maxRequestSize = -1L;
private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys", 1000);
@@ -130,6 +131,7 @@ public class MultiPartFilter implements Filter
String mfks = filterConfig.getInitParameter("maxFormKeys");
if (mfks!=null)
_maxFormKeys=Integer.parseInt(mfks);
+ _writeFilesWithFilenames = "true".equalsIgnoreCase(filterConfig.getInitParameter("writeFilesWithFilenames"));
}
/* ------------------------------------------------------------------------------- */
@@ -164,6 +166,7 @@ public class MultiPartFilter implements Filter
MultipartConfigElement config = new MultipartConfigElement(tempdir.getCanonicalPath(), _maxFileSize, _maxRequestSize, _fileOutputBuffer);
MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(in, content_type, config, tempdir);
mpis.setDeleteOnExit(_deleteFiles);
+ mpis.setWriteFilesWithFilenames(_writeFilesWithFilenames);
request.setAttribute(MULTIPART, mpis);
try
{
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/IncludedGzipTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/IncludedGzipTest.java
index 4e02fccbb8..bea2501e8b 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/IncludedGzipTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/IncludedGzipTest.java
@@ -89,8 +89,7 @@ public class IncludedGzipTest
tester.getContext().addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/");
GzipHandler gzipHandler = new GzipHandler();
- gzipHandler.setHandler(tester.getContext().getHandler());
- tester.getContext().setHandler(gzipHandler);
+ tester.getContext().insertHandler(gzipHandler);
tester.start();
}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java
index 01cdb45637..c2ce682774 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java
@@ -18,9 +18,10 @@
package org.eclipse.jetty.servlets;
-
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -30,10 +31,15 @@ import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
+import java.io.Reader;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
import java.util.EnumSet;
+import java.util.Enumeration;
import java.util.Map;
import javax.servlet.DispatcherType;
@@ -45,17 +51,59 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletTester;
+import org.eclipse.jetty.toolchain.test.FS;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.IO;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
public class MultipartFilterTest
{
private File _dir;
private ServletTester tester;
+ FilterHolder multipartFilter;
+
+ @SuppressWarnings("serial")
+ public static class FilenameServlet extends TestServlet
+ {
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ assertThat(req.getAttribute("fileup"), notNullValue());
+ super.doPost(req, resp);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class ParameterListServlet extends TestServlet
+ {
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ resp.setContentType("text/plain");
+ PrintWriter out = resp.getWriter();
+
+ Enumeration<String> pnames = req.getParameterNames();
+ while (pnames.hasMoreElements())
+ {
+ String pname = pnames.nextElement();
+ Object param = req.getParameter(pname);
+ out.printf("Parameter[%s] = ",pname);
+ if (param == null)
+ {
+ out.println(" <null>");
+ }
+ else
+ {
+ out.printf("(%s) %s%n",param.getClass().getName(),param);
+ }
+ }
+ }
+ }
-
+ @SuppressWarnings("serial")
public static class BoundaryServlet extends TestServlet
{
@Override
@@ -63,9 +111,11 @@ public class MultipartFilterTest
{
//we have configured the multipart filter to always store to disk (file size threshold == 1)
//but fileName has no filename param, so only the attribute should be set
- assertNull(req.getParameter("fileName"));
- assertNotNull(req.getAttribute("fileName"));
+ assertThat("getParameter('fileName')", req.getParameter("fileName"), nullValue());
+ assertThat("getAttribute('fileName')", req.getAttribute("fileName"), notNullValue());
+
File f = (File)req.getAttribute("fileName");
+ assertThat("File exists", f.exists(), is(true));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IO.copy(new FileInputStream(f), baos);
assertEquals(getServletContext().getAttribute("fileName"), baos.toString());
@@ -83,37 +133,39 @@ public class MultipartFilterTest
}
}
+ @SuppressWarnings("serial")
public static class TestServlet extends DumpServlet
{
+ @SuppressWarnings("deprecation")
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
- assertNotNull(req.getParameter("fileup"));
- System.err.println("Fileup="+req.getParameter("fileup"));
- assertNotNull(req.getParameter("fileup"+MultiPartFilter.CONTENT_TYPE_SUFFIX));
- assertEquals(req.getParameter("fileup"+MultiPartFilter.CONTENT_TYPE_SUFFIX), "application/octet-stream");
+ String fileup = req.getParameter("fileup");
+ assertThat("getParameter('fileup')",fileup,notNullValue());
+
+ System.err.println("Fileup=" + req.getParameter("fileup"));
+
+ String fileupType = req.getParameter("fileup" + MultiPartFilter.CONTENT_TYPE_SUFFIX);
+ assertThat("req.getParameter('fileup'+CONTENT_TYPE_SUFFIX)",fileupType,is("application/octet-stream"));
super.doPost(req, resp);
}
-
}
-
-
+ @SuppressWarnings("deprecation")
@Before
public void setUp() throws Exception
{
- _dir = File.createTempFile("testmultupart",null);
- assertTrue(_dir.delete());
- assertTrue(_dir.mkdir());
- _dir.deleteOnExit();
- assertTrue(_dir.isDirectory());
+ Path tmpDir = MavenTestingUtils.getTargetTestingPath("testmultupart");
+ FS.ensureEmpty(tmpDir);
+
+ _dir = tmpDir.toFile();
tester=new ServletTester("/context");
- tester.getContext().setResourceBase(_dir.getCanonicalPath());
+ tester.getContext().setResourceBase(tmpDir.toString());
tester.getContext().addServlet(TestServlet.class, "/");
tester.getContext().setAttribute("javax.servlet.context.tempdir", _dir);
- FilterHolder multipartFilter = tester.getContext().addFilter(MultiPartFilter.class,"/*", EnumSet.of(DispatcherType.REQUEST));
+ multipartFilter = tester.getContext().addFilter(MultiPartFilter.class,"/*", EnumSet.of(DispatcherType.REQUEST));
multipartFilter.setInitParameter("deleteFiles", "true");
multipartFilter.setInitParameter("fileOutputBuffer", "1"); //write a file if there's more than 1 byte content
tester.start();
@@ -780,6 +832,7 @@ public class MultipartFilterTest
assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.getStatus());
}
+ @SuppressWarnings("serial")
public static class TestServletParameterMap extends DumpServlet
{
@Override
@@ -790,7 +843,7 @@ public class MultipartFilterTest
super.doPost(req, resp);
}
}
-
+
/**
* Validate that the getParameterMap() call is correctly unencoding the parameters in the
* map that it returns.
@@ -820,7 +873,7 @@ public class MultipartFilterTest
"Content-Type: application/octet-stream\r\n\r\n"+
"How now brown cow."+
"\r\n--" + boundary + "\r\n"+
- "Content-Disposition: form-data; name=\"strup\""+
+ "Content-Disposition: form-data; name=\"strup\""+ // FIXME: this is missing a "\r\n"??
"Content-Type: application/octet-stream\r\n\r\n"+
"How now brown cow."+
"\r\n--" + boundary + "--\r\n\r\n";
@@ -831,6 +884,119 @@ public class MultipartFilterTest
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
assertTrue(response.getContent().indexOf("brown cow")>=0);
}
+
+ /**
+ * Validate that the uploaded file can be accessed on the name it was given
+ * @throws Exception on test failure
+ */
+ @Test
+ @Ignore("Fails for Bug #486394")
+ public void testFileUpload_AccessViaFilename() throws Exception
+ {
+ tester.addServlet(ParameterListServlet.class,"/paramlist");
+
+ multipartFilter.setInitParameter("fileOutputBuffer", "1");
+ multipartFilter.setInitParameter("deleteFiles", "false");
+ multipartFilter.setInitParameter("writeFilesWithFilenames", "true");
+
+ // generated and parsed test
+ HttpTester.Request request = HttpTester.newRequest();
+ HttpTester.Response response;
+
+ // test GET
+ request.setMethod("POST");
+ request.setURI("/context/paramlist");
+ request.setVersion("HTTP/1.1");
+ request.setHeader("Host","tester");
+ request.setHeader("Connection","close");
+ String boundary="XyXyXy";
+ request.setHeader("Content-Type","multipart/form-data; boundary=" + boundary);
+
+ StringBuilder content = new StringBuilder();
+ content.append("--").append(boundary).append("\r\n");
+ content.append("Content-Disposition: form-data; name=\"file\"; filename=\"tiny.dat\"\r\n");
+ content.append("Content-Type: application/octet-stream\r\n");
+ content.append("\r\n");
+ content.append("How now brown cow.\r\n");
+ content.append("--").append(boundary).append("--\r\n");
+ content.append("\r\n");
+
+ request.setContent(content.toString());
+
+ response = HttpTester.parseResponse(tester.getResponses(request.generate()));
+ assertThat("Response status", response.getStatus(), is(HttpServletResponse.SC_OK));
+ assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+
+ String contents = assertUploadedFileExists("tiny.dat");
+ assertThat("contents", contents, containsString("How now brown cow."));
+ }
+
+ /**
+ * Validate that the two upload files, with the same name="" on two different parts,
+ * can be accessed with the filename="" portions.
+ * @throws Exception on test failure
+ */
+ @Test
+ @Ignore("Fails for Bug #486394")
+ public void testTwoFileUploads_AccessViaFilename() throws Exception
+ {
+ tester.addServlet(ParameterListServlet.class,"/paramlist");
+
+ multipartFilter.setInitParameter("fileOutputBuffer", "1");
+ multipartFilter.setInitParameter("deleteFiles", "false");
+ multipartFilter.setInitParameter("writeFilesWithFilenames", "true");
+
+ // generated and parsed test
+ HttpTester.Request request = HttpTester.newRequest();
+ HttpTester.Response response;
+
+ // test GET
+ request.setMethod("POST");
+ request.setURI("/context/paramlist");
+ request.setVersion("HTTP/1.1");
+ request.setHeader("Host","tester");
+ request.setHeader("Connection","close");
+
+ String boundary="XyXyXy";
+ request.setHeader("Content-Type","multipart/form-data; boundary=" + boundary);
+
+ StringBuilder content = new StringBuilder();
+ content.append("--").append(boundary).append("\r\n");
+ content.append("Content-Disposition: form-data; name=\"same\"; filename=\"crocodile.dat\"\r\n");
+ content.append("Content-Type: application/octet-stream\r\n");
+ content.append("\r\n");
+ content.append("See ya later, aligator.\r\n");
+ content.append("--").append(boundary).append("\r\n");
+ content.append("Content-Disposition: form-data; name=\"same\"; filename=\"aligator.dat\"\r\n");
+ content.append("Content-Type: application/octet-stream\r\n");
+ content.append("\r\n");
+ content.append("In a while, crocodile.\r\n");
+ content.append("--").append(boundary).append("--\r\n");
+ content.append("\r\n");
+
+ request.setContent(content.toString());
+
+ response = HttpTester.parseResponse(tester.getResponses(request.generate()));
+ assertThat("Response status", response.getStatus(), is(HttpServletResponse.SC_OK));
+ assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+
+ String contents = assertUploadedFileExists("crocodile.dat");
+ assertThat("contents", contents, containsString("See ya later, aligator."));
+
+ contents = assertUploadedFileExists("aligator.dat");
+ assertThat("contents", contents, containsString("In a while, crocodile."));
+ }
+
+ private String assertUploadedFileExists(String filename) throws IOException
+ {
+ File uploadedFile = new File(_dir,filename);
+ assertThat("Uploaded File[" + uploadedFile + "].exists",uploadedFile.exists(),is(true));
+
+ try (Reader reader = new FileReader(uploadedFile))
+ {
+ return IO.toString(reader);
+ }
+ }
public static class TestServletCharSet extends HttpServlet
{
@@ -885,11 +1051,61 @@ public class MultipartFilterTest
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
}
+
+ @Test
+ public void testFilesWithFilenames ()
+ throws Exception
+ {
+ multipartFilter.setInitParameter("fileOutputBuffer", "0");
+ multipartFilter.setInitParameter("writeFilesWithFilenames", "true");
+
+
+ String boundary="XyXyXy";
+ HttpTester.Request request = HttpTester.newRequest();
+ HttpTester.Response response;
+ tester.addServlet(FilenameServlet.class,"/testf");
+ // test GET
+ request.setMethod("POST");
+ request.setVersion("HTTP/1.0");
+ request.setHeader("Host","tester");
+ request.setURI("/context/testf");
+ request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
+
+ String content = "--XyXyXy\r"+
+ "Content-Disposition: form-data; name=\"fileName\"\r"+
+ "Content-Type: text/plain; charset=US-ASCII\r"+
+ "Content-Transfer-Encoding: 8bit\r"+
+ "\r"+
+ "abc\r"+
+ "--XyXyXy\r"+
+ "Content-Disposition: form-data; name=\"desc\"\r"+
+ "Content-Type: text/plain; charset=US-ASCII\r"+
+ "Content-Transfer-Encoding: 8bit\r"+
+ "\r"+
+ "123\r"+
+ "--XyXyXy\r"+
+ "Content-Disposition: form-data; name=\"title\"\r"+
+ "Content-Type: text/plain; charset=US-ASCII\r"+
+ "Content-Transfer-Encoding: 8bit\r"+
+ "\r"+
+ "ttt\r"+
+ "--XyXyXy\r"+
+ "Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r"+
+ "Content-Type: application/octet-stream\r"+
+ "Content-Transfer-Encoding: binary\r"+
+ "\r"+
+ "000\r"+
+ "--XyXyXy--\r";
+ request.setContent(content);
+
+ response = HttpTester.parseResponse(tester.getResponses(request.generate()));
+ assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+ assertTrue(response.getContent().indexOf("000")>=0);
+ }
+
+ @SuppressWarnings("serial")
public static class DumpServlet extends HttpServlet
{
- private static final long serialVersionUID = 201012011130L;
-
- /* ------------------------------------------------------------ */
/**
* @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
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 72f53fb6e3..8b3ef9702e 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
@@ -63,6 +63,7 @@ public class MultiPartInputStreamParser
protected File _tmpDir;
protected File _contextTmpDir;
protected boolean _deleteOnExit;
+ protected boolean _writeFilesWithFilenames;
@@ -94,9 +95,19 @@ public class MultiPartInputStreamParser
protected void open()
throws IOException
{
- //Write to a buffer in memory until we discover we've exceed the
- //MultipartConfig fileSizeThreshold
- _out = _bout= new ByteArrayOutputStream2();
+ //We will either be writing to a file, if it has a filename on the content-disposition
+ //and otherwise a byte-array-input-stream, OR if we exceed the getFileSizeThreshold, we
+ //will need to change to write to a file.
+ if (isWriteFilesWithFilenames() && _filename != null && _filename.trim().length() > 0)
+ {
+ createFile();
+ }
+ else
+ {
+ //Write to a buffer in memory until we discover we've exceed the
+ //MultipartConfig fileSizeThreshold
+ _out = _bout= new ByteArrayOutputStream2();
+ }
}
protected void close()
@@ -751,6 +762,15 @@ public class MultiPartInputStreamParser
_deleteOnExit = deleteOnExit;
}
+ public void setWriteFilesWithFilenames (boolean writeFilesWithFilenames)
+ {
+ _writeFilesWithFilenames = writeFilesWithFilenames;
+ }
+
+ public boolean isWriteFilesWithFilenames ()
+ {
+ return _writeFilesWithFilenames;
+ }
public boolean isDeleteOnExit()
{
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java
index ef6a74bd82..acdf703e18 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java
@@ -20,6 +20,7 @@ package org.eclipse.jetty.util.thread;
import java.lang.reflect.Constructor;
import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.log.Log;
@@ -53,6 +54,15 @@ public interface ExecutionStrategy
*/
public void execute();
+
+ /**
+ * A task that can handle {@link RejectedExecutionException}
+ */
+ public interface Rejectable
+ {
+ public void reject();
+ }
+
/**
* <p>A producer of {@link Runnable} tasks to run.</p>
* <p>The {@link ExecutionStrategy} will repeatedly invoke {@link #produce()} until
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsume.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsume.java
index d3053221b0..4643775e6a 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsume.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsume.java
@@ -19,6 +19,7 @@
package org.eclipse.jetty.util.thread.strategy;
import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -140,7 +141,15 @@ public class ExecuteProduceConsume implements ExecutionStrategy, Runnable
while (_threadpool!=null && _threadpool.isLowOnThreads())
{
LOG.debug("EWYK low resources {}",this);
- _lowresources.execute();
+ try
+ {
+ _lowresources.execute();
+ }
+ catch(Throwable e)
+ {
+ // just warn if lowresources execute fails and keep producing
+ LOG.warn(e);
+ }
}
// no longer low resources so produceAndRun normally
@@ -204,13 +213,37 @@ public class ExecuteProduceConsume implements ExecutionStrategy, Runnable
// Spawn a new thread to continue production by running the produce loop.
if (LOG.isDebugEnabled())
LOG.debug("{} dispatch",this);
- _executor.execute(this);
+ try
+ {
+ _executor.execute(this);
+ }
+ catch(RejectedExecutionException e)
+ {
+ // If we cannot execute, then discard/reject the task and keep producing
+ LOG.debug(e);
+ LOG.warn("RejectedExecution {}",task);
+ try
+ {
+ if (task instanceof Rejectable)
+ ((Rejectable)task).reject();
+ }
+ catch (Exception x)
+ {
+ e.addSuppressed(x);
+ LOG.warn(e);
+ }
+ finally
+ {
+ task=null;
+ }
+ }
}
// Run the task.
if (LOG.isDebugEnabled())
LOG.debug("{} run {}",this,task);
- task.run();
+ if (task != null)
+ task.run();
if (LOG.isDebugEnabled())
LOG.debug("{} ran {}",this,task);
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ProduceExecuteConsume.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ProduceExecuteConsume.java
index 64903a6fbd..9310c05d5f 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ProduceExecuteConsume.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ProduceExecuteConsume.java
@@ -19,6 +19,7 @@
package org.eclipse.jetty.util.thread.strategy;
import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -55,7 +56,26 @@ public class ProduceExecuteConsume implements ExecutionStrategy
break;
// Execute the task.
- _executor.execute(task);
+ try
+ {
+ _executor.execute(task);
+ }
+ catch(RejectedExecutionException e)
+ {
+ // Discard/reject tasks that cannot be executed
+ if (task instanceof Rejectable)
+ {
+ try
+ {
+ ((Rejectable)task).reject();
+ }
+ catch (Throwable x)
+ {
+ e.addSuppressed(x);
+ LOG.warn(e);
+ }
+ }
+ }
}
}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java
index 6f164620b9..293fb3d6de 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java
@@ -657,6 +657,38 @@ public class MultiPartInputStreamTest
}
+ @Test
+ public void testWriteFilesIfContentDispositionFilename ()
+ throws Exception
+ {
+ String s = "--AaB03x\r\n"+
+ "content-disposition: form-data; name=\"field1\"; filename=\"frooble.txt\"\r\n"+
+ "\r\n"+
+ "Joe Blow\r\n"+
+ "--AaB03x\r\n"+
+ "content-disposition: form-data; name=\"stuff\"\r\n"+
+ "Content-Type: text/plain\r\n"+
+ "\r\n"+"sss"+
+ "aaa"+"\r\n" +
+ "--AaB03x--\r\n";
+ //all default values for multipartconfig, ie file size threshold 0
+ MultipartConfigElement config = new MultipartConfigElement(_dirname);
+ MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(s.getBytes()),
+ _contentType,
+ config,
+ _tmpDir);
+ mpis.setDeleteOnExit(true);
+ mpis.setWriteFilesWithFilenames(true);
+ Collection<Part> parts = mpis.getParts();
+ assertThat(parts.size(), is(2));
+ Part field1 = mpis.getPart("field1"); //has a filename, should be written to a file
+ File f = ((MultiPartInputStreamParser.MultiPart)field1).getFile();
+ assertThat(f,notNullValue()); // longer than 100 bytes, should already be a tmp file
+
+ Part stuff = mpis.getPart("stuff");
+ f = ((MultiPartInputStreamParser.MultiPart)stuff).getFile(); //should only be in memory, no filename
+ assertThat(f, nullValue());
+ }
private void testMulti(String filename) throws IOException, ServletException, InterruptedException
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/BinaryFrame.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/BinaryFrame.java
index b237b541e3..b7c930b2c7 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/BinaryFrame.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/BinaryFrame.java
@@ -51,6 +51,8 @@ public class BinaryFrame extends DataFrame
@Override
public Type getType()
{
+ if (getOpCode() == OpCode.CONTINUATION)
+ return Type.CONTINUATION;
return Type.BINARY;
}
}
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/TextFrame.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/TextFrame.java
index 6fc40b8f63..8aeb325315 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/TextFrame.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/TextFrame.java
@@ -34,6 +34,8 @@ public class TextFrame extends DataFrame
@Override
public Type getType()
{
+ if (getOpCode() == OpCode.CONTINUATION)
+ return Type.CONTINUATION;
return Type.TEXT;
}
diff --git a/tests/test-integration/src/test/resources/DefaultHandler.xml b/tests/test-integration/src/test/resources/DefaultHandler.xml
index a0504083bf..7920979deb 100644
--- a/tests/test-integration/src/test/resources/DefaultHandler.xml
+++ b/tests/test-integration/src/test/resources/DefaultHandler.xml
@@ -41,8 +41,8 @@
<New id="defcontext" class="org.eclipse.jetty.server.handler.ContextHandler">
<Set name="contextPath">/tests</Set>
<Set name="ResourceBase"><Property name="test.docroot.base"/>/default</Set>
- <Set name="Handler"><New id="reshandler" class="org.eclipse.jetty.server.handler.ResourceHandler"/></Set>
- <Set name="DisplayName">default</Set>
+ <Set name="Handler"><New id="reshandler" class="org.eclipse.jetty.server.handler.ResourceHandler"/></Set>
+ <Set name="DisplayName">default</Set>
</New>
</Item>
</Array>
diff --git a/tests/test-integration/src/test/resources/RFC2616Base.xml b/tests/test-integration/src/test/resources/RFC2616Base.xml
index a35088f5e8..9a1d4ae094 100644
--- a/tests/test-integration/src/test/resources/RFC2616Base.xml
+++ b/tests/test-integration/src/test/resources/RFC2616Base.xml
@@ -102,12 +102,10 @@
</Arg>
</Call>
-
-
- <!-- =========================================================== -->
- <!-- extra options -->
- <!-- =========================================================== -->
- <Set name="stopAtShutdown">true</Set>
- <Set name="stopTimeout">1000</Set>
+ <!-- =========================================================== -->
+ <!-- extra options -->
+ <!-- =========================================================== -->
+ <Set name="stopAtShutdown">true</Set>
+ <Set name="stopTimeout">1000</Set>
</Configure>
diff --git a/tests/test-integration/src/test/resources/RFC2616_Redirects.xml b/tests/test-integration/src/test/resources/RFC2616_Redirects.xml
index a777ad1e89..fca59dd34b 100644
--- a/tests/test-integration/src/test/resources/RFC2616_Redirects.xml
+++ b/tests/test-integration/src/test/resources/RFC2616_Redirects.xml
@@ -2,53 +2,51 @@
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
- <!-- =========================================================== -->
- <!-- Configure Rewrite Handler -->
- <!-- =========================================================== -->
- <Get id="oldhandler" name="handler"/>
+ <!-- =========================================================== -->
+ <!-- Configure Rewrite Handler -->
+ <!-- =========================================================== -->
- <Set name="handler">
+ <Call name="insertHandler">
+ <Arg>
<New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
-
- <Set name="handler"><Ref refid="oldhandler"/></Set>
<Set name="rewriteRequestURI">true</Set>
<Set name="rewritePathInfo">false</Set>
<Set name="originalPathAttribute">requestedPath</Set>
<Set name="rules">
- <Array type="org.eclipse.jetty.rewrite.handler.Rule">
-
- <!-- add a response rule -->
- <!--
- <Item>
- <New id="response" class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule">
- <Set name="pattern">/rewrite/session/</Set>
- <Set name="code">401</Set>
- <Set name="reason">Setting error code 401</Set>
- </New>
- </Item>
- -->
-
- <!-- add a simple redirect -->
- <!--
- <Item>
- <New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
- <Set name="pattern">/redirect/*</Set>
- <Set name="location">/tests/</Set>
- </New>
- </Item>
- -->
-
- <!-- add a regex rewrite redirect -->
- <Item>
- <New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectRegexRule">
- <Set name="regex">/redirect/(.*)</Set>
- <Set name="replacement">/tests/$1</Set>
- </New>
- </Item>
- </Array>
- </Set>
+ <Array type="org.eclipse.jetty.rewrite.handler.Rule">
+
+ <!-- add a response rule -->
+ <!--
+ <Item>
+ <New id="response" class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule">
+ <Set name="pattern">/rewrite/session/</Set>
+ <Set name="code">401</Set>
+ <Set name="reason">Setting error code 401</Set>
+ </New>
+ </Item>
+ -->
+
+ <!-- add a simple redirect -->
+ <!--
+ <Item>
+ <New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
+ <Set name="pattern">/redirect/*</Set>
+ <Set name="location">/tests/</Set>
+ </New>
+ </Item>
+ -->
+
+ <!-- add a regex rewrite redirect -->
+ <Item>
+ <New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectRegexRule">
+ <Set name="regex">/redirect/(.*)</Set>
+ <Set name="replacement">/tests/$1</Set>
+ </New>
+ </Item>
+ </Array>
+ </Set>
</New>
- </Set>
-
+ </Arg>
+ </Call>
</Configure>
diff --git a/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java b/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java
index 3670d1137d..6a2f716a97 100644
--- a/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java
+++ b/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java
@@ -160,13 +160,13 @@ public class JdbcLoginServiceTest
stopClient();
}
}
-
- public void testGetWithNonExistantUser() throws Exception
+
+ @Test
+ public void testGetNonExistantUser () throws Exception
{
try
{
startClient("foo", "bar");
-
ContentResponse response = _client.GET(_baseUri.resolve("input.txt"));
assertEquals(HttpServletResponse.SC_UNAUTHORIZED,response.getStatus());
}
@@ -219,12 +219,17 @@ public class JdbcLoginServiceTest
protected void startClient(String username, String pwd)
throws Exception
{
+ startClient("jetty", "jetty");
+ }
+
+ protected void startClient(String user, String pwd) throws Exception
+ {
_client = new HttpClient();
QueuedThreadPool executor = new QueuedThreadPool();
executor.setName(executor.getName() + "-client");
_client.setExecutor(executor);
AuthenticationStore authStore = _client.getAuthenticationStore();
- authStore.addAuthentication(new BasicAuthentication(_baseUri, __realm, username, pwd));
+ authStore.addAuthentication(new BasicAuthentication(_baseUri, __realm, user, pwd));
_client.start();
}
diff --git a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/AttributeNormalizerTest.java b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/AttributeNormalizerTest.java
index 8121d63e8e..e0bec424b7 100644
--- a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/AttributeNormalizerTest.java
+++ b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/AttributeNormalizerTest.java
@@ -18,12 +18,17 @@
package org.eclipse.jetty.quickstart;
-import static org.junit.Assert.assertEquals;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
@@ -43,16 +48,50 @@ public class AttributeNormalizerTest
public static List<String[]> data()
{
String[][] tests = {
- { "WAR", "/opt/jetty-distro/demo.base/webapps/root" },
- { "jetty.home", "/opt/jetty-distro" },
- { "jetty.base", "/opt/jetty-distro/demo.base" },
- { "user.home", "/home/user" },
- { "user.dir", "/etc/init.d" },
+ { "WAR", toSystemPath("/opt/jetty-distro/demo.base/webapps/root") },
+ { "jetty.home", toSystemPath("/opt/jetty-distro") },
+ { "jetty.base", toSystemPath("/opt/jetty-distro/demo.base") },
+ { "user.home", toSystemPath("/home/user") },
+ { "user.dir", toSystemPath("/etc/init.d") },
};
return Arrays.asList(tests);
}
+ /**
+ * As the declared paths in this testcase might be actual paths on the system
+ * running these tests, the expected paths should be cleaned up to represent
+ * the actual system paths.
+ * <p>
+ * Eg: on fedora /etc/init.d is a symlink to /etc/rc.d/init.d
+ */
+ private static String toSystemPath(String rawpath)
+ {
+ Path path = FileSystems.getDefault().getPath(rawpath);
+ if (Files.exists(path))
+ {
+ // It exists, resolve it to the real path
+ try
+ {
+ path = path.toRealPath();
+ }
+ catch (IOException e)
+ {
+ // something prevented us from resolving to real path, fallback to
+ // absolute path resolution (not as accurate)
+ path = path.toAbsolutePath();
+ e.printStackTrace();
+ }
+ }
+ else
+ {
+ // File doesn't exist, resolve to absolute path
+ // We can't rely on File.toCanonicalPath() here
+ path = path.toAbsolutePath();
+ }
+ return path.toString();
+ }
+
private static String origJettyBase;
private static String origJettyHome;
private static String origUserHome;
@@ -97,108 +136,108 @@ public class AttributeNormalizerTest
@Test
public void testEqual()
{
- assertEquals("file:${" + key + "}",normalizer.normalize("file:" + path));
+ assertThat(normalizer.normalize("file:" + path), is("file:${" + key + "}"));
}
@Test
public void testEqualsSlash()
{
- assertEquals("file:${" + key + "}",normalizer.normalize("file:" + path + "/"));
+ assertThat(normalizer.normalize("file:" + path + "/"), is("file:${" + key + "}"));
}
@Test
public void testEqualsSlashFile()
{
- assertEquals("file:${" + key + "}/file",normalizer.normalize("file:" + path + "/file"));
+ assertThat(normalizer.normalize("file:" + path + "/file"), is("file:${" + key + "}/file"));
}
@Test
public void testURIEquals() throws URISyntaxException
{
- assertEquals("file:${" + key + "}",normalizer.normalize(new URI("file:" + path)));
+ assertThat(normalizer.normalize(new URI("file:" + path)), is("file:${" + key + "}"));
}
@Test
public void testURIEqualsSlash() throws URISyntaxException
{
- assertEquals("file:${" + key + "}",normalizer.normalize(new URI("file:" + path + "/")));
+ assertThat(normalizer.normalize(new URI("file:" + path + "/")), is("file:${" + key + "}"));
}
@Test
public void testURIEqualsSlashFile() throws URISyntaxException
{
- assertEquals("file:${" + key + "}/file",normalizer.normalize(new URI("file:" + path + "/file")));
+ assertThat(normalizer.normalize(new URI("file:" + path + "/file")), is("file:${" + key + "}/file"));
}
@Test
public void testURLEquals() throws MalformedURLException
{
- assertEquals("file:${" + key + "}",normalizer.normalize(new URL("file:" + path)));
+ assertThat(normalizer.normalize(new URL("file:" + path)), is("file:${" + key + "}"));
}
@Test
public void testURLEqualsSlash() throws MalformedURLException
{
- assertEquals("file:${" + key + "}",normalizer.normalize(new URL("file:" + path + "/")));
+ assertThat(normalizer.normalize(new URL("file:" + path + "/")), is("file:${" + key + "}"));
}
@Test
public void testURLEqualsSlashFile() throws MalformedURLException
{
- assertEquals("file:${" + key + "}/file",normalizer.normalize(new URL("file:" + path + "/file")));
+ assertThat(normalizer.normalize(new URL("file:" + path + "/file")), is("file:${" + key + "}/file"));
}
@Test
public void testJarFileEquals_BangFile()
{
- assertEquals("jar:file:${" + key + "}!/file",normalizer.normalize("jar:file:" + path + "!/file"));
+ assertThat(normalizer.normalize("jar:file:" + path + "!/file"), is("jar:file:${" + key + "}!/file"));
}
@Test
public void testJarFileEquals_SlashBangFile()
{
- assertEquals("jar:file:${" + key + "}!/file",normalizer.normalize("jar:file:" + path + "/!/file"));
+ assertThat(normalizer.normalize("jar:file:" + path + "/!/file"), is("jar:file:${" + key + "}!/file"));
}
@Test
public void testJarFileEquals_FileBangFile()
{
- assertEquals("jar:file:${" + key + "}/file!/file",normalizer.normalize("jar:file:" + path + "/file!/file"));
+ assertThat(normalizer.normalize("jar:file:" + path + "/file!/file"), is("jar:file:${" + key + "}/file!/file"));
}
@Test
public void testJarFileEquals_URIBangFile() throws URISyntaxException
{
- assertEquals("jar:file:${" + key + "}!/file",normalizer.normalize(new URI("jar:file:" + path + "!/file")));
+ assertThat(normalizer.normalize(new URI("jar:file:" + path + "!/file")), is("jar:file:${" + key + "}!/file"));
}
@Test
public void testJarFileEquals_URISlashBangFile() throws URISyntaxException
{
- assertEquals("jar:file:${" + key + "}!/file",normalizer.normalize(new URI("jar:file:" + path + "/!/file")));
+ assertThat(normalizer.normalize(new URI("jar:file:" + path + "/!/file")), is("jar:file:${" + key + "}!/file"));
}
@Test
public void testJarFileEquals_URIFileBangFile() throws URISyntaxException
{
- assertEquals("jar:file:${" + key + "}/file!/file",normalizer.normalize(new URI("jar:file:" + path + "/file!/file")));
+ assertThat(normalizer.normalize(new URI("jar:file:" + path + "/file!/file")), is("jar:file:${" + key + "}/file!/file"));
}
@Test
public void testJarFileEquals_URLBangFile() throws MalformedURLException
{
- assertEquals("jar:file:${" + key + "}!/file",normalizer.normalize(new URL("jar:file:" + path + "!/file")));
+ assertThat(normalizer.normalize(new URL("jar:file:" + path + "!/file")), is("jar:file:${" + key + "}!/file"));
}
@Test
public void testJarFileEquals_URLSlashBangFile() throws MalformedURLException
{
- assertEquals("jar:file:${" + key + "}!/file",normalizer.normalize(new URL("jar:file:" + path + "/!/file")));
+ assertThat(normalizer.normalize(new URL("jar:file:" + path + "/!/file")), is("jar:file:${" + key + "}!/file"));
}
@Test
public void testJarFileEquals_URLFileBangFile() throws MalformedURLException
{
- assertEquals("jar:file:${" + key + "}/file!/file",normalizer.normalize(new URL("jar:file:" + path + "/file!/file")));
+ assertThat(normalizer.normalize(new URL("jar:file:" + path + "/file!/file")), is("jar:file:${" + key + "}/file!/file"));
}
}
diff --git a/tests/test-webapps/test-jetty-webapp/src/main/assembly/embedded-jetty-web-for-webbundle.xml b/tests/test-webapps/test-jetty-webapp/src/main/assembly/embedded-jetty-web-for-webbundle.xml
index 8726d91a68..bbd9ac4929 100644
--- a/tests/test-webapps/test-jetty-webapp/src/main/assembly/embedded-jetty-web-for-webbundle.xml
+++ b/tests/test-webapps/test-jetty-webapp/src/main/assembly/embedded-jetty-web-for-webbundle.xml
@@ -13,7 +13,6 @@ detected.
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
-
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- Required minimal context configuration : -->
<!-- + contextPath -->

Back to the top