diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java index b909749a4c9..a6c48ee5e05 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java @@ -49,13 +49,17 @@ import org.junit.Test; public class HostnameVerificationTest { private SslContextFactory clientSslContextFactory = new SslContextFactory(); - private Server server = new Server(); + private Server server; private HttpClient client; private NetworkConnector connector; @Before public void setUp() throws Exception { + QueuedThreadPool serverThreads = new QueuedThreadPool(); + serverThreads.setName("server"); + server = new Server(serverThreads); + SslContextFactory serverSslContextFactory = new SslContextFactory(); serverSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); serverSslContextFactory.setKeyStorePassword("storepwd"); @@ -76,10 +80,10 @@ public class HostnameVerificationTest clientSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); clientSslContextFactory.setKeyStorePassword("storepwd"); - QueuedThreadPool executor = new QueuedThreadPool(); - executor.setName(executor.getName() + "-client"); + QueuedThreadPool clientThreads = new QueuedThreadPool(); + clientThreads.setName("client"); client = new HttpClient(clientSslContextFactory); - client.setExecutor(executor); + client.setExecutor(clientThreads); client.start(); } 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 18526f84de7..3071e7f59e9 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 @@ -579,6 +579,7 @@ public class SslConnection extends AbstractConnection { synchronized (this) { + Throwable failure = null; try { // Do we already have some decrypted data? @@ -773,6 +774,7 @@ public class SslConnection extends AbstractConnection catch (SSLHandshakeException x) { notifyHandshakeFailed(_sslEngine, x); + failure = x; throw x; } catch (SSLException x) @@ -782,6 +784,12 @@ public class SslConnection extends AbstractConnection x = (SSLException)new SSLHandshakeException(x.getMessage()).initCause(x); notifyHandshakeFailed(_sslEngine, x); } + failure = x; + throw x; + } + catch (Throwable x) + { + failure = x; throw x; } finally @@ -790,7 +798,7 @@ public class SslConnection extends AbstractConnection if (_flushRequiresFillToProgress) { _flushRequiresFillToProgress = false; - getExecutor().execute(_runCompleteWrite); + getExecutor().execute(failure == null ? _runCompleteWrite : new FailWrite(failure)); } if (_encryptedInput != null && !_encryptedInput.hasRemaining()) @@ -1132,5 +1140,28 @@ public class SslConnection extends AbstractConnection { return super.toString()+"->"+getEndPoint().toString(); } + + private class FailWrite extends RunnableTask + { + private final Throwable failure; + + private FailWrite(Throwable failure) + { + super("runFailWrite"); + this.failure = failure; + } + + @Override + public void run() + { + getWriteFlusher().onFail(failure); + } + + @Override + public InvocationType getInvocationType() + { + return getWriteFlusher().getCallbackInvocationType(); + } + } } } diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncIOServletTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncIOServletTest.java index 393f4197ac4..af1c90507ff 100644 --- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncIOServletTest.java +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncIOServletTest.java @@ -1137,6 +1137,10 @@ public class AsyncIOServletTest extends AbstractTest break; case H2C: case H2: + // In case of HTTP/2, we not only send the request, but also the preface and + // SETTINGS frames. SETTINGS frame need to be replied, so we want to wait to + // write the reply before shutting output down, so that the test does not fail. + Thread.sleep(1000); Session session = ((HttpConnectionOverHTTP2)connection).getSession(); ((HTTP2Session)session).getEndPoint().shutdownOutput(); break;