From 0ca40b59c613704d81258af0b0dde6da0a83981e Mon Sep 17 00:00:00 2001
From: Simone Bordet
Date: Wed, 7 Oct 2015 21:39:02 +0200
Subject: 479277 - HttpClient with HTTP/2 transport does not work for "https"
URLs.
Fixed by reworking how ClientConnectionFactories are handled by both
HTTP2Client and by HttpClientTransportOverHTTP2, to avoid that the
latter wraps the nested factories with SslConnection twice.
---
.../eclipse/jetty/http2/client/HTTP2Client.java | 25 +++---
jetty-http2/http2-http-client-transport/pom.xml | 32 ++++++++
.../client/http/HttpClientTransportOverHTTP2.java | 19 ++++-
.../http/HttpClientTransportOverHTTP2Test.java | 24 ++++++
.../src/test/resources/jetty-logging.properties | 5 ++
tests/test-http-client-transport/pom.xml | 36 +++++++++
.../eclipse/jetty/http/client/AbstractTest.java | 87 ++++++++++++++++++---
.../jetty/http/client/AsyncRequestContentTest.java | 12 +--
.../http/client/HttpClientIdleTimeoutTest.java | 24 ++----
.../eclipse/jetty/http/client/HttpClientTest.java | 10 +--
.../src/test/resources/keystore.jks | Bin 0 -> 2206 bytes
.../src/test/resources/truststore.jks | Bin 0 -> 916 bytes
12 files changed, 219 insertions(+), 55 deletions(-)
create mode 100644 jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties
create mode 100644 tests/test-http-client-transport/src/test/resources/keystore.jks
create mode 100644 tests/test-http-client-transport/src/test/resources/truststore.jks
diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java
index dad32dc822..f038895538 100644
--- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java
+++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java
@@ -137,7 +137,18 @@ public class HTTP2Client extends ContainerLifeCycle
setByteBufferPool(new MappedByteBufferPool());
if (connectionFactory == null)
- setClientConnectionFactory(new HTTP2ClientConnectionFactory());
+ {
+ HTTP2ClientConnectionFactory h2 = new HTTP2ClientConnectionFactory();
+ ALPNClientConnectionFactory alpn = new ALPNClientConnectionFactory(getExecutor(), h2, getProtocols());
+ setClientConnectionFactory((endPoint, context) ->
+ {
+ ClientConnectionFactory factory = h2;
+ SslContextFactory sslContextFactory = (SslContextFactory)context.get(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY);
+ if (sslContextFactory != null)
+ factory = new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), alpn);
+ return factory.newConnection(endPoint, context);
+ });
+ }
if (sessions == null)
{
@@ -356,17 +367,7 @@ public class HTTP2Client extends ContainerLifeCycle
context.put(HTTP2ClientConnectionFactory.BYTE_BUFFER_POOL_CONTEXT_KEY, getByteBufferPool());
context.put(HTTP2ClientConnectionFactory.EXECUTOR_CONTEXT_KEY, getExecutor());
context.put(HTTP2ClientConnectionFactory.SCHEDULER_CONTEXT_KEY, getScheduler());
-
- ClientConnectionFactory factory = getClientConnectionFactory();
-
- SslContextFactory sslContextFactory = (SslContextFactory)context.get(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY);
- if (sslContextFactory != null)
- {
- ALPNClientConnectionFactory alpn = new ALPNClientConnectionFactory(getExecutor(), factory, getProtocols());
- factory = new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), alpn);
- }
-
- return factory.newConnection(endpoint, context);
+ return getClientConnectionFactory().newConnection(endpoint, context);
}
@Override
diff --git a/jetty-http2/http2-http-client-transport/pom.xml b/jetty-http2/http2-http-client-transport/pom.xml
index be073c272d..df28dd82e0 100644
--- a/jetty-http2/http2-http-client-transport/pom.xml
+++ b/jetty-http2/http2-http-client-transport/pom.xml
@@ -15,6 +15,38 @@
+
+
+ maven-dependency-plugin
+
+
+ copy
+ generate-resources
+
+ copy
+
+
+
+
+ org.mortbay.jetty.alpn
+ alpn-boot
+ ${alpn.version}
+ jar
+ false
+ ${project.build.directory}/alpn
+
+
+
+
+
+
+
+ maven-surefire-plugin
+
+ -Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar
+
+
+
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 82e4ba3f92..ea16c18fea 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
@@ -22,19 +22,24 @@ import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Map;
+import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
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.api.Connection;
+import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.client.HTTP2Client;
+import org.eclipse.jetty.http2.client.HTTP2ClientConnectionFactory;
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;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
@ManagedObject("The HTTP/2 client transport")
public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements HttpClientTransport
@@ -68,7 +73,7 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements
addBean(client);
super.doStart();
- this.connectionFactory = client.getClientConnectionFactory();
+ this.connectionFactory = new HTTP2ClientConnectionFactory();
client.setClientConnectionFactory((endPoint, context) ->
{
HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY);
@@ -128,13 +133,21 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements
}
};
- client.connect(httpClient.getSslContextFactory(), address, listener, promise, context);
+ SslContextFactory sslContextFactory = null;
+ if (HttpScheme.HTTPS.is(destination.getScheme()))
+ sslContextFactory = httpClient.getSslContextFactory();
+
+ client.connect(sslContextFactory, address, listener, promise, context);
}
@Override
public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map context) throws IOException
{
- return connectionFactory.newConnection(endPoint, context);
+ ClientConnectionFactory factory = connectionFactory;
+ SslContextFactory sslContextFactory = (SslContextFactory)context.get(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY);
+ if (sslContextFactory != null)
+ factory = new ALPNClientConnectionFactory(client.getExecutor(), factory, client.getProtocols());
+ return factory.newConnection(endPoint, context);
}
protected HttpConnectionOverHTTP2 newHttpConnection(HttpDestination destination, Session session)
diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java
index 40f322098c..7a061eca85 100644
--- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java
+++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java
@@ -21,9 +21,13 @@ package org.eclipse.jetty.http2.client.http;
import java.util.concurrent.Executor;
import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http2.client.HTTP2Client;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.Assert;
+import org.junit.Ignore;
import org.junit.Test;
public class HttpClientTransportOverHTTP2Test
@@ -51,4 +55,24 @@ public class HttpClientTransportOverHTTP2Test
Assert.assertTrue(http2Client.isStopped());
}
+
+ @Ignore
+ @Test
+ public void testExternalServer() throws Exception
+ {
+ HTTP2Client http2Client = new HTTP2Client();
+ SslContextFactory sslContextFactory = new SslContextFactory();
+ HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP2(http2Client), sslContextFactory);
+ Executor executor = new QueuedThreadPool();
+ httpClient.setExecutor(executor);
+
+ httpClient.start();
+
+// ContentResponse response = httpClient.GET("https://http2.akamai.com/");
+ ContentResponse response = httpClient.GET("https://webtide.com/");
+
+ Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
+
+ httpClient.stop();
+ }
}
diff --git a/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties b/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000000..287d28319e
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties
@@ -0,0 +1,5 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+#org.eclipse.jetty.client.LEVEL=DEBUG
+org.eclipse.jetty.http2.hpack.LEVEL=INFO
+#org.eclipse.jetty.http2.LEVEL=DEBUG
+#org.eclipse.jetty.io.ssl.LEVEL=DEBUG
diff --git a/tests/test-http-client-transport/pom.xml b/tests/test-http-client-transport/pom.xml
index ec8e245353..5913b35443 100644
--- a/tests/test-http-client-transport/pom.xml
+++ b/tests/test-http-client-transport/pom.xml
@@ -17,6 +17,36 @@
+
+ maven-dependency-plugin
+
+
+ copy
+ generate-resources
+
+ copy
+
+
+
+
+ org.mortbay.jetty.alpn
+ alpn-boot
+ ${alpn.version}
+ jar
+ false
+ ${project.build.directory}/alpn
+
+
+
+
+
+
+
+ maven-surefire-plugin
+
+ -Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar
+
+
org.apache.maven.plugins
maven-deploy-plugin
@@ -47,6 +77,12 @@
${project.version}
test
+
+ org.eclipse.jetty
+ jetty-alpn-server
+ ${project.version}
+ test
+
org.eclipse.jetty.http2
http2-http-client-transport
diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java
index 0cc5a0fb89..ca377c311c 100644
--- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java
+++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java
@@ -18,22 +18,28 @@
package org.eclipse.jetty.http.client;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.List;
+import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
+import org.eclipse.jetty.http2.HTTP2Cipher;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
+import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
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.HttpConnectionFactory;
+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.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.After;
import org.junit.Rule;
@@ -44,15 +50,16 @@ import org.junit.runners.Parameterized;
public abstract class AbstractTest
{
@Parameterized.Parameters(name = "transport: {0}")
- public static List