Apply server.undertow.* config to reactive servers

This commit applies `server.undertow.*` configuration properties
to Undertow when configured as a reactive web server.

See gh-11500
This commit is contained in:
Brian Clozel
2018-01-11 11:15:23 +01:00
parent 15bc718248
commit 98ac2218db
10 changed files with 581 additions and 190 deletions

View File

@@ -0,0 +1,110 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.web.embedded.undertow;
import java.time.Duration;
import io.undertow.UndertowOptions;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.cloud.CloudPlatform;
import org.springframework.boot.web.embedded.undertow.ConfigurableUndertowWebServerFactory;
import org.springframework.core.env.Environment;
/**
* Customization for Undertow-specific features common
* for both Servlet and Reactive servers.
*
* @author Brian Clozel
*/
public final class UndertowCustomizer {
private UndertowCustomizer() {
}
public static void customizeUndertow(ServerProperties serverProperties,
Environment environment, ConfigurableUndertowWebServerFactory factory) {
ServerProperties.Undertow undertowProperties = serverProperties.getUndertow();
ServerProperties.Undertow.Accesslog accesslogProperties = undertowProperties
.getAccesslog();
if (undertowProperties.getBufferSize() != null) {
factory.setBufferSize(undertowProperties.getBufferSize());
}
if (undertowProperties.getIoThreads() != null) {
factory.setIoThreads(undertowProperties.getIoThreads());
}
if (undertowProperties.getWorkerThreads() != null) {
factory.setWorkerThreads(undertowProperties.getWorkerThreads());
}
if (undertowProperties.getDirectBuffers() != null) {
factory.setUseDirectBuffers(undertowProperties.getDirectBuffers());
}
if (undertowProperties.getAccesslog().getEnabled() != null) {
factory.setAccessLogEnabled(accesslogProperties.getEnabled());
}
factory.setAccessLogDirectory(accesslogProperties.getDir());
factory.setAccessLogPattern(accesslogProperties.getPattern());
factory.setAccessLogPrefix(accesslogProperties.getPrefix());
factory.setAccessLogSuffix(accesslogProperties.getSuffix());
factory.setAccessLogRotate(accesslogProperties.isRotate());
factory.setUseForwardHeaders(getOrDeduceUseForwardHeaders(serverProperties, environment));
if (serverProperties.getMaxHttpHeaderSize() > 0) {
customizeMaxHttpHeaderSize(factory,
serverProperties.getMaxHttpHeaderSize());
}
if (undertowProperties.getMaxHttpPostSize() > 0) {
customizeMaxHttpPostSize(factory,
undertowProperties.getMaxHttpPostSize());
}
if (serverProperties.getConnectionTimeout() != null) {
customizeConnectionTimeout(factory,
serverProperties.getConnectionTimeout());
}
factory.addDeploymentInfoCustomizers((deploymentInfo) -> deploymentInfo
.setEagerFilterInit(undertowProperties.isEagerFilterInit()));
}
private static void customizeConnectionTimeout(
ConfigurableUndertowWebServerFactory factory, Duration connectionTimeout) {
factory.addBuilderCustomizers((builder) -> builder.setSocketOption(
UndertowOptions.NO_REQUEST_TIMEOUT,
(int) connectionTimeout.toMillis()));
}
private static void customizeMaxHttpHeaderSize(
ConfigurableUndertowWebServerFactory factory, int maxHttpHeaderSize) {
factory.addBuilderCustomizers((builder) -> builder
.setServerOption(UndertowOptions.MAX_HEADER_SIZE, maxHttpHeaderSize));
}
private static void customizeMaxHttpPostSize(
ConfigurableUndertowWebServerFactory factory, long maxHttpPostSize) {
factory.addBuilderCustomizers((builder) -> builder
.setServerOption(UndertowOptions.MAX_ENTITY_SIZE, maxHttpPostSize));
}
private static boolean getOrDeduceUseForwardHeaders(ServerProperties serverProperties,
Environment environment) {
if (serverProperties.isUseForwardHeaders() != null) {
return serverProperties.isUseForwardHeaders();
}
CloudPlatform platform = CloudPlatform.getActive(environment);
return platform != null && platform.isUsingForwardHeaders();
}
}

View File

@@ -19,8 +19,10 @@ package org.springframework.boot.autoconfigure.web.reactive;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.embedded.jetty.JettyCustomizer;
import org.springframework.boot.autoconfigure.web.embedded.tomcat.TomcatCustomizer;
import org.springframework.boot.autoconfigure.web.embedded.undertow.UndertowCustomizer;
import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.ConfigurableReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.EnvironmentAware;
@@ -79,6 +81,10 @@ public class DefaultReactiveWebServerFactoryCustomizer implements
JettyCustomizer.customizeJetty(this.serverProperties, this.environment,
(JettyReactiveWebServerFactory) factory);
}
if (factory instanceof UndertowReactiveWebServerFactory) {
UndertowCustomizer.customizeUndertow(this.serverProperties, this.environment,
(UndertowReactiveWebServerFactory) factory);
}
}
}

View File

@@ -16,7 +16,6 @@
package org.springframework.boot.autoconfigure.web.servlet;
import java.time.Duration;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -24,13 +23,11 @@ import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.SessionCookieConfig;
import io.undertow.UndertowOptions;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties.Session;
import org.springframework.boot.autoconfigure.web.embedded.jetty.JettyCustomizer;
import org.springframework.boot.autoconfigure.web.embedded.tomcat.TomcatCustomizer;
import org.springframework.boot.cloud.CloudPlatform;
import org.springframework.boot.autoconfigure.web.embedded.undertow.UndertowCustomizer;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
@@ -129,15 +126,6 @@ public class DefaultServletWebServerFactoryCustomizer
this.serverProperties.getServlet().getContextParameters()));
}
private static boolean getOrDeduceUseForwardHeaders(ServerProperties serverProperties,
Environment environment) {
if (serverProperties.isUseForwardHeaders() != null) {
return serverProperties.isUseForwardHeaders();
}
CloudPlatform platform = CloudPlatform.getActive(environment);
return platform != null && platform.isUsingForwardHeaders();
}
/**
* {@link ServletContextInitializer} to apply appropriate parts of the {@link Session}
* configuration.
@@ -231,71 +219,4 @@ public class DefaultServletWebServerFactoryCustomizer
}
}
private static class UndertowCustomizer {
protected static void customizeUndertow(ServerProperties serverProperties,
Environment environment, UndertowServletWebServerFactory factory) {
ServerProperties.Undertow undertowProperties = serverProperties.getUndertow();
ServerProperties.Undertow.Accesslog accesslogProperties = undertowProperties
.getAccesslog();
if (undertowProperties.getBufferSize() != null) {
factory.setBufferSize(undertowProperties.getBufferSize());
}
if (undertowProperties.getIoThreads() != null) {
factory.setIoThreads(undertowProperties.getIoThreads());
}
if (undertowProperties.getWorkerThreads() != null) {
factory.setWorkerThreads(undertowProperties.getWorkerThreads());
}
if (undertowProperties.getDirectBuffers() != null) {
factory.setDirectBuffers(undertowProperties.getDirectBuffers());
}
if (undertowProperties.getAccesslog().getEnabled() != null) {
factory.setAccessLogEnabled(accesslogProperties.getEnabled());
}
factory.setAccessLogDirectory(accesslogProperties.getDir());
factory.setAccessLogPattern(accesslogProperties.getPattern());
factory.setAccessLogPrefix(accesslogProperties.getPrefix());
factory.setAccessLogSuffix(accesslogProperties.getSuffix());
factory.setAccessLogRotate(accesslogProperties.isRotate());
factory.setUseForwardHeaders(
getOrDeduceUseForwardHeaders(serverProperties, environment));
if (serverProperties.getMaxHttpHeaderSize() > 0) {
customizeMaxHttpHeaderSize(factory,
serverProperties.getMaxHttpHeaderSize());
}
if (undertowProperties.getMaxHttpPostSize() > 0) {
customizeMaxHttpPostSize(factory,
undertowProperties.getMaxHttpPostSize());
}
if (serverProperties.getConnectionTimeout() != null) {
customizeConnectionTimeout(factory,
serverProperties.getConnectionTimeout());
}
factory.addDeploymentInfoCustomizers((deploymentInfo) -> deploymentInfo
.setEagerFilterInit(undertowProperties.isEagerFilterInit()));
}
private static void customizeConnectionTimeout(
UndertowServletWebServerFactory factory, Duration connectionTimeout) {
factory.addBuilderCustomizers((builder) -> builder.setSocketOption(
UndertowOptions.NO_REQUEST_TIMEOUT,
(int) connectionTimeout.toMillis()));
}
private static void customizeMaxHttpHeaderSize(
UndertowServletWebServerFactory factory, int maxHttpHeaderSize) {
factory.addBuilderCustomizers((builder) -> builder
.setServerOption(UndertowOptions.MAX_HEADER_SIZE, maxHttpHeaderSize));
}
private static void customizeMaxHttpPostSize(
UndertowServletWebServerFactory factory, long maxHttpPostSize) {
factory.addBuilderCustomizers((builder) -> builder
.setServerOption(UndertowOptions.MAX_ENTITY_SIZE, maxHttpPostSize));
}
}
}

View File

@@ -44,12 +44,15 @@ import org.springframework.boot.web.embedded.jetty.JettyReactiveWebServerFactory
import org.springframework.boot.web.embedded.jetty.JettyWebServer;
import org.springframework.boot.web.embedded.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.embedded.undertow.UndertowReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.ConfigurableReactiveWebServerFactory;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -434,6 +437,52 @@ public class DefaultReactiveWebServerFactoryCustomizerTests {
}
}
@Test
public void customizeUndertowAccessLog() {
Map<String, String> map = new HashMap<>();
map.put("server.undertow.accesslog.enabled", "true");
map.put("server.undertow.accesslog.pattern", "foo");
map.put("server.undertow.accesslog.prefix", "test_log");
map.put("server.undertow.accesslog.suffix", "txt");
map.put("server.undertow.accesslog.dir", "test-logs");
map.put("server.undertow.accesslog.rotate", "false");
bindProperties(map);
UndertowReactiveWebServerFactory factory = spy(
new UndertowReactiveWebServerFactory());
this.customizer.customize(factory);
verify(factory).setAccessLogEnabled(true);
verify(factory).setAccessLogPattern("foo");
verify(factory).setAccessLogPrefix("test_log");
verify(factory).setAccessLogSuffix("txt");
verify(factory).setAccessLogDirectory(new File("test-logs"));
verify(factory).setAccessLogRotate(false);
}
@Test
public void setUseForwardHeadersUndertow() {
this.properties.setUseForwardHeaders(true);
UndertowReactiveWebServerFactory factory = spy(new UndertowReactiveWebServerFactory());
this.customizer.customize(factory);
verify(factory).setUseForwardHeaders(true);
}
@Test
public void deduceUseForwardHeadersUndertow() {
this.customizer.setEnvironment(new MockEnvironment().withProperty("DYNO", "-"));
UndertowReactiveWebServerFactory factory = spy(
new UndertowReactiveWebServerFactory());
this.customizer.customize(factory);
verify(factory).setUseForwardHeaders(true);
}
@Test
public void skipNullElementsForUndertow() {
UndertowReactiveWebServerFactory factory = mock(
UndertowReactiveWebServerFactory.class);
this.customizer.customize(factory);
verify(factory, never()).setAccessLogEnabled(anyBoolean());
}
private NCSARequestLog getNCSARequestLog(JettyWebServer webServer) {
RequestLog requestLog = webServer.getServer().getRequestLog();
assertThat(requestLog).isInstanceOf(NCSARequestLog.class);