diff --git a/Jenkinsfile b/Jenkinsfile index 79402a71340..8e2db60c6ae 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -97,7 +97,7 @@ def mavenBuild(jdk, cmdline, mvnName, junitPublishDisabled) { mavenOpts: mavenOpts, mavenLocalRepo: localRepo) { // Some common Maven command line + provided command line - sh "mvn -V -B -T3 -e -fae -Dmaven.test.failure.ignore=true -Djetty.testtracker.log=true $cmdline -Dunix.socket.tmp=" + env.JENKINS_HOME + sh "mvn -Pci -V -B -T3 -e -fae -Dmaven.test.failure.ignore=true -Djetty.testtracker.log=true $cmdline -Dunix.socket.tmp=" + env.JENKINS_HOME } } diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java index 169ae96ec0a..5f23ad4fda2 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java @@ -25,7 +25,6 @@ import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.nio.file.StandardOpenOption; - import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -116,7 +115,8 @@ public class FastFileServer } String listing = Resource.newResource(file).getListHTML( request.getRequestURI(), - request.getPathInfo().lastIndexOf("/") > 0); + request.getPathInfo().lastIndexOf("/") > 0, + request.getQueryString()); response.setContentType("text/html; charset=utf-8"); response.getWriter().println(listing); return; diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java index 65bb9b8f878..e94411302c6 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java @@ -91,6 +91,7 @@ import org.eclipse.jetty.util.SocketAddressResolver; import org.eclipse.jetty.util.log.StacklessLogging; import org.hamcrest.Matchers; import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.condition.DisabledIfSystemProperty; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -740,6 +741,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest @ParameterizedTest @ArgumentsSource(ScenarioProvider.class) + @Tag("ipv6") public void testSendToIPv6Address(Scenario scenario) throws Exception { start(scenario, new EmptyServerHandler()); @@ -1609,6 +1611,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest @ParameterizedTest @ArgumentsSource(ScenarioProvider.class) + @Tag("ipv6") public void test_IPv6_Host(Scenario scenario) throws Exception { start(scenario, new AbstractHandler() diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientURITest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientURITest.java index 8523d0b2fc6..912234995bb 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientURITest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientURITest.java @@ -18,13 +18,6 @@ package org.eclipse.jetty.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -52,13 +45,22 @@ import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.URIUtil; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientURITest extends AbstractHttpClientServerTest { @ParameterizedTest @ArgumentsSource(ScenarioProvider.class) + @Tag("ipv6") public void testIPv6Host(Scenario scenario) throws Exception { start(scenario, new EmptyServerHandler()); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyConfigurationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyConfigurationTest.java index 2b112bcd9f9..6827fca3db9 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyConfigurationTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyConfigurationTest.java @@ -18,12 +18,12 @@ package org.eclipse.jetty.client; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.jupiter.api.Test; - public class ProxyConfigurationTest { @Test @@ -68,6 +68,7 @@ public class ProxyConfigurationTest } @Test + @Tag("ipv6") public void testProxyMatchesWithIncludesAndExcludesIPv6() throws Exception { HttpProxy proxy = new HttpProxy("host", 0); diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardDeployer.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardDeployer.java index dd58166c7be..5fa840a794a 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardDeployer.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardDeployer.java @@ -22,6 +22,7 @@ import org.eclipse.jetty.deploy.App; import org.eclipse.jetty.deploy.AppLifeCycle; import org.eclipse.jetty.deploy.graph.Node; import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.Callback; public class StandardDeployer implements AppLifeCycle.Binding { @@ -37,9 +38,10 @@ public class StandardDeployer implements AppLifeCycle.Binding { ContextHandler handler = app.getContextHandler(); if (handler == null) - { throw new NullPointerException("No Handler created for App: " + app); - } - app.getDeploymentManager().getContexts().addHandler(handler); + + Callback.Completable blocker = new Callback.Completable(); + app.getDeploymentManager().getContexts().deployHandler(handler, blocker); + blocker.get(); } } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardUndeployer.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardUndeployer.java index ad5b0377799..6502381cbe0 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardUndeployer.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/StandardUndeployer.java @@ -21,17 +21,12 @@ package org.eclipse.jetty.deploy.bindings; import org.eclipse.jetty.deploy.App; import org.eclipse.jetty.deploy.AppLifeCycle; import org.eclipse.jetty.deploy.graph.Node; -import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; -import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.Callback; public class StandardUndeployer implements AppLifeCycle.Binding { - private static final Logger LOG = Log.getLogger(StandardUndeployer.class); - @Override public String[] getBindingTargets() { @@ -42,33 +37,11 @@ public class StandardUndeployer implements AppLifeCycle.Binding @Override public void processBinding(Node node, App app) throws Exception { - ContextHandler handler = app.getContextHandler(); - ContextHandlerCollection chcoll = app.getDeploymentManager().getContexts(); - - recursiveRemoveContext(chcoll,handler); - } - - private void recursiveRemoveContext(HandlerCollection coll, ContextHandler context) - { - Handler children[] = coll.getHandlers(); - int originalCount = children.length; - - for (int i = 0, n = children.length; i < n; i++) - { - Handler child = children[i]; - LOG.debug("Child handler {}",child); - if (child.equals(context)) - { - LOG.debug("Removing handler {}",child); - coll.removeHandler(child); - child.destroy(); - if (LOG.isDebugEnabled()) - LOG.debug("After removal: {} (originally {})",coll.getHandlers().length,originalCount); - } - else if (child instanceof HandlerCollection) - { - recursiveRemoveContext((HandlerCollection)child,context); - } - } + ContextHandlerCollection contexts = app.getDeploymentManager().getContexts(); + ContextHandler context = app.getContextHandler(); + Callback.Completable blocker = new Callback.Completable(); + contexts.undeployHandler(context, blocker); + blocker.get(); + context.destroy(); } } diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java index e5aaccbc8c6..a30ed2370a3 100644 --- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java +++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java @@ -50,6 +50,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.toolchain.test.IO; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.StacklessLogging; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIfSystemProperty; @@ -473,10 +474,10 @@ public class HttpClientTest extends AbstractHttpClientServerTest ExecutionException x = assertThrows(ExecutionException.class, () -> client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .idleTimeout(4 * idleTimeout, TimeUnit.MILLISECONDS) - .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) - .send()); + .scheme(scheme) + .idleTimeout(4 * idleTimeout, TimeUnit.MILLISECONDS) + .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS) + .send()); assertThat(x.getCause(), instanceOf(EOFException.class)); connector.setIdleTimeout(5 * idleTimeout); @@ -493,6 +494,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest } @Test + @Tag("ipv6") public void testSendToIPv6Address() throws Exception { start(new EmptyServerHandler()); @@ -595,9 +597,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest { assertThrows(ExecutionException.class, () -> client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) - .timeout(60, TimeUnit.SECONDS) - .send()); + .scheme(scheme) + .timeout(60, TimeUnit.SECONDS) + .send()); } } diff --git a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod index 2263ae0807b..405b5209aaf 100644 --- a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod +++ b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod @@ -13,7 +13,7 @@ session-store sessions [files] -maven://com.hazelcast/hazelcast/3.8.2|lib/hazelcast/hazelcast-3.8.2.jar +maven://com.hazelcast/hazelcast/3.9.3|lib/hazelcast/hazelcast-3.9.3.jar [xml] etc/sessions/hazelcast/default.xml @@ -33,4 +33,4 @@ jetty.session.hazelcast.mapName=jetty-distributed-session-map jetty.session.hazelcast.hazelcastInstanceName=JETTY_DISTRIBUTED_SESSION_INSTANCE #jetty.session.hazelcast.configurationLocation= jetty.session.gracePeriod.seconds=3600 -jetty.session.savePeriod.seconds=0 \ No newline at end of file +jetty.session.savePeriod.seconds=0 diff --git a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod index c6a26fc7123..29e3a253171 100644 --- a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod +++ b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod @@ -13,8 +13,8 @@ session-store sessions [files] -maven://com.hazelcast/hazelcast/3.8.2|lib/hazelcast/hazelcast-3.8.2.jar -maven://com.hazelcast/hazelcast-client/3.8.2|lib/hazelcast/hazelcast-client-3.8.2.jar +maven://com.hazelcast/hazelcast/3.9.3|lib/hazelcast/hazelcast-3.9.3.jar +maven://com.hazelcast/hazelcast-client/3.9.3|lib/hazelcast/hazelcast-client-3.9.3.jar [xml] etc/sessions/hazelcast/remote.xml @@ -35,4 +35,4 @@ jetty.session.hazelcast.hazelcastInstanceName=JETTY_DISTRIBUTED_SESSION_INSTANCE jetty.session.hazelcast.onlyClient=true #jetty.session.hazelcast.configurationLocation= jetty.session.gracePeriod.seconds=3600 -jetty.session.savePeriod.seconds=0 \ No newline at end of file +jetty.session.savePeriod.seconds=0 diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index f9a8f95c0ba..1164d97cff5 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -28,6 +28,7 @@ import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.log.StacklessLogging; import org.hamcrest.Matchers; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import static org.eclipse.jetty.http.HttpCompliance.Violation.CASE_INSENSITIVE_METHOD; @@ -1975,6 +1976,7 @@ public class HttpParserTest } @Test + @Tag("ipv6") public void testIPv6Host() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( @@ -2056,6 +2058,7 @@ public class HttpParserTest } @Test + @Tag("ipv6") public void testIPv6HostPort() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( 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 4594b5a9299..88a604f1130 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 @@ -295,8 +295,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable } catch (Throwable x) { - if (LOG.isDebugEnabled()) - LOG.debug(x); + LOG.ignore(x); return -1; } } @@ -309,8 +308,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable } catch (Throwable x) { - if (LOG.isDebugEnabled()) - LOG.debug(x); + LOG.ignore(x); return -1; } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java b/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java index 0468f3a15ca..85173d9352e 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java @@ -389,9 +389,9 @@ abstract public class WriteFlusher boolean progress = true; while (progress && buffers != null) { - long before = remaining(buffers); + long before = BufferUtil.remaining(buffers); boolean flushed = _endPoint.flush(buffers); - long after = remaining(buffers); + long after = BufferUtil.remaining(buffers); long written = before - after; if (LOG.isDebugEnabled()) @@ -441,16 +441,6 @@ abstract public class WriteFlusher return buffers == null ? EMPTY_BUFFERS : buffers; } - private long remaining(ByteBuffer[] buffers) - { - if (buffers == null) - return 0; - long result = 0; - for (ByteBuffer buffer : buffers) - result += buffer.remaining(); - return result; - } - /** * Notify the flusher of a failure * diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java index 15518193881..3bfcf2e99f3 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java @@ -835,6 +835,12 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr LOG.debug("flush b[{}]={}", i++, BufferUtil.toDetailString(b)); } + // finish of any previous flushes + if (BufferUtil.hasContent(_encryptedOutput) && !getEndPoint().flush(_encryptedOutput)) + return false; + + boolean isEmpty = BufferUtil.isEmpty(appOuts); + Boolean result = null; try { @@ -866,7 +872,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr if (filled < 0) throw new IOException("Broken pipe"); } - return result = false; + return result = isEmpty; default: throw new IllegalStateException("Unexpected HandshakeStatus " + status); @@ -895,10 +901,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr _sslEngine.isOutboundDone()); // Was all the data consumed? - boolean allConsumed = true; - for (ByteBuffer b : appOuts) - if (BufferUtil.hasContent(b)) - allConsumed = false; + isEmpty = BufferUtil.isEmpty(appOuts); // if we have net bytes, let's try to flush them boolean flushed = true; @@ -906,7 +909,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr flushed = getEndPoint().flush(_encryptedOutput); if (LOG.isDebugEnabled()) - LOG.debug("net flushed={}, ac={}", flushed, allConsumed); + LOG.debug("net flushed={}, ac={}", flushed, isEmpty); // Now deal with the results returned from the wrap Status wrap = wrapResult.getStatus(); @@ -919,7 +922,7 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr if (!flushed) return result = false; getEndPoint().shutdownOutput(); - if (allConsumed) + if (isEmpty) return result = true; throw new IOException("Broken pipe"); } @@ -936,15 +939,20 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr if (isRenegotiating() && !allowRenegotiate()) { getEndPoint().shutdownOutput(); - if (allConsumed && BufferUtil.isEmpty(_encryptedOutput)) + if (isEmpty && BufferUtil.isEmpty(_encryptedOutput)) return result = true; throw new IOException("Broken pipe"); } if (!flushed) return result = false; - if (allConsumed) - return result = true; + + if (isEmpty) + { + if (wrapResult.getHandshakeStatus() != HandshakeStatus.NEED_WRAP || + wrapResult.bytesProduced() == 0) + return result = true; + } break; default: @@ -1073,14 +1081,15 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr @Override public void doShutdownOutput() { + final EndPoint endp = getEndPoint(); try { boolean close; boolean flush = false; synchronized (_decryptedEndPoint) { - boolean ishut = getEndPoint().isInputShutdown(); - boolean oshut = getEndPoint().isOutputShutdown(); + boolean ishut = endp.isInputShutdown(); + boolean oshut = endp.isOutputShutdown(); if (LOG.isDebugEnabled()) LOG.debug("shutdownOutput: {} oshut={}, ishut={} {}", SslConnection.this, oshut, ishut); @@ -1097,16 +1106,28 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr } if (flush) - flush(BufferUtil.EMPTY_BUFFER); // Send the TLS close message. + { + if (!flush(BufferUtil.EMPTY_BUFFER) && !close) + { + Thread.yield(); + // if we still can't flush, but we are not closing the endpoint, + // let's just flush the encrypted output in the background. + // and continue as if we are closed. The assumption here is that + // the encrypted buffer will contain the entire close handshake + // and that a call to flush(EMPTY_BUFFER) is not needed. + endp.write(Callback.from(() -> {}, t -> endp.close()), _encryptedOutput); + } + } + if (close) - getEndPoint().close(); + endp.close(); else ensureFillInterested(); } catch (Throwable x) { LOG.ignore(x); - getEndPoint().close(); + endp.close(); } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java index 28c5a9694e9..70634cac55a 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java @@ -23,6 +23,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; +import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; @@ -31,6 +32,7 @@ import java.nio.channels.SocketChannel; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import javax.net.ssl.SSLEngine; @@ -50,6 +52,8 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -63,6 +67,8 @@ public class SslConnectionTest private final SslContextFactory _sslCtxFactory = new SslContextFactory.Server(); protected volatile EndPoint _lastEndp; private volatile boolean _testFill=true; + private volatile boolean _onXWriteThenShutdown=false; + private volatile FutureCallback _writeCallback; protected ServerSocketChannel _connector; final AtomicInteger _dispatches = new AtomicInteger(); @@ -104,6 +110,7 @@ public class SslConnectionTest static final AtomicInteger __startBlocking = new AtomicInteger(); static final AtomicInteger __blockFor = new AtomicInteger(); + static final AtomicBoolean __onIncompleteFlush = new AtomicBoolean(); private static class TestEP extends SocketChannelEndPoint { public TestEP(SelectableChannel channel, ManagedSelector selector, SelectionKey key, Scheduler scheduler) @@ -114,13 +121,14 @@ public class SslConnectionTest @Override protected void onIncompleteFlush() { - super.onIncompleteFlush(); + __onIncompleteFlush.set(true); } @Override public boolean flush(ByteBuffer... buffers) throws IOException { + __onIncompleteFlush.set(false); if (__startBlocking.get()==0 || __startBlocking.decrementAndGet()==0) { if (__blockFor.get()>0 && __blockFor.getAndDecrement()>0) @@ -224,20 +232,23 @@ public class SslConnectionTest filled=endp.fill(_in); } + boolean shutdown = _onXWriteThenShutdown && BufferUtil.toString(_in).contains("X"); + // Write everything int l=_in.remaining(); if (l>0) { FutureCallback blockingWrite= new FutureCallback(); + endp.write(blockingWrite,_in); blockingWrite.get(); + if (shutdown) + endp.shutdownOutput(); } // are we done? - if (endp.isInputShutdown()) - { + if (endp.isInputShutdown() || shutdown) endp.shutdownOutput(); - } } } catch(InterruptedException|EofException e) @@ -423,7 +434,7 @@ public class SslConnectionTest public void testBlockedWrite() throws Exception { startSSL(); - try (Socket client = newClient()) + try (SSLSocket client = newClient()) { client.setSoTimeout(5000); try (SocketChannel server = _connector.accept()) @@ -431,21 +442,78 @@ public class SslConnectionTest server.configureBlocking(false); _manager.accept(server); - __startBlocking.set(5); - __blockFor.set(3); - client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8)); byte[] buffer = new byte[1024]; int len = client.getInputStream().read(buffer); - assertEquals(5, len); assertEquals("Hello", new String(buffer, 0, len, StandardCharsets.UTF_8)); + __startBlocking.set(0); + __blockFor.set(2); _dispatches.set(0); client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); - len = 5; - while (len > 0) - len -= client.getInputStream().read(buffer); - assertEquals(0, len); + + try + { + client.setSoTimeout(500); + client.getInputStream().read(buffer); + throw new IllegalStateException(); + } + catch(SocketTimeoutException e) + { + } + + + assertTrue(__onIncompleteFlush.get()); + ((TestEP)_lastEndp).getWriteFlusher().completeWrite(); + + len = client.getInputStream().read(buffer); + assertEquals("World", new String(buffer, 0, len, StandardCharsets.UTF_8)); + } + } + } + + @Test + public void testBlockedClose() throws Exception + { + startSSL(); + try (SSLSocket client = newClient()) + { + client.setSoTimeout(5000); + try (SocketChannel server = _connector.accept()) + { + server.configureBlocking(false); + _manager.accept(server); + + //__startBlocking.set(5); + //__blockFor.set(3); + + client.getOutputStream().write("Short".getBytes(StandardCharsets.UTF_8)); + byte[] buffer = new byte[1024]; + int len = client.getInputStream().read(buffer); + assertEquals("Short", new String(buffer, 0, len, StandardCharsets.UTF_8)); + + _onXWriteThenShutdown=true; + __startBlocking.set(2); // block on the close handshake flush + __blockFor.set(Integer.MAX_VALUE); // > retry loops in SslConnection + 1 + client.getOutputStream().write("This is a much longer example with X".getBytes(StandardCharsets.UTF_8)); + len = client.getInputStream().read(buffer); + assertEquals("This is a much longer example with X", new String(buffer, 0, len, StandardCharsets.UTF_8)); + + try + { + client.setSoTimeout(500); + client.getInputStream().read(buffer); + throw new IllegalStateException(); + } + catch(SocketTimeoutException e) + { + } + + __blockFor.set(0); + assertTrue(__onIncompleteFlush.get()); + ((TestEP)_lastEndp).getWriteFlusher().completeWrite(); + len = client.getInputStream().read(buffer); + assertThat(len, is(len)); } } } @@ -475,7 +543,6 @@ public class SslConnectionTest String line = in.readLine(); if (line == null) break; - // System.err.println(line); count.countDown(); } } @@ -488,7 +555,6 @@ public class SslConnectionTest for (int i = 0; i < LINES; i++) { client.getOutputStream().write(("HelloWorld " + i + "\n").getBytes(StandardCharsets.UTF_8)); - // System.err.println("wrote"); if (i % 1000 == 0) { client.getOutputStream().flush(); diff --git a/jetty-memcached/jetty-memcached-sessions/pom.xml b/jetty-memcached/jetty-memcached-sessions/pom.xml index 1635ddf8177..1b889901d19 100644 --- a/jetty-memcached/jetty-memcached-sessions/pom.xml +++ b/jetty-memcached/jetty-memcached-sessions/pom.xml @@ -24,7 +24,7 @@ org.slf4j slf4j-simple - 1.7.9 + ${slf4j.version} test diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ConnectHandlerTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ConnectHandlerTest.java index 1e55d99448f..705f0bad8db 100644 --- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ConnectHandlerTest.java +++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ConnectHandlerTest.java @@ -47,6 +47,7 @@ import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -88,6 +89,7 @@ public class ConnectHandlerTest extends AbstractConnectHandlerTest } @Test + @Tag("ipv6") public void testCONNECTwithIPv6() throws Exception { String hostPort = "[::1]:" + serverConnector.getLocalPort(); 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 891881004c8..d188ce467ea 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 @@ -1618,9 +1618,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu if (getServer() != null && (getServer().isStarting() || getServer().isStarted())) { - Handler[] contextCollections = getServer().getChildHandlersByClass(ContextHandlerCollection.class); + ContextHandlerCollection[] contextCollections = + (ContextHandlerCollection[])getServer().getChildHandlersByClass(ContextHandlerCollection.class); for (int h = 0; contextCollections != null && h < contextCollections.length; h++) - ((ContextHandlerCollection)contextCollections[h]).mapContexts(); + contextCollections[h].mapContexts(); } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java index 8c6fc7c57bf..d082ca7a89e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java @@ -24,8 +24,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -36,15 +35,16 @@ import org.eclipse.jetty.server.HttpChannelState; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.ArrayUtil; +import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.thread.SerializedExecutor; /* ------------------------------------------------------------ */ -/** ContextHandlerCollection. - * +/** * This {@link org.eclipse.jetty.server.handler.HandlerCollection} is creates a * Map of contexts to it's contained handlers based * on the context path and virtual hosts of any contained {@link org.eclipse.jetty.server.handler.ContextHandler}s. @@ -57,9 +57,9 @@ import org.eclipse.jetty.util.log.Logger; public class ContextHandlerCollection extends HandlerCollection { private static final Logger LOG = Log.getLogger(ContextHandlerCollection.class); + private final SerializedExecutor _serializedExecutor = new SerializedExecutor(); - private final ConcurrentMap _contextBranches = new ConcurrentHashMap<>(); - private volatile Trie> _pathBranches; + @Deprecated private Class _contextClass = ContextHandler.class; /* ------------------------------------------------------------ */ @@ -71,43 +71,57 @@ public class ContextHandlerCollection extends HandlerCollection /* ------------------------------------------------------------ */ public ContextHandlerCollection(ContextHandler... contexts) { - super(true,contexts); + super(true); + setHandlers(contexts); } - /* ------------------------------------------------------------ */ /** - * Remap the context paths. + * Remap the contexts. Normally this is not required as context + * mapping is maintained as a side effect of {@link #setHandlers(Handler[])} + * However, if configuration changes in the deep handler structure (eg contextpath is changed), then + * this call will trigger a remapping. + * This method is mutually excluded from {@link #deployHandler(Handler, Callback)} and + * {@link #undeployHandler(Handler, Callback)} */ - @ManagedOperation("update the mapping of context path to context") + @ManagedOperation("Update the mapping of context path to context") public void mapContexts() { - _contextBranches.clear(); - - Handler[] handlers = getHandlers(); - if (handlers==null) + _serializedExecutor.execute(()-> { - _pathBranches=new ArrayTernaryTrie<>(false,16); - return; - } - + while(true) + { + Handlers handlers = _handlers.get(); + if (handlers==null) + break; + if (updateHandlers(handlers, newHandlers(handlers.getHandlers()))) + break; + } + }); + } + + /* ------------------------------------------------------------ */ + @Override + protected Handlers newHandlers(Handler[] handlers) + { + if (handlers==null || handlers.length==0) + return null; + // Create map of contextPath to handler Branch - Map map = new HashMap<>(); + // A branch is a Handler that could contain 0 or more ContextHandlers + Map path2Branches = new HashMap<>(); for (Handler handler:handlers) { Branch branch=new Branch(handler); for (String contextPath : branch.getContextPaths()) { - Branch[] branches=map.get(contextPath); - map.put(contextPath, ArrayUtil.addToArray(branches, branch, Branch.class)); + Branch[] branches=path2Branches.get(contextPath); + path2Branches.put(contextPath, ArrayUtil.addToArray(branches, branch, Branch.class)); } - - for (ContextHandler context : branch.getContextHandlers()) - _contextBranches.putIfAbsent(context, branch.getHandler()); } - // Sort the branches so those with virtual hosts are considered before those without - for (Map.Entry entry: map.entrySet()) + // Sort the branches for each contextPath so those with virtual hosts are considered before those without + for (Map.Entry entry: path2Branches.entrySet()) { Branch[] branches=entry.getValue(); Branch[] sorted=new Branch[branches.length]; @@ -123,69 +137,56 @@ public class ContextHandlerCollection extends HandlerCollection // Loop until we have a big enough trie to hold all the context paths int capacity=512; - Trie> trie; + Mapping mapping; loop: while(true) { - trie=new ArrayTernaryTrie<>(false,capacity); - for (Map.Entry entry: map.entrySet()) + mapping = new Mapping(handlers, capacity); + for (Map.Entry entry: path2Branches.entrySet()) { - if (!trie.put(entry.getKey().substring(1),entry)) + if (!mapping._pathBranches.put(entry.getKey().substring(1),entry)) { capacity+=512; continue loop; } } - break loop; + break; } - if (LOG.isDebugEnabled()) { - for (String ctx : trie.keySet()) - LOG.debug("{}->{}",ctx,Arrays.asList(trie.get(ctx).getValue())); + for (String ctx : mapping._pathBranches.keySet()) + LOG.debug("{}->{}",ctx,Arrays.asList(mapping._pathBranches.get(ctx).getValue())); } - _pathBranches=trie; + + // add new context branches to concurrent map + for (Branch[] branches: path2Branches.values()) + { + for (Branch branch : branches) + { + for (ContextHandler context : branch.getContextHandlers()) + mapping._contextBranches.put(context, branch.getHandler()); + } + } + + return mapping; } /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.jetty.server.server.handler.HandlerCollection#setHandlers(org.eclipse.jetty.server.server.Handler[]) - */ - @Override - public void setHandlers(Handler[] handlers) - { - super.setHandlers(handlers); - if (isStarted()) - mapContexts(); - } - - /* ------------------------------------------------------------ */ - @Override - protected void doStart() throws Exception - { - mapContexts(); - super.doStart(); - } - - - /* ------------------------------------------------------------ */ - /* - * @see org.eclipse.jetty.server.server.Handler#handle(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int) - */ @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - Handler[] handlers = getHandlers(); - if (handlers==null || handlers.length==0) + Handlers handlers = _handlers.get(); + if (handlers==null) return; + Mapping mapping = (Mapping)handlers; HttpChannelState async = baseRequest.getHttpChannelState(); if (async.isAsync()) { ContextHandler context=async.getContextHandler(); if (context!=null) { - Handler branch = _contextBranches.get(context); + Handler branch = mapping._contextBranches.get(context); if (branch==null) context.handle(target,baseRequest,request, response); @@ -195,19 +196,19 @@ public class ContextHandlerCollection extends HandlerCollection } } - // data structure which maps a request to a context; first-best match wins - // { context path => [ context ] } - // } if (target.startsWith("/")) { + Trie> pathBranches = mapping._pathBranches; + if (pathBranches==null) + return; + int limit = target.length()-1; while (limit>=0) { // Get best match - Map.Entry branches = _pathBranches.getBest(target,1,limit); - - + Map.Entry branches = pathBranches.getBest(target,1,limit); + if (branches==null) break; @@ -227,10 +228,11 @@ public class ContextHandlerCollection extends HandlerCollection } else { - // This may not work in all circumstances... but then I think it should never be called - for (int i=0;i + * This method is the equivalent of {@link #addHandler(Handler)}, + * but its execution is non-block and mutually excluded from all + * other calls to {@link #deployHandler(Handler, Callback)} and + * {@link #undeployHandler(Handler, Callback)}. + * The handler may be added after this call returns. + *

+ * @param handler the handler to deploy + * @param callback Called after handler has been added + */ + public void deployHandler(Handler handler, Callback callback) + { + if (handler.getServer()!=getServer()) + handler.setServer(getServer()); + _serializedExecutor.execute(new SerializedExecutor.ErrorHandlingTask() + { + @Override + public void run() + { + addHandler(handler); + callback.succeeded(); + } + + @Override + public void accept(Throwable throwable) + { + callback.failed(throwable); + } + }); + } + + /* ------------------------------------------------------------ */ + /** + * Thread safe undeploy of a Handler. + *

+ * This method is the equivalent of {@link #removeHandler(Handler)}, + * but its execution is non-block and mutually excluded from all + * other calls to {@link #deployHandler(Handler,Callback)} and + * {@link #undeployHandler(Handler,Callback)}. + * The handler may be removed after this call returns. + *

+ * @param handler The handler to undeploy + * @param callback Called after handler has been removed + */ + public void undeployHandler(Handler handler, Callback callback) + { + _serializedExecutor.execute(new SerializedExecutor.ErrorHandlingTask() + { + @Override + public void run() + { + removeHandler(handler); + callback.succeeded(); + } + + @Override + public void accept(Throwable throwable) + { + callback.failed(throwable); + } + }); + } /* ------------------------------------------------------------ */ /** * @return The class to use to add new Contexts + * @deprecated Unused convenience mechanism not used. */ + @Deprecated public Class getContextClass() { return _contextClass; } - /* ------------------------------------------------------------ */ /** * @param contextClass The class to use to add new Contexts + * @deprecated Unused convenience mechanism not used. */ + @Deprecated public void setContextClass(Class contextClass) { if (contextClass ==null || !(ContextHandler.class.isAssignableFrom(contextClass))) @@ -342,5 +416,18 @@ public class ContextHandlerCollection extends HandlerCollection } } + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + private static class Mapping extends Handlers + { + private final Map _contextBranches = new HashMap<>(); + private final Trie> _pathBranches; + private Mapping(Handler[] handlers, int capacity) + { + super(handlers); + _pathBranches = new ArrayTernaryTrie<>(false, capacity); + } + } } 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 f7697255b06..e39077489ab 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 @@ -21,6 +21,7 @@ package org.eclipse.jetty.server.handler; import java.io.IOException; import java.util.Arrays; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -47,7 +48,7 @@ import org.eclipse.jetty.util.annotation.ManagedObject; public class HandlerCollection extends AbstractHandlerContainer { private final boolean _mutableWhenRunning; - private volatile Handler[] _handlers; + protected final AtomicReference _handlers = new AtomicReference<>(); /* ------------------------------------------------------------ */ public HandlerCollection() @@ -71,72 +72,93 @@ public class HandlerCollection extends AbstractHandlerContainer /* ------------------------------------------------------------ */ /** - * @return Returns the handlers. + * @return the array of handlers. */ @Override @ManagedAttribute(value="Wrapped handlers", readonly=true) public Handler[] getHandlers() { - return _handlers; + Handlers handlers = _handlers.get(); + return handlers==null ? null : handlers._handlers; } /* ------------------------------------------------------------ */ /** - * @param handlers The handlers to set. + * @param handlers the array of handlers to set. */ public void setHandlers(Handler[] handlers) { if (!_mutableWhenRunning && isStarted()) throw new IllegalStateException(STARTED); - if (handlers!=null) + while(true) { - // 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()); + if (updateHandlers(_handlers.get(), newHandlers(handlers))) + break; } - Handler[] old=_handlers;; - _handlers = handlers; - updateBeans(old, handlers); } /* ------------------------------------------------------------ */ - /** - * @see Handler#handle(String, Request, HttpServletRequest, HttpServletResponse) - */ + protected Handlers newHandlers(Handler[] handlers) + { + if (handlers==null || handlers.length==0) + return null; + return new Handlers(handlers); + } + + /* ------------------------------------------------------------ */ + protected boolean updateHandlers(Handlers old, Handlers handlers) + { + if (handlers!=null) + { + // check for loops + for (Handler handler:handlers._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._handlers) + if (handler.getServer()!=getServer()) + handler.setServer(getServer()); + } + + if (_handlers.compareAndSet(old, handlers)) + { + Handler[] oldBeans = old == null ? null : old._handlers; + Handler[] newBeans = handlers == null ? null : handlers._handlers; + updateBeans(oldBeans, newBeans); + return true; + } + return false; + } + + /* ------------------------------------------------------------ */ @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - if (_handlers!=null && isStarted()) + if (isStarted()) { - MultiException mex=null; + Handlers handlers = _handlers.get(); + if (handlers==null) + return; - for (int i=0;i<_handlers.length;i++) + MultiException mex=null; + for (Handler handler : handlers._handlers) { try { - _handlers[i].handle(target,baseRequest, request, response); + handler.handle(target, baseRequest, request, response); } - catch(IOException e) + catch (IOException | RuntimeException e) { throw e; } - catch(RuntimeException e) + catch (Exception e) { - throw e; - } - catch(Exception e) - { - if (mex==null) - mex=new MultiException(); + if (mex == null) + mex = new MultiException(); mex.add(e); } } @@ -147,37 +169,54 @@ public class HandlerCollection extends AbstractHandlerContainer else throw new ServletException(mex); } - } } /* ------------------------------------------------------------ */ - /* Add a handler. + /** + * Adds a handler. * This implementation adds the passed handler to the end of the existing collection of handlers. - * @see org.eclipse.jetty.server.server.HandlerContainer#addHandler(org.eclipse.jetty.server.server.Handler) + * If the handler is already added, it is removed and readded */ public void addHandler(Handler handler) { - setHandlers(ArrayUtil.addToArray(getHandlers(), handler, Handler.class)); + while(true) + { + Handlers old = _handlers.get(); + Handlers handlers = newHandlers(ArrayUtil.addToArray(old==null?null:ArrayUtil.removeFromArray(old._handlers, handler), handler, Handler.class)); + if (updateHandlers(old,handlers)) + break; + } } /* ------------------------------------------------------------ */ - /* Prepend a handler. + /** + * Prepends a handler. * This implementation adds the passed handler to the start of the existing collection of handlers. - * @see org.eclipse.jetty.server.server.HandlerContainer#addHandler(org.eclipse.jetty.server.server.Handler) */ public void prependHandler(Handler handler) { - setHandlers(ArrayUtil.prependToArray(handler, getHandlers(), Handler.class)); + while(true) + { + Handlers old = _handlers.get(); + Handlers handlers = newHandlers(ArrayUtil.prependToArray(handler, old==null?null:old._handlers, Handler.class)); + if (updateHandlers(old,handlers)) + break; + } } /* ------------------------------------------------------------ */ public void removeHandler(Handler handler) { - Handler[] handlers = getHandlers(); - - if (handlers!=null && handlers.length>0 ) - setHandlers(ArrayUtil.removeFromArray(handlers, handler)); + while(true) + { + Handlers old = _handlers.get(); + if (old==null || old._handlers.length==0) + break; + Handlers handlers = newHandlers(ArrayUtil.removeFromArray(old._handlers, handler)); + if (updateHandlers(old,handlers)) + break; + } } /* ------------------------------------------------------------ */ @@ -196,10 +235,28 @@ public class HandlerCollection extends AbstractHandlerContainer { if (!isStopped()) throw new IllegalStateException("!STOPPED"); - Handler[] children=getChildHandlers(); + Handler[] children = getChildHandlers(); setHandlers(null); for (Handler child: children) child.destroy(); super.destroy(); } + + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + /* ------------------------------------------------------------ */ + protected static class Handlers + { + private final Handler[] _handlers; + + protected Handlers(Handler[] handlers) + { + this._handlers = handlers; + } + + public Handler[] getHandlers() + { + return _handlers; + } + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java index 5525a49990f..c8e54f1a06d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ProxyConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ProxyConnectionTest.java index 579f6305194..7292631f600 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ProxyConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ProxyConnectionTest.java @@ -18,17 +18,17 @@ package org.eclipse.jetty.server; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertNull; - import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.util.log.StacklessLogging; import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; - import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertNull; + /** * */ @@ -82,6 +82,7 @@ public class ProxyConnectionTest } @Test + @Tag("ipv6") public void testIPv6() throws Exception { String response=_connector.getResponse("PROXY UNKNOWN eeee:eeee:eeee:eeee:eeee:eeee:eeee:eeee ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"+ diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java index b0eda81f5c3..d6b04538afe 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerCollectionTest.java @@ -18,16 +18,6 @@ package org.eclipse.jetty.server.handler; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.endsWith; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.io.IOException; import javax.servlet.AsyncContext; @@ -41,9 +31,18 @@ import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.hamcrest.Matchers; - import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + public class ContextHandlerCollectionTest { @Test @@ -214,7 +213,7 @@ public class ContextHandlerCollectionTest IsHandledHandler handler = (IsHandledHandler)context.getHandler(); context.setVirtualHosts(contextHosts); - // trigger this manually; it's supposed to be called when adding the handler + // trigger this manually handlerCollection.mapContexts(); for(String host : requestHosts) diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java index bc7a6c24b1e..1ca0baa01b7 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java @@ -167,7 +167,7 @@ public class ResourceHandlerTest _local.getResponse("GET /resource/ HTTP/1.0\r\n\r\n")); assertThat(response.getStatus(),equalTo(200)); assertThat(response.getContent(),containsString("jetty-dir.css")); - assertThat(response.getContent(),containsString("

Directory: /resource/")); + assertThat(response.getContent(),containsString("Directory: /resource/")); assertThat(response.getContent(),containsString("big.txt")); assertThat(response.getContent(),containsString("bigger.txt")); assertThat(response.getContent(),containsString("directory")); diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java index 69563a9c9f8..d7f87544921 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java @@ -23,7 +23,6 @@ import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; - import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.UnavailableException; @@ -48,8 +47,7 @@ import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceFactory; - -/** +/** * The default servlet. *

* This servlet, normally mapped to /, provides the handling for static @@ -79,9 +77,9 @@ import org.eclipse.jetty.util.resource.ResourceFactory; * * gzip If set to true, then static content will be served as * gzip content encoded if a matching resource is - * found ending with ".gz" (default false) + * found ending with ".gz" (default false) * (deprecated: use precompressed) - * + * * precompressed If set to a comma separated list of encoding types (that may be * listed in a requests Accept-Encoding header) to file * extension mappings to look for and serve. For example: @@ -131,10 +129,10 @@ import org.eclipse.jetty.util.resource.ResourceFactory; public class DefaultServlet extends HttpServlet implements ResourceFactory, WelcomeFactory { public static final String CONTEXT_INIT = "org.eclipse.jetty.servlet.Default."; - + private static final Logger LOG = Log.getLogger(DefaultServlet.class); - private static final long serialVersionUID = 4930458713846881193L; + private static final long serialVersionUID = 4930458713846881193L; private final ResourceService _resourceService; private ServletContext _servletContext; @@ -165,7 +163,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc { this(new ResourceService()); } - + /* ------------------------------------------------------------ */ @Override public void init() @@ -186,7 +184,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc _resourceService.setPrecompressedFormats(parsePrecompressedFormats(getInitParameter("precompressed"), getInitBoolean("gzip", false))); _resourceService.setPathInfoOnly(getInitBoolean("pathInfoOnly",_resourceService.isPathInfoOnly())); _resourceService.setEtags(getInitBoolean("etags",_resourceService.isEtags())); - + if ("exact".equals(getInitParameter("welcomeServlets"))) { _welcomeExactServlets=true; @@ -242,8 +240,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc String cc=getInitParameter("cacheControl"); if (cc!=null) _resourceService.setCacheControl(new PreEncodedHttpField(HttpHeader.CACHE_CONTROL,cc)); - - + String resourceCache = getInitParameter("resourceCache"); int max_cache_size=getInitInt("maxCacheSize", -2); int max_cached_file_size=getInitInt("maxCachedFileSize", -2); @@ -286,7 +283,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc } _resourceService.setContentFactory(contentFactory); _resourceService.setWelcomeFactory(this); - + List gzip_equivalent_file_extensions = new ArrayList(); String otherGzipExtensions = getInitParameter("otherGzipFileExtensions"); if (otherGzipExtensions != null) diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java index 7d7c2b163a7..690cafcfed4 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java @@ -157,10 +157,14 @@ public class DefaultServletTest defholder.setInitParameter("gzip", "false"); /* create some content in the docroot */ - FS.ensureDirExists(docRoot.resolve("one")); + Path one = docRoot.resolve("one"); + FS.ensureDirExists(one); FS.ensureDirExists(docRoot.resolve("two")); FS.ensureDirExists(docRoot.resolve("three")); + Path alert = one.resolve("onmouseclick='alert(oops)'"); + FS.touch(alert); + /* * Intentionally bad request URI. Sending a non-encoded URI with typically * encoded characters '<', '>', and '"'. @@ -172,6 +176,16 @@ public class DefaultServletTest String body = response.getContent(); assertThat(body, not(containsString("