001/* 002 * Copyright 2012-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.autoconfigure.web.embedded; 018 019import java.time.Duration; 020 021import io.undertow.UndertowOptions; 022 023import org.springframework.boot.autoconfigure.web.ServerProperties; 024import org.springframework.boot.cloud.CloudPlatform; 025import org.springframework.boot.context.properties.PropertyMapper; 026import org.springframework.boot.web.embedded.undertow.ConfigurableUndertowWebServerFactory; 027import org.springframework.boot.web.server.WebServerFactoryCustomizer; 028import org.springframework.core.Ordered; 029import org.springframework.core.env.Environment; 030import org.springframework.util.unit.DataSize; 031 032/** 033 * Customization for Undertow-specific features common for both Servlet and Reactive 034 * servers. 035 * 036 * @author Brian Clozel 037 * @author Yulin Qin 038 * @author Stephane Nicoll 039 * @author Phillip Webb 040 * @since 2.0.0 041 */ 042public class UndertowWebServerFactoryCustomizer implements 043 WebServerFactoryCustomizer<ConfigurableUndertowWebServerFactory>, Ordered { 044 045 private final Environment environment; 046 047 private final ServerProperties serverProperties; 048 049 public UndertowWebServerFactoryCustomizer(Environment environment, 050 ServerProperties serverProperties) { 051 this.environment = environment; 052 this.serverProperties = serverProperties; 053 } 054 055 @Override 056 public int getOrder() { 057 return 0; 058 } 059 060 @Override 061 public void customize(ConfigurableUndertowWebServerFactory factory) { 062 ServerProperties properties = this.serverProperties; 063 ServerProperties.Undertow undertowProperties = properties.getUndertow(); 064 ServerProperties.Undertow.Accesslog accesslogProperties = undertowProperties 065 .getAccesslog(); 066 PropertyMapper propertyMapper = PropertyMapper.get().alwaysApplyingWhenNonNull(); 067 propertyMapper.from(undertowProperties::getBufferSize).whenNonNull() 068 .asInt(DataSize::toBytes).to(factory::setBufferSize); 069 propertyMapper.from(undertowProperties::getIoThreads).to(factory::setIoThreads); 070 propertyMapper.from(undertowProperties::getWorkerThreads) 071 .to(factory::setWorkerThreads); 072 propertyMapper.from(undertowProperties::getDirectBuffers) 073 .to(factory::setUseDirectBuffers); 074 propertyMapper.from(accesslogProperties::isEnabled) 075 .to(factory::setAccessLogEnabled); 076 propertyMapper.from(accesslogProperties::getDir) 077 .to(factory::setAccessLogDirectory); 078 propertyMapper.from(accesslogProperties::getPattern) 079 .to(factory::setAccessLogPattern); 080 propertyMapper.from(accesslogProperties::getPrefix) 081 .to(factory::setAccessLogPrefix); 082 propertyMapper.from(accesslogProperties::getSuffix) 083 .to(factory::setAccessLogSuffix); 084 propertyMapper.from(accesslogProperties::isRotate) 085 .to(factory::setAccessLogRotate); 086 propertyMapper.from(this::getOrDeduceUseForwardHeaders) 087 .to(factory::setUseForwardHeaders); 088 propertyMapper.from(properties::getMaxHttpHeaderSize).whenNonNull() 089 .asInt(DataSize::toBytes).when(this::isPositive) 090 .to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, 091 maxHttpHeaderSize)); 092 propertyMapper.from(undertowProperties::getMaxHttpPostSize) 093 .asInt(DataSize::toBytes).when(this::isPositive) 094 .to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory, 095 maxHttpPostSize)); 096 propertyMapper.from(properties::getConnectionTimeout) 097 .to((connectionTimeout) -> customizeConnectionTimeout(factory, 098 connectionTimeout)); 099 factory.addDeploymentInfoCustomizers((deploymentInfo) -> deploymentInfo 100 .setEagerFilterInit(undertowProperties.isEagerFilterInit())); 101 } 102 103 private boolean isPositive(Number value) { 104 return value.longValue() > 0; 105 } 106 107 private void customizeConnectionTimeout(ConfigurableUndertowWebServerFactory factory, 108 Duration connectionTimeout) { 109 factory.addBuilderCustomizers((builder) -> builder.setSocketOption( 110 UndertowOptions.NO_REQUEST_TIMEOUT, (int) connectionTimeout.toMillis())); 111 } 112 113 private void customizeMaxHttpHeaderSize(ConfigurableUndertowWebServerFactory factory, 114 int maxHttpHeaderSize) { 115 factory.addBuilderCustomizers((builder) -> builder 116 .setServerOption(UndertowOptions.MAX_HEADER_SIZE, maxHttpHeaderSize)); 117 } 118 119 private void customizeMaxHttpPostSize(ConfigurableUndertowWebServerFactory factory, 120 long maxHttpPostSize) { 121 factory.addBuilderCustomizers((builder) -> builder 122 .setServerOption(UndertowOptions.MAX_ENTITY_SIZE, maxHttpPostSize)); 123 } 124 125 private boolean getOrDeduceUseForwardHeaders() { 126 if (this.serverProperties.isUseForwardHeaders() != null) { 127 return this.serverProperties.isUseForwardHeaders(); 128 } 129 CloudPlatform platform = CloudPlatform.getActive(this.environment); 130 return platform != null && platform.isUsingForwardHeaders(); 131 } 132 133}