Merge pull request #17356 from htztomic
* pr/17356: Polish "Allow Undertow's options to be configured via the environment Allow Undertow's options to be configured via the environment Closes gh-17356
This commit is contained in:
commit
c19bed15d2
|
|
@ -24,6 +24,7 @@ import java.time.Duration;
|
|||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -1119,6 +1120,8 @@ public class ServerProperties {
|
|||
|
||||
private final Accesslog accesslog = new Accesslog();
|
||||
|
||||
private final Options options = new Options();
|
||||
|
||||
public DataSize getMaxHttpPostSize() {
|
||||
return this.maxHttpPostSize;
|
||||
}
|
||||
|
|
@ -1227,6 +1230,10 @@ public class ServerProperties {
|
|||
return this.accesslog;
|
||||
}
|
||||
|
||||
public Options getOptions() {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undertow access log properties.
|
||||
*/
|
||||
|
|
@ -1312,6 +1319,22 @@ public class ServerProperties {
|
|||
|
||||
}
|
||||
|
||||
public static class Options {
|
||||
|
||||
private Map<String, String> socket = new LinkedHashMap<>();
|
||||
|
||||
private Map<String, String> server = new LinkedHashMap<>();
|
||||
|
||||
public Map<String, String> getServer() {
|
||||
return this.server;
|
||||
}
|
||||
|
||||
public Map<String, String> getSocket() {
|
||||
return this.socket;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.web.embedded;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import io.undertow.UndertowOptions;
|
||||
import org.xnio.Option;
|
||||
|
||||
|
|
@ -61,6 +63,7 @@ public class UndertowWebServerFactoryCustomizer
|
|||
public void customize(ConfigurableUndertowWebServerFactory factory) {
|
||||
ServerProperties properties = this.serverProperties;
|
||||
ServerProperties.Undertow undertowProperties = properties.getUndertow();
|
||||
ServerProperties.Undertow.Options undertowOptions = undertowProperties.getOptions();
|
||||
ServerProperties.Undertow.Accesslog accesslogProperties = undertowProperties.getAccesslog();
|
||||
PropertyMapper propertyMapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
propertyMapper.from(undertowProperties::getBufferSize).whenNonNull().asInt(DataSize::toBytes)
|
||||
|
|
@ -109,6 +112,12 @@ public class UndertowWebServerFactoryCustomizer
|
|||
.to((alwaysSetKeepAlive) -> customizeServerOption(factory, UndertowOptions.ALWAYS_SET_KEEP_ALIVE,
|
||||
alwaysSetKeepAlive));
|
||||
|
||||
propertyMapper.from(undertowOptions::getServer)
|
||||
.to((server) -> server.forEach((key, value) -> setCustomOption(factory, key, value, "server")));
|
||||
|
||||
propertyMapper.from(undertowOptions::getSocket)
|
||||
.to((socket) -> socket.forEach((key, value) -> setCustomOption(factory, key, value, "socket")));
|
||||
|
||||
factory.addDeploymentInfoCustomizers(
|
||||
(deploymentInfo) -> deploymentInfo.setEagerFilterInit(undertowProperties.isEagerFilterInit()));
|
||||
}
|
||||
|
|
@ -121,6 +130,10 @@ public class UndertowWebServerFactoryCustomizer
|
|||
factory.addBuilderCustomizers((builder) -> builder.setServerOption(option, value));
|
||||
}
|
||||
|
||||
private <T> void customizeSocketOption(ConfigurableUndertowWebServerFactory factory, Option<T> option, T value) {
|
||||
factory.addBuilderCustomizers((builder) -> builder.setSocketOption(option, value));
|
||||
}
|
||||
|
||||
private boolean getOrDeduceUseForwardHeaders() {
|
||||
if (this.serverProperties.getForwardHeadersStrategy().equals(ServerProperties.ForwardHeadersStrategy.NONE)) {
|
||||
CloudPlatform platform = CloudPlatform.getActive(this.environment);
|
||||
|
|
@ -129,4 +142,31 @@ public class UndertowWebServerFactoryCustomizer
|
|||
return this.serverProperties.getForwardHeadersStrategy().equals(ServerProperties.ForwardHeadersStrategy.NATIVE);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> void setCustomOption(ConfigurableUndertowWebServerFactory factory, String key, String value,
|
||||
String type) {
|
||||
Field[] fields = UndertowOptions.class.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if (getCanonicalName(field.getName()).equals(getCanonicalName(key))) {
|
||||
Option<T> option = (Option<T>) Option.fromString(
|
||||
UndertowOptions.class.getName() + '.' + field.getName(), getClass().getClassLoader());
|
||||
T parsed = option.parseValue(value, getClass().getClassLoader());
|
||||
if (type.equals("server")) {
|
||||
customizeServerOption(factory, option, parsed);
|
||||
}
|
||||
else if (type.equals("socket")) {
|
||||
customizeSocketOption(factory, option, parsed);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getCanonicalName(String key) {
|
||||
StringBuilder canonicalName = new StringBuilder(key.length());
|
||||
key.chars().map((c) -> (char) c).filter(Character::isLetterOrDigit).map(Character::toLowerCase)
|
||||
.forEach((c) -> canonicalName.append((char) c));
|
||||
return canonicalName.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,6 +214,20 @@ class ServerPropertiesTests {
|
|||
assertThat(this.properties.getJetty().getSelectors()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomizeUndertowServerOption() {
|
||||
bind("server.undertow.options.server.ALWAYS_SET_KEEP_ALIVE", "true");
|
||||
assertThat(this.properties.getUndertow().getOptions().getServer().containsKey("ALWAYS_SET_KEEP_ALIVE"));
|
||||
assertThat(this.properties.getUndertow().getOptions().getServer().get("ALWAYS_SET_KEEP_ALIVE").equals("true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomizeUndertowSocketOption() {
|
||||
bind("server.undertow.options.socket.ALWAYS_SET_KEEP_ALIVE", "true");
|
||||
assertThat(this.properties.getUndertow().getOptions().getSocket().containsKey("ALWAYS_SET_KEEP_ALIVE"));
|
||||
assertThat(this.properties.getUndertow().getOptions().getSocket().get("ALWAYS_SET_KEEP_ALIVE").equals("true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomizeJettyAccessLog() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
|
|
|
|||
|
|
@ -155,6 +155,29 @@ class UndertowWebServerFactoryCustomizerTests {
|
|||
assertThat(boundServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void customServerOption() {
|
||||
bind("server.undertow.options.server.ALWAYS_SET_KEEP_ALIVE=false");
|
||||
assertThat(boundServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void customServerOptionShouldBeRelaxed() {
|
||||
bind("server.undertow.options.server.always-set-keep-alive=false");
|
||||
assertThat(boundServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void customSocketOption() {
|
||||
bind("server.undertow.options.socket.ALWAYS_SET_KEEP_ALIVE=false");
|
||||
assertThat(boundSocketOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE)).isFalse();
|
||||
}
|
||||
|
||||
void customSocketOptionShouldBeRelaxed() {
|
||||
bind("server.undertow.options.socket.always-set-keep-alive=false");
|
||||
assertThat(boundSocketOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void deduceUseForwardHeaders() {
|
||||
this.environment.setProperty("DYNO", "-");
|
||||
|
|
@ -186,6 +209,14 @@ class UndertowWebServerFactoryCustomizerTests {
|
|||
return map.get(option);
|
||||
}
|
||||
|
||||
private <T> T boundSocketOption(Option<T> option) {
|
||||
Builder builder = Undertow.builder();
|
||||
ConfigurableUndertowWebServerFactory factory = mockFactory(builder);
|
||||
this.customizer.customize(factory);
|
||||
OptionMap map = ((OptionMap.Builder) ReflectionTestUtils.getField(builder, "socketOptions")).getMap();
|
||||
return map.get(option);
|
||||
}
|
||||
|
||||
private ConfigurableUndertowWebServerFactory mockFactory(Builder builder) {
|
||||
ConfigurableUndertowWebServerFactory factory = mock(ConfigurableUndertowWebServerFactory.class);
|
||||
willAnswer((invocation) -> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue