HTTP2 Support (#2363)
Adds HttpProtocol.H2 if server.http2.enabled=true. Deprecates defaultConfigurationType as it is no longer used. Updates to use new HttpClient ProtocolSslContextSpec for configuring ssl. Fixes gh-7 Fixes gh-2206
This commit is contained in:
@@ -23,15 +23,18 @@ import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.handler.ssl.SslContextBuilder;
|
||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.netty.http.Http11SslContextSpec;
|
||||
import reactor.netty.http.Http2SslContextSpec;
|
||||
import reactor.netty.http.HttpProtocol;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.netty.http.client.WebsocketClientSpec;
|
||||
import reactor.netty.http.server.WebsocketServerSpec;
|
||||
import reactor.netty.resources.ConnectionProvider;
|
||||
import reactor.netty.tcp.SslProvider.ProtocolSslContextSpec;
|
||||
import reactor.netty.transport.ProxyProvider;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
@@ -641,7 +644,8 @@ public class GatewayAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public HttpClient gatewayHttpClient(HttpClientProperties properties, List<HttpClientCustomizer> customizers) {
|
||||
public HttpClient gatewayHttpClient(HttpClientProperties properties, ServerProperties serverProperties,
|
||||
List<HttpClientCustomizer> customizers) {
|
||||
|
||||
// configure pool resources
|
||||
ConnectionProvider connectionProvider = buildConnectionProvider(properties);
|
||||
@@ -658,57 +662,66 @@ public class GatewayAutoConfiguration {
|
||||
spec.maxInitialLineLength((int) properties.getMaxInitialLineLength().toBytes());
|
||||
}
|
||||
return spec;
|
||||
}).tcpConfiguration(tcpClient -> {
|
||||
|
||||
if (properties.getConnectTimeout() != null) {
|
||||
tcpClient = tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,
|
||||
properties.getConnectTimeout());
|
||||
}
|
||||
|
||||
// configure proxy if proxy host is set.
|
||||
HttpClientProperties.Proxy proxy = properties.getProxy();
|
||||
|
||||
if (StringUtils.hasText(proxy.getHost())) {
|
||||
|
||||
tcpClient = tcpClient.proxy(proxySpec -> {
|
||||
ProxyProvider.Builder builder = proxySpec.type(proxy.getType()).host(proxy.getHost());
|
||||
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
|
||||
map.from(proxy::getPort).whenNonNull().to(builder::port);
|
||||
map.from(proxy::getUsername).whenHasText().to(builder::username);
|
||||
map.from(proxy::getPassword).whenHasText()
|
||||
.to(password -> builder.password(s -> password));
|
||||
map.from(proxy::getNonProxyHostsPattern).whenHasText().to(builder::nonProxyHosts);
|
||||
});
|
||||
}
|
||||
return tcpClient;
|
||||
});
|
||||
|
||||
if (serverProperties.getHttp2().isEnabled()) {
|
||||
httpClient = httpClient.protocol(HttpProtocol.HTTP11, HttpProtocol.H2);
|
||||
}
|
||||
|
||||
if (properties.getConnectTimeout() != null) {
|
||||
httpClient = httpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, properties.getConnectTimeout());
|
||||
}
|
||||
|
||||
// configure proxy if proxy host is set.
|
||||
if (StringUtils.hasText(properties.getProxy().getHost())) {
|
||||
HttpClientProperties.Proxy proxy = properties.getProxy();
|
||||
|
||||
httpClient = httpClient.proxy(proxySpec -> {
|
||||
ProxyProvider.Builder builder = proxySpec.type(proxy.getType()).host(proxy.getHost());
|
||||
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
|
||||
map.from(proxy::getPort).whenNonNull().to(builder::port);
|
||||
map.from(proxy::getUsername).whenHasText().to(builder::username);
|
||||
map.from(proxy::getPassword).whenHasText().to(password -> builder.password(s -> password));
|
||||
map.from(proxy::getNonProxyHostsPattern).whenHasText().to(builder::nonProxyHosts);
|
||||
});
|
||||
}
|
||||
|
||||
HttpClientProperties.Ssl ssl = properties.getSsl();
|
||||
if ((ssl.getKeyStore() != null && ssl.getKeyStore().length() > 0)
|
||||
|| ssl.getTrustedX509CertificatesForTrustManager().length > 0 || ssl.isUseInsecureTrustManager()) {
|
||||
httpClient = httpClient.secure(sslContextSpec -> {
|
||||
// configure ssl
|
||||
SslContextBuilder sslContextBuilder = SslContextBuilder.forClient();
|
||||
ProtocolSslContextSpec clientSslContext = (serverProperties.getHttp2().isEnabled())
|
||||
? Http2SslContextSpec.forClient() : Http11SslContextSpec.forClient();
|
||||
clientSslContext.configure(sslContextBuilder -> {
|
||||
X509Certificate[] trustedX509Certificates = ssl.getTrustedX509CertificatesForTrustManager();
|
||||
if (trustedX509Certificates.length > 0) {
|
||||
sslContextBuilder.trustManager(trustedX509Certificates);
|
||||
}
|
||||
else if (ssl.isUseInsecureTrustManager()) {
|
||||
sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE);
|
||||
}
|
||||
|
||||
X509Certificate[] trustedX509Certificates = ssl.getTrustedX509CertificatesForTrustManager();
|
||||
if (trustedX509Certificates.length > 0) {
|
||||
sslContextBuilder = sslContextBuilder.trustManager(trustedX509Certificates);
|
||||
}
|
||||
else if (ssl.isUseInsecureTrustManager()) {
|
||||
sslContextBuilder = sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE);
|
||||
}
|
||||
try {
|
||||
sslContextBuilder.keyManager(ssl.getKeyManagerFactory());
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
sslContextBuilder = sslContextBuilder.keyManager(ssl.getKeyManagerFactory());
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error(e);
|
||||
}
|
||||
|
||||
sslContextSpec.sslContext(sslContextBuilder).defaultConfiguration(ssl.getDefaultConfigurationType())
|
||||
.handshakeTimeout(ssl.getHandshakeTimeout())
|
||||
sslContextSpec.sslContext(clientSslContext).handshakeTimeout(ssl.getHandshakeTimeout())
|
||||
.closeNotifyFlushTimeout(ssl.getCloseNotifyFlushTimeout())
|
||||
.closeNotifyReadTimeout(ssl.getCloseNotifyReadTimeout());
|
||||
});
|
||||
}
|
||||
else if (serverProperties.getHttp2().isEnabled()) {
|
||||
httpClient = httpClient.secure(sslContextSpec -> {
|
||||
Http2SslContextSpec clientSslCtxt = Http2SslContextSpec.forClient()
|
||||
.configure(builder -> builder.trustManager(InsecureTrustManagerFactory.INSTANCE));
|
||||
sslContextSpec.sslContext(clientSslCtxt).handshakeTimeout(ssl.getHandshakeTimeout())
|
||||
.closeNotifyFlushTimeout(ssl.getCloseNotifyFlushTimeout())
|
||||
.closeNotifyReadTimeout(ssl.getCloseNotifyReadTimeout());
|
||||
});
|
||||
|
||||
@@ -403,6 +403,7 @@ public class HttpClientProperties {
|
||||
private Duration closeNotifyReadTimeout = Duration.ZERO;
|
||||
|
||||
/** The default ssl configuration type. Defaults to TCP. */
|
||||
@Deprecated
|
||||
private SslProvider.DefaultConfigurationType defaultConfigurationType = SslProvider.DefaultConfigurationType.TCP;
|
||||
|
||||
/** Keystore path for Netty HttpClient. */
|
||||
@@ -568,10 +569,12 @@ public class HttpClientProperties {
|
||||
this.closeNotifyReadTimeout = closeNotifyReadTimeout;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public SslProvider.DefaultConfigurationType getDefaultConfigurationType() {
|
||||
return defaultConfigurationType;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setDefaultConfigurationType(SslProvider.DefaultConfigurationType defaultConfigurationType) {
|
||||
this.defaultConfigurationType = defaultConfigurationType;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,9 @@ import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.cloud.gateway.actuate.GatewayControllerEndpoint;
|
||||
import org.springframework.cloud.gateway.actuate.GatewayLegacyControllerEndpoint;
|
||||
@@ -68,7 +70,8 @@ public class GatewayAutoConfigurationTests {
|
||||
public void nettyHttpClientDefaults() {
|
||||
new ReactiveWebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class, MetricsAutoConfiguration.class,
|
||||
SimpleMetricsExportAutoConfiguration.class, GatewayAutoConfiguration.class))
|
||||
SimpleMetricsExportAutoConfiguration.class, GatewayAutoConfiguration.class,
|
||||
ServerPropertiesConfig.class))
|
||||
.withPropertyValues("debug=true").run(context -> {
|
||||
assertThat(context).hasSingleBean(HttpClient.class);
|
||||
assertThat(context).hasBean("gatewayHttpClient");
|
||||
@@ -94,7 +97,7 @@ public class GatewayAutoConfigurationTests {
|
||||
new ReactiveWebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class, MetricsAutoConfiguration.class,
|
||||
SimpleMetricsExportAutoConfiguration.class, GatewayAutoConfiguration.class,
|
||||
HttpClientCustomizedConfig.class))
|
||||
HttpClientCustomizedConfig.class, ServerPropertiesConfig.class))
|
||||
.withPropertyValues("spring.cloud.gateway.httpclient.ssl.use-insecure-trust-manager=true",
|
||||
"spring.cloud.gateway.httpclient.connect-timeout=10",
|
||||
"spring.cloud.gateway.httpclient.response-timeout=10s",
|
||||
@@ -228,6 +231,12 @@ public class GatewayAutoConfigurationTests {
|
||||
assertThat(spec2.protocols()).isNull();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(ServerProperties.class)
|
||||
protected static class ServerPropertiesConfig {
|
||||
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@SpringBootConfiguration
|
||||
protected static class Config {
|
||||
|
||||
Reference in New Issue
Block a user