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 @@
+ * 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 extends ContextHandler> 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
* 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