You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by re...@apache.org on 2023/05/07 17:31:19 UTC
[cxf] branch 3.4.x-fixes updated (a82d1970b8 -> 1b5b589c3c)
This is an automated email from the ASF dual-hosted git repository.
reta pushed a change to branch 3.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
from a82d1970b8 Bump maven-checkstyle-plugin from 3.2.1 to 3.2.2 (#1245)
new b19c4509f2 Update Brave Reporter to 2.16.4
new 69ecbb9a45 Update Zipkin Brave to 2.24.1
new 589453d9c7 CXF-8606: Introduce HTTP/2 Transport: client-side support (#1017)
new 37e70b822b CXF-8606: Introduce HTTP/2 Transport: client-side support (fixing netty-codec-http2 dependency scope)
new 93f8458b4d CXF-8606: Introduce HTTP/2 Transport: client-side support (fixing jetty-alpn-java-server dependency)
new 1b5b589c3c Recording .gitmergeinfo Changes
The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.gitmergeinfo | 7 +
.../karaf/features/src/main/resources/features.xml | 1 +
parent/pom.xml | 4 +-
.../http/asyncclient/hc5/AsyncHTTPConduit.java | 16 +
.../asyncclient/hc5/AsyncHTTPConduitFactory.java | 5 +
rt/transports/http-netty/netty-client/pom.xml | 5 +
.../client/NettyHttpClientPipelineFactory.java | 201 +++++++++-
.../http/netty/client/NettyHttpClientRequest.java | 15 +-
.../http/netty/client/NettyHttpConduit.java | 45 ++-
.../org/apache/cxf/transport/http/HTTPConduit.java | 1 -
.../src/main/resources/schemas/wsdl/http-conf.xsd | 8 +
systests/transport-hc5/pom.xml | 41 +++
.../AbstractApacheClientServerHttp2Test.java} | 111 +++---
.../hc5/http2}/AbstractBookServerHttp2.java | 2 +-
.../hc5/http2/ApacheClientServerHttp2Test.java} | 4 +-
.../hc5/http2/ApacheClientServerHttp2cTest.java} | 4 +-
.../org/apache/cxf/systest/hc5/http2}/Book.java | 2 +-
.../cxf/systest/hc5/http2}/BookServerHttp2.java | 4 +-
.../cxf/systest/hc5/http2}/BookServerHttp2c.java | 4 +-
.../apache/cxf/systest/hc5/http2}/BookStore.java | 3 +-
.../apache/cxf/systest/hc5/http2}/server-tls.xml | 2 +-
.../org/apache/cxf/systest/hc5/http2}/server.xml | 2 +-
systests/transport-netty/pom.xml | 5 +
.../netty/AbstractNettyClientServerHttp2Test.java | 89 ++---
.../cxf/systest/http2/netty/Http2TestClient.java | 405 ---------------------
25 files changed, 447 insertions(+), 539 deletions(-)
copy systests/{transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractNettyClientServerHttp2Test.java => transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/AbstractApacheClientServerHttp2Test.java} (56%)
copy systests/{transport-netty/src/test/java/org/apache/cxf/systest/http2/netty => transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2}/AbstractBookServerHttp2.java (98%)
copy systests/{transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/NettyClientServerHttp2Test.java => transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/ApacheClientServerHttp2Test.java} (91%)
copy systests/{transports/src/test/java/org/apache/cxf/systest/http2_jetty/JettyClientServerHttp2cTest.java => transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/ApacheClientServerHttp2cTest.java} (91%)
copy systests/{transports/src/test/java/org/apache/cxf/systest/http2_jetty => transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2}/Book.java (97%)
copy systests/{transport-netty/src/test/java/org/apache/cxf/systest/http2/netty => transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2}/BookServerHttp2.java (91%)
copy systests/{transports/src/test/java/org/apache/cxf/systest/http2_jetty => transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2}/BookServerHttp2c.java (91%)
copy systests/{transports/src/test/java/org/apache/cxf/systest/http2_jetty => transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2}/BookStore.java (98%)
copy systests/{transports/src/test/resources/org/apache/cxf/systest/http2_jetty => transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/http2}/server-tls.xml (97%)
copy systests/{transports/src/test/resources/org/apache/cxf/systest/http2_jetty => transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/http2}/server.xml (96%)
delete mode 100644 systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/Http2TestClient.java
[cxf] 05/06: CXF-8606: Introduce HTTP/2 Transport: client-side support (fixing jetty-alpn-java-server dependency)
Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch 3.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 93f8458b4dd9cb1ceaa3f2d5af6464abd1c2132f
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Sun May 7 10:30:01 2023 -0400
CXF-8606: Introduce HTTP/2 Transport: client-side support (fixing jetty-alpn-java-server dependency)
(cherry picked from commit c0561a43eff7d97db117b73b93f5de0bc99ed716)
---
systests/transport-hc5/pom.xml | 37 +++++++++++++++++++++++++++++++------
1 file changed, 31 insertions(+), 6 deletions(-)
diff --git a/systests/transport-hc5/pom.xml b/systests/transport-hc5/pom.xml
index ea3f231cda..f4e22446a9 100644
--- a/systests/transport-hc5/pom.xml
+++ b/systests/transport-hc5/pom.xml
@@ -107,12 +107,6 @@
<artifactId>jetty-alpn-server</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-alpn-java-server</artifactId>
- <version>${cxf.jetty9.version}</version>
- <scope>test</scope>
- </dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
@@ -186,4 +180,35 @@
<scope>test</scope>
</dependency>
</dependencies>
+
+ <profiles>
+ <profile>
+ <id>jdk8</id>
+ <activation>
+ <jdk>1.8</jdk>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-openjdk8-server</artifactId>
+ <version>${cxf.jetty9.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+ <profile>
+ <id>jdk9+</id>
+ <activation>
+ <jdk>[9,)</jdk>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-java-server</artifactId>
+ <version>${cxf.jetty9.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+ </profiles>
</project>
[cxf] 03/06: CXF-8606: Introduce HTTP/2 Transport: client-side support (#1017)
Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch 3.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 589453d9c721b6fffa02970a4c9e70e982c5a894
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Sat May 6 09:36:32 2023 -0400
CXF-8606: Introduce HTTP/2 Transport: client-side support (#1017)
(cherry picked from commit a744e7f595486ea34a0e0edc255d60a353942e81)
# Conflicts:
# systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/Http2TestClient.java
(cherry picked from commit 40f09e6a0db63c8cddbd937bc4e26c3dd7ab7425)
# Conflicts:
# rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduit.java
# rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpConduit.java
# systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractNettyClientServerHttp2Test.java
(cherry picked from commit 80d4da129dfdf82e3c7c15e6c0548fc5ad78ee6c)
---
.../http/asyncclient/hc5/AsyncHTTPConduit.java | 16 +
.../asyncclient/hc5/AsyncHTTPConduitFactory.java | 5 +
rt/transports/http-netty/netty-client/pom.xml | 6 +
.../client/NettyHttpClientPipelineFactory.java | 201 +++++++++-
.../http/netty/client/NettyHttpClientRequest.java | 15 +-
.../http/netty/client/NettyHttpConduit.java | 45 ++-
.../org/apache/cxf/transport/http/HTTPConduit.java | 1 -
.../src/main/resources/schemas/wsdl/http-conf.xsd | 8 +
systests/transport-hc5/pom.xml | 16 +
.../AbstractApacheClientServerHttp2Test.java} | 111 +++---
.../systest/hc5/http2/AbstractBookServerHttp2.java | 64 ++++
.../hc5/http2/ApacheClientServerHttp2Test.java | 48 +++
.../hc5/http2/ApacheClientServerHttp2cTest.java | 47 +++
.../org/apache/cxf/systest/hc5/http2/Book.java | 69 ++++
.../cxf/systest/hc5/http2/BookServerHttp2.java | 47 +++
.../cxf/systest/hc5/http2/BookServerHttp2c.java | 45 +++
.../apache/cxf/systest/hc5/http2/BookStore.java | 67 ++++
.../apache/cxf/systest/hc5/http2/server-tls.xml | 41 +++
.../org/apache/cxf/systest/hc5/http2/server.xml | 32 ++
systests/transport-netty/pom.xml | 5 +
.../netty/AbstractNettyClientServerHttp2Test.java | 89 ++---
.../cxf/systest/http2/netty/Http2TestClient.java | 405 ---------------------
22 files changed, 860 insertions(+), 523 deletions(-)
diff --git a/rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduit.java b/rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduit.java
index ec15b42b40..6d1bb0e3c5 100644
--- a/rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduit.java
+++ b/rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduit.java
@@ -98,6 +98,10 @@ import org.apache.hc.core5.util.Timeout;
* Async HTTP Conduit using Apache HttpClient 5
*/
public class AsyncHTTPConduit extends URLConnectionHTTPConduit {
+ /**
+ * Enable HTTP/2 support
+ */
+ public static final String ENABLE_HTTP2 = "org.apache.cxf.transports.http2.enabled";
public static final String USE_ASYNC = "use.async.http.conduit";
private final AsyncHTTPConduitFactory factory;
@@ -137,7 +141,10 @@ public class AsyncHTTPConduit extends URLConnectionHTTPConduit {
super.setupConnection(message, address, csPolicy);
return;
}
+
propagateJaxwsSpecTimeoutSettings(message, csPolicy);
+ propagateProtocolSettings(message, csPolicy);
+
boolean addressChanged = false;
// need to do some clean up work on the URI address
URI uri = address.getURI();
@@ -252,6 +259,15 @@ public class AsyncHTTPConduit extends URLConnectionHTTPConduit {
message.put(CXFHttpRequest.class, e);
}
+ private void propagateProtocolSettings(Message message, HTTPClientPolicy csPolicy) {
+ if (message != null) {
+ final Object o = message.getContextualProperty(ENABLE_HTTP2);
+ if (o != null) {
+ csPolicy.setEnableHttp2(PropertyUtils.isTrue(o));
+ }
+ }
+ }
+
private void propagateJaxwsSpecTimeoutSettings(Message message, HTTPClientPolicy csPolicy) {
int receiveTimeout = determineReceiveTimeout(message, csPolicy);
if (csPolicy.getReceiveTimeout() == 60000) {
diff --git a/rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduitFactory.java b/rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduitFactory.java
index f660288056..a2df8b61b8 100644
--- a/rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduitFactory.java
+++ b/rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduitFactory.java
@@ -54,6 +54,7 @@ import org.apache.hc.core5.http.config.Lookup;
import org.apache.hc.core5.http.config.RegistryBuilder;
import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.http2.HttpVersionPolicy;
import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
import org.apache.hc.core5.pool.PoolReusePolicy;
import org.apache.hc.core5.reactor.IOReactorConfig;
@@ -372,6 +373,10 @@ public class AsyncHTTPConduitFactory implements HTTPConduitFactory {
}
});
+ if (Boolean.FALSE.equals(clientPolicy.isEnableHttp2())) {
+ httpAsyncClientBuilder.setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_1);
+ }
+
adaptClientBuilder(httpAsyncClientBuilder);
final CloseableHttpAsyncClient client = httpAsyncClientBuilder
diff --git a/rt/transports/http-netty/netty-client/pom.xml b/rt/transports/http-netty/netty-client/pom.xml
index c435b04621..8d2538931b 100644
--- a/rt/transports/http-netty/netty-client/pom.xml
+++ b/rt/transports/http-netty/netty-client/pom.xml
@@ -49,6 +49,12 @@
<artifactId>netty-codec-http</artifactId>
<version>${cxf.netty.version}</version>
</dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-codec-http2</artifactId>
+ <version>${cxf.netty.version}</version>
+ <optional>true</optional>
+ </dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
diff --git a/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpClientPipelineFactory.java b/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpClientPipelineFactory.java
index 658c5660f4..be44b9c4ec 100644
--- a/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpClientPipelineFactory.java
+++ b/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpClientPipelineFactory.java
@@ -19,27 +19,57 @@
package org.apache.cxf.transport.http.netty.client;
+import java.security.KeyStore;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.ManagerFactoryParameters;
import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManager;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
+import org.apache.cxf.transport.https.SSLContextInitParameters;
import org.apache.cxf.transport.https.SSLUtils;
import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
+import io.netty.channel.ChannelPromise;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.HttpClientCodec;
+import io.netty.handler.codec.http.HttpClientUpgradeHandler;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponseDecoder;
+import io.netty.handler.codec.http2.DefaultHttp2Connection;
+import io.netty.handler.codec.http2.DelegatingDecompressorFrameListener;
+import io.netty.handler.codec.http2.Http2ClientUpgradeCodec;
+import io.netty.handler.codec.http2.Http2Connection;
+import io.netty.handler.codec.http2.Http2ConnectionHandler;
+import io.netty.handler.codec.http2.Http2SecurityUtil;
+import io.netty.handler.codec.http2.Http2Settings;
+import io.netty.handler.codec.http2.HttpToHttp2ConnectionHandlerBuilder;
+import io.netty.handler.codec.http2.InboundHttp2ToHttpAdapterBuilder;
+import io.netty.handler.ssl.ApplicationProtocolConfig;
+import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
+import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
+import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
+import io.netty.handler.ssl.ApplicationProtocolNames;
+import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
+import io.netty.handler.ssl.SupportedCipherSuiteFilter;
+import io.netty.handler.ssl.util.SimpleKeyManagerFactory;
+import io.netty.handler.ssl.util.SimpleTrustManagerFactory;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
-
public class NettyHttpClientPipelineFactory extends ChannelInitializer<Channel> {
private static final Logger LOG =
@@ -48,6 +78,8 @@ public class NettyHttpClientPipelineFactory extends ChannelInitializer<Channel>
private final TLSClientParameters tlsClientParameters;
private final int readTimeout;
private final int maxContentLength;
+ private final boolean enableHttp2;
+ private ChannelPromise readyFuture;
public NettyHttpClientPipelineFactory(TLSClientParameters clientParameters) {
this(clientParameters, 0);
@@ -59,16 +91,22 @@ public class NettyHttpClientPipelineFactory extends ChannelInitializer<Channel>
public NettyHttpClientPipelineFactory(TLSClientParameters clientParameters, int readTimeout,
int maxResponseContentLength) {
+ this(clientParameters, readTimeout, maxResponseContentLength, false);
+ }
+
+ public NettyHttpClientPipelineFactory(TLSClientParameters clientParameters, int readTimeout,
+ int maxResponseContentLength, boolean enableHttp2) {
this.tlsClientParameters = clientParameters;
this.readTimeout = readTimeout;
this.maxContentLength = maxResponseContentLength;
+ this.enableHttp2 = enableHttp2;
}
@Override
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
- SslHandler sslHandler = configureClientSSLOnDemand();
+ SslHandler sslHandler = configureClientSSLOnDemand(ch);
if (sslHandler != null) {
LOG.log(Level.FINE,
"Server SSL handler configured and added as an interceptor against the ChannelPipeline: {}",
@@ -76,25 +114,166 @@ public class NettyHttpClientPipelineFactory extends ChannelInitializer<Channel>
pipeline.addLast("ssl", sslHandler);
}
+ final NettyHttpClientHandler responseHandler = new NettyHttpClientHandler();
+ readyFuture = ch.newPromise();
+
+ if (enableHttp2) {
+ final Http2Connection connection = new DefaultHttp2Connection(false);
+ final Http2SettingsHandler settingsHandler = new Http2SettingsHandler(readyFuture);
+
+ Http2ConnectionHandler connectionHandler = new HttpToHttp2ConnectionHandlerBuilder()
+ .connection(connection)
+ .frameListener(new DelegatingDecompressorFrameListener(connection,
+ new InboundHttp2ToHttpAdapterBuilder(connection)
+ .maxContentLength(maxContentLength)
+ .propagateSettings(true)
+ .build()))
+ .build();
+
+ if (sslHandler != null) {
+ // Wait for the handshake to finish and the protocol to be negotiated before
+ // configuring the HTTP/2 components of the pipeline.
+ pipeline.addLast(new ApplicationProtocolNegotiationHandler(ApplicationProtocolNames.HTTP_1_1) {
+ @Override
+ protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {
+ final ChannelPipeline p = ctx.pipeline();
+ if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
+ p.addLast(connectionHandler);
+ p.addLast(settingsHandler);
+ p.addLast("client", responseHandler);
+ } else if (ApplicationProtocolNames.HTTP_1_1.equals(protocol)) {
+ p.addLast("decoder", new HttpResponseDecoder());
+ p.addLast("aggregator", new HttpObjectAggregator(maxContentLength));
+ p.addLast("encoder", new HttpRequestEncoder());
+ p.addLast("chunkedWriter", new ChunkedWriteHandler());
+ readyFuture.setSuccess(null);
+ } else {
+ ctx.close();
+ final IllegalStateException ex = new IllegalStateException("Unknown protocol: " + protocol);
+ readyFuture.setFailure(ex);
+ throw ex;
+ }
+ }
+ });
+
+ if (readTimeout > 0) {
+ pipeline.addLast("readTimeoutHandler", new ReadTimeoutHandler(readTimeout, TimeUnit.MILLISECONDS));
+ }
+ } else {
+ final HttpClientCodec sourceCodec = new HttpClientCodec();
+ final Http2ClientUpgradeCodec upgradeCodec = new Http2ClientUpgradeCodec(connectionHandler);
+ final HttpClientUpgradeHandler upgradeHandler = new HttpClientUpgradeHandler(sourceCodec,
+ upgradeCodec, maxContentLength);
- pipeline.addLast("decoder", new HttpResponseDecoder());
- pipeline.addLast("aggregator", new HttpObjectAggregator(maxContentLength));
- pipeline.addLast("encoder", new HttpRequestEncoder());
- pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
- if (readTimeout > 0) {
- pipeline.addLast("readTimeoutHandler", new ReadTimeoutHandler(readTimeout, TimeUnit.MILLISECONDS));
+ pipeline.addLast(sourceCodec);
+ pipeline.addLast(upgradeHandler);
+
+ if (readTimeout > 0) {
+ pipeline.addLast("readTimeoutHandler", new ReadTimeoutHandler(readTimeout, TimeUnit.MILLISECONDS));
+ }
+
+ pipeline.addLast("client", responseHandler);
+ readyFuture.setSuccess(null);
+ }
+ } else {
+ pipeline.addLast("decoder", new HttpResponseDecoder());
+ pipeline.addLast("aggregator", new HttpObjectAggregator(maxContentLength));
+ pipeline.addLast("encoder", new HttpRequestEncoder());
+ pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
+ if (readTimeout > 0) {
+ pipeline.addLast("readTimeoutHandler", new ReadTimeoutHandler(readTimeout, TimeUnit.MILLISECONDS));
+ }
+ pipeline.addLast("client", responseHandler);
+ readyFuture.setSuccess(null);
}
- pipeline.addLast("client", new NettyHttpClientHandler());
}
+ public ChannelFuture whenReady() {
+ return readyFuture;
+ }
- private SslHandler configureClientSSLOnDemand() throws Exception {
+ private SslHandler configureClientSSLOnDemand(Channel channel) throws Exception {
if (tlsClientParameters != null) {
- SSLEngine sslEngine = SSLUtils.createClientSSLEngine(tlsClientParameters);
+ final SSLEngine sslEngine;
+
+ if (enableHttp2) {
+ final SSLContextInitParameters initParams = SSLUtils.getSSLContextInitParameters(tlsClientParameters);
+
+ sslEngine = SslContextBuilder
+ .forClient()
+ .sslProvider(SslContext.defaultClientProvider())
+ .keyManager(new SimpleKeyManagerFactory() {
+
+ @Override
+ protected void engineInit(KeyStore keyStore, char[] var2) throws Exception {
+ }
+
+ @Override
+ protected void engineInit(ManagerFactoryParameters params) throws Exception {
+ }
+
+ @Override
+ protected KeyManager[] engineGetKeyManagers() {
+ final KeyManager[] keyManagers = initParams.getKeyManagers();
+ if (keyManagers == null) {
+ return new KeyManager[0];
+ }
+ return keyManagers;
+ }
+ })
+ .trustManager(new SimpleTrustManagerFactory() {
+ @Override
+ protected void engineInit(KeyStore keyStore) throws Exception {
+ }
+
+ @Override
+ protected void engineInit(ManagerFactoryParameters params) throws Exception {
+ }
+
+ @Override
+ protected TrustManager[] engineGetTrustManagers() {
+ final TrustManager[] trustManagers = initParams.getTrustManagers();
+ if (trustManagers == null) {
+ return new TrustManager[0];
+ }
+ return trustManagers;
+ }
+
+ })
+ .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
+ .applicationProtocolConfig(
+ new ApplicationProtocolConfig(
+ Protocol.ALPN,
+ // NO_ADVERTISE is currently the only mode supported by both OpenSsl and JDK providers.
+ SelectorFailureBehavior.NO_ADVERTISE,
+ // ACCEPT is currently the only mode supported by both OpenSsl and JDK providers.
+ SelectedListenerFailureBehavior.ACCEPT,
+ ApplicationProtocolNames.HTTP_2,
+ ApplicationProtocolNames.HTTP_1_1
+ )
+ )
+ .build()
+ .newEngine(channel.alloc());
+ } else {
+ sslEngine = SSLUtils.createClientSSLEngine(tlsClientParameters);
+ }
+
return new SslHandler(sslEngine);
}
return null;
}
+ private static class Http2SettingsHandler extends SimpleChannelInboundHandler<Http2Settings> {
+ private ChannelPromise promise;
+ Http2SettingsHandler(ChannelPromise promise) {
+ this.promise = promise;
+ }
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext ctx, Http2Settings msg) throws Exception {
+ promise.setSuccess();
+ ctx.pipeline().remove(this);
+ }
+ }
}
diff --git a/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpClientRequest.java b/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpClientRequest.java
index 6110281af1..5e935623c9 100644
--- a/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpClientRequest.java
+++ b/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpClientRequest.java
@@ -27,21 +27,28 @@ import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpVersion;
+import io.netty.handler.codec.http2.HttpConversionUtil.ExtensionHeaderNames;
public class NettyHttpClientRequest {
private HttpRequest request;
private HttpResponse response;
- private URI uri;
- private String method;
+ private final URI uri;
+ private final String method;
private CxfResponseCallBack cxfResponseCallback;
private int connectionTimeout;
private int receiveTimeout;
private int maxResponseContentLength;
+ private final boolean enableHttp2;
public NettyHttpClientRequest(URI requestUri, String method) {
+ this(requestUri, method, false);
+ }
+
+ public NettyHttpClientRequest(URI requestUri, String method, boolean enableHttp2) {
this.uri = requestUri;
this.method = method;
+ this.enableHttp2 = enableHttp2;
}
public void createRequest(ByteBuf content) {
@@ -53,6 +60,10 @@ public class NettyHttpClientRequest {
request.headers().set("Connection", "keep-alive");
request.headers().set("Host", uri.getHost() + ":"
+ (uri.getPort() != -1 ? uri.getPort() : "http".equals(uri.getScheme()) ? 80 : 443));
+
+ if (enableHttp2) {
+ request.headers().set(ExtensionHeaderNames.SCHEME.text(), uri.getScheme());
+ }
}
public HttpRequest getRequest() {
diff --git a/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpConduit.java b/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpConduit.java
index de94af8ddf..c8ce0064b8 100644
--- a/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpConduit.java
+++ b/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpConduit.java
@@ -80,6 +80,10 @@ import io.netty.handler.ssl.SslHandler;
public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLifeCycleListener {
+ /**
+ * Enable HTTP/2 support
+ */
+ public static final String ENABLE_HTTP2 = "org.apache.cxf.transports.http2.enabled";
public static final String USE_ASYNC = "use.async.http.conduit";
public static final String MAX_RESPONSE_CONTENT_LENGTH =
"org.apache.cxf.transport.http.netty.maxResponseContentLength";
@@ -107,6 +111,7 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif
// Using Netty API directly
protected void setupConnection(Message message, Address address, HTTPClientPolicy csPolicy) throws IOException {
+ propagateProtocolSettings(message, csPolicy);
URI uri = address.getURI();
boolean addressChanged = false;
@@ -177,7 +182,8 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif
message.put(Message.HTTP_REQUEST_METHOD, httpRequestMethod);
}
// setup a new NettyHttpClientRequest
- final NettyHttpClientRequest request = new NettyHttpClientRequest(uri, httpRequestMethod);
+ final boolean enableHttp2 = csPolicy.isSetEnableHttp2() && csPolicy.isEnableHttp2();
+ final NettyHttpClientRequest request = new NettyHttpClientRequest(uri, httpRequestMethod, enableHttp2);
final int ctimeout = determineConnectionTimeout(message, csPolicy);
final int rtimeout = determineReceiveTimeout(message, csPolicy);
final int maxResponseContentLength = determineMaxResponseContentLength(message);
@@ -189,6 +195,15 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif
}
+ private void propagateProtocolSettings(Message message, HTTPClientPolicy csPolicy) {
+ if (message != null) {
+ final Object o = message.getContextualProperty(ENABLE_HTTP2);
+ if (o != null) {
+ csPolicy.setEnableHttp2(PropertyUtils.isTrue(o));
+ }
+ }
+ }
+
protected OutputStream createOutputStream(Message message,
boolean needToCacheRequest,
boolean isChunking,
@@ -217,6 +232,7 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif
public class NettyWrappedOutputStream extends WrappedOutputStream {
final HTTPClientPolicy csPolicy;
+ final boolean enableHttp2;
NettyHttpClientRequest entity;
volatile HttpResponse httpResponse;
volatile Throwable exception;
@@ -238,6 +254,7 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif
int bufSize = csPolicy.getChunkLength() > 0 ? csPolicy.getChunkLength() : 16320;
outBuffer = Unpooled.buffer(bufSize);
outputStream = new ByteBufOutputStream(outBuffer);
+ enableHttp2 = csPolicy.isSetEnableHttp2() && csPolicy.isEnableHttp2();
}
protected ByteBuf getOutBuffer() {
@@ -281,7 +298,6 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif
return (HttpContent) getHttpResponse();
}
-
protected Channel getChannel() throws IOException {
syncLock.lock();
try {
@@ -371,22 +387,25 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif
}
protected void connect(boolean output) {
+ final NettyHttpClientPipelineFactory handler;
if ("https".equals(url.getScheme())) {
TLSClientParameters clientParameters = findTLSClientParameters();
- bootstrap.handler(new NettyHttpClientPipelineFactory(clientParameters, entity.getReceiveTimeout(),
- entity.getMaxResponseContentLength()));
+ handler = new NettyHttpClientPipelineFactory(clientParameters, entity.getReceiveTimeout(),
+ entity.getMaxResponseContentLength(), enableHttp2);
} else {
- bootstrap.handler(new NettyHttpClientPipelineFactory(null, entity.getReceiveTimeout(),
- entity.getMaxResponseContentLength()));
+ handler = new NettyHttpClientPipelineFactory(null, entity.getReceiveTimeout(),
+ entity.getMaxResponseContentLength(), enableHttp2);
}
+ // Set handler
+ bootstrap.handler(handler);
+
ChannelFuture connFuture =
bootstrap.connect(new InetSocketAddress(url.getHost(), url.getPort() != -1 ? url.getPort()
: "http".equals(url.getScheme()) ? 80 : 443));
// Setup the call back on the NettyHttpClientRequest
ChannelFutureListener listener = new ChannelFutureListener() {
-
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
@@ -408,7 +427,6 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif
connFuture.addListener(listener);
-
// setup the CxfResponseCallBack
CxfResponseCallBack callBack = new CxfResponseCallBack() {
@Override
@@ -440,8 +458,15 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
- ChannelFuture channelFuture = future.channel().writeAndFlush(entity);
- channelFuture.addListener(writeFailureListener);
+ handler.whenReady().addListener(new ChannelFutureListener() {
+ @Override
+ public void operationComplete(ChannelFuture future) throws Exception {
+ if (future.isSuccess()) {
+ ChannelFuture channelFuture = future.channel().writeAndFlush(entity);
+ channelFuture.addListener(writeFailureListener);
+ }
+ }
+ });
}
}
});
diff --git a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
index cfc33246c4..7de1af9c92 100644
--- a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
+++ b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HTTPConduit.java
@@ -152,7 +152,6 @@ public abstract class HTTPConduit
extends AbstractConduit
implements Configurable, Assertor, PropertyChangeListener {
-
/**
* This constant is the Message(Map) key for the HttpURLConnection that
* is used to get the response.
diff --git a/rt/transports/http/src/main/resources/schemas/wsdl/http-conf.xsd b/rt/transports/http/src/main/resources/schemas/wsdl/http-conf.xsd
index 0109368d85..766d16accd 100644
--- a/rt/transports/http/src/main/resources/schemas/wsdl/http-conf.xsd
+++ b/rt/transports/http/src/main/resources/schemas/wsdl/http-conf.xsd
@@ -390,6 +390,14 @@
</xs:documentation>
</xs:annotation>
</xs:attribute>
+ <xs:attribute name="EnableHttp2" type="ptp:ParameterizedBoolean" use="optional" default="true">
+ <xs:annotation>
+ <xs:documentation>
+ If true, the client is free to use HTTP/2 if it supports it, but it is not
+ required to do so. If false, the client must use HTTP/1.1 in all cases.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
<xs:anyAttribute namespace="http://schemas.xmlsoap.org/wsdl/"/>
</xs:complexType>
diff --git a/systests/transport-hc5/pom.xml b/systests/transport-hc5/pom.xml
index b35c916049..ea3f231cda 100644
--- a/systests/transport-hc5/pom.xml
+++ b/systests/transport-hc5/pom.xml
@@ -97,6 +97,22 @@
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.http2</groupId>
+ <artifactId>http2-server</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-server</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-java-server</artifactId>
+ <version>${cxf.jetty9.version}</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
diff --git a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractNettyClientServerHttp2Test.java b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/AbstractApacheClientServerHttp2Test.java
similarity index 56%
copy from systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractNettyClientServerHttp2Test.java
copy to systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/AbstractApacheClientServerHttp2Test.java
index 5945b1fb8f..9da63c85e2 100644
--- a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractNettyClientServerHttp2Test.java
+++ b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/AbstractApacheClientServerHttp2Test.java
@@ -17,109 +17,123 @@
* under the License.
*/
-package org.apache.cxf.systest.http2.netty;
+package org.apache.cxf.systest.hc5.http2;
import javax.ws.rs.core.Response;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.jaxrs.client.WebClient;
-import org.apache.cxf.systest.http2.netty.Http2TestClient.ClientResponse;
import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
import org.apache.cxf.transport.http.HTTPConduit;
+import org.apache.cxf.transport.http.asyncclient.hc5.AsyncHTTPConduit;
import org.apache.cxf.transport.https.InsecureTrustManager;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-abstract class AbstractNettyClientServerHttp2Test extends AbstractBusClientServerTestBase {
+abstract class AbstractApacheClientServerHttp2Test extends AbstractBusClientServerTestBase {
@Test
public void testBookNotFoundWithHttp2() throws Exception {
- final Http2TestClient client = new Http2TestClient(isSecure());
+ final WebClient client = createWebClient("/web/bookstore/notFound", true);
+ assertThat(WebClient.getConfig(client).getHttpConduit(), instanceOf(AsyncHTTPConduit.class));
- final ClientResponse response = client
- .request(getAddress())
+ final Response response = client
.accept("text/plain")
.path(getContext() + "/web/bookstore/notFound")
- .http2()
.get();
- assertThat(response.getResponseCode(), equalTo(404));
- assertThat(response.getProtocol(), equalTo("HTTP/2.0"));
+ assertThat(response.getStatus(), equalTo(404));
}
-
+
@Test
public void testBookTraceWithHttp2() throws Exception {
- final Http2TestClient client = new Http2TestClient(isSecure());
-
- final ClientResponse response = client
- .request(getAddress())
+ final WebClient client = createWebClient("/web/bookstore/trace", true);
+ assertThat(WebClient.getConfig(client).getHttpConduit(), instanceOf(AsyncHTTPConduit.class));
+
+ final Response response = client
.accept("text/plain")
- .path(getContext() + "/web/bookstore/trace")
- .http2()
- .trace();
+ .invoke("TRACE", null);
- assertThat(response.getResponseCode(), equalTo(406));
- assertThat(response.getProtocol(), equalTo("HTTP/2.0"));
+ // Apache CXF Jetty transport does not allow TRACE HTTP verb
+ assertThat(response.getStatus(), equalTo(405));
+
+ client.close();
}
@Test
public void testBookWithHttp2() throws Exception {
- final Http2TestClient client = new Http2TestClient(isSecure());
+ final WebClient client = createWebClient("/web/bookstore/booknames", true);
+ assertThat(WebClient.getConfig(client).getHttpConduit(), instanceOf(AsyncHTTPConduit.class));
- final ClientResponse response = client
- .request(getAddress())
+ final Response response = client
.accept("text/plain")
- .path(getContext() + "/web/bookstore/booknames")
- .http2()
.get();
- assertThat(response.getResponseCode(), equalTo(200));
- assertThat(response.getProtocol(), equalTo("HTTP/2.0"));
- assertEquals("CXF in Action", response.getBody());
+ assertThat(response.getStatus(), equalTo(200));
+ assertEquals("CXF in Action", response.readEntity(String.class));
+
+ client.close();
}
@Test
public void testGetBookStreamHttp2() throws Exception {
- final Http2TestClient client = new Http2TestClient(isSecure());
+ final WebClient client = createWebClient("/web/bookstore/bookstream", true);
+ assertThat(WebClient.getConfig(client).getHttpConduit(), instanceOf(AsyncHTTPConduit.class));
- final ClientResponse response = client
- .request(getAddress())
+ final Response response = client
.accept("application/xml")
- .path(getContext() + "/web/bookstore/bookstream")
- .http2()
.get();
- assertThat(response.getResponseCode(), equalTo(200));
- assertThat(response.getProtocol(), equalTo("HTTP/2.0"));
+ assertThat(response.getStatus(), equalTo(200));
assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
- + "<Book><id>1</id><name>Book1</name></Book>", response.getBody());
+ + "<Book><id>1</id><name>Book1</name></Book>", response.readEntity(String.class));
+
+ client.close();
}
@Test
public void testBookWithHttp() throws Exception {
- final WebClient wc = createWebClient("/web/bookstore/booknames");
- try (Response resp = wc.get()) {
+ final WebClient client = createWebClient("/web/bookstore/booknames", false);
+
+ try (Response resp = client.get()) {
assertThat(resp.getStatus(), equalTo(200));
assertEquals("CXF in Action", resp.readEntity(String.class));
}
+
+ client.close();
}
@Test
public void testBookTraceWithHttp() throws Exception {
- final WebClient wc = createWebClient("/web/bookstore/trace");
- try (Response response = wc.invoke("TRACE", null)) {
- assertThat(response.getStatus(), equalTo(406));
- }
+ final WebClient client = createWebClient("/web/bookstore/trace", false);
+
+ // Apache CXF Jetty transport does not allow TRACE HTTP verb
+ try (Response response = client.invoke("TRACE", null)) {
+ assertThat(response.getStatus(), equalTo(405));
+ }
+
+ client.close();
}
- private WebClient createWebClient(final String path) {
+ protected abstract String getAddress();
+ protected abstract String getContext();
+
+ protected boolean isSecure() {
+ return getAddress().startsWith("https");
+ }
+
+ private WebClient createWebClient(final String path, final boolean enableHttp2) {
final WebClient wc = WebClient
.create(getAddress() + getContext() + path)
.accept("text/plain");
-
+
+ WebClient.getConfig(wc).getRequestContext().put(AsyncHTTPConduit.ENABLE_HTTP2, enableHttp2);
+ WebClient.getConfig(wc).getRequestContext().put(AsyncHTTPConduit.USE_ASYNC, "ALWAYS");
+
if (isSecure()) {
final HTTPConduit conduit = WebClient.getConfig(wc).getHttpConduit();
TLSClientParameters params = conduit.getTlsClientParameters();
@@ -136,11 +150,4 @@ abstract class AbstractNettyClientServerHttp2Test extends AbstractBusClientServe
return wc;
}
-
- protected abstract String getAddress();
- protected abstract String getContext();
-
- protected boolean isSecure() {
- return getAddress().startsWith("https");
- }
-}
\ No newline at end of file
+}
diff --git a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/AbstractBookServerHttp2.java b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/AbstractBookServerHttp2.java
new file mode 100644
index 0000000000..920e70512e
--- /dev/null
+++ b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/AbstractBookServerHttp2.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.hc5.http2;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.customer.book.Book;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.jaxrs.provider.StreamingResponseProvider;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
+
+abstract class AbstractBookServerHttp2 extends AbstractBusTestServerBase {
+ org.apache.cxf.endpoint.Server server;
+
+ private final String port;
+ private final String context;
+ private final String scheme;
+
+ AbstractBookServerHttp2(String port, String context, String scheme) {
+ this.port = port;
+ this.context = context;
+ this.scheme = scheme;
+ }
+
+ protected void run() {
+ SpringBusFactory factory = new SpringBusFactory();
+ Bus bus = factory.createBus(context);
+ bus.setProperty(HttpServerEngineSupport.ENABLE_HTTP2, true);
+ setBus(bus);
+ JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+ sf.setBus(bus);
+ sf.setResourceClasses(BookStore.class);
+ sf.setProvider(new StreamingResponseProvider<Book>());
+ sf.setResourceProvider(BookStore.class,
+ new SingletonResourceProvider(new BookStore(), true));
+ sf.setAddress(scheme + "://localhost:" + port + "/http2");
+ server = sf.create();
+ }
+
+ public void tearDown() throws Exception {
+ server.stop();
+ server.destroy();
+ server = null;
+ }
+}
diff --git a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/ApacheClientServerHttp2Test.java b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/ApacheClientServerHttp2Test.java
new file mode 100644
index 0000000000..66c2b66791
--- /dev/null
+++ b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/ApacheClientServerHttp2Test.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.hc5.http2;
+
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+
+import org.junit.BeforeClass;
+
+import static org.junit.Assert.assertTrue;
+
+public class ApacheClientServerHttp2Test extends AbstractApacheClientServerHttp2Test {
+ private static final String PORT = BookServerHttp2.PORT;
+
+ @BeforeClass
+ public static void startServers() throws Exception {
+ AbstractResourceInfo.clearAllMaps();
+ assertTrue("server did not launch correctly", launchServer(new BookServerHttp2()));
+ createStaticBus();
+ }
+
+
+ @Override
+ protected String getAddress() {
+ return "https://localhost:" + PORT;
+ }
+
+ @Override
+ protected String getContext() {
+ return "/http2";
+ }
+}
diff --git a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/ApacheClientServerHttp2cTest.java b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/ApacheClientServerHttp2cTest.java
new file mode 100644
index 0000000000..5dc91f190f
--- /dev/null
+++ b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/ApacheClientServerHttp2cTest.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.hc5.http2;
+
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+
+import org.junit.BeforeClass;
+
+import static org.junit.Assert.assertTrue;
+
+public class ApacheClientServerHttp2cTest extends AbstractApacheClientServerHttp2Test {
+ private static final String PORT = BookServerHttp2c.PORT;
+
+ @BeforeClass
+ public static void startServers() throws Exception {
+ AbstractResourceInfo.clearAllMaps();
+ assertTrue("server did not launch correctly", launchServer(new BookServerHttp2c()));
+ createStaticBus();
+ }
+
+ @Override
+ protected String getAddress() {
+ return "http://localhost:" + PORT;
+ }
+
+ @Override
+ protected String getContext() {
+ return "/http2";
+ }
+}
diff --git a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/Book.java b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/Book.java
new file mode 100644
index 0000000000..020a584f08
--- /dev/null
+++ b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/Book.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.hc5.http2;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+
+@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "class")
+@XmlRootElement(name = "Book")
+public class Book {
+ private String name;
+ private long id;
+
+ public Book() {
+ }
+
+ public Book(String name, long id) {
+ this.name = name;
+ this.id = id;
+ }
+
+ public void setName(String n) {
+ name = n;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setId(long i) {
+ id = i;
+ }
+ public long getId() {
+ return id;
+ }
+
+ @PUT
+ public void cloneState(Book book) {
+ id = book.getId();
+ name = book.getName();
+ }
+
+ @GET
+ public Book retrieveState() {
+ return this;
+ }
+}
diff --git a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/BookServerHttp2.java b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/BookServerHttp2.java
new file mode 100644
index 0000000000..5a094f5b64
--- /dev/null
+++ b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/BookServerHttp2.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.hc5.http2;
+
+public class BookServerHttp2 extends AbstractBookServerHttp2 {
+ public static final String PORT = allocatePort(BookServerHttp2.class);
+
+ org.apache.cxf.endpoint.Server server;
+
+ public BookServerHttp2() {
+ this(PORT);
+ }
+
+ public BookServerHttp2(String port) {
+ super(port, "org/apache/cxf/systest/hc5/http2/server-tls.xml", "https");
+ }
+
+ public static void main(String[] args) {
+ try {
+ BookServerHttp2 s = new BookServerHttp2();
+ s.start();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ System.exit(-1);
+ } finally {
+ System.out.println("done!");
+ }
+ }
+
+}
diff --git a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/BookServerHttp2c.java b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/BookServerHttp2c.java
new file mode 100644
index 0000000000..6c8d90f951
--- /dev/null
+++ b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/BookServerHttp2c.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.hc5.http2;
+
+public class BookServerHttp2c extends AbstractBookServerHttp2 {
+ public static final String PORT = allocatePort(BookServerHttp2c.class);
+
+ public BookServerHttp2c() {
+ this(PORT);
+ }
+
+ public BookServerHttp2c(String port) {
+ super(port, "org/apache/cxf/systest/hc5/http2/server.xml", "http");
+ }
+
+ public static void main(String[] args) {
+ try {
+ BookServerHttp2c s = new BookServerHttp2c();
+ s.start();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ System.exit(-1);
+ } finally {
+ System.out.println("done!");
+ }
+ }
+
+}
diff --git a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/BookStore.java b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/BookStore.java
new file mode 100644
index 0000000000..e67dd40e97
--- /dev/null
+++ b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/http2/BookStore.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.hc5.http2;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+
+import org.apache.cxf.jaxrs.ext.StreamingResponse;
+
+@Path("/web/bookstore")
+public class BookStore {
+ private static ExecutorService executor = Executors.newSingleThreadExecutor();
+
+ @GET
+ @Path("/booknames")
+ @Produces("text/plain")
+ public byte[] getBookName() {
+ return "CXF in Action".getBytes();
+ }
+
+ @GET
+ @Path("/bookstream")
+ @Produces("application/xml")
+ public StreamingResponse<Book> getBookStream() {
+ return new StreamingResponse<Book>() {
+ public void writeTo(final StreamingResponse.Writer<Book> out) throws IOException {
+ out.write(new Book("Book1", 1));
+ executor.execute(new Runnable() {
+ public void run() {
+ try {
+ for (int i = 2; i <= 5; i++) {
+ Thread.sleep(500);
+ out.write(new Book("Book" + i, i));
+ out.getEntityStream().flush();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+ };
+ }
+}
+
diff --git a/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/http2/server-tls.xml b/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/http2/server-tls.xml
new file mode 100644
index 0000000000..134774ee7a
--- /dev/null
+++ b/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/http2/server-tls.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:http-jetty="http://cxf.apache.org/transports/http-jetty/configuration"
+ xmlns:sec="http://cxf.apache.org/configuration/security"
+ xsi:schemaLocation="http://cxf.apache.org/transports/http-jetty/configuration
+ http://cxf.apache.org/schemas/configuration/http-jetty.xsd
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://cxf.apache.org/configuration/security
+ http://cxf.apache.org/schemas/configuration/security.xsd">
+ <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
+ <http-jetty:engine-factory bus="cxf">
+ <http-jetty:engine port="${testutil.ports.org.apache.cxf.systest.hc5.http2.BookServerHttp2}">
+ <http-jetty:tlsServerParameters>
+ <sec:keyManagers keyPassword="password">
+ <sec:keyStore type="jks" password="password" resource="keys/Bethal.jks"/>
+ </sec:keyManagers>
+ <sec:clientAuthentication want="false" required="false"/>
+ </http-jetty:tlsServerParameters>
+ </http-jetty:engine>
+ </http-jetty:engine-factory>
+</beans>
\ No newline at end of file
diff --git a/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/http2/server.xml b/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/http2/server.xml
new file mode 100644
index 0000000000..5251ef1562
--- /dev/null
+++ b/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/http2/server.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:http-jetty="http://cxf.apache.org/transports/http-jetty/configuration"
+ xsi:schemaLocation="http://cxf.apache.org/transports/http-jetty/configuration
+ http://cxf.apache.org/schemas/configuration/http-jetty.xsd
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd">
+ <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
+ <http-jetty:engine-factory bus="cxf">
+ <http-jetty:engine port="${testutil.ports.org.apache.cxf.systest.hc5.http2.BookServerHttp2c}">
+ </http-jetty:engine>
+ </http-jetty:engine-factory>
+</beans>
\ No newline at end of file
diff --git a/systests/transport-netty/pom.xml b/systests/transport-netty/pom.xml
index 486f72bd54..6a03d3baa2 100644
--- a/systests/transport-netty/pom.xml
+++ b/systests/transport-netty/pom.xml
@@ -137,6 +137,11 @@
<artifactId>cxf-rt-transports-http-netty-server</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-transports-http-netty-client</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
diff --git a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractNettyClientServerHttp2Test.java b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractNettyClientServerHttp2Test.java
index 5945b1fb8f..c9917426cc 100644
--- a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractNettyClientServerHttp2Test.java
+++ b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractNettyClientServerHttp2Test.java
@@ -23,103 +23,108 @@ import javax.ws.rs.core.Response;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.jaxrs.client.WebClient;
-import org.apache.cxf.systest.http2.netty.Http2TestClient.ClientResponse;
import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
import org.apache.cxf.transport.http.HTTPConduit;
+import org.apache.cxf.transport.http.netty.client.NettyHttpConduit;
import org.apache.cxf.transport.https.InsecureTrustManager;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
abstract class AbstractNettyClientServerHttp2Test extends AbstractBusClientServerTestBase {
@Test
public void testBookNotFoundWithHttp2() throws Exception {
- final Http2TestClient client = new Http2TestClient(isSecure());
-
- final ClientResponse response = client
- .request(getAddress())
+ final WebClient client = createWebClient("/web/bookstore/notFound", true);
+ assertThat(WebClient.getConfig(client).getHttpConduit(), instanceOf(NettyHttpConduit.class));
+
+ final Response response = client
.accept("text/plain")
- .path(getContext() + "/web/bookstore/notFound")
- .http2()
.get();
- assertThat(response.getResponseCode(), equalTo(404));
- assertThat(response.getProtocol(), equalTo("HTTP/2.0"));
+ assertThat(response.getStatus(), equalTo(404));
+ client.close();
}
@Test
public void testBookTraceWithHttp2() throws Exception {
- final Http2TestClient client = new Http2TestClient(isSecure());
-
- final ClientResponse response = client
- .request(getAddress())
+ final WebClient client = createWebClient("/web/bookstore/trace", true);
+ assertThat(WebClient.getConfig(client).getHttpConduit(), instanceOf(NettyHttpConduit.class));
+
+ final Response response = client
.accept("text/plain")
- .path(getContext() + "/web/bookstore/trace")
- .http2()
- .trace();
+ .invoke("TRACE", null);
- assertThat(response.getResponseCode(), equalTo(406));
- assertThat(response.getProtocol(), equalTo("HTTP/2.0"));
+ assertThat(response.getStatus(), equalTo(406));
+
+ client.close();
}
@Test
public void testBookWithHttp2() throws Exception {
- final Http2TestClient client = new Http2TestClient(isSecure());
+ final WebClient client = createWebClient("/web/bookstore/booknames", true);
+ assertThat(WebClient.getConfig(client).getHttpConduit(), instanceOf(NettyHttpConduit.class));
- final ClientResponse response = client
- .request(getAddress())
+ final Response response = client
.accept("text/plain")
- .path(getContext() + "/web/bookstore/booknames")
- .http2()
.get();
- assertThat(response.getResponseCode(), equalTo(200));
- assertThat(response.getProtocol(), equalTo("HTTP/2.0"));
- assertEquals("CXF in Action", response.getBody());
+ assertThat(response.getStatus(), equalTo(200));
+ assertEquals("CXF in Action", response.readEntity(String.class));
+
+ client.close();
}
@Test
public void testGetBookStreamHttp2() throws Exception {
- final Http2TestClient client = new Http2TestClient(isSecure());
+ final WebClient client = createWebClient("/web/bookstore/bookstream", true);
+ assertThat(WebClient.getConfig(client).getHttpConduit(), instanceOf(NettyHttpConduit.class));
- final ClientResponse response = client
- .request(getAddress())
+ final Response response = client
.accept("application/xml")
- .path(getContext() + "/web/bookstore/bookstream")
- .http2()
.get();
- assertThat(response.getResponseCode(), equalTo(200));
- assertThat(response.getProtocol(), equalTo("HTTP/2.0"));
+ assertThat(response.getStatus(), equalTo(200));
assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
- + "<Book><id>1</id><name>Book1</name></Book>", response.getBody());
+ + "<Book><id>1</id><name>Book1</name></Book>", response.readEntity(String.class));
+
+ client.close();
}
@Test
public void testBookWithHttp() throws Exception {
- final WebClient wc = createWebClient("/web/bookstore/booknames");
- try (Response resp = wc.get()) {
+ final WebClient client = createWebClient("/web/bookstore/booknames", false);
+
+ try (Response resp = client.get()) {
assertThat(resp.getStatus(), equalTo(200));
assertEquals("CXF in Action", resp.readEntity(String.class));
}
+
+ client.close();
}
@Test
public void testBookTraceWithHttp() throws Exception {
- final WebClient wc = createWebClient("/web/bookstore/trace");
- try (Response response = wc.invoke("TRACE", null)) {
+ final WebClient client = createWebClient("/web/bookstore/trace", false);
+
+ try (Response response = client.invoke("TRACE", null)) {
assertThat(response.getStatus(), equalTo(406));
- }
+ }
+
+ client.close();
}
- private WebClient createWebClient(final String path) {
+ private WebClient createWebClient(final String path, final boolean enableHttp2) {
final WebClient wc = WebClient
.create(getAddress() + getContext() + path)
.accept("text/plain");
-
+
+ WebClient.getConfig(wc).getRequestContext().put(NettyHttpConduit.ENABLE_HTTP2, enableHttp2);
+ WebClient.getConfig(wc).getRequestContext().put(NettyHttpConduit.USE_ASYNC, "ALWAYS");
+
if (isSecure()) {
final HTTPConduit conduit = WebClient.getConfig(wc).getHttpConduit();
TLSClientParameters params = conduit.getTlsClientParameters();
diff --git a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/Http2TestClient.java b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/Http2TestClient.java
deleted file mode 100644
index b88e610ad0..0000000000
--- a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/Http2TestClient.java
+++ /dev/null
@@ -1,405 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.cxf.systest.http2.netty;
-
-import java.io.IOException;
-import java.net.URI;
-import java.util.AbstractMap.SimpleEntry;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.TimeUnit;
-
-import javax.ws.rs.core.MediaType;
-
-import io.netty.bootstrap.Bootstrap;
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.ChannelOption;
-import io.netty.channel.ChannelPromise;
-import io.netty.channel.SimpleChannelInboundHandler;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.channel.socket.nio.NioSocketChannel;
-import io.netty.handler.codec.http.DefaultFullHttpRequest;
-import io.netty.handler.codec.http.FullHttpRequest;
-import io.netty.handler.codec.http.FullHttpResponse;
-import io.netty.handler.codec.http.HttpClientCodec;
-import io.netty.handler.codec.http.HttpClientUpgradeHandler;
-import io.netty.handler.codec.http.HttpHeaderNames;
-import io.netty.handler.codec.http.HttpMethod;
-import io.netty.handler.codec.http.HttpVersion;
-import io.netty.handler.codec.http2.DefaultHttp2Connection;
-import io.netty.handler.codec.http2.DelegatingDecompressorFrameListener;
-import io.netty.handler.codec.http2.Http2ClientUpgradeCodec;
-import io.netty.handler.codec.http2.Http2Connection;
-import io.netty.handler.codec.http2.Http2ConnectionHandler;
-import io.netty.handler.codec.http2.Http2SecurityUtil;
-import io.netty.handler.codec.http2.Http2Settings;
-import io.netty.handler.codec.http2.HttpConversionUtil;
-import io.netty.handler.codec.http2.HttpToHttp2ConnectionHandlerBuilder;
-import io.netty.handler.codec.http2.InboundHttp2ToHttpAdapterBuilder;
-import io.netty.handler.ssl.ApplicationProtocolConfig;
-import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
-import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
-import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
-import io.netty.handler.ssl.ApplicationProtocolNames;
-import io.netty.handler.ssl.SslContext;
-import io.netty.handler.ssl.SslProvider;
-import io.netty.handler.ssl.SupportedCipherSuiteFilter;
-import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
-import io.netty.util.internal.PlatformDependent;
-
-/**
- * TODO: Use CXF client once https://issues.apache.org/jira/browse/CXF-8606 is dones
- */
-public class Http2TestClient implements AutoCloseable {
- private final SslContext ssl;
-
- public Http2TestClient(boolean secure) throws Exception {
- if (secure) {
- ssl = SslContext.newClientContext(
- SslProvider.JDK,
- null,
- InsecureTrustManagerFactory.INSTANCE,
- Http2SecurityUtil.CIPHERS,
- SupportedCipherSuiteFilter.INSTANCE,
- new ApplicationProtocolConfig(
- Protocol.ALPN,
- SelectorFailureBehavior.FATAL_ALERT,
- SelectedListenerFailureBehavior.FATAL_ALERT,
- ApplicationProtocolNames.HTTP_2,
- ApplicationProtocolNames.HTTP_1_1),
- 0, 0);
- } else {
- ssl = null;
- }
- }
-
- public static class ClientResponse {
- private String body;
- private String protocol;
- private int responseCode;
-
- public ClientResponse(int responseCode, String protocol) {
- this.responseCode = responseCode;
- this.protocol = protocol;
- }
-
- public void setBody(String body) {
- this.body = body;
- }
-
- public String getBody() {
- return body;
- }
-
- public void setResponseCode(int rc) {
- this.responseCode = rc;
- }
-
- public int getResponseCode() {
- return responseCode;
- }
-
- public String getProtocol() {
- return protocol;
- }
-
- public void setProtocol(String protocol) {
- this.protocol = protocol;
- }
- }
-
- public class RequestBuilder {
- private final String address;
- private String path = "";
- private String accept = MediaType.WILDCARD;
- private HttpVersion version = HttpVersion.HTTP_1_1;
-
- public RequestBuilder(final String address) {
- this.address = address;
- }
-
- public RequestBuilder path(final String p) {
- this.path = p;
- return this;
- }
-
-
- public RequestBuilder accept(final String a) {
- this.accept = a;
- return this;
- }
-
- public RequestBuilder http2() {
- version = null;
- return this;
- }
-
- public ClientResponse get() throws Exception {
- return request(address, path, version, HttpMethod.GET, accept);
- }
-
- public ClientResponse trace() throws Exception {
- return request(address, path, version, HttpMethod.TRACE, accept);
- }
- }
-
- public RequestBuilder request(final String address) throws IOException {
- return new RequestBuilder(address);
- }
-
- public ClientResponse request(final String address, final String path,
- final HttpVersion version, final HttpMethod method, final String accept)
- throws Exception {
-
- final URI uri = URI.create(address);
-
- final Http2ClientInitializer initializer = new Http2ClientInitializer(Integer.MAX_VALUE);
- final NioEventLoopGroup worker = new NioEventLoopGroup();
-
- final Bootstrap bootstrap = new Bootstrap();
- bootstrap.group(worker);
- bootstrap.channel(NioSocketChannel.class);
- bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
- bootstrap.remoteAddress(uri.getHost(), uri.getPort());
- bootstrap.handler(initializer);
-
- final Channel channel = bootstrap.connect().syncUninterruptibly().channel();
- final HttpResponseHandler responseHandler = initializer.getResponseHandler();
- final Http2SettingsHandler http2SettingsHandler = initializer.getSettingsHandler();
-
- try {
- final FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, method, path);
- request.headers().add(HttpHeaderNames.HOST, uri.getHost());
- request.headers().add(HttpHeaderNames.ACCEPT, accept);
- request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), uri.getScheme());
-
- http2SettingsHandler.awaitSettings(5, TimeUnit.SECONDS);
- responseHandler.put(3, channel.write(request), channel.newPromise());
-
- channel.flush();
- responseHandler.awaitResponses(15, TimeUnit.SECONDS);
- } finally {
- channel.close().awaitUninterruptibly();
- worker.shutdownGracefully();
- }
-
-
- final List<ClientResponse> responses = responseHandler.responses();
- if (responses.size() != 1) {
- throw new IllegalStateException("Expected exactly one response, but got 0 or more");
- }
-
- return responses.get(0);
- }
-
- @Override
- public void close() throws Exception {
- }
-
- private class Http2SettingsHandler extends SimpleChannelInboundHandler<Http2Settings> {
- private ChannelPromise promise;
-
- Http2SettingsHandler(ChannelPromise promise) {
- this.promise = promise;
- }
-
- /**
- * Wait for this handler to be added after the upgrade to HTTP/2, and for initial preface
- * handshake to complete.
- */
- void awaitSettings(long timeout, TimeUnit unit) throws Exception {
- if (!promise.awaitUninterruptibly(timeout, unit)) {
- throw new IllegalStateException("Timed out waiting for settings");
- }
- if (!promise.isSuccess()) {
- throw new RuntimeException(promise.cause());
- }
- }
-
- @Override
- protected void channelRead0(ChannelHandlerContext ctx, Http2Settings msg) throws Exception {
- promise.setSuccess();
- ctx.pipeline().remove(this);
- }
- }
-
- private class HttpResponseHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
- private final Map<Integer, Entry<ChannelFuture, ChannelPromise>> streamidPromiseMap;
- private final List<ClientResponse> responses = new CopyOnWriteArrayList<>();
-
- HttpResponseHandler() {
- streamidPromiseMap = PlatformDependent.newConcurrentHashMap();
- }
-
- Entry<ChannelFuture, ChannelPromise> put(int streamId, ChannelFuture writeFuture, ChannelPromise promise) {
- return streamidPromiseMap.put(streamId, new SimpleEntry<>(writeFuture, promise));
- }
-
- void awaitResponses(long timeout, TimeUnit unit) {
- final Iterator<Entry<Integer, Entry<ChannelFuture, ChannelPromise>>> itr = streamidPromiseMap
- .entrySet()
- .iterator();
-
- while (itr.hasNext()) {
- final Entry<Integer, Entry<ChannelFuture, ChannelPromise>> entry = itr.next();
-
- final ChannelFuture writeFuture = entry.getValue().getKey();
- if (!writeFuture.awaitUninterruptibly(timeout, unit)) {
- throw new IllegalStateException("Timed out waiting to write for stream id " + entry.getKey());
- }
-
- if (!writeFuture.isSuccess()) {
- throw new RuntimeException(writeFuture.cause());
- }
-
- final ChannelPromise promise = entry.getValue().getValue();
- if (!promise.awaitUninterruptibly(timeout, unit)) {
- throw new IllegalStateException("Timed out waiting for response on stream id " + entry.getKey());
- }
-
- if (!promise.isSuccess()) {
- throw new RuntimeException(promise.cause());
- }
-
- itr.remove();
- }
- }
-
- List<ClientResponse> responses() {
- return responses;
- }
-
- @Override
- protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception {
- Integer streamId = msg.headers().getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text());
- if (streamId == null) {
- System.err.println("HttpResponseHandler unexpected message received: " + msg);
- return;
- }
-
- final Entry<ChannelFuture, ChannelPromise> entry = streamidPromiseMap.get(streamId);
- if (entry == null) {
- System.err.println("Message received for unknown stream id " + streamId);
- } else {
- final ByteBuf content = msg.content();
- final ClientResponse response = new ClientResponse(msg.status().code(), "HTTP/2.0");
-
- if (content.isReadable()) {
- int contentLength = content.readableBytes();
- byte[] arr = new byte[contentLength];
- content.readBytes(arr);
- response.setBody(new String(arr));
- }
-
- responses.add(response);
- entry.getValue().setSuccess();
- }
- }
- }
-
- private class Http2ClientInitializer extends ChannelInitializer<SocketChannel> {
- private final int maxContentLength;
- private HttpResponseHandler responseHandler;
- private Http2SettingsHandler settingsHandler;
- private Http2ConnectionHandler connectionHandler;
-
- Http2ClientInitializer(int maxContentLength) {
- this.maxContentLength = maxContentLength;
- }
-
- @Override
- public void initChannel(SocketChannel ch) throws Exception {
- final Http2Connection connection = new DefaultHttp2Connection(false);
-
- responseHandler = new HttpResponseHandler();
- settingsHandler = new Http2SettingsHandler(ch.newPromise());
-
- connectionHandler = new HttpToHttp2ConnectionHandlerBuilder()
- .connection(connection)
- .frameListener(new DelegatingDecompressorFrameListener(connection,
- new InboundHttp2ToHttpAdapterBuilder(connection)
- .maxContentLength(maxContentLength)
- .propagateSettings(true)
- .build()))
- .build();
-
- if (ssl != null) {
- ch.pipeline().addLast(ssl.newHandler(ch.alloc()));
- ch.pipeline().addLast(connectionHandler);
- ch.pipeline().addLast(settingsHandler);
- ch.pipeline().addLast(responseHandler);
- } else {
- final HttpClientCodec sourceCodec = new HttpClientCodec();
- final Http2ClientUpgradeCodec upgradeCodec = new Http2ClientUpgradeCodec(connectionHandler);
- final HttpClientUpgradeHandler upgradeHandler = new HttpClientUpgradeHandler(sourceCodec,
- upgradeCodec, 65536);
-
- ch.pipeline().addLast(sourceCodec);
- ch.pipeline().addLast(upgradeHandler);
- ch.pipeline().addLast(new UpgradeRequestHandler(settingsHandler, responseHandler));
- }
- }
-
- HttpResponseHandler getResponseHandler() {
- return responseHandler;
- }
-
- Http2SettingsHandler getSettingsHandler() {
- return settingsHandler;
- }
- }
-
- /**
- * A handler that triggers the cleartext upgrade to HTTP/2 by sending an
- * initial HTTP request.
- */
- private class UpgradeRequestHandler extends ChannelInboundHandlerAdapter {
- private final Http2SettingsHandler settingsHandler;
- private final HttpResponseHandler responseHandler;
-
- UpgradeRequestHandler(final Http2SettingsHandler settingsHandler, final HttpResponseHandler responseHandler) {
- this.settingsHandler = settingsHandler;
- this.responseHandler = responseHandler;
- }
-
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- final FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
- request.headers().add(HttpHeaderNames.HOST, "localhost");
- request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), "http");
-
- ctx.writeAndFlush(request);
- ctx.fireChannelActive();
-
- ctx.pipeline().remove(this);
- ctx.pipeline().addLast(settingsHandler);
- ctx.pipeline().addLast(responseHandler);
- }
- }
-}
[cxf] 06/06: Recording .gitmergeinfo Changes
Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch 3.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 1b5b589c3c8b0df5fac20db6dfe5bf09cd9e2461
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Sun May 7 13:24:15 2023 -0400
Recording .gitmergeinfo Changes
---
.gitmergeinfo | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/.gitmergeinfo b/.gitmergeinfo
index 74c4807684..5b5b211e18 100644
--- a/.gitmergeinfo
+++ b/.gitmergeinfo
@@ -168,6 +168,7 @@ B 983d15c06dafbfb883250b2d763bd3d6956ad114
B 9940b6f38d5380fc150cf6409c99197a595c840a
B 99718a61f0123f6767c81905da3f631b9ad724d4
B 9af2b5a79664da5e8b21cf30a53309489be8326a
+B 9b9868a2797ab56afdfdd2ab22f82d9044560a5b
B 9ba0178cc44b2b5babafccf056bfc96aa9eea0eb
B 9c5658b9b39403cc95d38a61de900af0591222d5
B 9ed98f36a381b8f881c2d63a5846572ba83a4ed9
@@ -489,6 +490,7 @@ M 79f8c812ec3e61d5702adb5ec54f5aecb7e04a8e
M 7a05e4fb0b67a89b86ed6eee68b9416005d6f631
M 7afa3c470d651b73c915c3ec65ba16a30bb561e5
M 7c15ae9596cf879bb4e8089816c3deffcd309c76
+M 7e15456d3b191e29e446d9a5895554a3bdf19fbd
M 7e5ec1dccff0827835bcf3dd2d5dea2dc9f65ac5
M 7e693ae2e65fc3c7715327a3e515f09929e4985e
M 7ed3afca7b5436dbcecc1ce7ea6d8de232a54ace
@@ -513,6 +515,7 @@ M 9003ea397e4e9f557b3a40148f408b64c954ea7d
M 906ce39eb6de0be51e0e8cc0ea0bd9f3a297cecf
M 910168db187d4e34ef3228de7ca178e789cefd5f
M 9225580122e38bc6c531fe47077804d5ce514cde
+M 9277a37a113f7342d55b74505703646e6a397b86
M 92db608461b62b76f2e9a52551361a75a4f2826d
M 941ed53ce451b809809f8270b74aa546be681aa6
M 954085421900efbf89643b5ab8f187a237e42eb4
@@ -539,6 +542,7 @@ M 9f939eefbd41ee5c0e88b41c2e177fdbc5cbdd26
M 9fb50062390769e1c0e16b4180bef7736c8ad3ba
M 9fc476860b14687ea3f2ca4a65a693fe4c2584b4
M a018a587094cb822feb56705fd9f5fcba4322804
+M a216f5da3a12189d66b7014b9359541c9e448483
M a28c4a4f8f1f8f5abd24cfd655cd55ed620746ab
M a2a48bd789e66ffae82d35d156d02e58fbb4bb2b
M a2fc449969afa082065b1be644a3af890abcc1db
@@ -575,11 +579,14 @@ M b3fc1996eada7b808d8e8e629e12e07f989be495
M b4a5d1de32995bef9b8f7c2d68badd0b0daf15b6
M b5c6ed22d517c217f178b4403ad367e5a3bab1bf
M b5ff2d8eb91ab76381157934cf574f13c9a5e3a2
+M b64fbe96c347303c6422f88cb8a96646915d45cf
M b683d4ee1194d8efeae8bef4050bf34abf82501e
M b6d097b020b69d62ee63703b68fb5ad9f8203a2a
M b72f0ce5426eb342145611ee5529c7df172d71c7
+M b79d02ed8b7d88b7206cfb63a807233b2d5bbcbe
M b8a2f139f8a4f80a90ef49c2a0757395cb303be6
M b909e6dd478272d2c3e094922801a201ef94eeb5
+M ba414fe02b12bb6cab753713a461f5db86a3fb07
M ba463164bbc34192ee24e756f615a8bd3f15a75c
M bb73cfaaebea3c74025c51da7b6478b91122a245
M bb8b2ccfddb26d28f3bb95267e9c93d39843cfca
[cxf] 02/06: Update Zipkin Brave to 2.24.1
Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch 3.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 69ecbb9a459e690782fc369e7606dd93c8448f1a
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Wed May 3 10:57:29 2023 -0400
Update Zipkin Brave to 2.24.1
(cherry picked from commit c980047209f6cb66788c5015a93a277422bc79c6)
(cherry picked from commit a216f5da3a12189d66b7014b9359541c9e448483)
---
parent/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/parent/pom.xml b/parent/pom.xml
index ba3f2c9d15..4b468fbfe5 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -91,7 +91,7 @@
<cxf.bcprov.version>1.69</cxf.bcprov.version>
<cxf.brave.reporter.version>2.16.4</cxf.brave.reporter.version>
<cxf.brave.version>5.15.1</cxf.brave.version>
- <cxf.brave.zipkin.version>2.24.0</cxf.brave.zipkin.version>
+ <cxf.brave.zipkin.version>2.24.1</cxf.brave.zipkin.version>
<cxf.cda.api.osgi.range>[1.1,2)</cxf.cda.api.osgi.range>
<cxf.cdi.api.version>2.0.2</cxf.cdi.api.version>
<cxf.classgraph.version>4.8.25</cxf.classgraph.version>
[cxf] 01/06: Update Brave Reporter to 2.16.4
Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch 3.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
commit b19c4509f2bc35647899e973c90ee73e1d9e904b
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Mon May 1 21:07:16 2023 -0400
Update Brave Reporter to 2.16.4
(cherry picked from commit b79d02ed8b7d88b7206cfb63a807233b2d5bbcbe)
# Conflicts:
# parent/pom.xml
---
parent/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/parent/pom.xml b/parent/pom.xml
index a5247b1745..ba3f2c9d15 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -89,7 +89,7 @@
<cxf.atmosphere.version.range>[2.4,3.0)</cxf.atmosphere.version.range>
<cxf.atmosphere.version>2.6.1</cxf.atmosphere.version>
<cxf.bcprov.version>1.69</cxf.bcprov.version>
- <cxf.brave.reporter.version>2.16.2</cxf.brave.reporter.version>
+ <cxf.brave.reporter.version>2.16.4</cxf.brave.reporter.version>
<cxf.brave.version>5.15.1</cxf.brave.version>
<cxf.brave.zipkin.version>2.24.0</cxf.brave.zipkin.version>
<cxf.cda.api.osgi.range>[1.1,2)</cxf.cda.api.osgi.range>
[cxf] 04/06: CXF-8606: Introduce HTTP/2 Transport: client-side support (fixing netty-codec-http2 dependency scope)
Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch 3.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 37e70b822bca07b058422289e130f041e637e38a
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Sat May 6 13:09:52 2023 -0400
CXF-8606: Introduce HTTP/2 Transport: client-side support (fixing netty-codec-http2 dependency scope)
(cherry picked from commit 07a7d018b444d0b524ad0d433b96596e84f76931)
(cherry picked from commit ff7edcd72307a50941536bede634055c80a596ba)
---
osgi/karaf/features/src/main/resources/features.xml | 1 +
rt/transports/http-netty/netty-client/pom.xml | 1 -
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/osgi/karaf/features/src/main/resources/features.xml b/osgi/karaf/features/src/main/resources/features.xml
index 1f1b68f154..5ad41c6368 100644
--- a/osgi/karaf/features/src/main/resources/features.xml
+++ b/osgi/karaf/features/src/main/resources/features.xml
@@ -203,6 +203,7 @@
<bundle start-level="40">mvn:io.netty/netty-resolver/${cxf.netty.version}</bundle>
<bundle start-level="40">mvn:io.netty/netty-codec/${cxf.netty.version}</bundle>
<bundle start-level="40">mvn:io.netty/netty-codec-http/${cxf.netty.version}</bundle>
+ <bundle start-level="40">mvn:io.netty/netty-codec-http2/${cxf.netty.version}</bundle>
<bundle start-level="40">mvn:org.apache.cxf/cxf-rt-transports-http-netty-client/${project.version}</bundle>
</feature>
<feature name="cxf-http-netty-server" version="${project.version}">
diff --git a/rt/transports/http-netty/netty-client/pom.xml b/rt/transports/http-netty/netty-client/pom.xml
index 8d2538931b..2213aaae44 100644
--- a/rt/transports/http-netty/netty-client/pom.xml
+++ b/rt/transports/http-netty/netty-client/pom.xml
@@ -53,7 +53,6 @@
<groupId>io.netty</groupId>
<artifactId>netty-codec-http2</artifactId>
<version>${cxf.netty.version}</version>
- <optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>