Polish "Restore max-http-header-size default value support"
Fix Jetty and Undertow customizers to restore Spring Boot 2.0 behavior where a negative or zero `max-http-header-size` indicates that the server default should be used. Closes gh-14986
This commit is contained in:
parent
8b40ce14cb
commit
1451c0c069
|
|
@ -75,7 +75,7 @@ public class JettyWebServerFactoryCustomizer implements
|
||||||
propertyMapper.from(jettyProperties::getSelectors).whenNonNull()
|
propertyMapper.from(jettyProperties::getSelectors).whenNonNull()
|
||||||
.to(factory::setSelectors);
|
.to(factory::setSelectors);
|
||||||
propertyMapper.from(properties::getMaxHttpHeaderSize).whenNonNull()
|
propertyMapper.from(properties::getMaxHttpHeaderSize).whenNonNull()
|
||||||
.asInt(DataSize::toBytes)
|
.asInt(DataSize::toBytes).when(this::isPositive)
|
||||||
.to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory,
|
.to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory,
|
||||||
maxHttpHeaderSize));
|
maxHttpHeaderSize));
|
||||||
propertyMapper.from(jettyProperties::getMaxHttpPostSize).asInt(DataSize::toBytes)
|
propertyMapper.from(jettyProperties::getMaxHttpPostSize).asInt(DataSize::toBytes)
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ public class UndertowWebServerFactoryCustomizer implements
|
||||||
propertyMapper.from(this::getOrDeduceUseForwardHeaders)
|
propertyMapper.from(this::getOrDeduceUseForwardHeaders)
|
||||||
.to(factory::setUseForwardHeaders);
|
.to(factory::setUseForwardHeaders);
|
||||||
propertyMapper.from(properties::getMaxHttpHeaderSize).whenNonNull()
|
propertyMapper.from(properties::getMaxHttpHeaderSize).whenNonNull()
|
||||||
.asInt(DataSize::toBytes)
|
.asInt(DataSize::toBytes).when(this::isPositive)
|
||||||
.to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory,
|
.to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory,
|
||||||
maxHttpHeaderSize));
|
maxHttpHeaderSize));
|
||||||
propertyMapper.from(undertowProperties::getMaxHttpPostSize)
|
propertyMapper.from(undertowProperties::getMaxHttpPostSize)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.web.embedded;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
|
@ -38,6 +40,7 @@ import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
|
||||||
import org.springframework.boot.web.embedded.jetty.JettyWebServer;
|
import org.springframework.boot.web.embedded.jetty.JettyWebServer;
|
||||||
import org.springframework.mock.env.MockEnvironment;
|
import org.springframework.mock.env.MockEnvironment;
|
||||||
import org.springframework.test.context.support.TestPropertySourceUtils;
|
import org.springframework.test.context.support.TestPropertySourceUtils;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
@ -147,15 +150,40 @@ public class JettyWebServerFactoryCustomizerTests {
|
||||||
public void customizeMaxHttpHeaderSize() {
|
public void customizeMaxHttpHeaderSize() {
|
||||||
bind("server.max-http-header-size=2048");
|
bind("server.max-http-header-size=2048");
|
||||||
JettyWebServer server = customizeAndGetServer();
|
JettyWebServer server = customizeAndGetServer();
|
||||||
for (Connector connector : server.getServer().getConnectors()) {
|
List<Integer> requestHeaderSizes = getRequestHeaderSizes(server);
|
||||||
|
assertThat(requestHeaderSizes).containsOnly(2048);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customMaxHttpHeaderSizeIgnoredIfNegative() {
|
||||||
|
bind("server.max-http-header-size=-1");
|
||||||
|
JettyWebServer server = customizeAndGetServer();
|
||||||
|
List<Integer> requestHeaderSizes = getRequestHeaderSizes(server);
|
||||||
|
assertThat(requestHeaderSizes).containsOnly(8192);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customMaxHttpHeaderSizeIgnoredIfZero() {
|
||||||
|
bind("server.max-http-header-size=0");
|
||||||
|
JettyWebServer server = customizeAndGetServer();
|
||||||
|
List<Integer> requestHeaderSizes = getRequestHeaderSizes(server);
|
||||||
|
assertThat(requestHeaderSizes).containsOnly(8192);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Integer> getRequestHeaderSizes(JettyWebServer server) {
|
||||||
|
List<Integer> requestHeaderSizes = new ArrayList<>();
|
||||||
|
Connector[] connectors = (Connector[]) ReflectionTestUtils.getField(server,
|
||||||
|
"connectors");
|
||||||
|
for (Connector connector : connectors) {
|
||||||
connector.getConnectionFactories().stream()
|
connector.getConnectionFactories().stream()
|
||||||
.filter((factory) -> factory instanceof ConnectionFactory)
|
.filter((factory) -> factory instanceof ConnectionFactory)
|
||||||
.forEach((cf) -> {
|
.forEach((cf) -> {
|
||||||
ConnectionFactory factory = (ConnectionFactory) cf;
|
ConnectionFactory factory = (ConnectionFactory) cf;
|
||||||
HttpConfiguration configuration = factory.getHttpConfiguration();
|
HttpConfiguration configuration = factory.getHttpConfiguration();
|
||||||
assertThat(configuration.getRequestHeaderSize()).isEqualTo(2048);
|
requestHeaderSizes.add(configuration.getRequestHeaderSize());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return requestHeaderSizes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bind(String... inlinedProperties) {
|
private void bind(String... inlinedProperties) {
|
||||||
|
|
|
||||||
|
|
@ -17,18 +17,28 @@
|
||||||
package org.springframework.boot.autoconfigure.web.embedded;
|
package org.springframework.boot.autoconfigure.web.embedded;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import io.undertow.Undertow;
|
||||||
|
import io.undertow.Undertow.Builder;
|
||||||
|
import io.undertow.UndertowOptions;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.xnio.OptionMap;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||||
import org.springframework.boot.context.properties.bind.Bindable;
|
import org.springframework.boot.context.properties.bind.Bindable;
|
||||||
import org.springframework.boot.context.properties.bind.Binder;
|
import org.springframework.boot.context.properties.bind.Binder;
|
||||||
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
||||||
import org.springframework.boot.web.embedded.undertow.ConfigurableUndertowWebServerFactory;
|
import org.springframework.boot.web.embedded.undertow.ConfigurableUndertowWebServerFactory;
|
||||||
|
import org.springframework.boot.web.embedded.undertow.UndertowBuilderCustomizer;
|
||||||
import org.springframework.mock.env.MockEnvironment;
|
import org.springframework.mock.env.MockEnvironment;
|
||||||
import org.springframework.test.context.support.TestPropertySourceUtils;
|
import org.springframework.test.context.support.TestPropertySourceUtils;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.BDDMockito.willAnswer;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
|
@ -100,6 +110,54 @@ public class UndertowWebServerFactoryCustomizerTests {
|
||||||
verify(factory).setUseForwardHeaders(true);
|
verify(factory).setUseForwardHeaders(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customizeMaxHttpHeaderSize() {
|
||||||
|
bind("server.max-http-header-size=2048");
|
||||||
|
Builder builder = Undertow.builder();
|
||||||
|
ConfigurableUndertowWebServerFactory factory = mockFactory(builder);
|
||||||
|
this.customizer.customize(factory);
|
||||||
|
OptionMap map = ((OptionMap.Builder) ReflectionTestUtils.getField(builder,
|
||||||
|
"serverOptions")).getMap();
|
||||||
|
assertThat(map.get(UndertowOptions.MAX_HEADER_SIZE).intValue()).isEqualTo(2048);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customMaxHttpHeaderSizeIgnoredIfNegative() {
|
||||||
|
bind("server.max-http-header-size=-1");
|
||||||
|
Builder builder = Undertow.builder();
|
||||||
|
ConfigurableUndertowWebServerFactory factory = mockFactory(builder);
|
||||||
|
this.customizer.customize(factory);
|
||||||
|
OptionMap map = ((OptionMap.Builder) ReflectionTestUtils.getField(builder,
|
||||||
|
"serverOptions")).getMap();
|
||||||
|
assertThat(map.contains(UndertowOptions.MAX_HEADER_SIZE)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customMaxHttpHeaderSizeIgnoredIfZero() {
|
||||||
|
bind("server.max-http-header-size=0");
|
||||||
|
Builder builder = Undertow.builder();
|
||||||
|
ConfigurableUndertowWebServerFactory factory = mockFactory(builder);
|
||||||
|
this.customizer.customize(factory);
|
||||||
|
OptionMap map = ((OptionMap.Builder) ReflectionTestUtils.getField(builder,
|
||||||
|
"serverOptions")).getMap();
|
||||||
|
assertThat(map.contains(UndertowOptions.MAX_HEADER_SIZE)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConfigurableUndertowWebServerFactory mockFactory(Builder builder) {
|
||||||
|
ConfigurableUndertowWebServerFactory factory = mock(
|
||||||
|
ConfigurableUndertowWebServerFactory.class);
|
||||||
|
willAnswer((invocation) -> {
|
||||||
|
Object argument = invocation.getArgument(0);
|
||||||
|
Arrays.stream((argument instanceof UndertowBuilderCustomizer)
|
||||||
|
? new UndertowBuilderCustomizer[] {
|
||||||
|
(UndertowBuilderCustomizer) argument }
|
||||||
|
: (UndertowBuilderCustomizer[]) argument)
|
||||||
|
.forEach((customizer) -> customizer.customize(builder));
|
||||||
|
return null;
|
||||||
|
}).given(factory).addBuilderCustomizers(any());
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
private void bind(String... inlinedProperties) {
|
private void bind(String... inlinedProperties) {
|
||||||
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
|
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
|
||||||
inlinedProperties);
|
inlinedProperties);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue