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:
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user