diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 367934c40e..ed10ef42ee 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -68,6 +68,7 @@ import org.springframework.util.unit.DataSize; * @author Victor Mandujano * @author Chris Bono * @author Parviz Rozikov + * @author Leo Li * @since 1.0.0 */ @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) @@ -1351,6 +1352,11 @@ public class ServerProperties { */ private Duration idleTimeout; + /** + * Maximum number of requests that can be made per connection. + */ + private int maxKeepAliveRequests = -1; + public Duration getConnectionTimeout() { return this.connectionTimeout; } @@ -1407,6 +1413,14 @@ public class ServerProperties { this.idleTimeout = idleTimeout; } + public int getMaxKeepAliveRequests() { + return this.maxKeepAliveRequests; + } + + public void setMaxKeepAliveRequests(int maxKeepAliveRequests) { + this.maxKeepAliveRequests = maxKeepAliveRequests; + } + } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java index 5309f5ee1e..51af7a45a9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizer.java @@ -34,6 +34,7 @@ import org.springframework.core.env.Environment; * @author Brian Clozel * @author Chentao Qu * @author Artsiom Yudovin + * @author Leo Li * @since 2.1.0 */ public class NettyWebServerFactoryCustomizer @@ -62,6 +63,8 @@ public class NettyWebServerFactoryCustomizer .to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout)); propertyMapper.from(nettyProperties::getIdleTimeout).whenNonNull() .to((idleTimeout) -> customizeIdleTimeout(factory, idleTimeout)); + propertyMapper.from(nettyProperties::getMaxKeepAliveRequests).whenNonNull() + .to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests)); customizeRequestDecoder(factory, propertyMapper); } @@ -104,4 +107,8 @@ public class NettyWebServerFactoryCustomizer factory.addServerCustomizers((httpServer) -> httpServer.idleTimeout(idleTimeout)); } + private void customizeMaxKeepAliveRequests(NettyReactiveWebServerFactory factory, int maxKeepAliveRequests) { + factory.addServerCustomizers((httpServer) -> httpServer.maxKeepAliveRequests(maxKeepAliveRequests)); + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index ea1ede9841..489c2af8d4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -84,6 +84,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Rafiullah Hamedy * @author Chris Bono * @author Parviz Rozikov + * @author Leo Li */ class ServerPropertiesTests { @@ -339,6 +340,17 @@ class ServerPropertiesTests { assertThat(this.properties.getNetty().getIdleTimeout()).isEqualTo(Duration.ofSeconds(10)); } + @Test + void testCustomizeNettyMaxKeepAliveRequests() { + bind("server.netty.max-keep-alive-requests", "100"); + assertThat(this.properties.getNetty().getMaxKeepAliveRequests()).isEqualTo(100); + } + + @Test + void testCustomizeNettyMaxKeepAliveRequestsDefault() { + assertThat(this.properties.getNetty().getMaxKeepAliveRequests()).isEqualTo(-1); + } + @Test void tomcatAcceptCountMatchesProtocolDefault() throws Exception { assertThat(this.properties.getTomcat().getAcceptCount()).isEqualTo(getDefaultProtocol().getAcceptCount()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java index 1ea1a95cc4..6ef976dd19 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/NettyWebServerFactoryCustomizerTests.java @@ -48,6 +48,7 @@ import static org.mockito.Mockito.verify; * * @author Brian Clozel * @author Artsiom Yudovin + * @author Leo Li */ @ExtendWith(MockitoExtension.class) class NettyWebServerFactoryCustomizerTests { @@ -117,6 +118,14 @@ class NettyWebServerFactoryCustomizerTests { verifyIdleTimeout(factory, Duration.ofSeconds(1)); } + @Test + void setMaxKeepAliveRequests() { + this.serverProperties.getNetty().setMaxKeepAliveRequests(100); + NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class); + this.customizer.customize(factory); + verifyMaxKeepAliveRequests(factory, 100); + } + @Test void configureHttpRequestDecoder() { ServerProperties.Netty nettyProperties = this.serverProperties.getNetty(); @@ -162,4 +171,12 @@ class NettyWebServerFactoryCustomizerTests { assertThat(idleTimeout).isEqualTo(expected); } + private void verifyMaxKeepAliveRequests(NettyReactiveWebServerFactory factory, int expected) { + verify(factory, times(2)).addServerCustomizers(this.customizerCaptor.capture()); + NettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0); + HttpServer httpServer = serverCustomizer.apply(HttpServer.create()); + int maxKeepAliveRequests = httpServer.configuration().maxKeepAliveRequests(); + assertThat(maxKeepAliveRequests).isEqualTo(expected); + } + }