Skip to content

Commit

Permalink
Set max request header size on Netty when using HTTP/2
Browse files Browse the repository at this point in the history
Fix an issue that server.max-http-request-header-size doesn't have an
effect on Netty server with http2 enabled.

See gh-36766
  • Loading branch information
NersesAM authored and mhalbritter committed Aug 17, 2023
1 parent da7eea4 commit ee5b23b
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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))));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -126,21 +127,32 @@ 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));
nettyProperties.setMaxChunkSize(DataSize.ofKilobytes(16));
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());
Expand All @@ -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<ChannelOption<?>, ?> options = httpServer.configuration().options();
Expand All @@ -164,19 +176,27 @@ 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();
assertThat(idleTimeout).isEqualTo(expected);
}

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);
}

}

0 comments on commit ee5b23b

Please sign in to comment.