Skip to content

Commit 7113d41

Browse files
committed
Merge branch '2.1.x'
Closes gh-18618
2 parents 6440121 + e4fa9ce commit 7113d41

File tree

9 files changed

+137
-10
lines changed

9 files changed

+137
-10
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ public class ServerProperties {
118118

119119
private final Jetty jetty = new Jetty();
120120

121+
private final Netty netty = new Netty();
122+
121123
private final Undertow undertow = new Undertow();
122124

123125
public Integer getPort() {
@@ -163,10 +165,14 @@ public void setMaxHttpHeaderSize(DataSize maxHttpHeaderSize) {
163165
this.maxHttpHeaderSize = maxHttpHeaderSize;
164166
}
165167

168+
@Deprecated
169+
@DeprecatedConfigurationProperty(
170+
reason = "Each server behaves differently. Use server specific properties instead.")
166171
public Duration getConnectionTimeout() {
167172
return this.connectionTimeout;
168173
}
169174

175+
@Deprecated
170176
public void setConnectionTimeout(Duration connectionTimeout) {
171177
this.connectionTimeout = connectionTimeout;
172178
}
@@ -203,6 +209,10 @@ public Jetty getJetty() {
203209
return this.jetty;
204210
}
205211

212+
public Netty getNetty() {
213+
return this.netty;
214+
}
215+
206216
public Undertow getUndertow() {
207217
return this.undertow;
208218
}
@@ -414,6 +424,12 @@ public static class Tomcat {
414424
*/
415425
private List<Character> relaxedQueryChars = new ArrayList<>();
416426

427+
/**
428+
* Amount of time the connector will wait, after accepting a connection, for the
429+
* request URI line to be presented.
430+
*/
431+
private Duration connectionTimeout;
432+
417433
/**
418434
* Static resource configuration.
419435
*/
@@ -596,6 +612,14 @@ public void setRelaxedQueryChars(List<Character> relaxedQueryChars) {
596612
this.relaxedQueryChars = relaxedQueryChars;
597613
}
598614

615+
public Duration getConnectionTimeout() {
616+
return this.connectionTimeout;
617+
}
618+
619+
public void setConnectionTimeout(Duration connectionTimeout) {
620+
this.connectionTimeout = connectionTimeout;
621+
}
622+
599623
public Resource getResource() {
600624
return this.resource;
601625
}
@@ -934,6 +958,11 @@ public static class Jetty {
934958
*/
935959
private Duration idleTimeout = Duration.ofMillis(60000);
936960

961+
/**
962+
* Time that the connection can be idle before it is closed.
963+
*/
964+
private Duration connectionIdleTimeout;
965+
937966
public Accesslog getAccesslog() {
938967
return this.accesslog;
939968
}
@@ -986,6 +1015,14 @@ public Duration getIdleTimeout() {
9861015
return this.idleTimeout;
9871016
}
9881017

1018+
public Duration getConnectionIdleTimeout() {
1019+
return this.connectionIdleTimeout;
1020+
}
1021+
1022+
public void setConnectionIdleTimeout(Duration connectionIdleTimeout) {
1023+
this.connectionIdleTimeout = connectionIdleTimeout;
1024+
}
1025+
9891026
/**
9901027
* Jetty access log properties.
9911028
*/
@@ -1118,6 +1155,26 @@ public enum FORMAT {
11181155

11191156
}
11201157

1158+
/**
1159+
* Netty properties.
1160+
*/
1161+
public static class Netty {
1162+
1163+
/**
1164+
* Connection timeout of the Netty channel.
1165+
*/
1166+
private Duration connectionTimeout;
1167+
1168+
public Duration getConnectionTimeout() {
1169+
return this.connectionTimeout;
1170+
}
1171+
1172+
public void setConnectionTimeout(Duration connectionTimeout) {
1173+
this.connectionTimeout = connectionTimeout;
1174+
}
1175+
1176+
}
1177+
11211178
/**
11221179
* Undertow properties.
11231180
*/
@@ -1200,6 +1257,12 @@ public static class Undertow {
12001257
*/
12011258
private boolean alwaysSetKeepAlive = true;
12021259

1260+
/**
1261+
* Amount of time a connection can sit idle without processing a request, before
1262+
* it is closed by the server.
1263+
*/
1264+
private Duration noRequestTimeout;
1265+
12031266
private final Accesslog accesslog = new Accesslog();
12041267

12051268
private final Options options = new Options();
@@ -1308,6 +1371,14 @@ public void setAlwaysSetKeepAlive(boolean alwaysSetKeepAlive) {
13081371
this.alwaysSetKeepAlive = alwaysSetKeepAlive;
13091372
}
13101373

1374+
public Duration getNoRequestTimeout() {
1375+
return this.noRequestTimeout;
1376+
}
1377+
1378+
public void setNoRequestTimeout(Duration noRequestTimeout) {
1379+
this.noRequestTimeout = noRequestTimeout;
1380+
}
1381+
13111382
public Accesslog getAccesslog() {
13121383
return this.accesslog;
13131384
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizer.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ public void customize(ConfigurableJettyWebServerFactory factory) {
8989
propertyMapper.from(jettyProperties::getIdleTimeout).whenNonNull().asInt(Duration::toMillis).to(
9090
(idleTimeout) -> customizeThreadPool(factory, (threadPool) -> threadPool.setIdleTimeout(idleTimeout)));
9191
propertyMapper.from(properties::getConnectionTimeout).whenNonNull()
92-
.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
92+
.to((connectionTimeout) -> customizeIdleTimeout(factory, connectionTimeout));
93+
propertyMapper.from(jettyProperties::getConnectionIdleTimeout).whenNonNull()
94+
.to((idleTimeout) -> customizeIdleTimeout(factory, idleTimeout));
9395
propertyMapper.from(jettyProperties::getAccesslog).when(ServerProperties.Jetty.Accesslog::isEnabled)
9496
.to((accesslog) -> customizeAccessLog(factory, accesslog));
9597
}
@@ -106,7 +108,7 @@ private boolean getOrDeduceUseForwardHeaders() {
106108
return this.serverProperties.getForwardHeadersStrategy().equals(ServerProperties.ForwardHeadersStrategy.NATIVE);
107109
}
108110

109-
private void customizeConnectionTimeout(ConfigurableJettyWebServerFactory factory, Duration connectionTimeout) {
111+
private void customizeIdleTimeout(ConfigurableJettyWebServerFactory factory, Duration connectionTimeout) {
110112
factory.addServerCustomizers((server) -> {
111113
for (org.eclipse.jetty.server.Connector connector : server.getConnectors()) {
112114
if (connector instanceof AbstractConnector) {

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ public void customize(NettyReactiveWebServerFactory factory) {
6161
propertyMapper.from(this.serverProperties::getMaxHttpHeaderSize)
6262
.to((maxHttpRequestHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpRequestHeaderSize));
6363
propertyMapper.from(this.serverProperties::getConnectionTimeout)
64+
.to((connectionTimeout) -> customizeGenericConnectionTimeout(factory, connectionTimeout));
65+
ServerProperties.Netty nettyProperties = this.serverProperties.getNetty();
66+
propertyMapper.from(nettyProperties::getConnectionTimeout).whenNonNull()
6467
.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
6568
}
6669

@@ -77,12 +80,17 @@ private void customizeMaxHttpHeaderSize(NettyReactiveWebServerFactory factory, D
7780
(httpRequestDecoderSpec) -> httpRequestDecoderSpec.maxHeaderSize((int) maxHttpHeaderSize.toBytes())));
7881
}
7982

80-
private void customizeConnectionTimeout(NettyReactiveWebServerFactory factory, Duration connectionTimeout) {
83+
private void customizeGenericConnectionTimeout(NettyReactiveWebServerFactory factory, Duration connectionTimeout) {
8184
if (!connectionTimeout.isZero()) {
8285
long timeoutMillis = connectionTimeout.isNegative() ? 0 : connectionTimeout.toMillis();
8386
factory.addServerCustomizers((httpServer) -> httpServer.tcpConfiguration((tcpServer) -> tcpServer
8487
.selectorOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) timeoutMillis)));
8588
}
8689
}
8790

91+
private void customizeConnectionTimeout(NettyReactiveWebServerFactory factory, Duration connectionTimeout) {
92+
factory.addServerCustomizers((httpServer) -> httpServer.tcpConfiguration((tcpServer) -> tcpServer
93+
.selectorOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) connectionTimeout.toMillis())));
94+
}
95+
8896
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ public void customize(ConfigurableTomcatWebServerFactory factory) {
9999
propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull().to(factory::setUriEncoding);
100100
propertyMapper.from(properties::getConnectionTimeout).whenNonNull()
101101
.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
102+
propertyMapper.from(tomcatProperties::getConnectionTimeout).whenNonNull()
103+
.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
102104
propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive)
103105
.to((maxConnections) -> customizeMaxConnections(factory, maxConnections));
104106
propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive)

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ private void mapUndertowProperties(ConfigurableUndertowWebServerFactory factory,
101101
map.from(properties::isDecodeUrl).to(options.server(UndertowOptions.DECODE_URL));
102102
map.from(properties::getUrlCharset).as(Charset::name).to(options.server(UndertowOptions.URL_CHARSET));
103103
map.from(properties::isAlwaysSetKeepAlive).to(options.server(UndertowOptions.ALWAYS_SET_KEEP_ALIVE));
104+
map.from(properties::getNoRequestTimeout).asInt(Duration::toMillis)
105+
.to(options.server(UndertowOptions.NO_REQUEST_TIMEOUT));
104106
map.from(properties.getOptions()::getServer).to(options.forEach(options::server));
105107
map.from(properties.getOptions()::getSocket).to(options.forEach(options::socket));
106108
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/JettyWebServerFactoryCustomizerTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
import java.io.File;
2020
import java.io.IOException;
2121
import java.util.ArrayList;
22+
import java.util.Arrays;
2223
import java.util.List;
24+
import java.util.stream.Collectors;
2325

26+
import org.eclipse.jetty.server.AbstractConnector;
2427
import org.eclipse.jetty.server.Connector;
2528
import org.eclipse.jetty.server.CustomRequestLog;
2629
import org.eclipse.jetty.server.HttpConfiguration;
@@ -182,6 +185,23 @@ void customMaxHttpHeaderSizeIgnoredIfZero() {
182185
assertThat(requestHeaderSizes).containsOnly(8192);
183186
}
184187

188+
@Test
189+
void customIdleTimeout() {
190+
bind("server.jetty.idle-timeout=60s");
191+
JettyWebServer server = customizeAndGetServer();
192+
List<Long> timeouts = connectorsIdleTimeouts(server);
193+
assertThat(timeouts).containsOnly(60000L);
194+
}
195+
196+
private List<Long> connectorsIdleTimeouts(JettyWebServer server) {
197+
// Start (and directly stop) server to have connectors available
198+
server.start();
199+
server.stop();
200+
return Arrays.stream(server.getServer().getConnectors())
201+
.filter((connector) -> connector instanceof AbstractConnector).map(Connector::getIdleTimeout)
202+
.collect(Collectors.toList());
203+
}
204+
185205
private List<Integer> getRequestHeaderSizes(JettyWebServer server) {
186206
List<Integer> requestHeaderSizes = new ArrayList<>();
187207
// Start (and directly stop) server to have connectors available

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,21 +93,29 @@ void setUseForwardHeaders() {
9393
}
9494

9595
@Test
96-
void setConnectionTimeoutAsZero() {
97-
setupConnectionTimeout(Duration.ZERO);
96+
void setServerConnectionTimeoutAsZero() {
97+
setupServerConnectionTimeout(Duration.ZERO);
9898
NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);
9999
this.customizer.customize(factory);
100100
verifyConnectionTimeout(factory, null);
101101
}
102102

103103
@Test
104-
void setConnectionTimeoutAsMinusOne() {
105-
setupConnectionTimeout(Duration.ofNanos(-1));
104+
void setServerConnectionTimeoutAsMinusOne() {
105+
setupServerConnectionTimeout(Duration.ofNanos(-1));
106106
NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);
107107
this.customizer.customize(factory);
108108
verifyConnectionTimeout(factory, 0);
109109
}
110110

111+
@Test
112+
void setServerConnectionTimeout() {
113+
setupServerConnectionTimeout(Duration.ofSeconds(1));
114+
NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);
115+
this.customizer.customize(factory);
116+
verifyConnectionTimeout(factory, 1000);
117+
}
118+
111119
@Test
112120
void setConnectionTimeout() {
113121
setupConnectionTimeout(Duration.ofSeconds(1));
@@ -131,10 +139,16 @@ private void verifyConnectionTimeout(NettyReactiveWebServerFactory factory, Inte
131139
assertThat(options).containsEntry(ChannelOption.CONNECT_TIMEOUT_MILLIS, expected);
132140
}
133141

134-
private void setupConnectionTimeout(Duration connectionTimeout) {
142+
private void setupServerConnectionTimeout(Duration connectionTimeout) {
135143
this.serverProperties.setUseForwardHeaders(null);
136144
this.serverProperties.setMaxHttpHeaderSize(null);
137145
this.serverProperties.setConnectionTimeout(connectionTimeout);
138146
}
139147

148+
private void setupConnectionTimeout(Duration connectionTimeout) {
149+
this.serverProperties.setUseForwardHeaders(null);
150+
this.serverProperties.setMaxHttpHeaderSize(null);
151+
this.serverProperties.getNetty().setConnectionTimeout(connectionTimeout);
152+
}
153+
140154
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,14 @@ void testCustomizeMinSpareThreads() {
288288
assertThat(this.serverProperties.getTomcat().getMinSpareThreads()).isEqualTo(10);
289289
}
290290

291+
@Test
292+
void customConnectionTimeout() {
293+
bind("server.tomcat.connection-timeout=30s");
294+
customizeAndRunServer((server) -> assertThat(
295+
((AbstractProtocol<?>) server.getTomcat().getConnector().getProtocolHandler()).getConnectionTimeout())
296+
.isEqualTo(30000));
297+
}
298+
291299
@Test
292300
void accessLogBufferingCanBeDisabled() {
293301
bind("server.tomcat.accesslog.enabled=true", "server.tomcat.accesslog.buffered=false");

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/UndertowWebServerFactoryCustomizerTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ void customMaxHttpPostSize() {
110110

111111
@Test
112112
void customConnectionTimeout() {
113-
bind("server.connectionTimeout=100");
114-
assertThat(boundServerOption(UndertowOptions.NO_REQUEST_TIMEOUT)).isEqualTo(100);
113+
bind("server.undertow.no-request-timeout=1m");
114+
assertThat(boundServerOption(UndertowOptions.NO_REQUEST_TIMEOUT)).isEqualTo(60000);
115115
}
116116

117117
@Test

0 commit comments

Comments
 (0)