Skip to content

Commit ee5b23b

Browse files
NersesAMmhalbritter
authored andcommitted
Set max request header size on Netty when using HTTP/2
Fix an issue that server.max-http-request-header-size doesn't have an effect on Netty server with http2 enabled. See gh-36766
1 parent da7eea4 commit ee5b23b

File tree

2 files changed

+32
-5
lines changed

2 files changed

+32
-5
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ public void customize(NettyReactiveWebServerFactory factory) {
6666
.to((idleTimeout) -> customizeIdleTimeout(factory, idleTimeout));
6767
propertyMapper.from(nettyProperties::getMaxKeepAliveRequests)
6868
.to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests));
69+
propertyMapper.from(this.serverProperties.getMaxHttpRequestHeaderSize())
70+
.to((maxHttpRequestHeaderSize) -> customizeHttp2MaxHeaderSize(factory, maxHttpRequestHeaderSize.toBytes()));
6971
customizeRequestDecoder(factory, propertyMapper);
7072
}
7173

@@ -118,4 +120,9 @@ private void customizeMaxKeepAliveRequests(NettyReactiveWebServerFactory factory
118120
factory.addServerCustomizers((httpServer) -> httpServer.maxKeepAliveRequests(maxKeepAliveRequests));
119121
}
120122

123+
private void customizeHttp2MaxHeaderSize(NettyReactiveWebServerFactory factory, long maxHttpRequestHeaderSize) {
124+
factory.addServerCustomizers(((httpServer) -> httpServer.http2Settings(
125+
(http2SettingsSpecBuilder) -> http2SettingsSpecBuilder.maxHeaderListSize(maxHttpRequestHeaderSize))));
126+
}
127+
121128
}

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

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.mockito.ArgumentCaptor;
2727
import org.mockito.Captor;
2828
import org.mockito.junit.jupiter.MockitoExtension;
29+
import reactor.netty.http.Http2SettingsSpec;
2930
import reactor.netty.http.server.HttpRequestDecoderSpec;
3031
import reactor.netty.http.server.HttpServer;
3132

@@ -126,21 +127,32 @@ void setMaxKeepAliveRequests() {
126127
verifyMaxKeepAliveRequests(factory, 100);
127128
}
128129

130+
@Test
131+
void setHttp2MaxRequestHeaderSize() {
132+
DataSize headerSize = DataSize.ofKilobytes(24);
133+
this.serverProperties.setMaxHttpHeaderSize(headerSize);
134+
NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);
135+
this.customizer.customize(factory);
136+
verifyHttp2MaxHeaderSize(factory, headerSize.toBytes());
137+
}
138+
129139
@Test
130140
void configureHttpRequestDecoder() {
131141
ServerProperties.Netty nettyProperties = this.serverProperties.getNetty();
142+
this.serverProperties.setMaxHttpHeaderSize(DataSize.ofKilobytes(24));
132143
nettyProperties.setValidateHeaders(false);
133144
nettyProperties.setInitialBufferSize(DataSize.ofBytes(512));
134145
nettyProperties.setH2cMaxContentLength(DataSize.ofKilobytes(1));
135146
nettyProperties.setMaxChunkSize(DataSize.ofKilobytes(16));
136147
nettyProperties.setMaxInitialLineLength(DataSize.ofKilobytes(32));
137148
NettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);
138149
this.customizer.customize(factory);
139-
then(factory).should().addServerCustomizers(this.customizerCaptor.capture());
140-
NettyServerCustomizer serverCustomizer = this.customizerCaptor.getValue();
150+
then(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture());
151+
NettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(1);
141152
HttpServer httpServer = serverCustomizer.apply(HttpServer.create());
142153
HttpRequestDecoderSpec decoder = httpServer.configuration().decoder();
143154
assertThat(decoder.validateHeaders()).isFalse();
155+
assertThat(decoder.maxHeaderSize()).isEqualTo(this.serverProperties.getMaxHttpHeaderSize().toBytes());
144156
assertThat(decoder.initialBufferSize()).isEqualTo(nettyProperties.getInitialBufferSize().toBytes());
145157
assertThat(decoder.h2cMaxContentLength()).isEqualTo(nettyProperties.getH2cMaxContentLength().toBytes());
146158
assertThat(decoder.maxChunkSize()).isEqualTo(nettyProperties.getMaxChunkSize().toBytes());
@@ -152,7 +164,7 @@ private void verifyConnectionTimeout(NettyReactiveWebServerFactory factory, Inte
152164
then(factory).should(never()).addServerCustomizers(any(NettyServerCustomizer.class));
153165
return;
154166
}
155-
then(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture());
167+
then(factory).should(times(3)).addServerCustomizers(this.customizerCaptor.capture());
156168
NettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0);
157169
HttpServer httpServer = serverCustomizer.apply(HttpServer.create());
158170
Map<ChannelOption<?>, ?> options = httpServer.configuration().options();
@@ -164,19 +176,27 @@ private void verifyIdleTimeout(NettyReactiveWebServerFactory factory, Duration e
164176
then(factory).should(never()).addServerCustomizers(any(NettyServerCustomizer.class));
165177
return;
166178
}
167-
then(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture());
179+
then(factory).should(times(3)).addServerCustomizers(this.customizerCaptor.capture());
168180
NettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0);
169181
HttpServer httpServer = serverCustomizer.apply(HttpServer.create());
170182
Duration idleTimeout = httpServer.configuration().idleTimeout();
171183
assertThat(idleTimeout).isEqualTo(expected);
172184
}
173185

174186
private void verifyMaxKeepAliveRequests(NettyReactiveWebServerFactory factory, int expected) {
175-
then(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture());
187+
then(factory).should(times(3)).addServerCustomizers(this.customizerCaptor.capture());
176188
NettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0);
177189
HttpServer httpServer = serverCustomizer.apply(HttpServer.create());
178190
int maxKeepAliveRequests = httpServer.configuration().maxKeepAliveRequests();
179191
assertThat(maxKeepAliveRequests).isEqualTo(expected);
180192
}
181193

194+
private void verifyHttp2MaxHeaderSize(NettyReactiveWebServerFactory factory, long expected) {
195+
then(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture());
196+
NettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0);
197+
HttpServer httpServer = serverCustomizer.apply(HttpServer.create());
198+
Http2SettingsSpec decoder = httpServer.configuration().http2SettingsSpec();
199+
assertThat(decoder.maxHeaderListSize()).isEqualTo(expected);
200+
}
201+
182202
}

0 commit comments

Comments
 (0)