Merge branch '2.1.x'
Closes gh-18618
This commit is contained in:
@@ -118,6 +118,8 @@ public class ServerProperties {
|
||||
|
||||
private final Jetty jetty = new Jetty();
|
||||
|
||||
private final Netty netty = new Netty();
|
||||
|
||||
private final Undertow undertow = new Undertow();
|
||||
|
||||
public Integer getPort() {
|
||||
@@ -163,10 +165,14 @@ public class ServerProperties {
|
||||
this.maxHttpHeaderSize = maxHttpHeaderSize;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@DeprecatedConfigurationProperty(
|
||||
reason = "Each server behaves differently. Use server specific properties instead.")
|
||||
public Duration getConnectionTimeout() {
|
||||
return this.connectionTimeout;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setConnectionTimeout(Duration connectionTimeout) {
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
}
|
||||
@@ -203,6 +209,10 @@ public class ServerProperties {
|
||||
return this.jetty;
|
||||
}
|
||||
|
||||
public Netty getNetty() {
|
||||
return this.netty;
|
||||
}
|
||||
|
||||
public Undertow getUndertow() {
|
||||
return this.undertow;
|
||||
}
|
||||
@@ -414,6 +424,12 @@ public class ServerProperties {
|
||||
*/
|
||||
private List<Character> relaxedQueryChars = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Amount of time the connector will wait, after accepting a connection, for the
|
||||
* request URI line to be presented.
|
||||
*/
|
||||
private Duration connectionTimeout;
|
||||
|
||||
/**
|
||||
* Static resource configuration.
|
||||
*/
|
||||
@@ -596,6 +612,14 @@ public class ServerProperties {
|
||||
this.relaxedQueryChars = relaxedQueryChars;
|
||||
}
|
||||
|
||||
public Duration getConnectionTimeout() {
|
||||
return this.connectionTimeout;
|
||||
}
|
||||
|
||||
public void setConnectionTimeout(Duration connectionTimeout) {
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
}
|
||||
|
||||
public Resource getResource() {
|
||||
return this.resource;
|
||||
}
|
||||
@@ -934,6 +958,11 @@ public class ServerProperties {
|
||||
*/
|
||||
private Duration idleTimeout = Duration.ofMillis(60000);
|
||||
|
||||
/**
|
||||
* Time that the connection can be idle before it is closed.
|
||||
*/
|
||||
private Duration connectionIdleTimeout;
|
||||
|
||||
public Accesslog getAccesslog() {
|
||||
return this.accesslog;
|
||||
}
|
||||
@@ -986,6 +1015,14 @@ public class ServerProperties {
|
||||
return this.idleTimeout;
|
||||
}
|
||||
|
||||
public Duration getConnectionIdleTimeout() {
|
||||
return this.connectionIdleTimeout;
|
||||
}
|
||||
|
||||
public void setConnectionIdleTimeout(Duration connectionIdleTimeout) {
|
||||
this.connectionIdleTimeout = connectionIdleTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Jetty access log properties.
|
||||
*/
|
||||
@@ -1118,6 +1155,26 @@ public class ServerProperties {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Netty properties.
|
||||
*/
|
||||
public static class Netty {
|
||||
|
||||
/**
|
||||
* Connection timeout of the Netty channel.
|
||||
*/
|
||||
private Duration connectionTimeout;
|
||||
|
||||
public Duration getConnectionTimeout() {
|
||||
return this.connectionTimeout;
|
||||
}
|
||||
|
||||
public void setConnectionTimeout(Duration connectionTimeout) {
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Undertow properties.
|
||||
*/
|
||||
@@ -1200,6 +1257,12 @@ public class ServerProperties {
|
||||
*/
|
||||
private boolean alwaysSetKeepAlive = true;
|
||||
|
||||
/**
|
||||
* Amount of time a connection can sit idle without processing a request, before
|
||||
* it is closed by the server.
|
||||
*/
|
||||
private Duration noRequestTimeout;
|
||||
|
||||
private final Accesslog accesslog = new Accesslog();
|
||||
|
||||
private final Options options = new Options();
|
||||
@@ -1308,6 +1371,14 @@ public class ServerProperties {
|
||||
this.alwaysSetKeepAlive = alwaysSetKeepAlive;
|
||||
}
|
||||
|
||||
public Duration getNoRequestTimeout() {
|
||||
return this.noRequestTimeout;
|
||||
}
|
||||
|
||||
public void setNoRequestTimeout(Duration noRequestTimeout) {
|
||||
this.noRequestTimeout = noRequestTimeout;
|
||||
}
|
||||
|
||||
public Accesslog getAccesslog() {
|
||||
return this.accesslog;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,9 @@ public class JettyWebServerFactoryCustomizer
|
||||
propertyMapper.from(jettyProperties::getIdleTimeout).whenNonNull().asInt(Duration::toMillis).to(
|
||||
(idleTimeout) -> customizeThreadPool(factory, (threadPool) -> threadPool.setIdleTimeout(idleTimeout)));
|
||||
propertyMapper.from(properties::getConnectionTimeout).whenNonNull()
|
||||
.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
|
||||
.to((connectionTimeout) -> customizeIdleTimeout(factory, connectionTimeout));
|
||||
propertyMapper.from(jettyProperties::getConnectionIdleTimeout).whenNonNull()
|
||||
.to((idleTimeout) -> customizeIdleTimeout(factory, idleTimeout));
|
||||
propertyMapper.from(jettyProperties::getAccesslog).when(ServerProperties.Jetty.Accesslog::isEnabled)
|
||||
.to((accesslog) -> customizeAccessLog(factory, accesslog));
|
||||
}
|
||||
@@ -106,7 +108,7 @@ public class JettyWebServerFactoryCustomizer
|
||||
return this.serverProperties.getForwardHeadersStrategy().equals(ServerProperties.ForwardHeadersStrategy.NATIVE);
|
||||
}
|
||||
|
||||
private void customizeConnectionTimeout(ConfigurableJettyWebServerFactory factory, Duration connectionTimeout) {
|
||||
private void customizeIdleTimeout(ConfigurableJettyWebServerFactory factory, Duration connectionTimeout) {
|
||||
factory.addServerCustomizers((server) -> {
|
||||
for (org.eclipse.jetty.server.Connector connector : server.getConnectors()) {
|
||||
if (connector instanceof AbstractConnector) {
|
||||
|
||||
@@ -61,6 +61,9 @@ public class NettyWebServerFactoryCustomizer
|
||||
propertyMapper.from(this.serverProperties::getMaxHttpHeaderSize)
|
||||
.to((maxHttpRequestHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpRequestHeaderSize));
|
||||
propertyMapper.from(this.serverProperties::getConnectionTimeout)
|
||||
.to((connectionTimeout) -> customizeGenericConnectionTimeout(factory, connectionTimeout));
|
||||
ServerProperties.Netty nettyProperties = this.serverProperties.getNetty();
|
||||
propertyMapper.from(nettyProperties::getConnectionTimeout).whenNonNull()
|
||||
.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
|
||||
}
|
||||
|
||||
@@ -77,7 +80,7 @@ public class NettyWebServerFactoryCustomizer
|
||||
(httpRequestDecoderSpec) -> httpRequestDecoderSpec.maxHeaderSize((int) maxHttpHeaderSize.toBytes())));
|
||||
}
|
||||
|
||||
private void customizeConnectionTimeout(NettyReactiveWebServerFactory factory, Duration connectionTimeout) {
|
||||
private void customizeGenericConnectionTimeout(NettyReactiveWebServerFactory factory, Duration connectionTimeout) {
|
||||
if (!connectionTimeout.isZero()) {
|
||||
long timeoutMillis = connectionTimeout.isNegative() ? 0 : connectionTimeout.toMillis();
|
||||
factory.addServerCustomizers((httpServer) -> httpServer.tcpConfiguration((tcpServer) -> tcpServer
|
||||
@@ -85,4 +88,9 @@ public class NettyWebServerFactoryCustomizer
|
||||
}
|
||||
}
|
||||
|
||||
private void customizeConnectionTimeout(NettyReactiveWebServerFactory factory, Duration connectionTimeout) {
|
||||
factory.addServerCustomizers((httpServer) -> httpServer.tcpConfiguration((tcpServer) -> tcpServer
|
||||
.selectorOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) connectionTimeout.toMillis())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -99,6 +99,8 @@ public class TomcatWebServerFactoryCustomizer
|
||||
propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull().to(factory::setUriEncoding);
|
||||
propertyMapper.from(properties::getConnectionTimeout).whenNonNull()
|
||||
.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
|
||||
propertyMapper.from(tomcatProperties::getConnectionTimeout).whenNonNull()
|
||||
.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
|
||||
propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive)
|
||||
.to((maxConnections) -> customizeMaxConnections(factory, maxConnections));
|
||||
propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive)
|
||||
|
||||
@@ -101,6 +101,8 @@ public class UndertowWebServerFactoryCustomizer
|
||||
map.from(properties::isDecodeUrl).to(options.server(UndertowOptions.DECODE_URL));
|
||||
map.from(properties::getUrlCharset).as(Charset::name).to(options.server(UndertowOptions.URL_CHARSET));
|
||||
map.from(properties::isAlwaysSetKeepAlive).to(options.server(UndertowOptions.ALWAYS_SET_KEEP_ALIVE));
|
||||
map.from(properties::getNoRequestTimeout).asInt(Duration::toMillis)
|
||||
.to(options.server(UndertowOptions.NO_REQUEST_TIMEOUT));
|
||||
map.from(properties.getOptions()::getServer).to(options.forEach(options::server));
|
||||
map.from(properties.getOptions()::getSocket).to(options.forEach(options::socket));
|
||||
}
|
||||
|
||||
@@ -19,8 +19,11 @@ package org.springframework.boot.autoconfigure.web.embedded;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jetty.server.AbstractConnector;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.CustomRequestLog;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
@@ -182,6 +185,23 @@ class JettyWebServerFactoryCustomizerTests {
|
||||
assertThat(requestHeaderSizes).containsOnly(8192);
|
||||
}
|
||||
|
||||
@Test
|
||||
void customIdleTimeout() {
|
||||
bind("server.jetty.idle-timeout=60s");
|
||||
JettyWebServer server = customizeAndGetServer();
|
||||
List<Long> timeouts = connectorsIdleTimeouts(server);
|
||||
assertThat(timeouts).containsOnly(60000L);
|
||||
}
|
||||
|
||||
private List<Long> connectorsIdleTimeouts(JettyWebServer server) {
|
||||
// Start (and directly stop) server to have connectors available
|
||||
server.start();
|
||||
server.stop();
|
||||
return Arrays.stream(server.getServer().getConnectors())
|
||||
.filter((connector) -> connector instanceof AbstractConnector).map(Connector::getIdleTimeout)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<Integer> getRequestHeaderSizes(JettyWebServer server) {
|
||||
List<Integer> requestHeaderSizes = new ArrayList<>();
|
||||
// Start (and directly stop) server to have connectors available
|
||||
|
||||
@@ -93,21 +93,29 @@ class NettyWebServerFactoryCustomizerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void setConnectionTimeoutAsZero() {
|
||||
setupConnectionTimeout(Duration.ZERO);
|
||||
void setServerConnectionTimeoutAsZero() {
|
||||
setupServerConnectionTimeout(Duration.ZERO);
|
||||
NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);
|
||||
this.customizer.customize(factory);
|
||||
verifyConnectionTimeout(factory, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void setConnectionTimeoutAsMinusOne() {
|
||||
setupConnectionTimeout(Duration.ofNanos(-1));
|
||||
void setServerConnectionTimeoutAsMinusOne() {
|
||||
setupServerConnectionTimeout(Duration.ofNanos(-1));
|
||||
NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);
|
||||
this.customizer.customize(factory);
|
||||
verifyConnectionTimeout(factory, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void setServerConnectionTimeout() {
|
||||
setupServerConnectionTimeout(Duration.ofSeconds(1));
|
||||
NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);
|
||||
this.customizer.customize(factory);
|
||||
verifyConnectionTimeout(factory, 1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
void setConnectionTimeout() {
|
||||
setupConnectionTimeout(Duration.ofSeconds(1));
|
||||
@@ -131,10 +139,16 @@ class NettyWebServerFactoryCustomizerTests {
|
||||
assertThat(options).containsEntry(ChannelOption.CONNECT_TIMEOUT_MILLIS, expected);
|
||||
}
|
||||
|
||||
private void setupConnectionTimeout(Duration connectionTimeout) {
|
||||
private void setupServerConnectionTimeout(Duration connectionTimeout) {
|
||||
this.serverProperties.setUseForwardHeaders(null);
|
||||
this.serverProperties.setMaxHttpHeaderSize(null);
|
||||
this.serverProperties.setConnectionTimeout(connectionTimeout);
|
||||
}
|
||||
|
||||
private void setupConnectionTimeout(Duration connectionTimeout) {
|
||||
this.serverProperties.setUseForwardHeaders(null);
|
||||
this.serverProperties.setMaxHttpHeaderSize(null);
|
||||
this.serverProperties.getNetty().setConnectionTimeout(connectionTimeout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -288,6 +288,14 @@ class TomcatWebServerFactoryCustomizerTests {
|
||||
assertThat(this.serverProperties.getTomcat().getMinSpareThreads()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
void customConnectionTimeout() {
|
||||
bind("server.tomcat.connection-timeout=30s");
|
||||
customizeAndRunServer((server) -> assertThat(
|
||||
((AbstractProtocol<?>) server.getTomcat().getConnector().getProtocolHandler()).getConnectionTimeout())
|
||||
.isEqualTo(30000));
|
||||
}
|
||||
|
||||
@Test
|
||||
void accessLogBufferingCanBeDisabled() {
|
||||
bind("server.tomcat.accesslog.enabled=true", "server.tomcat.accesslog.buffered=false");
|
||||
|
||||
@@ -110,8 +110,8 @@ class UndertowWebServerFactoryCustomizerTests {
|
||||
|
||||
@Test
|
||||
void customConnectionTimeout() {
|
||||
bind("server.connectionTimeout=100");
|
||||
assertThat(boundServerOption(UndertowOptions.NO_REQUEST_TIMEOUT)).isEqualTo(100);
|
||||
bind("server.undertow.no-request-timeout=1m");
|
||||
assertThat(boundServerOption(UndertowOptions.NO_REQUEST_TIMEOUT)).isEqualTo(60000);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user