From 0e94b2ce6ee0e656ef0d1842363b2779193110bd Mon Sep 17 00:00:00 2001 From: Leo Li <269739606@qq.com> Date: Wed, 1 Dec 2021 11:38:04 +0800 Subject: [PATCH 1/2] Add server.netty.max-keep-alive-requests See gh-28875 --- .../autoconfigure/web/ServerProperties.java | 14 ++++++++++++++ .../NettyWebServerFactoryCustomizer.java | 7 +++++++ .../web/ServerPropertiesTests.java | 12 ++++++++++++ .../NettyWebServerFactoryCustomizerTests.java | 17 +++++++++++++++++ 4 files changed, 50 insertions(+) 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 367934c40ed..ed10ef42ee3 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 5309f5ee1e3..51af7a45a97 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 ea1ede9841b..489c2af8d4f 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 1ea1a95cc46..6ef976dd19c 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); + } + } From 076ddc85798ef1b36d29bc0a443aad94fde1dc62 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 4 Jan 2022 10:25:39 +0100 Subject: [PATCH 2/2] Polish "Add server.netty.max-keep-alive-requests" See gh-28875 --- .../autoconfigure/web/ServerProperties.java | 30 +++++++++---------- .../NettyWebServerFactoryCustomizer.java | 5 ++-- .../web/ServerPropertiesTests.java | 8 +---- .../NettyWebServerFactoryCustomizerTests.java | 2 +- 4 files changed, 19 insertions(+), 26 deletions(-) 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 ed10ef42ee3..67eec8c266f 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -68,7 +68,6 @@ 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) @@ -1341,6 +1340,12 @@ public class ServerProperties { */ private DataSize maxInitialLineLength = DataSize.ofKilobytes(4); + /** + * Maximum number of requests that can be made per connection. By default, a + * connection serves unlimited number of requests. + */ + private Integer maxKeepAliveRequests; + /** * Whether to validate headers when decoding requests. */ @@ -1352,11 +1357,6 @@ 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; } @@ -1397,6 +1397,14 @@ public class ServerProperties { this.maxInitialLineLength = maxInitialLineLength; } + public Integer getMaxKeepAliveRequests() { + return this.maxKeepAliveRequests; + } + + public void setMaxKeepAliveRequests(Integer maxKeepAliveRequests) { + this.maxKeepAliveRequests = maxKeepAliveRequests; + } + public boolean isValidateHeaders() { return this.validateHeaders; } @@ -1413,14 +1421,6 @@ 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 51af7a45a97..1776b8c97b4 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -34,7 +34,6 @@ 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 @@ -63,7 +62,7 @@ public class NettyWebServerFactoryCustomizer .to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout)); propertyMapper.from(nettyProperties::getIdleTimeout).whenNonNull() .to((idleTimeout) -> customizeIdleTimeout(factory, idleTimeout)); - propertyMapper.from(nettyProperties::getMaxKeepAliveRequests).whenNonNull() + propertyMapper.from(nettyProperties::getMaxKeepAliveRequests) .to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests)); customizeRequestDecoder(factory, propertyMapper); } 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 489c2af8d4f..8623ebb9eb9 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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. @@ -84,7 +84,6 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Rafiullah Hamedy * @author Chris Bono * @author Parviz Rozikov - * @author Leo Li */ class ServerPropertiesTests { @@ -346,11 +345,6 @@ class ServerPropertiesTests { 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 6ef976dd19c..9304603f380 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2022 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.