Auto-configure H2C when HTTP/2 is enabled and SSL is disabled
This commit is contained in:
parent
288e86d871
commit
713c0fce7c
|
|
@ -594,26 +594,23 @@ We recommend using `application.properties` to configure HTTPS, as the HTTP conn
|
|||
[[howto-configure-http2]]
|
||||
=== Configure HTTP/2
|
||||
You can enable HTTP/2 support in your Spring Boot application with the configprop:server.http2.enabled[] configuration property.
|
||||
This support depends on the chosen web server and the application environment, since that protocol is not supported out-of-the-box by all JDK8 releases.
|
||||
Both `h2` (HTTP/2 over TLS) and `h2c` (HTTP/2 over TCP) are supported.
|
||||
To use `h2`, SSL must also be enabled.
|
||||
When SSL is not enabled, `h2c` will be used.
|
||||
The details of the `h2` support depend on the chosen web server and the application environment, since that protocol is not supported out-of-the-box by all JDK 8 releases.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Spring Boot does not advise using `h2c`, the cleartext version of the HTTP/2 protocol.
|
||||
As a result, the following sections require you to <<howto-configure-ssl, configure SSL first>>.
|
||||
If you still choose to use `h2c`, you can check <<howto-configure-http2-h2c, the dedicated section>>.
|
||||
====
|
||||
|
||||
|
||||
[[howto-configure-http2-tomcat]]
|
||||
==== HTTP/2 with Tomcat
|
||||
Spring Boot ships by default with Tomcat 9.0.x which supports HTTP/2 out of the box when using JDK 9 or later.
|
||||
Alternatively, HTTP/2 can be used on JDK 8 if the `libtcnative` library and its dependencies are installed on the host operating system.
|
||||
Spring Boot ships by default with Tomcat 9.0.x which supports `h2c` out of the box and `h2` out of the box when using JDK 9 or later.
|
||||
Alternatively, `h2` can be used on JDK 8 if the `libtcnative` library and its dependencies are installed on the host operating system.
|
||||
|
||||
The library directory must be made available, if not already, to the JVM library path.
|
||||
You can do so with a JVM argument such as `-Djava.library.path=/usr/local/opt/tomcat-native/lib`.
|
||||
More on this in the https://tomcat.apache.org/tomcat-9.0-doc/apr.html[official Tomcat documentation].
|
||||
|
||||
Starting Tomcat 9.0.x on JDK 8 without that native support logs the following error:
|
||||
Starting Tomcat 9.0.x on JDK 8 with HTTP/2 and SSL enabled but without that native support logs the following error:
|
||||
|
||||
[indent=0,subs="attributes"]
|
||||
----
|
||||
|
|
@ -626,7 +623,8 @@ This error is not fatal, and the application still starts with HTTP/1.1 SSL supp
|
|||
[[howto-configure-http2-jetty]]
|
||||
==== HTTP/2 with Jetty
|
||||
For HTTP/2 support, Jetty requires the additional `org.eclipse.jetty.http2:http2-server` dependency.
|
||||
Now depending on your deployment, you also need to choose other dependencies:
|
||||
To use `h2c` no other dependencies are required.
|
||||
To use `h2`, you also need to choose one of the following dependencies, depending on your deployment:
|
||||
|
||||
* `org.eclipse.jetty:jetty-alpn-java-server` for applications running on JDK9+
|
||||
* `org.eclipse.jetty:jetty-alpn-openjdk8-server` for applications running on JDK8u252+
|
||||
|
|
@ -637,8 +635,9 @@ Now depending on your deployment, you also need to choose other dependencies:
|
|||
[[howto-configure-http2-netty]]
|
||||
==== HTTP/2 with Reactor Netty
|
||||
The `spring-boot-webflux-starter` is using by default Reactor Netty as a server.
|
||||
Reactor Netty can be configured for HTTP/2 using the JDK support with JDK 9 or later.
|
||||
For JDK 8 environments, or for optimal runtime performance, this server also supports HTTP/2 with native libraries.
|
||||
Reactor Netty supports `h2c` using JDK 8 or later with no additional dependencies.
|
||||
Reactor Netty supports `h2` using the JDK support with JDK 9 or later.
|
||||
For JDK 8 environments, or for optimal runtime performance, this server also supports `h2` with native libraries.
|
||||
To enable that, your application needs to have an additional dependency.
|
||||
|
||||
Spring Boot manages the version for the `io.netty:netty-tcnative-boringssl-static` "uber jar", containing native libraries for all platforms.
|
||||
|
|
@ -648,65 +647,7 @@ Developers can choose to import only the required dependencies using a classifie
|
|||
|
||||
[[howto-configure-http2-undertow]]
|
||||
==== HTTP/2 with Undertow
|
||||
As of Undertow 1.4.0+, HTTP/2 is supported without any additional requirement on JDK8.
|
||||
|
||||
|
||||
|
||||
[[howto-configure-http2-h2c]]
|
||||
==== HTTP/2 Cleartext with supported servers
|
||||
To enable HTTP/2 with cleartext support, you need to leave the configprop:server.http2.enabled[] property set to `false`,
|
||||
and instead apply a customizer specific to your choice of server:
|
||||
|
||||
For Tomcat, we need to add an upgrade protocol:
|
||||
|
||||
[source,java,pending-extract=true,indent=0,subs="verbatim,quotes,attributes"]
|
||||
----
|
||||
@Bean
|
||||
public TomcatConnectorCustomizer connectorCustomizer() {
|
||||
return (connector) -> connector.addUpgradeProtocol(new Http2Protocol());
|
||||
}
|
||||
----
|
||||
|
||||
For Jetty, we need to add a connection factory to the existing connector:
|
||||
|
||||
[source,java,pending-extract=true,indent=0,subs="verbatim,quotes,attributes"]
|
||||
----
|
||||
@Bean
|
||||
public JettyServerCustomizer serverCustomizer() {
|
||||
return (server) -> {
|
||||
HttpConfiguration configuration = new HttpConfiguration();
|
||||
configuration.setSendServerVersion(false);
|
||||
Arrays.stream(server.getConnectors())
|
||||
.filter(connector -> connector instanceof ServerConnector)
|
||||
.map(ServerConnector.class::cast)
|
||||
.forEach(connector -> {
|
||||
connector.addConnectionFactory(new HTTP2CServerConnectionFactory(configuration));
|
||||
});
|
||||
};
|
||||
}
|
||||
----
|
||||
|
||||
For Netty, we need to add `h2c` as a supported protocol:
|
||||
|
||||
[source,java,pending-extract=true,indent=0,subs="verbatim,quotes,attributes"]
|
||||
----
|
||||
@Bean
|
||||
public NettyServerCustomizer serverCustomizer() {
|
||||
return (server) -> server.protocol(HttpProtocol.H2C);
|
||||
}
|
||||
----
|
||||
|
||||
For Undertow, we need to enable the HTTP2 option:
|
||||
|
||||
[source,java,pending-extract=true,indent=0,subs="verbatim,quotes,attributes"]
|
||||
----
|
||||
@Bean
|
||||
public UndertowBuilderCustomizer builderCustomizer() {
|
||||
return (builder) -> {
|
||||
builder.setServerOption(ENABLE_HTTP2, true);
|
||||
};
|
||||
}
|
||||
----
|
||||
As of Undertow 1.4.0+, both `h2` and `h2c` are supported on JDK 8 without any additional dependencies.
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ dependencies {
|
|||
optional("junit:junit")
|
||||
optional("org.apache.commons:commons-dbcp2")
|
||||
optional("org.apache.httpcomponents:httpclient")
|
||||
optional("org.apache.httpcomponents.client5:httpclient5")
|
||||
optional("org.apache.logging.log4j:log4j-api")
|
||||
optional("org.apache.logging.log4j:log4j-core")
|
||||
optional("org.apache.tomcat.embed:tomcat-embed-core")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -17,13 +17,16 @@
|
|||
package org.springframework.boot.web.embedded.jetty;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
|
||||
import org.eclipse.jetty.server.AbstractConnector;
|
||||
import org.eclipse.jetty.server.ConnectionFactory;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
|
|
@ -193,23 +196,26 @@ public class JettyReactiveWebServerFactory extends AbstractReactiveWebServerFact
|
|||
}
|
||||
|
||||
private AbstractConnector createConnector(InetSocketAddress address, Server server) {
|
||||
ServerConnector connector;
|
||||
HttpConfiguration httpConfiguration = new HttpConfiguration();
|
||||
httpConfiguration.setSendServerVersion(false);
|
||||
List<ConnectionFactory> connectionFactories = new ArrayList<>();
|
||||
if (getHttp2() != null && getHttp2().isEnabled()) {
|
||||
connectionFactories.add(new HTTP2ServerConnectionFactory(httpConfiguration));
|
||||
}
|
||||
connectionFactories.add(new HttpConnectionFactory(httpConfiguration));
|
||||
JettyResourceFactory resourceFactory = getResourceFactory();
|
||||
ServerConnector connector;
|
||||
if (resourceFactory != null) {
|
||||
connector = new ServerConnector(server, resourceFactory.getExecutor(), resourceFactory.getScheduler(),
|
||||
resourceFactory.getByteBufferPool(), this.acceptors, this.selectors, new HttpConnectionFactory());
|
||||
resourceFactory.getByteBufferPool(), this.acceptors, this.selectors,
|
||||
connectionFactories.toArray(new ConnectionFactory[0]));
|
||||
}
|
||||
else {
|
||||
connector = new ServerConnector(server, this.acceptors, this.selectors);
|
||||
connector = new ServerConnector(server, this.acceptors, this.selectors,
|
||||
connectionFactories.toArray(new ConnectionFactory[0]));
|
||||
}
|
||||
connector.setHost(address.getHostString());
|
||||
connector.setPort(address.getPort());
|
||||
for (ConnectionFactory connectionFactory : connector.getConnectionFactories()) {
|
||||
if (connectionFactory instanceof HttpConfiguration.ConnectionFactory) {
|
||||
((HttpConfiguration.ConnectionFactory) connectionFactory).getHttpConfiguration()
|
||||
.setSendServerVersion(false);
|
||||
}
|
||||
}
|
||||
return connector;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,11 +34,13 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
|
||||
import org.eclipse.jetty.server.AbstractConnector;
|
||||
import org.eclipse.jetty.server.ConnectionFactory;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.ErrorHandler;
|
||||
|
|
@ -175,15 +177,17 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
|
|||
}
|
||||
|
||||
private AbstractConnector createConnector(InetSocketAddress address, Server server) {
|
||||
ServerConnector connector = new ServerConnector(server, this.acceptors, this.selectors);
|
||||
HttpConfiguration httpConfiguration = new HttpConfiguration();
|
||||
httpConfiguration.setSendServerVersion(false);
|
||||
List<ConnectionFactory> connectionFactories = new ArrayList<>();
|
||||
if (getHttp2() != null && getHttp2().isEnabled()) {
|
||||
connectionFactories.add(new HTTP2ServerConnectionFactory(httpConfiguration));
|
||||
}
|
||||
connectionFactories.add(new HttpConnectionFactory(httpConfiguration));
|
||||
ServerConnector connector = new ServerConnector(server, this.acceptors, this.selectors,
|
||||
connectionFactories.toArray(new ConnectionFactory[0]));
|
||||
connector.setHost(address.getHostString());
|
||||
connector.setPort(address.getPort());
|
||||
for (ConnectionFactory connectionFactory : connector.getConnectionFactories()) {
|
||||
if (connectionFactory instanceof HttpConfiguration.ConnectionFactory) {
|
||||
((HttpConfiguration.ConnectionFactory) connectionFactory).getHttpConfiguration()
|
||||
.setSendServerVersion(false);
|
||||
}
|
||||
}
|
||||
return connector;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -183,10 +183,17 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact
|
|||
}
|
||||
|
||||
private HttpProtocol[] listProtocols() {
|
||||
if (getHttp2() != null && getHttp2().isEnabled() && getSsl() != null && getSsl().isEnabled()) {
|
||||
return new HttpProtocol[] { HttpProtocol.H2, HttpProtocol.HTTP11 };
|
||||
List<HttpProtocol> protocols = new ArrayList<>();
|
||||
protocols.add(HttpProtocol.HTTP11);
|
||||
if (getHttp2() != null && getHttp2().isEnabled()) {
|
||||
if (getSsl() != null && getSsl().isEnabled()) {
|
||||
protocols.add(HttpProtocol.H2);
|
||||
}
|
||||
else {
|
||||
protocols.add(HttpProtocol.H2C);
|
||||
}
|
||||
}
|
||||
return new HttpProtocol[] { HttpProtocol.HTTP11 };
|
||||
return protocols.toArray(new HttpProtocol[0]);
|
||||
}
|
||||
|
||||
private InetSocketAddress getListenAddress() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -190,6 +190,9 @@ public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFac
|
|||
}
|
||||
// Don't bind to the socket prematurely if ApplicationContext is slow to start
|
||||
connector.setProperty("bindOnInit", "false");
|
||||
if (getHttp2() != null && getHttp2().isEnabled()) {
|
||||
connector.addUpgradeProtocol(new Http2Protocol());
|
||||
}
|
||||
if (getSsl() != null && getSsl().isEnabled()) {
|
||||
customizeSsl(connector);
|
||||
}
|
||||
|
|
@ -214,9 +217,6 @@ public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFac
|
|||
|
||||
private void customizeSsl(Connector connector) {
|
||||
new SslConnectorCustomizer(getSsl(), getSslStoreProvider()).customize(connector);
|
||||
if (getHttp2() != null && getHttp2().isEnabled()) {
|
||||
connector.addUpgradeProtocol(new Http2Protocol());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -322,6 +322,9 @@ public class TomcatServletWebServerFactory extends AbstractServletWebServerFacto
|
|||
}
|
||||
// Don't bind to the socket prematurely if ApplicationContext is slow to start
|
||||
connector.setProperty("bindOnInit", "false");
|
||||
if (getHttp2() != null && getHttp2().isEnabled()) {
|
||||
connector.addUpgradeProtocol(new Http2Protocol());
|
||||
}
|
||||
if (getSsl() != null && getSsl().isEnabled()) {
|
||||
customizeSsl(connector);
|
||||
}
|
||||
|
|
@ -346,9 +349,6 @@ public class TomcatServletWebServerFactory extends AbstractServletWebServerFacto
|
|||
|
||||
private void customizeSsl(Connector connector) {
|
||||
new SslConnectorCustomizer(getSsl(), getSslStoreProvider()).customize(connector);
|
||||
if (getHttp2() != null && getHttp2().isEnabled()) {
|
||||
connector.addUpgradeProtocol(new Http2Protocol());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -158,12 +158,12 @@ class UndertowWebServerFactoryDelegate {
|
|||
if (this.directBuffers != null) {
|
||||
builder.setDirectBuffers(this.directBuffers);
|
||||
}
|
||||
Http2 http2 = factory.getHttp2();
|
||||
if (http2 != null) {
|
||||
builder.setServerOption(UndertowOptions.ENABLE_HTTP2, http2.isEnabled());
|
||||
}
|
||||
if (ssl != null && ssl.isEnabled()) {
|
||||
new SslBuilderCustomizer(factory.getPort(), address, ssl, factory.getSslStoreProvider()).customize(builder);
|
||||
Http2 http2 = factory.getHttp2();
|
||||
if (http2 != null) {
|
||||
builder.setServerOption(UndertowOptions.ENABLE_HTTP2, http2.isEnabled());
|
||||
}
|
||||
}
|
||||
else {
|
||||
builder.addHttpListener(port, (address != null) ? address.getHostAddress() : "0.0.0.0");
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.boot.web.reactive.server;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
|
@ -28,6 +29,7 @@ import java.util.concurrent.BlockingQueue;
|
|||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
|
|
@ -39,6 +41,13 @@ import io.netty.handler.codec.http.HttpHeaderNames;
|
|||
import io.netty.handler.codec.http.HttpResponse;
|
||||
import io.netty.handler.ssl.SslProvider;
|
||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
|
||||
import org.apache.hc.client5.http.async.methods.SimpleHttpRequests;
|
||||
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
|
||||
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
|
||||
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
|
||||
import org.apache.hc.core5.concurrent.FutureCallback;
|
||||
import org.apache.hc.core5.http.ContentType;
|
||||
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
|
@ -52,6 +61,7 @@ import reactor.test.StepVerifier;
|
|||
|
||||
import org.springframework.boot.web.server.Compression;
|
||||
import org.springframework.boot.web.server.GracefulShutdownResult;
|
||||
import org.springframework.boot.web.server.Http2;
|
||||
import org.springframework.boot.web.server.Shutdown;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.server.WebServer;
|
||||
|
|
@ -448,6 +458,39 @@ public abstract class AbstractReactiveWebServerFactoryTests {
|
|||
blockingHandler.completeOne();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenHttp2IsEnabledAndSslIsDisabledThenH2cCanBeUsed()
|
||||
throws InterruptedException, ExecutionException, IOException {
|
||||
AbstractReactiveWebServerFactory factory = getFactory();
|
||||
Http2 http2 = new Http2();
|
||||
http2.setEnabled(true);
|
||||
factory.setHttp2(http2);
|
||||
this.webServer = factory.getWebServer(new EchoHandler());
|
||||
this.webServer.start();
|
||||
try (CloseableHttpAsyncClient http2Client = HttpAsyncClients.createHttp2Default()) {
|
||||
http2Client.start();
|
||||
SimpleHttpRequest request = SimpleHttpRequests.post("http://localhost:" + this.webServer.getPort());
|
||||
request.setBody("Hello World", ContentType.TEXT_PLAIN);
|
||||
SimpleHttpResponse response = http2Client.execute(request, new FutureCallback<SimpleHttpResponse>() {
|
||||
|
||||
@Override
|
||||
public void failed(Exception ex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(SimpleHttpResponse result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelled() {
|
||||
}
|
||||
|
||||
}).get();
|
||||
assertThat(response.getCode() == HttpStatus.OK.value());
|
||||
assertThat(response.getBodyText()).isEqualTo("Hello World");
|
||||
}
|
||||
}
|
||||
|
||||
protected WebClient prepareCompressionTest() {
|
||||
Compression compression = new Compression();
|
||||
compression.setEnabled(true);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import java.util.concurrent.BlockingQueue;
|
|||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.RunnableFuture;
|
||||
|
|
@ -78,6 +79,12 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
|
||||
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
|
||||
import org.apache.hc.client5.http.async.methods.SimpleHttpRequests;
|
||||
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
|
||||
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
|
||||
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
|
||||
import org.apache.hc.core5.concurrent.FutureCallback;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.InputStreamFactory;
|
||||
|
|
@ -112,6 +119,7 @@ import org.springframework.boot.testsupport.web.servlet.ExampleServlet;
|
|||
import org.springframework.boot.web.server.Compression;
|
||||
import org.springframework.boot.web.server.ErrorPage;
|
||||
import org.springframework.boot.web.server.GracefulShutdownResult;
|
||||
import org.springframework.boot.web.server.Http2;
|
||||
import org.springframework.boot.web.server.MimeMappings;
|
||||
import org.springframework.boot.web.server.PortInUseException;
|
||||
import org.springframework.boot.web.server.Shutdown;
|
||||
|
|
@ -1121,6 +1129,39 @@ public abstract class AbstractServletWebServerFactoryTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenHttp2IsEnabledAndSslIsDisabledThenH2cCanBeUsed()
|
||||
throws InterruptedException, ExecutionException, IOException {
|
||||
AbstractServletWebServerFactory factory = getFactory();
|
||||
Http2 http2 = new Http2();
|
||||
http2.setEnabled(true);
|
||||
factory.setHttp2(http2);
|
||||
this.webServer = factory.getWebServer(exampleServletRegistration());
|
||||
this.webServer.start();
|
||||
try (CloseableHttpAsyncClient http2Client = HttpAsyncClients.createHttp2Default()) {
|
||||
http2Client.start();
|
||||
SimpleHttpRequest request = SimpleHttpRequests
|
||||
.get("http://localhost:" + this.webServer.getPort() + "/hello");
|
||||
SimpleHttpResponse response = http2Client.execute(request, new FutureCallback<SimpleHttpResponse>() {
|
||||
|
||||
@Override
|
||||
public void failed(Exception ex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(SimpleHttpResponse result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelled() {
|
||||
}
|
||||
|
||||
}).get();
|
||||
assertThat(response.getCode()).isEqualTo(HttpStatus.OK.value());
|
||||
assertThat(response.getBodyText()).isEqualTo("Hello World");
|
||||
}
|
||||
}
|
||||
|
||||
protected Future<Object> initiateGetRequest(int port, String path) {
|
||||
return initiateGetRequest(HttpClients.createMinimal(), port, path);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue