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 7f81f5e0ec..1574e1973c 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 @@ -66,6 +66,11 @@ public class NettyWebServerFactoryCustomizer .to((idleTimeout) -> customizeIdleTimeout(factory, idleTimeout)); propertyMapper.from(nettyProperties::getMaxKeepAliveRequests) .to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests)); + if (this.serverProperties.getHttp2() != null && this.serverProperties.getHttp2().isEnabled()) { + propertyMapper.from(this.serverProperties.getMaxHttpHeaderSize()) + .whenNonNull() + .to((size) -> customizeHttp2MaxHeaderSize(factory, size.toBytes())); + } customizeRequestDecoder(factory, propertyMapper); } @@ -118,4 +123,9 @@ public class NettyWebServerFactoryCustomizer factory.addServerCustomizers((httpServer) -> httpServer.maxKeepAliveRequests(maxKeepAliveRequests)); } + private void customizeHttp2MaxHeaderSize(NettyReactiveWebServerFactory factory, long size) { + factory.addServerCustomizers( + ((httpServer) -> httpServer.http2Settings((settings) -> settings.maxHeaderListSize(size)))); + } + } 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 dbb9785edc..65795b60bd 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 @@ -26,6 +26,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.junit.jupiter.MockitoExtension; +import reactor.netty.http.Http2SettingsSpec; import reactor.netty.http.server.HttpRequestDecoderSpec; import reactor.netty.http.server.HttpServer; @@ -126,9 +127,20 @@ class NettyWebServerFactoryCustomizerTests { verifyMaxKeepAliveRequests(factory, 100); } + @Test + void setHttp2MaxRequestHeaderSize() { + DataSize headerSize = DataSize.ofKilobytes(24); + this.serverProperties.getHttp2().setEnabled(true); + this.serverProperties.setMaxHttpHeaderSize(headerSize); + NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class); + this.customizer.customize(factory); + verifyHttp2MaxHeaderSize(factory, headerSize.toBytes()); + } + @Test void configureHttpRequestDecoder() { ServerProperties.Netty nettyProperties = this.serverProperties.getNetty(); + this.serverProperties.setMaxHttpHeaderSize(DataSize.ofKilobytes(24)); nettyProperties.setValidateHeaders(false); nettyProperties.setInitialBufferSize(DataSize.ofBytes(512)); nettyProperties.setH2cMaxContentLength(DataSize.ofKilobytes(1)); @@ -137,10 +149,11 @@ class NettyWebServerFactoryCustomizerTests { NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class); this.customizer.customize(factory); then(factory).should().addServerCustomizers(this.customizerCaptor.capture()); - NettyServerCustomizer serverCustomizer = this.customizerCaptor.getValue(); + NettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0); HttpServer httpServer = serverCustomizer.apply(HttpServer.create()); HttpRequestDecoderSpec decoder = httpServer.configuration().decoder(); assertThat(decoder.validateHeaders()).isFalse(); + assertThat(decoder.maxHeaderSize()).isEqualTo(this.serverProperties.getMaxHttpHeaderSize().toBytes()); assertThat(decoder.initialBufferSize()).isEqualTo(nettyProperties.getInitialBufferSize().toBytes()); assertThat(decoder.h2cMaxContentLength()).isEqualTo(nettyProperties.getH2cMaxContentLength().toBytes()); assertThat(decoder.maxChunkSize()).isEqualTo(nettyProperties.getMaxChunkSize().toBytes()); @@ -179,4 +192,12 @@ class NettyWebServerFactoryCustomizerTests { assertThat(maxKeepAliveRequests).isEqualTo(expected); } + private void verifyHttp2MaxHeaderSize(NettyReactiveWebServerFactory factory, long expected) { + then(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture()); + NettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0); + HttpServer httpServer = serverCustomizer.apply(HttpServer.create()); + Http2SettingsSpec decoder = httpServer.configuration().http2SettingsSpec(); + assertThat(decoder.maxHeaderListSize()).isEqualTo(expected); + } + }