diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java index 9d0bc38d7f5..4d7f45179a1 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java @@ -40,6 +40,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.SearchStrategy; import org.springframework.boot.autoconfigure.hateoas.HypermediaHttpMessageConverterConfiguration; +import org.springframework.boot.autoconfigure.web.DefaultServletContainerCustomizer; import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.ErrorAttributes; import org.springframework.boot.autoconfigure.web.ServerProperties; @@ -182,6 +183,8 @@ public class EndpointWebMvcChildContextConfiguration { private ServerProperties server; + private DefaultServletContainerCustomizer serverCustomizer; + @Override public int getOrder() { return 0; @@ -195,10 +198,12 @@ public class EndpointWebMvcChildContextConfiguration { ManagementServerProperties.class); this.server = BeanFactoryUtils.beanOfTypeIncludingAncestors( this.beanFactory, ServerProperties.class); + this.serverCustomizer = BeanFactoryUtils.beanOfTypeIncludingAncestors( + this.beanFactory, DefaultServletContainerCustomizer.class); } // Customize as per the parent context first (so e.g. the access logs go to // the same place) - this.server.customize(container); + this.serverCustomizer.customize(container); // Then reset the error pages container.setErrorPages(Collections.emptySet()); // and the context path diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java index 5a15633a9b0..18767797d3b 100755 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java @@ -736,7 +736,7 @@ public class EndpointWebMvcAutoConfigurationTests { } @Configuration - @Import({ PropertyPlaceholderAutoConfiguration.class, + @Import({PropertyPlaceholderAutoConfiguration.class, EmbeddedServletContainerAutoConfiguration.class, JacksonAutoConfiguration.class, EndpointAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/DefaultServletContainerCustomizer.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/DefaultServletContainerCustomizer.java new file mode 100644 index 00000000000..bb497997888 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/DefaultServletContainerCustomizer.java @@ -0,0 +1,619 @@ +/* + * Copyright 2012-2017 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; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.SessionCookieConfig; + +import io.undertow.Undertow; +import io.undertow.UndertowOptions; +import org.apache.catalina.Context; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.valves.AccessLogValve; +import org.apache.catalina.valves.RemoteIpValve; +import org.apache.coyote.AbstractProtocol; +import org.apache.coyote.ProtocolHandler; +import org.apache.coyote.http11.AbstractHttp11Protocol; +import org.eclipse.jetty.server.AbstractConnector; +import org.eclipse.jetty.server.ConnectionFactory; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.server.handler.HandlerCollection; +import org.eclipse.jetty.server.handler.HandlerWrapper; + +import org.springframework.boot.cloud.CloudPlatform; +import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; +import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; +import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor; +import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.InitParameterConfiguringServletContextInitializer; +import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.jetty.JettyServerCustomizer; +import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer; +import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer; +import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.undertow.UndertowBuilderCustomizer; +import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory; +import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.Ordered; +import org.springframework.core.env.Environment; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +/** + * Customizer used by an {@link EmbeddedServletContainerFactory} when an + * {@link EmbeddedServletContainerCustomizerBeanPostProcessor} is active. + * + * @author Brian Clozel + * @since 2.0.0 + */ +public class DefaultServletContainerCustomizer + implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered { + + private final ServerProperties serverProperties; + + private Environment environment; + + public DefaultServletContainerCustomizer(ServerProperties serverProperties) { + this.serverProperties = serverProperties; + } + + public void setLoader(String value) { + // no op to support Tomcat running as a traditional container (not embedded) + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public void customize(ConfigurableEmbeddedServletContainer container) { + if (this.serverProperties.getPort() != null) { + container.setPort(this.serverProperties.getPort()); + } + if (this.serverProperties.getAddress() != null) { + container.setAddress(this.serverProperties.getAddress()); + } + if (this.serverProperties.getServlet().getContextPath() != null) { + container.setContextPath(this.serverProperties.getServlet().getContextPath()); + } + if (this.serverProperties.getDisplayName() != null) { + container.setDisplayName(this.serverProperties.getDisplayName()); + } + if (this.serverProperties.getSession().getTimeout() != null) { + container.setSessionTimeout(this.serverProperties.getSession().getTimeout()); + } + container.setPersistSession(this.serverProperties.getSession().isPersistent()); + container.setSessionStoreDir(this.serverProperties.getSession().getStoreDir()); + if (this.serverProperties.getSsl() != null) { + container.setSsl(this.serverProperties.getSsl()); + } + if (this.serverProperties.getServlet() != null) { + container.setJsp(this.serverProperties.getServlet().getJsp()); + } + if (this.serverProperties.getCompression() != null) { + container.setCompression(this.serverProperties.getCompression()); + } + container.setServerHeader(this.serverProperties.getServerHeader()); + if (container instanceof TomcatEmbeddedServletContainerFactory) { + TomcatCustomizer.customizeTomcat(this.serverProperties, this.environment, + (TomcatEmbeddedServletContainerFactory) container); + } + if (container instanceof JettyEmbeddedServletContainerFactory) { + JettyCustomizer.customizeJetty(this.serverProperties, this.environment, + (JettyEmbeddedServletContainerFactory) container); + } + + if (container instanceof UndertowEmbeddedServletContainerFactory) { + UndertowCustomizer.customizeUndertow(this.serverProperties, this.environment, + (UndertowEmbeddedServletContainerFactory) container); + } + container.addInitializers(new SessionConfiguringInitializer(this.serverProperties.getSession())); + container.addInitializers(new InitParameterConfiguringServletContextInitializer( + 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 ? false : platform.isUsingForwardHeaders()); + } + + /** + * {@link ServletContextInitializer} to apply appropriate parts of the {@link ServerProperties.Session} + * configuration. + */ + private static class SessionConfiguringInitializer + implements ServletContextInitializer { + + private final ServerProperties.Session session; + + SessionConfiguringInitializer(ServerProperties.Session session) { + this.session = session; + } + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + if (this.session.getTrackingModes() != null) { + servletContext.setSessionTrackingModes(this.session.getTrackingModes()); + } + configureSessionCookie(servletContext.getSessionCookieConfig()); + } + + private void configureSessionCookie(SessionCookieConfig config) { + ServerProperties.Session.Cookie cookie = this.session.getCookie(); + if (cookie.getName() != null) { + config.setName(cookie.getName()); + } + if (cookie.getDomain() != null) { + config.setDomain(cookie.getDomain()); + } + if (cookie.getPath() != null) { + config.setPath(cookie.getPath()); + } + if (cookie.getComment() != null) { + config.setComment(cookie.getComment()); + } + if (cookie.getHttpOnly() != null) { + config.setHttpOnly(cookie.getHttpOnly()); + } + if (cookie.getSecure() != null) { + config.setSecure(cookie.getSecure()); + } + if (cookie.getMaxAge() != null) { + config.setMaxAge(cookie.getMaxAge()); + } + } + + } + + private static class TomcatCustomizer { + + public static void customizeTomcat(ServerProperties serverProperties, Environment environment, + TomcatEmbeddedServletContainerFactory factory) { + + ServerProperties.Tomcat tomcatProperties = serverProperties.getTomcat(); + if (tomcatProperties.getBasedir() != null) { + factory.setBaseDirectory(tomcatProperties.getBasedir()); + } + factory.setBackgroundProcessorDelay(tomcatProperties.getBackgroundProcessorDelay()); + customizeRemoteIpValve(serverProperties, environment, factory); + if (tomcatProperties.getMaxThreads() > 0) { + customizeMaxThreads(factory, tomcatProperties.getMaxThreads()); + } + if (tomcatProperties.getMinSpareThreads() > 0) { + customizeMinThreads(factory, tomcatProperties.getMinSpareThreads()); + } + int maxHttpHeaderSize = (serverProperties.getMaxHttpHeaderSize() > 0 + ? serverProperties.getMaxHttpHeaderSize() : tomcatProperties.getMaxHttpHeaderSize()); + if (maxHttpHeaderSize > 0) { + customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize); + } + if (tomcatProperties.getMaxHttpPostSize() > 0) { + customizeMaxHttpPostSize(factory, tomcatProperties.getMaxHttpPostSize()); + } + if (tomcatProperties.getAccesslog().isEnabled()) { + customizeAccessLog(tomcatProperties, factory); + } + if (tomcatProperties.getUriEncoding() != null) { + factory.setUriEncoding(tomcatProperties.getUriEncoding()); + } + if (serverProperties.getConnectionTimeout() != null) { + customizeConnectionTimeout(factory, + serverProperties.getConnectionTimeout()); + } + if (tomcatProperties.getRedirectContextRoot() != null) { + customizeRedirectContextRoot(factory, tomcatProperties.getRedirectContextRoot()); + } + if (tomcatProperties.getMaxConnections() > 0) { + customizeMaxConnections(factory, tomcatProperties.getMaxConnections()); + } + if (tomcatProperties.getAcceptCount() > 0) { + customizeAcceptCount(factory, tomcatProperties.getAcceptCount()); + } + if (!ObjectUtils.isEmpty(tomcatProperties.getAdditionalTldSkipPatterns())) { + factory.getTldSkipPatterns().addAll(tomcatProperties.getAdditionalTldSkipPatterns()); + } + } + + private static void customizeAcceptCount(TomcatEmbeddedServletContainerFactory factory, + final int acceptCount) { + factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { + + @Override + public void customize(Connector connector) { + ProtocolHandler handler = connector.getProtocolHandler(); + if (handler instanceof AbstractProtocol) { + AbstractProtocol protocol = (AbstractProtocol) handler; + protocol.setBacklog(acceptCount); + } + } + + }); + } + + private static void customizeMaxConnections( + TomcatEmbeddedServletContainerFactory factory, final int maxConnections) { + factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { + + @Override + public void customize(Connector connector) { + ProtocolHandler handler = connector.getProtocolHandler(); + if (handler instanceof AbstractProtocol) { + AbstractProtocol protocol = (AbstractProtocol) handler; + protocol.setMaxConnections(maxConnections); + } + } + + }); + } + + private static void customizeConnectionTimeout( + TomcatEmbeddedServletContainerFactory factory, final int connectionTimeout) { + factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { + + @Override + public void customize(Connector connector) { + ProtocolHandler handler = connector.getProtocolHandler(); + if (handler instanceof AbstractProtocol) { + AbstractProtocol protocol = (AbstractProtocol) handler; + protocol.setConnectionTimeout(connectionTimeout); + } + } + + }); + } + + private static void customizeRemoteIpValve(ServerProperties properties, Environment environment, + TomcatEmbeddedServletContainerFactory factory) { + String protocolHeader = properties.getTomcat().getProtocolHeader(); + String remoteIpHeader = properties.getTomcat().getRemoteIpHeader(); + // For back compatibility the valve is also enabled if protocol-header is set + if (StringUtils.hasText(protocolHeader) || StringUtils.hasText(remoteIpHeader) + || getOrDeduceUseForwardHeaders(properties, environment)) { + RemoteIpValve valve = new RemoteIpValve(); + valve.setProtocolHeader(StringUtils.hasLength(protocolHeader) + ? protocolHeader : "X-Forwarded-Proto"); + if (StringUtils.hasLength(remoteIpHeader)) { + valve.setRemoteIpHeader(remoteIpHeader); + } + // The internal proxies default to a white list of "safe" internal IP + // addresses + valve.setInternalProxies(properties.getTomcat().getInternalProxies()); + valve.setPortHeader(properties.getTomcat().getPortHeader()); + valve.setProtocolHeaderHttpsValue(properties.getTomcat().getProtocolHeaderHttpsValue()); + // ... so it's safe to add this valve by default. + factory.addEngineValves(valve); + } + } + + @SuppressWarnings("rawtypes") + private static void customizeMaxThreads(TomcatEmbeddedServletContainerFactory factory, + final int maxThreads) { + factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { + @Override + public void customize(Connector connector) { + + ProtocolHandler handler = connector.getProtocolHandler(); + if (handler instanceof AbstractProtocol) { + AbstractProtocol protocol = (AbstractProtocol) handler; + protocol.setMaxThreads(maxThreads); + } + + } + }); + } + + @SuppressWarnings("rawtypes") + private static void customizeMinThreads(TomcatEmbeddedServletContainerFactory factory, + final int minSpareThreads) { + factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { + @Override + public void customize(Connector connector) { + + ProtocolHandler handler = connector.getProtocolHandler(); + if (handler instanceof AbstractProtocol) { + AbstractProtocol protocol = (AbstractProtocol) handler; + protocol.setMinSpareThreads(minSpareThreads); + } + + } + }); + } + + @SuppressWarnings("rawtypes") + private static void customizeMaxHttpHeaderSize( + TomcatEmbeddedServletContainerFactory factory, final int maxHttpHeaderSize) { + factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { + + @Override + public void customize(Connector connector) { + ProtocolHandler handler = connector.getProtocolHandler(); + if (handler instanceof AbstractHttp11Protocol) { + AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler; + protocol.setMaxHttpHeaderSize(maxHttpHeaderSize); + } + } + + }); + } + + private static void customizeMaxHttpPostSize( + TomcatEmbeddedServletContainerFactory factory, final int maxHttpPostSize) { + factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { + + @Override + public void customize(Connector connector) { + connector.setMaxPostSize(maxHttpPostSize); + } + + }); + } + + private static void customizeAccessLog(ServerProperties.Tomcat tomcatProperties, + TomcatEmbeddedServletContainerFactory factory) { + + AccessLogValve valve = new AccessLogValve(); + valve.setPattern(tomcatProperties.getAccesslog().getPattern()); + valve.setDirectory(tomcatProperties.getAccesslog().getDirectory()); + valve.setPrefix(tomcatProperties.getAccesslog().getPrefix()); + valve.setSuffix(tomcatProperties.getAccesslog().getSuffix()); + valve.setRenameOnRotate(tomcatProperties.getAccesslog().isRenameOnRotate()); + valve.setRequestAttributesEnabled( + tomcatProperties.getAccesslog().isRequestAttributesEnabled()); + valve.setRotatable(tomcatProperties.getAccesslog().isRotate()); + valve.setBuffered(tomcatProperties.getAccesslog().isBuffered()); + factory.addEngineValves(valve); + } + + private static void customizeRedirectContextRoot( + TomcatEmbeddedServletContainerFactory factory, + final boolean redirectContextRoot) { + factory.addContextCustomizers(new TomcatContextCustomizer() { + + @Override + public void customize(Context context) { + context.setMapperContextRootRedirectEnabled(redirectContextRoot); + } + + }); + } + + } + + private static class UndertowCustomizer { + + protected static void customizeUndertow(final ServerProperties serverProperties, + Environment environment, UndertowEmbeddedServletContainerFactory 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()); + } + } + + private static void customizeConnectionTimeout( + UndertowEmbeddedServletContainerFactory factory, + final int connectionTimeout) { + factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { + @Override + public void customize(Undertow.Builder builder) { + builder.setSocketOption(UndertowOptions.NO_REQUEST_TIMEOUT, + connectionTimeout); + } + }); + } + + private static void customizeMaxHttpHeaderSize( + UndertowEmbeddedServletContainerFactory factory, + final int maxHttpHeaderSize) { + factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { + + @Override + public void customize(Undertow.Builder builder) { + builder.setServerOption(UndertowOptions.MAX_HEADER_SIZE, + maxHttpHeaderSize); + } + + }); + } + + private static void customizeMaxHttpPostSize( + UndertowEmbeddedServletContainerFactory factory, + final long maxHttpPostSize) { + factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { + + @Override + public void customize(Undertow.Builder builder) { + builder.setServerOption(UndertowOptions.MAX_ENTITY_SIZE, + maxHttpPostSize); + } + + }); + } + + } + + private static class JettyCustomizer { + + public static void customizeJetty(final ServerProperties serverProperties, + Environment environment, JettyEmbeddedServletContainerFactory factory) { + ServerProperties.Jetty jettyProperties = serverProperties.getJetty(); + factory.setUseForwardHeaders(getOrDeduceUseForwardHeaders(serverProperties, environment)); + if (jettyProperties.getAcceptors() != null) { + factory.setAcceptors(jettyProperties.getAcceptors()); + } + if (jettyProperties.getSelectors() != null) { + factory.setSelectors(jettyProperties.getSelectors()); + } + if (serverProperties.getMaxHttpHeaderSize() > 0) { + customizeMaxHttpHeaderSize(factory, + serverProperties.getMaxHttpHeaderSize()); + } + if (jettyProperties.getMaxHttpPostSize() > 0) { + customizeMaxHttpPostSize(factory, jettyProperties.getMaxHttpPostSize()); + } + + if (serverProperties.getConnectionTimeout() != null) { + customizeConnectionTimeout(factory, + serverProperties.getConnectionTimeout()); + } + } + + private static void customizeConnectionTimeout( + JettyEmbeddedServletContainerFactory factory, + final int connectionTimeout) { + factory.addServerCustomizers(new JettyServerCustomizer() { + + @Override + public void customize(Server server) { + for (org.eclipse.jetty.server.Connector connector : server + .getConnectors()) { + if (connector instanceof AbstractConnector) { + ((AbstractConnector) connector) + .setIdleTimeout(connectionTimeout); + } + } + } + + }); + } + + private static void customizeMaxHttpHeaderSize( + JettyEmbeddedServletContainerFactory factory, + final int maxHttpHeaderSize) { + factory.addServerCustomizers(new JettyServerCustomizer() { + + @Override + public void customize(Server server) { + for (org.eclipse.jetty.server.Connector connector : server + .getConnectors()) { + try { + for (ConnectionFactory connectionFactory : connector + .getConnectionFactories()) { + if (connectionFactory instanceof HttpConfiguration.ConnectionFactory) { + customize( + (HttpConfiguration.ConnectionFactory) connectionFactory); + } + } + } + catch (NoSuchMethodError ex) { + customizeOnJetty8(connector, maxHttpHeaderSize); + } + } + + } + + private void customize(HttpConfiguration.ConnectionFactory factory) { + HttpConfiguration configuration = factory.getHttpConfiguration(); + configuration.setRequestHeaderSize(maxHttpHeaderSize); + configuration.setResponseHeaderSize(maxHttpHeaderSize); + } + + private void customizeOnJetty8( + org.eclipse.jetty.server.Connector connector, + int maxHttpHeaderSize) { + try { + connector.getClass().getMethod("setRequestHeaderSize", int.class) + .invoke(connector, maxHttpHeaderSize); + connector.getClass().getMethod("setResponseHeaderSize", int.class) + .invoke(connector, maxHttpHeaderSize); + } + catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + }); + } + + private static void customizeMaxHttpPostSize( + JettyEmbeddedServletContainerFactory factory, final int maxHttpPostSize) { + factory.addServerCustomizers(new JettyServerCustomizer() { + + @Override + public void customize(Server server) { + setHandlerMaxHttpPostSize(maxHttpPostSize, server.getHandlers()); + } + + private void setHandlerMaxHttpPostSize(int maxHttpPostSize, + Handler... handlers) { + for (Handler handler : handlers) { + if (handler instanceof ContextHandler) { + ((ContextHandler) handler) + .setMaxFormContentSize(maxHttpPostSize); + } + else if (handler instanceof HandlerWrapper) { + setHandlerMaxHttpPostSize(maxHttpPostSize, + ((HandlerWrapper) handler).getHandler()); + } + else if (handler instanceof HandlerCollection) { + setHandlerMaxHttpPostSize(maxHttpPostSize, + ((HandlerCollection) handler).getHandlers()); + } + } + } + + }); + } + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration.java index 93af3444948..1487a3f1a46 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration.java @@ -60,6 +60,7 @@ import org.springframework.util.ObjectUtils; * @author Phillip Webb * @author Dave Syer * @author Ivan Sopov + * @author Brian Clozel */ @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Configuration @@ -68,6 +69,13 @@ import org.springframework.util.ObjectUtils; @Import(BeanPostProcessorsRegistrar.class) public class EmbeddedServletContainerAutoConfiguration { + @Bean + @ConditionalOnMissingBean + public DefaultServletContainerCustomizer serverPropertiesServletContainerCustomizer( + ServerProperties serverProperties) { + return new DefaultServletContainerCustomizer(serverProperties); + } + /** * Nested configuration if Tomcat is being used. */ diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index f947596617d..9e466aab7a9 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -23,60 +23,17 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.SessionCookieConfig; import javax.servlet.SessionTrackingMode; -import io.undertow.Undertow.Builder; -import io.undertow.UndertowOptions; -import org.apache.catalina.Context; -import org.apache.catalina.connector.Connector; -import org.apache.catalina.valves.AccessLogValve; -import org.apache.catalina.valves.RemoteIpValve; -import org.apache.coyote.AbstractProtocol; -import org.apache.coyote.ProtocolHandler; -import org.apache.coyote.http11.AbstractHttp11Protocol; -import org.eclipse.jetty.server.AbstractConnector; -import org.eclipse.jetty.server.ConnectionFactory; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.server.handler.HandlerWrapper; - -import org.springframework.boot.autoconfigure.web.ServerProperties.Session.Cookie; -import org.springframework.boot.cloud.CloudPlatform; import org.springframework.boot.context.embedded.Compression; -import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; -import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; -import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor; -import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; -import org.springframework.boot.context.embedded.InitParameterConfiguringServletContextInitializer; import org.springframework.boot.context.embedded.Servlet; import org.springframework.boot.context.embedded.Ssl; -import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory; -import org.springframework.boot.context.embedded.jetty.JettyServerCustomizer; -import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer; -import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer; -import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; -import org.springframework.boot.context.embedded.undertow.UndertowBuilderCustomizer; -import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; import org.springframework.boot.context.properties.NestedConfigurationProperty; -import org.springframework.boot.web.servlet.ServletContextInitializer; -import org.springframework.context.EnvironmentAware; -import org.springframework.core.Ordered; -import org.springframework.core.env.Environment; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; /** - * {@link ConfigurationProperties} for a web server (e.g. port and path settings). Will be - * used to customize an {@link EmbeddedServletContainerFactory} when an - * {@link EmbeddedServletContainerCustomizerBeanPostProcessor} is active. + * {@link ConfigurationProperties} for a web server (e.g. port and path settings). * * @author Dave Syer * @author Stephane Nicoll @@ -87,10 +44,10 @@ import org.springframework.util.StringUtils; * @author Quinten De Swaef * @author Venil Noronha * @author Aurélien Leboulanger + * @author Brian Clozel */ @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) -public class ServerProperties - implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered { +public class ServerProperties { /** * Server HTTP port. @@ -149,69 +106,6 @@ public class ServerProperties private final Undertow undertow = new Undertow(); - private Environment environment; - - @Override - public int getOrder() { - return 0; - } - - @Override - public void setEnvironment(Environment environment) { - this.environment = environment; - } - - @Override - public void customize(ConfigurableEmbeddedServletContainer container) { - if (getPort() != null) { - container.setPort(getPort()); - } - if (getAddress() != null) { - container.setAddress(getAddress()); - } - if (getServlet().getContextPath() != null) { - container.setContextPath(getServlet().getContextPath()); - } - if (getDisplayName() != null) { - container.setDisplayName(getDisplayName()); - } - if (getSession().getTimeout() != null) { - container.setSessionTimeout(getSession().getTimeout()); - } - container.setPersistSession(getSession().isPersistent()); - container.setSessionStoreDir(getSession().getStoreDir()); - if (getSsl() != null) { - container.setSsl(getSsl()); - } - if (getServlet().getJsp() != null) { - container.setJsp(getServlet().getJsp()); - } - if (getCompression() != null) { - container.setCompression(getCompression()); - } - container.setServerHeader(getServerHeader()); - if (container instanceof TomcatEmbeddedServletContainerFactory) { - getTomcat().customizeTomcat(this, - (TomcatEmbeddedServletContainerFactory) container); - } - if (container instanceof JettyEmbeddedServletContainerFactory) { - getJetty().customizeJetty(this, - (JettyEmbeddedServletContainerFactory) container); - } - - if (container instanceof UndertowEmbeddedServletContainerFactory) { - getUndertow().customizeUndertow(this, - (UndertowEmbeddedServletContainerFactory) container); - } - container.addInitializers(new SessionConfiguringInitializer(this.session)); - container.addInitializers(new InitParameterConfiguringServletContextInitializer( - getServlet().getContextParameters())); - } - - public void setLoader(String value) { - // no op to support Tomcat running as a traditional container (not embedded) - } - public Integer getPort() { return this.port; } @@ -260,14 +154,6 @@ public class ServerProperties this.maxHttpHeaderSize = maxHttpHeaderSize; } - protected final boolean getOrDeduceUseForwardHeaders() { - if (this.useForwardHeaders != null) { - return this.useForwardHeaders; - } - CloudPlatform platform = CloudPlatform.getActive(this.environment); - return (platform == null ? false : platform.isUsingForwardHeaders()); - } - public Integer getConnectionTimeout() { return this.connectionTimeout; } @@ -684,6 +570,14 @@ public class ServerProperties this.maxConnections = maxConnections; } + public int getMaxHttpHeaderSize() { + return this.maxHttpHeaderSize; + } + + public void setMaxHttpHeaderSize(int maxHttpHeaderSize) { + this.maxHttpHeaderSize = maxHttpHeaderSize; + } + public int getAcceptCount() { return this.acceptCount; } @@ -700,212 +594,6 @@ public class ServerProperties this.additionalTldSkipPatterns = additionalTldSkipPatterns; } - void customizeTomcat(ServerProperties serverProperties, - TomcatEmbeddedServletContainerFactory factory) { - if (getBasedir() != null) { - factory.setBaseDirectory(getBasedir()); - } - factory.setBackgroundProcessorDelay(Tomcat.this.backgroundProcessorDelay); - customizeRemoteIpValve(serverProperties, factory); - if (this.maxThreads > 0) { - customizeMaxThreads(factory); - } - if (this.minSpareThreads > 0) { - customizeMinThreads(factory); - } - int maxHttpHeaderSize = (serverProperties.getMaxHttpHeaderSize() > 0 - ? serverProperties.getMaxHttpHeaderSize() : this.maxHttpHeaderSize); - if (maxHttpHeaderSize > 0) { - customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize); - } - if (this.maxHttpPostSize > 0) { - customizeMaxHttpPostSize(factory, this.maxHttpPostSize); - } - if (this.accesslog.enabled) { - customizeAccessLog(factory); - } - if (getUriEncoding() != null) { - factory.setUriEncoding(getUriEncoding()); - } - if (serverProperties.getConnectionTimeout() != null) { - customizeConnectionTimeout(factory, - serverProperties.getConnectionTimeout()); - } - if (this.redirectContextRoot != null) { - customizeRedirectContextRoot(factory, this.redirectContextRoot); - } - if (this.maxConnections > 0) { - customizeMaxConnections(factory); - } - if (this.acceptCount > 0) { - customizeAcceptCount(factory); - } - if (!ObjectUtils.isEmpty(this.additionalTldSkipPatterns)) { - factory.getTldSkipPatterns().addAll(this.additionalTldSkipPatterns); - } - } - - private void customizeAcceptCount(TomcatEmbeddedServletContainerFactory factory) { - factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { - - @Override - public void customize(Connector connector) { - ProtocolHandler handler = connector.getProtocolHandler(); - if (handler instanceof AbstractProtocol) { - AbstractProtocol protocol = (AbstractProtocol) handler; - protocol.setBacklog(Tomcat.this.acceptCount); - } - } - - }); - } - - private void customizeMaxConnections( - TomcatEmbeddedServletContainerFactory factory) { - factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { - - @Override - public void customize(Connector connector) { - ProtocolHandler handler = connector.getProtocolHandler(); - if (handler instanceof AbstractProtocol) { - AbstractProtocol protocol = (AbstractProtocol) handler; - protocol.setMaxConnections(Tomcat.this.maxConnections); - } - } - - }); - } - - private void customizeConnectionTimeout( - TomcatEmbeddedServletContainerFactory factory, - final int connectionTimeout) { - factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { - - @Override - public void customize(Connector connector) { - ProtocolHandler handler = connector.getProtocolHandler(); - if (handler instanceof AbstractProtocol) { - AbstractProtocol protocol = (AbstractProtocol) handler; - protocol.setConnectionTimeout(connectionTimeout); - } - } - - }); - } - - private void customizeRemoteIpValve(ServerProperties properties, - TomcatEmbeddedServletContainerFactory factory) { - String protocolHeader = getProtocolHeader(); - String remoteIpHeader = getRemoteIpHeader(); - // For back compatibility the valve is also enabled if protocol-header is set - if (StringUtils.hasText(protocolHeader) || StringUtils.hasText(remoteIpHeader) - || properties.getOrDeduceUseForwardHeaders()) { - RemoteIpValve valve = new RemoteIpValve(); - valve.setProtocolHeader(StringUtils.hasLength(protocolHeader) - ? protocolHeader : "X-Forwarded-Proto"); - if (StringUtils.hasLength(remoteIpHeader)) { - valve.setRemoteIpHeader(remoteIpHeader); - } - // The internal proxies default to a white list of "safe" internal IP - // addresses - valve.setInternalProxies(getInternalProxies()); - valve.setPortHeader(getPortHeader()); - valve.setProtocolHeaderHttpsValue(getProtocolHeaderHttpsValue()); - // ... so it's safe to add this valve by default. - factory.addEngineValves(valve); - } - } - - @SuppressWarnings("rawtypes") - private void customizeMaxThreads(TomcatEmbeddedServletContainerFactory factory) { - factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { - @Override - public void customize(Connector connector) { - - ProtocolHandler handler = connector.getProtocolHandler(); - if (handler instanceof AbstractProtocol) { - AbstractProtocol protocol = (AbstractProtocol) handler; - protocol.setMaxThreads(Tomcat.this.maxThreads); - } - - } - }); - } - - @SuppressWarnings("rawtypes") - private void customizeMinThreads(TomcatEmbeddedServletContainerFactory factory) { - factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { - @Override - public void customize(Connector connector) { - - ProtocolHandler handler = connector.getProtocolHandler(); - if (handler instanceof AbstractProtocol) { - AbstractProtocol protocol = (AbstractProtocol) handler; - protocol.setMinSpareThreads(Tomcat.this.minSpareThreads); - } - - } - }); - } - - @SuppressWarnings("rawtypes") - private void customizeMaxHttpHeaderSize( - TomcatEmbeddedServletContainerFactory factory, - final int maxHttpHeaderSize) { - factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { - - @Override - public void customize(Connector connector) { - ProtocolHandler handler = connector.getProtocolHandler(); - if (handler instanceof AbstractHttp11Protocol) { - AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler; - protocol.setMaxHttpHeaderSize(maxHttpHeaderSize); - } - } - - }); - } - - private void customizeMaxHttpPostSize( - TomcatEmbeddedServletContainerFactory factory, - final int maxHttpPostSize) { - factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { - - @Override - public void customize(Connector connector) { - connector.setMaxPostSize(maxHttpPostSize); - } - - }); - } - - private void customizeAccessLog(TomcatEmbeddedServletContainerFactory factory) { - AccessLogValve valve = new AccessLogValve(); - valve.setPattern(this.accesslog.getPattern()); - valve.setDirectory(this.accesslog.getDirectory()); - valve.setPrefix(this.accesslog.getPrefix()); - valve.setSuffix(this.accesslog.getSuffix()); - valve.setRenameOnRotate(this.accesslog.isRenameOnRotate()); - valve.setRequestAttributesEnabled( - this.accesslog.isRequestAttributesEnabled()); - valve.setRotatable(this.accesslog.isRotate()); - valve.setBuffered(this.accesslog.isBuffered()); - factory.addEngineValves(valve); - } - - private void customizeRedirectContextRoot( - TomcatEmbeddedServletContainerFactory factory, - final boolean redirectContextRoot) { - factory.addContextCustomizers(new TomcatContextCustomizer() { - - @Override - public void customize(Context context) { - context.setMapperContextRootRedirectEnabled(redirectContextRoot); - } - - }); - } - public static class Accesslog { /** @@ -1072,126 +760,6 @@ public class ServerProperties this.selectors = selectors; } - void customizeJetty(final ServerProperties serverProperties, - JettyEmbeddedServletContainerFactory factory) { - factory.setUseForwardHeaders(serverProperties.getOrDeduceUseForwardHeaders()); - if (this.acceptors != null) { - factory.setAcceptors(this.acceptors); - } - if (this.selectors != null) { - factory.setSelectors(this.selectors); - } - if (serverProperties.getMaxHttpHeaderSize() > 0) { - customizeMaxHttpHeaderSize(factory, - serverProperties.getMaxHttpHeaderSize()); - } - if (this.maxHttpPostSize > 0) { - customizeMaxHttpPostSize(factory, this.maxHttpPostSize); - } - - if (serverProperties.getConnectionTimeout() != null) { - customizeConnectionTimeout(factory, - serverProperties.getConnectionTimeout()); - } - } - - private void customizeConnectionTimeout( - JettyEmbeddedServletContainerFactory factory, - final int connectionTimeout) { - factory.addServerCustomizers(new JettyServerCustomizer() { - - @Override - public void customize(Server server) { - for (org.eclipse.jetty.server.Connector connector : server - .getConnectors()) { - if (connector instanceof AbstractConnector) { - ((AbstractConnector) connector) - .setIdleTimeout(connectionTimeout); - } - } - } - - }); - } - - private void customizeMaxHttpHeaderSize( - JettyEmbeddedServletContainerFactory factory, - final int maxHttpHeaderSize) { - factory.addServerCustomizers(new JettyServerCustomizer() { - - @Override - public void customize(Server server) { - for (org.eclipse.jetty.server.Connector connector : server - .getConnectors()) { - try { - for (ConnectionFactory connectionFactory : connector - .getConnectionFactories()) { - if (connectionFactory instanceof HttpConfiguration.ConnectionFactory) { - customize( - (HttpConfiguration.ConnectionFactory) connectionFactory); - } - } - } - catch (NoSuchMethodError ex) { - customizeOnJetty8(connector, maxHttpHeaderSize); - } - } - - } - - private void customize(HttpConfiguration.ConnectionFactory factory) { - HttpConfiguration configuration = factory.getHttpConfiguration(); - configuration.setRequestHeaderSize(maxHttpHeaderSize); - configuration.setResponseHeaderSize(maxHttpHeaderSize); - } - - private void customizeOnJetty8( - org.eclipse.jetty.server.Connector connector, - int maxHttpHeaderSize) { - try { - connector.getClass().getMethod("setRequestHeaderSize", int.class) - .invoke(connector, maxHttpHeaderSize); - connector.getClass().getMethod("setResponseHeaderSize", int.class) - .invoke(connector, maxHttpHeaderSize); - } - catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - }); - } - - private void customizeMaxHttpPostSize( - JettyEmbeddedServletContainerFactory factory, final int maxHttpPostSize) { - factory.addServerCustomizers(new JettyServerCustomizer() { - - @Override - public void customize(Server server) { - setHandlerMaxHttpPostSize(maxHttpPostSize, server.getHandlers()); - } - - private void setHandlerMaxHttpPostSize(int maxHttpPostSize, - Handler... handlers) { - for (Handler handler : handlers) { - if (handler instanceof ContextHandler) { - ((ContextHandler) handler) - .setMaxFormContentSize(maxHttpPostSize); - } - else if (handler instanceof HandlerWrapper) { - setHandlerMaxHttpPostSize(maxHttpPostSize, - ((HandlerWrapper) handler).getHandler()); - } - else if (handler instanceof HandlerCollection) { - setHandlerMaxHttpPostSize(maxHttpPostSize, - ((HandlerCollection) handler).getHandlers()); - } - } - } - - }); - } - } public static class Undertow { @@ -1282,82 +850,6 @@ public class ServerProperties return this.accesslog; } - void customizeUndertow(final ServerProperties serverProperties, - UndertowEmbeddedServletContainerFactory factory) { - if (this.bufferSize != null) { - factory.setBufferSize(this.bufferSize); - } - if (this.ioThreads != null) { - factory.setIoThreads(this.ioThreads); - } - if (this.workerThreads != null) { - factory.setWorkerThreads(this.workerThreads); - } - if (this.directBuffers != null) { - factory.setDirectBuffers(this.directBuffers); - } - if (this.accesslog.enabled != null) { - factory.setAccessLogEnabled(this.accesslog.enabled); - } - factory.setAccessLogDirectory(this.accesslog.dir); - factory.setAccessLogPattern(this.accesslog.pattern); - factory.setAccessLogPrefix(this.accesslog.prefix); - factory.setAccessLogSuffix(this.accesslog.suffix); - factory.setAccessLogRotate(this.accesslog.rotate); - factory.setUseForwardHeaders(serverProperties.getOrDeduceUseForwardHeaders()); - if (serverProperties.getMaxHttpHeaderSize() > 0) { - customizeMaxHttpHeaderSize(factory, - serverProperties.getMaxHttpHeaderSize()); - } - if (this.maxHttpPostSize > 0) { - customizeMaxHttpPostSize(factory, this.maxHttpPostSize); - } - - if (serverProperties.getConnectionTimeout() != null) { - customizeConnectionTimeout(factory, - serverProperties.getConnectionTimeout()); - } - } - - private void customizeConnectionTimeout( - UndertowEmbeddedServletContainerFactory factory, - final int connectionTimeout) { - factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { - @Override - public void customize(Builder builder) { - builder.setSocketOption(UndertowOptions.NO_REQUEST_TIMEOUT, - connectionTimeout); - } - }); - } - - private void customizeMaxHttpHeaderSize( - UndertowEmbeddedServletContainerFactory factory, - final int maxHttpHeaderSize) { - factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { - - @Override - public void customize(Builder builder) { - builder.setServerOption(UndertowOptions.MAX_HEADER_SIZE, - maxHttpHeaderSize); - } - - }); - } - - private void customizeMaxHttpPostSize( - UndertowEmbeddedServletContainerFactory factory, - final long maxHttpPostSize) { - factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { - - @Override - public void customize(Builder builder) { - builder.setServerOption(UndertowOptions.MAX_ENTITY_SIZE, - maxHttpPostSize); - } - - }); - } public static class Accesslog { @@ -1443,52 +935,4 @@ public class ServerProperties } - /** - * {@link ServletContextInitializer} to apply appropriate parts of the {@link Session} - * configuration. - */ - private static class SessionConfiguringInitializer - implements ServletContextInitializer { - - private final Session session; - - SessionConfiguringInitializer(Session session) { - this.session = session; - } - - @Override - public void onStartup(ServletContext servletContext) throws ServletException { - if (this.session.getTrackingModes() != null) { - servletContext.setSessionTrackingModes(this.session.getTrackingModes()); - } - configureSessionCookie(servletContext.getSessionCookieConfig()); - } - - private void configureSessionCookie(SessionCookieConfig config) { - Cookie cookie = this.session.getCookie(); - if (cookie.getName() != null) { - config.setName(cookie.getName()); - } - if (cookie.getDomain() != null) { - config.setDomain(cookie.getDomain()); - } - if (cookie.getPath() != null) { - config.setPath(cookie.getPath()); - } - if (cookie.getComment() != null) { - config.setComment(cookie.getComment()); - } - if (cookie.getHttpOnly() != null) { - config.setHttpOnly(cookie.getHttpOnly()); - } - if (cookie.getSecure() != null) { - config.setSecure(cookie.getSecure()); - } - if (cookie.getMaxAge() != null) { - config.setMaxAge(cookie.getMaxAge()); - } - } - - } - } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationCustomFilterContextPathTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationCustomFilterContextPathTests.java index aa2bad5210c..3fc0bcefab2 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationCustomFilterContextPathTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationCustomFilterContextPathTests.java @@ -54,7 +54,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { - "spring.jersey.type=filter", "server.servlet.contextPath=/app" }) + "spring.jersey.type=filter", "server.servlet.context-path=/app" }) @DirtiesContext public class JerseyAutoConfigurationCustomFilterContextPathTests { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesIntegrationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/DefaultServletContainerCustomizerIntegrationTests.java similarity index 94% rename from spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesIntegrationTests.java rename to spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/DefaultServletContainerCustomizerIntegrationTests.java index 9d5df546951..e3fed86fb97 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesIntegrationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/DefaultServletContainerCustomizerIntegrationTests.java @@ -44,12 +44,12 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; /** - * Integration tests for {@link ServerProperties}. + * Integration tests for {@link DefaultServletContainerCustomizer}. * * @author Dave Syer * @author Ivan Sopov */ -public class ServerPropertiesIntegrationTests { +public class DefaultServletContainerCustomizerIntegrationTests { private static AbstractEmbeddedServletContainerFactory containerFactory; @@ -142,9 +142,14 @@ public class ServerPropertiesIntegrationTests { @EnableConfigurationProperties(ServerProperties.class) protected static class Config { + @Bean + public DefaultServletContainerCustomizer defaultServletContainerCustomizer(ServerProperties properties) { + return new DefaultServletContainerCustomizer(properties); + } + @Bean public EmbeddedServletContainerFactory containerFactory() { - return ServerPropertiesIntegrationTests.containerFactory; + return DefaultServletContainerCustomizerIntegrationTests.containerFactory; } @Bean diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/DefaultServletContainerCustomizerTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/DefaultServletContainerCustomizerTests.java new file mode 100644 index 00000000000..8f01d7d3464 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/DefaultServletContainerCustomizerTests.java @@ -0,0 +1,519 @@ +/* + * Copyright 2012-2017 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; + +import java.io.File; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; + +import org.apache.catalina.Context; +import org.apache.catalina.Valve; +import org.apache.catalina.valves.AccessLogValve; +import org.apache.catalina.valves.RemoteIpValve; +import org.apache.coyote.AbstractProtocol; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.MockitoAnnotations; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.boot.bind.RelaxedDataBinder; +import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; +import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer; +import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer; +import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory; +import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.mock.env.MockEnvironment; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link DefaultServletContainerCustomizer}. + * + * @author Brian Clozel + */ +public class DefaultServletContainerCustomizerTests { + + private final ServerProperties properties = new ServerProperties(); + + private DefaultServletContainerCustomizer customizer; + + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + this.customizer = new DefaultServletContainerCustomizer(this.properties); + } + + @Test + public void tomcatAccessLogIsDisabledByDefault() { + TomcatEmbeddedServletContainerFactory tomcatContainer = new TomcatEmbeddedServletContainerFactory(); + this.customizer.customize(tomcatContainer); + assertThat(tomcatContainer.getEngineValves()).isEmpty(); + } + + @Test + public void tomcatAccessLogCanBeEnabled() { + TomcatEmbeddedServletContainerFactory tomcatContainer = new TomcatEmbeddedServletContainerFactory(); + Map map = new HashMap(); + map.put("server.tomcat.accesslog.enabled", "true"); + bindProperties(map); + this.customizer.customize(tomcatContainer); + assertThat(tomcatContainer.getEngineValves()).hasSize(1); + assertThat(tomcatContainer.getEngineValves()).first() + .isInstanceOf(AccessLogValve.class); + } + + @Test + public void tomcatAccessLogIsBufferedByDefault() { + TomcatEmbeddedServletContainerFactory tomcatContainer = new TomcatEmbeddedServletContainerFactory(); + Map map = new HashMap(); + map.put("server.tomcat.accesslog.enabled", "true"); + bindProperties(map); + this.customizer.customize(tomcatContainer); + assertThat(((AccessLogValve) tomcatContainer.getEngineValves().iterator().next()) + .isBuffered()).isTrue(); + } + + @Test + public void tomcatAccessLogBufferingCanBeDisabled() { + TomcatEmbeddedServletContainerFactory tomcatContainer = new TomcatEmbeddedServletContainerFactory(); + Map map = new HashMap(); + map.put("server.tomcat.accesslog.enabled", "true"); + map.put("server.tomcat.accesslog.buffered", "false"); + bindProperties(map); + this.customizer.customize(tomcatContainer); + assertThat(((AccessLogValve) tomcatContainer.getEngineValves().iterator().next()) + .isBuffered()).isFalse(); + } + + @Test + public void redirectContextRootCanBeConfigured() throws Exception { + Map map = new HashMap(); + map.put("server.tomcat.redirect-context-root", "false"); + bindProperties(map); + ServerProperties.Tomcat tomcat = this.properties.getTomcat(); + assertThat(tomcat.getRedirectContextRoot()).isEqualTo(false); + TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); + this.customizer.customize(container); + Context context = mock(Context.class); + for (TomcatContextCustomizer customizer : container + .getTomcatContextCustomizers()) { + customizer.customize(context); + } + verify(context).setMapperContextRootRedirectEnabled(false); + } + + @Test + public void testCustomizeTomcat() throws Exception { + ConfigurableEmbeddedServletContainer factory = mock( + ConfigurableEmbeddedServletContainer.class); + this.customizer.customize(factory); + verify(factory, never()).setContextPath(""); + } + + @Test + public void testDefaultDisplayName() throws Exception { + ConfigurableEmbeddedServletContainer factory = mock( + ConfigurableEmbeddedServletContainer.class); + this.customizer.customize(factory); + verify(factory).setDisplayName("application"); + } + + @Test + public void testCustomizeDisplayName() throws Exception { + ConfigurableEmbeddedServletContainer factory = mock( + ConfigurableEmbeddedServletContainer.class); + this.properties.setDisplayName("TestName"); + this.customizer.customize(factory); + verify(factory).setDisplayName("TestName"); + } + + @Test + public void customizeSessionProperties() throws Exception { + Map map = new HashMap(); + map.put("server.session.timeout", "123"); + map.put("server.session.tracking-modes", "cookie,url"); + map.put("server.session.cookie.name", "testname"); + map.put("server.session.cookie.domain", "testdomain"); + map.put("server.session.cookie.path", "/testpath"); + map.put("server.session.cookie.comment", "testcomment"); + map.put("server.session.cookie.http-only", "true"); + map.put("server.session.cookie.secure", "true"); + map.put("server.session.cookie.max-age", "60"); + bindProperties(map); + ConfigurableEmbeddedServletContainer factory = mock( + ConfigurableEmbeddedServletContainer.class); + ServletContext servletContext = mock(ServletContext.class); + SessionCookieConfig sessionCookieConfig = mock(SessionCookieConfig.class); + given(servletContext.getSessionCookieConfig()).willReturn(sessionCookieConfig); + this.customizer.customize(factory); + triggerInitializers(factory, servletContext); + verify(factory).setSessionTimeout(123); + verify(servletContext).setSessionTrackingModes( + EnumSet.of(SessionTrackingMode.COOKIE, SessionTrackingMode.URL)); + verify(sessionCookieConfig).setName("testname"); + verify(sessionCookieConfig).setDomain("testdomain"); + verify(sessionCookieConfig).setPath("/testpath"); + verify(sessionCookieConfig).setComment("testcomment"); + verify(sessionCookieConfig).setHttpOnly(true); + verify(sessionCookieConfig).setSecure(true); + verify(sessionCookieConfig).setMaxAge(60); + } + + @Test + public void testCustomizeTomcatPort() throws Exception { + ConfigurableEmbeddedServletContainer factory = mock( + ConfigurableEmbeddedServletContainer.class); + this.properties.setPort(8080); + this.customizer.customize(factory); + verify(factory).setPort(8080); + } + + @Test + public void customizeTomcatDisplayName() throws Exception { + Map map = new HashMap(); + map.put("server.display-name", "MyBootApp"); + bindProperties(map); + TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); + this.customizer.customize(container); + assertThat(container.getDisplayName()).isEqualTo("MyBootApp"); + } + + @Test + public void disableTomcatRemoteIpValve() throws Exception { + Map map = new HashMap(); + map.put("server.tomcat.remote_ip_header", ""); + map.put("server.tomcat.protocol_header", ""); + bindProperties(map); + TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); + this.customizer.customize(container); + assertThat(container.getEngineValves()).isEmpty(); + } + + @Test + public void defaultTomcatBackgroundProcessorDelay() throws Exception { + TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); + this.customizer.customize(container); + assertThat( + ((TomcatEmbeddedServletContainer) container.getEmbeddedServletContainer()) + .getTomcat().getEngine().getBackgroundProcessorDelay()) + .isEqualTo(30); + } + + @Test + public void customTomcatBackgroundProcessorDelay() throws Exception { + Map map = new HashMap(); + map.put("server.tomcat.background-processor-delay", "5"); + bindProperties(map); + TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); + this.customizer.customize(container); + assertThat( + ((TomcatEmbeddedServletContainer) container.getEmbeddedServletContainer()) + .getTomcat().getEngine().getBackgroundProcessorDelay()) + .isEqualTo(5); + } + + @Test + public void defaultTomcatRemoteIpValve() throws Exception { + Map map = new HashMap(); + // Since 1.1.7 you need to specify at least the protocol + map.put("server.tomcat.protocol_header", "X-Forwarded-Proto"); + map.put("server.tomcat.remote_ip_header", "X-Forwarded-For"); + bindProperties(map); + testRemoteIpValveConfigured(); + } + + @Test + public void setUseForwardHeadersTomcat() throws Exception { + // Since 1.3.0 no need to explicitly set header names if use-forward-header=true + this.properties.setUseForwardHeaders(true); + testRemoteIpValveConfigured(); + } + + @Test + public void deduceUseForwardHeadersTomcat() throws Exception { + this.customizer.setEnvironment(new MockEnvironment().withProperty("DYNO", "-")); + testRemoteIpValveConfigured(); + } + + private void testRemoteIpValveConfigured() { + TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); + this.customizer.customize(container); + assertThat(container.getEngineValves()).hasSize(1); + Valve valve = container.getEngineValves().iterator().next(); + assertThat(valve).isInstanceOf(RemoteIpValve.class); + RemoteIpValve remoteIpValve = (RemoteIpValve) valve; + assertThat(remoteIpValve.getProtocolHeader()).isEqualTo("X-Forwarded-Proto"); + assertThat(remoteIpValve.getProtocolHeaderHttpsValue()).isEqualTo("https"); + assertThat(remoteIpValve.getRemoteIpHeader()).isEqualTo("X-Forwarded-For"); + String expectedInternalProxies = "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" // 10/8 + + "192\\.168\\.\\d{1,3}\\.\\d{1,3}|" // 192.168/16 + + "169\\.254\\.\\d{1,3}\\.\\d{1,3}|" // 169.254/16 + + "127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" // 127/8 + + "172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" // 172.16/12 + + "172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" + + "172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}"; + assertThat(remoteIpValve.getInternalProxies()).isEqualTo(expectedInternalProxies); + } + + @Test + public void customTomcatRemoteIpValve() throws Exception { + Map map = new HashMap(); + map.put("server.tomcat.remote_ip_header", "x-my-remote-ip-header"); + map.put("server.tomcat.protocol_header", "x-my-protocol-header"); + map.put("server.tomcat.internal_proxies", "192.168.0.1"); + map.put("server.tomcat.port-header", "x-my-forward-port"); + map.put("server.tomcat.protocol-header-https-value", "On"); + bindProperties(map); + TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); + this.customizer.customize(container); + assertThat(container.getEngineValves()).hasSize(1); + Valve valve = container.getEngineValves().iterator().next(); + assertThat(valve).isInstanceOf(RemoteIpValve.class); + RemoteIpValve remoteIpValve = (RemoteIpValve) valve; + assertThat(remoteIpValve.getProtocolHeader()).isEqualTo("x-my-protocol-header"); + assertThat(remoteIpValve.getProtocolHeaderHttpsValue()).isEqualTo("On"); + assertThat(remoteIpValve.getRemoteIpHeader()).isEqualTo("x-my-remote-ip-header"); + assertThat(remoteIpValve.getPortHeader()).isEqualTo("x-my-forward-port"); + assertThat(remoteIpValve.getInternalProxies()).isEqualTo("192.168.0.1"); + } + + @Test + public void customTomcatAcceptCount() { + Map map = new HashMap(); + map.put("server.tomcat.accept-count", "10"); + bindProperties(map); + TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory( + 0); + this.customizer.customize(container); + TomcatEmbeddedServletContainer embeddedContainer = (TomcatEmbeddedServletContainer) container + .getEmbeddedServletContainer(); + embeddedContainer.start(); + try { + assertThat(((AbstractProtocol) embeddedContainer.getTomcat().getConnector() + .getProtocolHandler()).getBacklog()).isEqualTo(10); + } + finally { + embeddedContainer.stop(); + } + } + + @Test + public void customTomcatMaxConnections() { + Map map = new HashMap(); + map.put("server.tomcat.max-connections", "5"); + bindProperties(map); + TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory( + 0); + this.customizer.customize(container); + TomcatEmbeddedServletContainer embeddedContainer = (TomcatEmbeddedServletContainer) container + .getEmbeddedServletContainer(); + embeddedContainer.start(); + try { + assertThat(((AbstractProtocol) embeddedContainer.getTomcat().getConnector() + .getProtocolHandler()).getMaxConnections()).isEqualTo(5); + } + finally { + embeddedContainer.stop(); + } + } + + @Test + public void customTomcatMaxHttpPostSize() { + Map map = new HashMap(); + map.put("server.tomcat.max-http-post-size", "10000"); + bindProperties(map); + TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory( + 0); + this.customizer.customize(container); + TomcatEmbeddedServletContainer embeddedContainer = (TomcatEmbeddedServletContainer) container + .getEmbeddedServletContainer(); + embeddedContainer.start(); + try { + assertThat(embeddedContainer.getTomcat().getConnector().getMaxPostSize()) + .isEqualTo(10000); + } + finally { + embeddedContainer.stop(); + } + } + + @Test + public void customizeUndertowAccessLog() { + Map 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); + UndertowEmbeddedServletContainerFactory container = spy( + new UndertowEmbeddedServletContainerFactory()); + this.customizer.customize(container); + verify(container).setAccessLogEnabled(true); + verify(container).setAccessLogPattern("foo"); + verify(container).setAccessLogPrefix("test_log"); + verify(container).setAccessLogSuffix("txt"); + verify(container).setAccessLogDirectory(new File("test-logs")); + verify(container).setAccessLogRotate(false); + } + + @Test + public void testCustomizeTomcatMinSpareThreads() throws Exception { + Map map = new HashMap(); + map.put("server.tomcat.min-spare-threads", "10"); + bindProperties(map); + assertThat(this.properties.getTomcat().getMinSpareThreads()).isEqualTo(10); + } + + @Test + public void customTomcatTldSkip() { + Map map = new HashMap(); + map.put("server.tomcat.additional-tld-skip-patterns", "foo.jar,bar.jar"); + bindProperties(map); + testCustomTomcatTldSkip("foo.jar", "bar.jar"); + } + + @Test + public void customTomcatTldSkipAsList() { + Map map = new HashMap(); + map.put("server.tomcat.additional-tld-skip-patterns[0]", "biz.jar"); + map.put("server.tomcat.additional-tld-skip-patterns[1]", "bah.jar"); + bindProperties(map); + testCustomTomcatTldSkip("biz.jar", "bah.jar"); + } + + private void testCustomTomcatTldSkip(String... expectedJars) { + TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); + this.customizer.customize(container); + assertThat(container.getTldSkipPatterns()).contains(expectedJars); + assertThat(container.getTldSkipPatterns()).contains("junit-*.jar", + "spring-boot-*.jar"); + } + + @Test + public void defaultUseForwardHeadersUndertow() throws Exception { + UndertowEmbeddedServletContainerFactory container = spy( + new UndertowEmbeddedServletContainerFactory()); + this.customizer.customize(container); + verify(container).setUseForwardHeaders(false); + } + + @Test + public void setUseForwardHeadersUndertow() throws Exception { + this.properties.setUseForwardHeaders(true); + UndertowEmbeddedServletContainerFactory container = spy( + new UndertowEmbeddedServletContainerFactory()); + this.customizer.customize(container); + verify(container).setUseForwardHeaders(true); + } + + @Test + public void deduceUseForwardHeadersUndertow() throws Exception { + this.customizer.setEnvironment(new MockEnvironment().withProperty("DYNO", "-")); + UndertowEmbeddedServletContainerFactory container = spy( + new UndertowEmbeddedServletContainerFactory()); + this.customizer.customize(container); + verify(container).setUseForwardHeaders(true); + } + + @Test + public void defaultUseForwardHeadersJetty() throws Exception { + JettyEmbeddedServletContainerFactory container = spy( + new JettyEmbeddedServletContainerFactory()); + this.customizer.customize(container); + verify(container).setUseForwardHeaders(false); + } + + @Test + public void setUseForwardHeadersJetty() throws Exception { + this.properties.setUseForwardHeaders(true); + JettyEmbeddedServletContainerFactory container = spy( + new JettyEmbeddedServletContainerFactory()); + this.customizer.customize(container); + verify(container).setUseForwardHeaders(true); + } + + @Test + public void deduceUseForwardHeadersJetty() throws Exception { + this.customizer.setEnvironment(new MockEnvironment().withProperty("DYNO", "-")); + JettyEmbeddedServletContainerFactory container = spy( + new JettyEmbeddedServletContainerFactory()); + this.customizer.customize(container); + verify(container).setUseForwardHeaders(true); + } + + @Test + public void sessionStoreDir() throws Exception { + Map map = new HashMap(); + map.put("server.session.store-dir", "myfolder"); + bindProperties(map); + JettyEmbeddedServletContainerFactory container = spy( + new JettyEmbeddedServletContainerFactory()); + this.customizer.customize(container); + verify(container).setSessionStoreDir(new File("myfolder")); + } + + @Test + public void skipNullElementsForUndertow() throws Exception { + UndertowEmbeddedServletContainerFactory container = mock( + UndertowEmbeddedServletContainerFactory.class); + this.customizer.customize(container); + verify(container, never()).setAccessLogEnabled(anyBoolean()); + } + + private void triggerInitializers(ConfigurableEmbeddedServletContainer container, + ServletContext servletContext) throws ServletException { + verify(container, atLeastOnce()) + .addInitializers(this.initializersCaptor.capture()); + for (Object initializers : this.initializersCaptor.getAllValues()) { + if (initializers instanceof ServletContextInitializer) { + ((ServletContextInitializer) initializers).onStartup(servletContext); + } + else { + for (ServletContextInitializer initializer : (ServletContextInitializer[]) initializers) { + initializer.onStartup(servletContext); + } + } + } + } + + @Captor + private ArgumentCaptor initializersCaptor; + + private void bindProperties(Map map) { + new RelaxedDataBinder(this.properties, "server") + .bind(new MutablePropertyValues(map)); + } +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfigurationTests.java index 00d2479136b..5baf102d7d7 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfigurationTests.java @@ -122,8 +122,8 @@ public class EmbeddedServletContainerAutoConfigurationTests { public void initParametersAreConfiguredOnTheServletContext() { this.context = new AnnotationConfigEmbeddedWebApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, - "server.servlet.context_parameters.a:alpha", - "server.servlet.context_parameters.b:bravo"); + "server.servlet.context-parameters.a:alpha", + "server.servlet.context-parameters.b:bravo"); this.context.register(BaseConfiguration.class); this.context.refresh(); diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index ab263a80e4e..c5e44aee6b9 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -16,49 +16,18 @@ package org.springframework.boot.autoconfigure.web; -import java.io.File; import java.net.InetAddress; import java.nio.charset.Charset; import java.util.Collections; -import java.util.EnumSet; import java.util.HashMap; import java.util.Map; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.SessionCookieConfig; -import javax.servlet.SessionTrackingMode; - -import org.apache.catalina.Context; -import org.apache.catalina.Valve; -import org.apache.catalina.valves.AccessLogValve; -import org.apache.catalina.valves.RemoteIpValve; -import org.apache.coyote.AbstractProtocol; -import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.MockitoAnnotations; import org.springframework.beans.MutablePropertyValues; import org.springframework.boot.bind.RelaxedDataBinder; -import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; -import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory; -import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer; -import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer; -import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; -import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory; -import org.springframework.boot.web.servlet.ServletContextInitializer; -import org.springframework.mock.env.MockEnvironment; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; /** * Tests for {@link ServerProperties}. @@ -75,14 +44,6 @@ public class ServerPropertiesTests { private final ServerProperties properties = new ServerProperties(); - @Captor - private ArgumentCaptor initializersCaptor; - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - } - @Test public void testAddressBinding() throws Exception { RelaxedDataBinder binder = new RelaxedDataBinder(this.properties, "server"); @@ -141,48 +102,6 @@ public class ServerPropertiesTests { assertThat(this.properties.getServlet().getServletPrefix()).isEqualTo("/foo"); } - @Test - public void tomcatAccessLogIsDisabledByDefault() { - TomcatEmbeddedServletContainerFactory tomcatContainer = new TomcatEmbeddedServletContainerFactory(); - this.properties.customize(tomcatContainer); - assertThat(tomcatContainer.getEngineValves()).isEmpty(); - } - - @Test - public void tomcatAccessLogCanBeEnabled() { - TomcatEmbeddedServletContainerFactory tomcatContainer = new TomcatEmbeddedServletContainerFactory(); - Map map = new HashMap(); - map.put("server.tomcat.accesslog.enabled", "true"); - bindProperties(map); - this.properties.customize(tomcatContainer); - assertThat(tomcatContainer.getEngineValves()).hasSize(1); - assertThat(tomcatContainer.getEngineValves()).first() - .isInstanceOf(AccessLogValve.class); - } - - @Test - public void tomcatAccessLogIsBufferedByDefault() { - TomcatEmbeddedServletContainerFactory tomcatContainer = new TomcatEmbeddedServletContainerFactory(); - Map map = new HashMap(); - map.put("server.tomcat.accesslog.enabled", "true"); - bindProperties(map); - this.properties.customize(tomcatContainer); - assertThat(((AccessLogValve) tomcatContainer.getEngineValves().iterator().next()) - .isBuffered()).isTrue(); - } - - @Test - public void tomcatAccessLogBufferingCanBeDisabled() { - TomcatEmbeddedServletContainerFactory tomcatContainer = new TomcatEmbeddedServletContainerFactory(); - Map map = new HashMap(); - map.put("server.tomcat.accesslog.enabled", "true"); - map.put("server.tomcat.accesslog.buffered", "false"); - bindProperties(map); - this.properties.customize(tomcatContainer); - assertThat(((AccessLogValve) tomcatContainer.getEngineValves().iterator().next()) - .isBuffered()).isFalse(); - } - @Test public void testTomcatBinding() throws Exception { Map map = new HashMap(); @@ -218,23 +137,6 @@ public class ServerPropertiesTests { assertThat(tomcat.getRedirectContextRoot()).isNull(); } - @Test - public void redirectContextRootCanBeConfigured() throws Exception { - Map map = new HashMap(); - map.put("server.tomcat.redirect-context-root", "false"); - bindProperties(map); - ServerProperties.Tomcat tomcat = this.properties.getTomcat(); - assertThat(tomcat.getRedirectContextRoot()).isEqualTo(false); - TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); - this.properties.customize(container); - Context context = mock(Context.class); - for (TomcatContextCustomizer customizer : container - .getTomcatContextCustomizers()) { - customizer.customize(context); - } - verify(context).setMapperContextRootRedirectEnabled(false); - } - @Test public void testTrailingSlashOfContextPathIsRemoved() { new RelaxedDataBinder(this.properties, "server").bind(new MutablePropertyValues( @@ -249,88 +151,6 @@ public class ServerPropertiesTests { assertThat(this.properties.getServlet().getContextPath()).isEqualTo(""); } - @Test - public void testCustomizeTomcat() throws Exception { - ConfigurableEmbeddedServletContainer factory = mock( - ConfigurableEmbeddedServletContainer.class); - this.properties.customize(factory); - verify(factory, never()).setContextPath(""); - } - - @Test - public void testDefaultDisplayName() throws Exception { - ConfigurableEmbeddedServletContainer factory = mock( - ConfigurableEmbeddedServletContainer.class); - this.properties.customize(factory); - verify(factory).setDisplayName("application"); - } - - @Test - public void testCustomizeDisplayName() throws Exception { - ConfigurableEmbeddedServletContainer factory = mock( - ConfigurableEmbeddedServletContainer.class); - this.properties.setDisplayName("TestName"); - this.properties.customize(factory); - verify(factory).setDisplayName("TestName"); - } - - @Test - public void customizeSessionProperties() throws Exception { - Map map = new HashMap(); - map.put("server.session.timeout", "123"); - map.put("server.session.tracking-modes", "cookie,url"); - map.put("server.session.cookie.name", "testname"); - map.put("server.session.cookie.domain", "testdomain"); - map.put("server.session.cookie.path", "/testpath"); - map.put("server.session.cookie.comment", "testcomment"); - map.put("server.session.cookie.http-only", "true"); - map.put("server.session.cookie.secure", "true"); - map.put("server.session.cookie.max-age", "60"); - bindProperties(map); - ConfigurableEmbeddedServletContainer factory = mock( - ConfigurableEmbeddedServletContainer.class); - ServletContext servletContext = mock(ServletContext.class); - SessionCookieConfig sessionCookieConfig = mock(SessionCookieConfig.class); - given(servletContext.getSessionCookieConfig()).willReturn(sessionCookieConfig); - this.properties.customize(factory); - triggerInitializers(factory, servletContext); - verify(factory).setSessionTimeout(123); - verify(servletContext).setSessionTrackingModes( - EnumSet.of(SessionTrackingMode.COOKIE, SessionTrackingMode.URL)); - verify(sessionCookieConfig).setName("testname"); - verify(sessionCookieConfig).setDomain("testdomain"); - verify(sessionCookieConfig).setPath("/testpath"); - verify(sessionCookieConfig).setComment("testcomment"); - verify(sessionCookieConfig).setHttpOnly(true); - verify(sessionCookieConfig).setSecure(true); - verify(sessionCookieConfig).setMaxAge(60); - } - - private void triggerInitializers(ConfigurableEmbeddedServletContainer container, - ServletContext servletContext) throws ServletException { - verify(container, atLeastOnce()) - .addInitializers(this.initializersCaptor.capture()); - for (Object initializers : this.initializersCaptor.getAllValues()) { - if (initializers instanceof ServletContextInitializer) { - ((ServletContextInitializer) initializers).onStartup(servletContext); - } - else { - for (ServletContextInitializer initializer : (ServletContextInitializer[]) initializers) { - initializer.onStartup(servletContext); - } - } - } - } - - @Test - public void testCustomizeTomcatPort() throws Exception { - ConfigurableEmbeddedServletContainer factory = mock( - ConfigurableEmbeddedServletContainer.class); - this.properties.setPort(8080); - this.properties.customize(factory); - verify(factory).setPort(8080); - } - @Test public void testCustomizeUriEncoding() throws Exception { Map map = new HashMap(); @@ -364,300 +184,6 @@ public class ServerPropertiesTests { assertThat(this.properties.getJetty().getSelectors()).isEqualTo(10); } - @Test - public void testCustomizeTomcatMinSpareThreads() throws Exception { - Map map = new HashMap(); - map.put("server.tomcat.min-spare-threads", "10"); - bindProperties(map); - assertThat(this.properties.getTomcat().getMinSpareThreads()).isEqualTo(10); - } - - @Test - public void customizeTomcatDisplayName() throws Exception { - Map map = new HashMap(); - map.put("server.display-name", "MyBootApp"); - bindProperties(map); - TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); - this.properties.customize(container); - assertThat(container.getDisplayName()).isEqualTo("MyBootApp"); - } - - @Test - public void disableTomcatRemoteIpValve() throws Exception { - Map map = new HashMap(); - map.put("server.tomcat.remote_ip_header", ""); - map.put("server.tomcat.protocol_header", ""); - bindProperties(map); - TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); - this.properties.customize(container); - assertThat(container.getEngineValves()).isEmpty(); - } - - @Test - public void defaultTomcatRemoteIpValve() throws Exception { - Map map = new HashMap(); - // Since 1.1.7 you need to specify at least the protocol - map.put("server.tomcat.protocol_header", "X-Forwarded-Proto"); - map.put("server.tomcat.remote_ip_header", "X-Forwarded-For"); - bindProperties(map); - testRemoteIpValveConfigured(); - } - - @Test - public void defaultTomcatBackgroundProcessorDelay() throws Exception { - TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); - this.properties.customize(container); - assertThat( - ((TomcatEmbeddedServletContainer) container.getEmbeddedServletContainer()) - .getTomcat().getEngine().getBackgroundProcessorDelay()) - .isEqualTo(30); - } - - @Test - public void customTomcatBackgroundProcessorDelay() throws Exception { - Map map = new HashMap(); - map.put("server.tomcat.background-processor-delay", "5"); - bindProperties(map); - TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); - this.properties.customize(container); - assertThat( - ((TomcatEmbeddedServletContainer) container.getEmbeddedServletContainer()) - .getTomcat().getEngine().getBackgroundProcessorDelay()) - .isEqualTo(5); - } - - @Test - public void setUseForwardHeadersTomcat() throws Exception { - // Since 1.3.0 no need to explicitly set header names if use-forward-header=true - this.properties.setUseForwardHeaders(true); - testRemoteIpValveConfigured(); - } - - @Test - public void deduceUseForwardHeadersTomcat() throws Exception { - this.properties.setEnvironment(new MockEnvironment().withProperty("DYNO", "-")); - testRemoteIpValveConfigured(); - } - - private void testRemoteIpValveConfigured() { - TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); - this.properties.customize(container); - assertThat(container.getEngineValves()).hasSize(1); - Valve valve = container.getEngineValves().iterator().next(); - assertThat(valve).isInstanceOf(RemoteIpValve.class); - RemoteIpValve remoteIpValve = (RemoteIpValve) valve; - assertThat(remoteIpValve.getProtocolHeader()).isEqualTo("X-Forwarded-Proto"); - assertThat(remoteIpValve.getProtocolHeaderHttpsValue()).isEqualTo("https"); - assertThat(remoteIpValve.getRemoteIpHeader()).isEqualTo("X-Forwarded-For"); - String expectedInternalProxies = "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" // 10/8 - + "192\\.168\\.\\d{1,3}\\.\\d{1,3}|" // 192.168/16 - + "169\\.254\\.\\d{1,3}\\.\\d{1,3}|" // 169.254/16 - + "127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" // 127/8 - + "172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" // 172.16/12 - + "172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" - + "172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}"; - assertThat(remoteIpValve.getInternalProxies()).isEqualTo(expectedInternalProxies); - } - - @Test - public void customTomcatRemoteIpValve() throws Exception { - Map map = new HashMap(); - map.put("server.tomcat.remote_ip_header", "x-my-remote-ip-header"); - map.put("server.tomcat.protocol_header", "x-my-protocol-header"); - map.put("server.tomcat.internal_proxies", "192.168.0.1"); - map.put("server.tomcat.port-header", "x-my-forward-port"); - map.put("server.tomcat.protocol-header-https-value", "On"); - bindProperties(map); - TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); - this.properties.customize(container); - assertThat(container.getEngineValves()).hasSize(1); - Valve valve = container.getEngineValves().iterator().next(); - assertThat(valve).isInstanceOf(RemoteIpValve.class); - RemoteIpValve remoteIpValve = (RemoteIpValve) valve; - assertThat(remoteIpValve.getProtocolHeader()).isEqualTo("x-my-protocol-header"); - assertThat(remoteIpValve.getProtocolHeaderHttpsValue()).isEqualTo("On"); - assertThat(remoteIpValve.getRemoteIpHeader()).isEqualTo("x-my-remote-ip-header"); - assertThat(remoteIpValve.getPortHeader()).isEqualTo("x-my-forward-port"); - assertThat(remoteIpValve.getInternalProxies()).isEqualTo("192.168.0.1"); - } - - @Test - public void customTomcatAcceptCount() { - Map map = new HashMap(); - map.put("server.tomcat.accept-count", "10"); - bindProperties(map); - TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory( - 0); - this.properties.customize(container); - TomcatEmbeddedServletContainer embeddedContainer = (TomcatEmbeddedServletContainer) container - .getEmbeddedServletContainer(); - embeddedContainer.start(); - try { - assertThat(((AbstractProtocol) embeddedContainer.getTomcat().getConnector() - .getProtocolHandler()).getBacklog()).isEqualTo(10); - } - finally { - embeddedContainer.stop(); - } - } - - @Test - public void customTomcatMaxConnections() { - Map map = new HashMap(); - map.put("server.tomcat.max-connections", "5"); - bindProperties(map); - TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory( - 0); - this.properties.customize(container); - TomcatEmbeddedServletContainer embeddedContainer = (TomcatEmbeddedServletContainer) container - .getEmbeddedServletContainer(); - embeddedContainer.start(); - try { - assertThat(((AbstractProtocol) embeddedContainer.getTomcat().getConnector() - .getProtocolHandler()).getMaxConnections()).isEqualTo(5); - } - finally { - embeddedContainer.stop(); - } - } - - @Test - public void customTomcatMaxHttpPostSize() { - Map map = new HashMap(); - map.put("server.tomcat.max-http-post-size", "10000"); - bindProperties(map); - TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory( - 0); - this.properties.customize(container); - TomcatEmbeddedServletContainer embeddedContainer = (TomcatEmbeddedServletContainer) container - .getEmbeddedServletContainer(); - embeddedContainer.start(); - try { - assertThat(embeddedContainer.getTomcat().getConnector().getMaxPostSize()) - .isEqualTo(10000); - } - finally { - embeddedContainer.stop(); - } - } - - @Test - public void customizeUndertowAccessLog() { - Map 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); - UndertowEmbeddedServletContainerFactory container = spy( - new UndertowEmbeddedServletContainerFactory()); - this.properties.getUndertow().customizeUndertow(this.properties, container); - verify(container).setAccessLogEnabled(true); - verify(container).setAccessLogPattern("foo"); - verify(container).setAccessLogPrefix("test_log"); - verify(container).setAccessLogSuffix("txt"); - verify(container).setAccessLogDirectory(new File("test-logs")); - verify(container).setAccessLogRotate(false); - } - - @Test - public void customTomcatTldSkip() { - Map map = new HashMap(); - map.put("server.tomcat.additional-tld-skip-patterns", "foo.jar,bar.jar"); - bindProperties(map); - testCustomTomcatTldSkip("foo.jar", "bar.jar"); - } - - @Test - public void customTomcatTldSkipAsList() { - Map map = new HashMap(); - map.put("server.tomcat.additional-tld-skip-patterns[0]", "biz.jar"); - map.put("server.tomcat.additional-tld-skip-patterns[1]", "bah.jar"); - bindProperties(map); - testCustomTomcatTldSkip("biz.jar", "bah.jar"); - } - - private void testCustomTomcatTldSkip(String... expectedJars) { - TomcatEmbeddedServletContainerFactory container = new TomcatEmbeddedServletContainerFactory(); - this.properties.customize(container); - assertThat(container.getTldSkipPatterns()).contains(expectedJars); - assertThat(container.getTldSkipPatterns()).contains("junit-*.jar", - "spring-boot-*.jar"); - } - - @Test - public void defaultUseForwardHeadersUndertow() throws Exception { - UndertowEmbeddedServletContainerFactory container = spy( - new UndertowEmbeddedServletContainerFactory()); - this.properties.customize(container); - verify(container).setUseForwardHeaders(false); - } - - @Test - public void setUseForwardHeadersUndertow() throws Exception { - this.properties.setUseForwardHeaders(true); - UndertowEmbeddedServletContainerFactory container = spy( - new UndertowEmbeddedServletContainerFactory()); - this.properties.customize(container); - verify(container).setUseForwardHeaders(true); - } - - @Test - public void deduceUseForwardHeadersUndertow() throws Exception { - this.properties.setEnvironment(new MockEnvironment().withProperty("DYNO", "-")); - UndertowEmbeddedServletContainerFactory container = spy( - new UndertowEmbeddedServletContainerFactory()); - this.properties.customize(container); - verify(container).setUseForwardHeaders(true); - } - - @Test - public void defaultUseForwardHeadersJetty() throws Exception { - JettyEmbeddedServletContainerFactory container = spy( - new JettyEmbeddedServletContainerFactory()); - this.properties.customize(container); - verify(container).setUseForwardHeaders(false); - } - - @Test - public void setUseForwardHeadersJetty() throws Exception { - this.properties.setUseForwardHeaders(true); - JettyEmbeddedServletContainerFactory container = spy( - new JettyEmbeddedServletContainerFactory()); - this.properties.customize(container); - verify(container).setUseForwardHeaders(true); - } - - @Test - public void deduceUseForwardHeadersJetty() throws Exception { - this.properties.setEnvironment(new MockEnvironment().withProperty("DYNO", "-")); - JettyEmbeddedServletContainerFactory container = spy( - new JettyEmbeddedServletContainerFactory()); - this.properties.customize(container); - verify(container).setUseForwardHeaders(true); - } - - @Test - public void sessionStoreDir() throws Exception { - Map map = new HashMap(); - map.put("server.session.store-dir", "myfolder"); - bindProperties(map); - JettyEmbeddedServletContainerFactory container = spy( - new JettyEmbeddedServletContainerFactory()); - this.properties.customize(container); - verify(container).setSessionStoreDir(new File("myfolder")); - } - - @Test - public void skipNullElementsForUndertow() throws Exception { - UndertowEmbeddedServletContainerFactory container = mock( - UndertowEmbeddedServletContainerFactory.class); - this.properties.customize(container); - verify(container, never()).setAccessLogEnabled(anyBoolean()); - } - private void bindProperties(Map map) { new RelaxedDataBinder(this.properties, "server") .bind(new MutablePropertyValues(map)); diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java index 8c6a5d156f4..60d9ea13d56 100644 --- a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java +++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java @@ -35,10 +35,8 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration; import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; import org.springframework.boot.autoconfigure.web.ResourceProperties; -import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.devtools.classpath.ClassPathChangedEvent; import org.springframework.boot.devtools.classpath.ClassPathFileSystemWatcher; import org.springframework.boot.devtools.filewatch.ChangedFiles; @@ -281,7 +279,6 @@ public class LocalDevToolsAutoConfigurationTests { @Configuration @Import({ EmbeddedServletContainerAutoConfiguration.class, LocalDevToolsAutoConfiguration.class, ThymeleafAutoConfiguration.class }) - @EnableConfigurationProperties(ServerProperties.class) public static class Config { } @@ -289,7 +286,6 @@ public class LocalDevToolsAutoConfigurationTests { @Configuration @Import({ EmbeddedServletContainerAutoConfiguration.class, LocalDevToolsAutoConfiguration.class, ThymeleafAutoConfiguration.class }) - @EnableConfigurationProperties(ServerProperties.class) public static class ConfigWithMockLiveReload { @Bean @@ -302,7 +298,6 @@ public class LocalDevToolsAutoConfigurationTests { @Configuration @Import({ EmbeddedServletContainerAutoConfiguration.class, LocalDevToolsAutoConfiguration.class, ResourceProperties.class }) - @EnableConfigurationProperties(ServerProperties.class) public static class WebResourcesConfig { }