From df9de50f96b7c21270ef2e173a89ca29abdea087 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 17 Mar 2016 10:33:58 +1100 Subject: [PATCH 1/2] Issue #434 RequestTest stack traces Added reset to ShutdownMonitor --- .../java/org/eclipse/jetty/server/ShutdownMonitor.java | 5 +++++ .../java/org/eclipse/jetty/server/ShutdownMonitorTest.java | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java index f6f3f1c526b..9e418932111 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java @@ -64,6 +64,11 @@ public class ShutdownMonitor return Holder.instance; } + protected static void reset() + { + Holder.instance = new ShutdownMonitor(); + } + public static void register(LifeCycle... lifeCycles) { getInstance().addLifeCycles(lifeCycles); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java index a56639929e8..f0e4e7f1f67 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java @@ -26,6 +26,7 @@ import java.net.InetAddress; import java.net.Socket; import org.eclipse.jetty.util.thread.ShutdownThread; +import org.junit.AfterClass; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -33,6 +34,12 @@ import static org.junit.Assert.assertTrue; public class ShutdownMonitorTest { + @AfterClass + public static void afterClass() + { + ShutdownMonitor.reset(); + } + @Test public void testShutdownMonitor() throws Exception { From 0e0edbb6db0d3576467f9e37c31387cec0ceda59 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 18 Mar 2016 10:49:03 +0100 Subject: [PATCH 2/2] Fixes #441 (Simplify direct HTTP/2 over TLS HttpClient usage) Added useALPN property to HttpClientTransportOverHTTP2 to disable usage of ALPN and therefore allow direct HTTP/2 over TLS. --- .../http/HttpClientTransportOverHTTP2.java | 53 ++++--- .../client/http/DirectHTTP2OverTLSTest.java | 132 ++++++++++++++++++ .../src/test/resources/keystore.jks | Bin 0 -> 2206 bytes 3 files changed, 168 insertions(+), 17 deletions(-) create mode 100644 jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/DirectHTTP2OverTLSTest.java create mode 100644 jetty-http2/http2-http-client-transport/src/test/resources/keystore.jks diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java index 844be1a5e37..ad637c1b3e2 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java @@ -28,6 +28,7 @@ import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClientTransport; import org.eclipse.jetty.client.HttpDestination; import org.eclipse.jetty.client.Origin; +import org.eclipse.jetty.client.ProxyConfiguration; import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http2.HTTP2Session; @@ -38,7 +39,6 @@ import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -51,6 +51,7 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements private final HTTP2Client client; private ClientConnectionFactory connectionFactory; private HttpClient httpClient; + private boolean useALPN = true; public HttpClientTransportOverHTTP2(HTTP2Client client) { @@ -63,6 +64,16 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements return client.getSelectors(); } + public boolean isUseALPN() + { + return useALPN; + } + + public void setUseALPN(boolean useALPN) + { + this.useALPN = useALPN; + } + @Override protected void doStart() throws Exception { @@ -110,12 +121,9 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements { client.setConnectTimeout(httpClient.getConnectTimeout()); + SessionListenerPromise listenerPromise = new SessionListenerPromise(context); + HttpDestinationOverHTTP2 destination = (HttpDestinationOverHTTP2)context.get(HTTP_DESTINATION_CONTEXT_KEY); - @SuppressWarnings("unchecked") - Promise connectionPromise = (Promise)context.get(HTTP_CONNECTION_PROMISE_CONTEXT_KEY); - - SessionListenerPromise listenerPromise = new SessionListenerPromise(destination, connectionPromise); - SslContextFactory sslContextFactory = null; if (HttpScheme.HTTPS.is(destination.getScheme())) sslContextFactory = httpClient.getSslContextFactory(); @@ -127,8 +135,10 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map context) throws IOException { ClientConnectionFactory factory = connectionFactory; - SslContextFactory sslContextFactory = (SslContextFactory)context.get(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY); - if (sslContextFactory != null) + HttpDestinationOverHTTP2 destination = (HttpDestinationOverHTTP2)context.get(HTTP_DESTINATION_CONTEXT_KEY); + ProxyConfiguration.Proxy proxy = destination.getProxy(); + boolean ssl = proxy == null ? HttpScheme.HTTPS.is(destination.getScheme()) : proxy.isSecure(); + if (ssl && isUseALPN()) factory = new ALPNClientConnectionFactory(client.getExecutor(), factory, client.getProtocols()); return factory.newConnection(endPoint, context); } @@ -145,27 +155,36 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements private class SessionListenerPromise extends Session.Listener.Adapter implements Promise { - private final HttpDestinationOverHTTP2 destination; - private final Promise promise; + private final Map context; private HttpConnectionOverHTTP2 connection; - public SessionListenerPromise(HttpDestinationOverHTTP2 destination, Promise promise) + private SessionListenerPromise(Map context) { - this.destination = destination; - this.promise = promise; + this.context = context; } @Override public void succeeded(Session session) { - connection = newHttpConnection(destination, session); - promise.succeeded(connection); + connection = newHttpConnection(destination(), session); + promise().succeeded(connection); } @Override public void failed(Throwable failure) { - promise.failed(failure); + promise().failed(failure); + } + + private HttpDestinationOverHTTP2 destination() + { + return (HttpDestinationOverHTTP2)context.get(HTTP_DESTINATION_CONTEXT_KEY); + } + + @SuppressWarnings("unchecked") + private Promise promise() + { + return (Promise)context.get(HTTP_CONNECTION_PROMISE_CONTEXT_KEY); } @Override @@ -181,7 +200,7 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements { Map settings = frame.getSettings(); if (settings.containsKey(SettingsFrame.MAX_CONCURRENT_STREAMS)) - destination.setMaxRequestsPerConnection(settings.get(SettingsFrame.MAX_CONCURRENT_STREAMS)); + destination().setMaxRequestsPerConnection(settings.get(SettingsFrame.MAX_CONCURRENT_STREAMS)); } @Override diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/DirectHTTP2OverTLSTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/DirectHTTP2OverTLSTest.java new file mode 100644 index 00000000000..8daa09fd953 --- /dev/null +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/DirectHTTP2OverTLSTest.java @@ -0,0 +1,132 @@ +// +// ======================================================================== +// 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.http2.client.http; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http2.HTTP2Cipher; +import org.eclipse.jetty.http2.client.HTTP2Client; +import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; +import org.eclipse.jetty.server.ConnectionFactory; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.toolchain.test.TestTracker; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.After; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class DirectHTTP2OverTLSTest +{ + @Rule + public TestTracker tracker = new TestTracker(); + private Server server; + private ServerConnector connector; + private HttpClient client; + + private void start(Handler handler) throws Exception + { + startServer(handler); + startClient(); + } + + private void startServer(Handler handler) throws Exception + { + QueuedThreadPool serverThreads = new QueuedThreadPool(); + serverThreads.setName("server"); + server = new Server(serverThreads); + HttpConfiguration httpsConfig = new HttpConfiguration(); + httpsConfig.addCustomizer(new SecureRequestCustomizer()); + ConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig); + ConnectionFactory ssl = new SslConnectionFactory(newSslContextFactory(), h2.getProtocol()); + connector = new ServerConnector(server, 1, 1, ssl, h2); + server.addConnector(connector); + server.setHandler(handler); + server.start(); + } + + private void startClient() throws Exception + { + QueuedThreadPool clientThreads = new QueuedThreadPool(); + clientThreads.setName("client"); + HttpClientTransportOverHTTP2 transport = new HttpClientTransportOverHTTP2(new HTTP2Client()); + transport.setUseALPN(false); + client = new HttpClient(transport, newSslContextFactory()); + client.setExecutor(clientThreads); + client.start(); + } + + @After + public void dispose() throws Exception + { + if (client != null) + client.stop(); + if (server != null) + server.stop(); + } + + private SslContextFactory newSslContextFactory() + { + SslContextFactory sslContextFactory = new SslContextFactory(); + sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); + sslContextFactory.setKeyStorePassword("storepwd"); + sslContextFactory.setUseCipherSuitesOrder(true); + sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR); + return sslContextFactory; + } + + @Test + public void testDirectHTTP2OverTLS() throws Exception + { + // The client knows a priori that the server speaks h2 on a particular port. + + start(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + } + }); + + ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) + .scheme(HttpScheme.HTTPS.asString()) + .timeout(5, TimeUnit.SECONDS) + .send(); + + Assert.assertEquals(HttpStatus.OK_200, response.getStatus()); + } +} diff --git a/jetty-http2/http2-http-client-transport/src/test/resources/keystore.jks b/jetty-http2/http2-http-client-transport/src/test/resources/keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..428ba54776ede2fdcdeedd879edb927c2abd9953 GIT binary patch literal 2206 zcmcgt`9Bkm8{cNkoMUp6gmShKn!AQX*(l6Nj(i=TnQPOKYtv{*Wg>ItE=Q!pRYH8a z$Sp#S#2lYw#aw;$y9u4T}83H*%lp zAKZay0sy=q1Qoo85aAQh;$ zD(c2EIN#D7WwYDLKUg!CotQPD@dp;5FR#bgaace(^x$6g5frD~(_b(MI^J&*A2DRp zf5Q2onfE(zvUb9|9C`66)YFRNM6~xrz4;iVbU=P|*YT2eWHFJJtr+M@zt2qPm)K~rRcqcs=LM12)PX0TT%QO zlf*xkqD3}7l)1J`5W(>=9nR0e6j-<79<11v3ZuXXcQpoCsqY~n`$FN+S}hcVm5Y>G zXnD{@DYs1@{S0z(lW+?86LWKtku$$-(khsh>0qRUXn=84`GRn?77M^_JY`durnN;KE zW#OJ`h<6xcB{I))ekGpc*Ylt}0cx4|OMBDPQvx4`r`}4Ze5_ipdObGMTi3bZHd5PC zcY0;?uBWu$PSvjJeb87nY7ghNv?%M@SoDl6IWt`bQCosfSh$#D6$ea~QhKM^ud2Ut z+9PYJuVpoELmN-A`F$BicO{BSYg@#tS%avVfb}DxL)|NanJ)#zB!2~?#Ot%H7--9N zU$bs0fS5G!m5M4&WK3#a|H|Tgw*?X-;H+Lu@kwA>qSR~7UC7b)7MJXTn6PG>n@8jP zW+}F^X$$c;U~4ryqRF; z>`j!tbLMK4ZGyY643|~?%Mu#fm!l%wAKjBDmd+VYmp3S#$scD$~bxbf|z#)hShN0*AhRaPDcmqrftGlHq4^54MM$Xfy(2> zH8QYVMzmn_oHbvJCB`IN~E&{1*h&0gEM{e zKvWvzp(!BqMX8`t#)~0nq}Wa zr6>FRPyp;AAB&)1$5@;r$23J{K&~>TWjZf7V$wFzmGM95CXhFG1cJNVAXks}C+&2- zbf9Qn*D8N}Afd2kpwDxns3%1uaFhAqDV8ksWiWY|quuLGZ0)SqrJ!Y8yX}@}IyC$C zQ3rCUsn}#>F#D8%D?q~ySy4j&he%Bs{{7V%rl!ui`@KQP?NTi+_iN{cwom&9RaMRR zB~z!hz|0HAgB9_Ijvpe-zr#jLbckJsc>vmo{+im?t8lA;N#fD4?{lb&J0V8Gocq%; f1ihv=QIDh{M_<9V+45Z2{KE4_qW}V3B0uV%GgrOJ literal 0 HcmV?d00001