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 7f81f5e0eccf..36ee77d7e886 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,8 @@ public void customize(NettyReactiveWebServerFactory factory) { .to((idleTimeout) -> customizeIdleTimeout(factory, idleTimeout)); propertyMapper.from(nettyProperties::getMaxKeepAliveRequests) .to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests)); + propertyMapper.from(this.serverProperties.getMaxHttpRequestHeaderSize()) + .to((maxHttpRequestHeaderSize) -> customizeHttp2MaxHeaderSize(factory, maxHttpRequestHeaderSize.toBytes())); customizeRequestDecoder(factory, propertyMapper); } @@ -118,4 +120,9 @@ private void customizeMaxKeepAliveRequests(NettyReactiveWebServerFactory factory factory.addServerCustomizers((httpServer) -> httpServer.maxKeepAliveRequests(maxKeepAliveRequests)); } + private void customizeHttp2MaxHeaderSize(NettyReactiveWebServerFactory factory, long maxHttpRequestHeaderSize) { + factory.addServerCustomizers(((httpServer) -> httpServer.http2Settings( + (http2SettingsSpecBuilder) -> http2SettingsSpecBuilder.maxHeaderListSize(maxHttpRequestHeaderSize)))); + } + } 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 dbb9785edc77..81ab1ebace19 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.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,19 @@ void setMaxKeepAliveRequests() { verifyMaxKeepAliveRequests(factory, 100); } + @Test + void setHttp2MaxRequestHeaderSize() { + DataSize headerSize = DataSize.ofKilobytes(24); + 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)); @@ -136,11 +147,12 @@ void configureHttpRequestDecoder() { nettyProperties.setMaxInitialLineLength(DataSize.ofKilobytes(32)); NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class); this.customizer.customize(factory); - then(factory).should().addServerCustomizers(this.customizerCaptor.capture()); - NettyServerCustomizer serverCustomizer = this.customizerCaptor.getValue(); + then(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture()); + NettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(1); 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()); @@ -152,7 +164,7 @@ private void verifyConnectionTimeout(NettyReactiveWebServerFactory factory, Inte then(factory).should(never()).addServerCustomizers(any(NettyServerCustomizer.class)); return; } - then(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture()); + then(factory).should(times(3)).addServerCustomizers(this.customizerCaptor.capture()); NettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0); HttpServer httpServer = serverCustomizer.apply(HttpServer.create()); Map, ?> options = httpServer.configuration().options(); @@ -164,7 +176,7 @@ private void verifyIdleTimeout(NettyReactiveWebServerFactory factory, Duration e then(factory).should(never()).addServerCustomizers(any(NettyServerCustomizer.class)); return; } - then(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture()); + then(factory).should(times(3)).addServerCustomizers(this.customizerCaptor.capture()); NettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0); HttpServer httpServer = serverCustomizer.apply(HttpServer.create()); Duration idleTimeout = httpServer.configuration().idleTimeout(); @@ -172,11 +184,19 @@ private void verifyIdleTimeout(NettyReactiveWebServerFactory factory, Duration e } private void verifyMaxKeepAliveRequests(NettyReactiveWebServerFactory factory, int expected) { - then(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture()); + then(factory).should(times(3)).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); } + 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); + } + }