Skip to content

Commit

Permalink
Add configuration properties for configuring Tomcat's keepAliveTimeout
Browse files Browse the repository at this point in the history
 and maxKeepAliveRequests
 See #25805
  • Loading branch information
parviz-93 authored and Rozikov.P committed Mar 27, 2021
1 parent 90b4ced commit 91e4af2
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 0 deletions.
Expand Up @@ -66,6 +66,7 @@
* @author HaiTao Zhang
* @author Victor Mandujano
* @author Chris Bono
* @author Parviz Rozikov
* @since 1.0.0
*/
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
Expand Down Expand Up @@ -370,6 +371,22 @@ public static class Tomcat {
*/
private int processorCache = 200;

/**
* The number of milliseconds this Connector will wait for another HTTP request
* before closing the connection. The default value is to use the value that has
* been set for the connectionTimeout attribute. Use a value of -1 to indicate no
* (i.e. infinite) timeout.
*/
private Duration keepAliveTimeout;

/**
* The maximum number of HTTP requests which can be pipelined until the connection
* is closed by the server./ Setting this attribute to 1 will disable HTTP/1.0
* keep-alive as well as HTTP/1.1 keep-alive and pipelining. Setting this to -1
* will allow an unlimited amount of pipelined or keep-alive HTTP requests.
*/
private int maxKeepAliveRequests = 100;

/**
* Comma-separated list of additional patterns that match jars to ignore for TLD
* scanning. The special '?' and '*' characters can be used in the pattern to
Expand Down Expand Up @@ -498,6 +515,22 @@ public void setProcessorCache(int processorCache) {
this.processorCache = processorCache;
}

public Duration getKeepAliveTimeout() {
return this.keepAliveTimeout;
}

public void setKeepAliveTimeout(Duration keepAliveTimeout) {
this.keepAliveTimeout = keepAliveTimeout;
}

public int getMaxKeepAliveRequests() {
return this.maxKeepAliveRequests;
}

public void setMaxKeepAliveRequests(int maxKeepAliveRequests) {
this.maxKeepAliveRequests = maxKeepAliveRequests;
}

public List<String> getAdditionalTldSkipPatterns() {
return this.additionalTldSkipPatterns;
}
Expand Down
Expand Up @@ -56,6 +56,7 @@
* @author Dirk Deyne
* @author Rafiullah Hamedy
* @author Victor Mandujano
* @author Parviz Rozikov
* @since 2.0.0
*/
public class TomcatWebServerFactoryCustomizer
Expand Down Expand Up @@ -108,6 +109,10 @@ public void customize(ConfigurableTomcatWebServerFactory factory) {
.to((acceptCount) -> customizeAcceptCount(factory, acceptCount));
propertyMapper.from(tomcatProperties::getProcessorCache)
.to((processorCache) -> customizeProcessorCache(factory, processorCache));
propertyMapper.from(tomcatProperties::getKeepAliveTimeout).whenNonNull()
.to((keepAliveTimeout) -> customizeKeepAliveTimeout(factory, keepAliveTimeout));
propertyMapper.from(tomcatProperties::getMaxKeepAliveRequests)
.to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests));
propertyMapper.from(tomcatProperties::getRelaxedPathChars).as(this::joinCharacters).whenHasText()
.to((relaxedChars) -> customizeRelaxedPathChars(factory, relaxedChars));
propertyMapper.from(tomcatProperties::getRelaxedQueryChars).as(this::joinCharacters).whenHasText()
Expand Down Expand Up @@ -139,6 +144,26 @@ private void customizeProcessorCache(ConfigurableTomcatWebServerFactory factory,
});
}

private void customizeKeepAliveTimeout(ConfigurableTomcatWebServerFactory factory, Duration keepAliveTimeout) {
factory.addConnectorCustomizers((connector) -> {
ProtocolHandler handler = connector.getProtocolHandler();
if (handler instanceof AbstractProtocol) {
final AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
protocol.setKeepAliveTimeout((int) keepAliveTimeout.toMillis());
}
});
}

private void customizeMaxKeepAliveRequests(ConfigurableTomcatWebServerFactory factory, int maxKeepAliveRequests) {
factory.addConnectorCustomizers((connector) -> {
ProtocolHandler handler = connector.getProtocolHandler();
if (handler instanceof AbstractHttp11Protocol) {
AbstractHttp11Protocol<?> protocol = (AbstractHttp11Protocol<?>) handler;
protocol.setMaxKeepAliveRequests(maxKeepAliveRequests);
}
});
}

private void customizeMaxConnections(ConfigurableTomcatWebServerFactory factory, int maxConnections) {
factory.addConnectorCustomizers((connector) -> {
ProtocolHandler handler = connector.getProtocolHandler();
Expand Down
Expand Up @@ -38,6 +38,7 @@
import org.apache.catalina.valves.AccessLogValve;
import org.apache.catalina.valves.RemoteIpValve;
import org.apache.coyote.AbstractProtocol;
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
Expand Down Expand Up @@ -82,6 +83,7 @@
* @author HaiTao Zhang
* @author Rafiullah Hamedy
* @author Chris Bono
* @author Parviz Rozikov
*/
class ServerPropertiesTests {

Expand Down Expand Up @@ -216,6 +218,25 @@ void testCustomizeTomcatMaxThreads() {
assertThat(this.properties.getTomcat().getThreads().getMax()).isEqualTo(10);
}

@Test
void testCustomizeTomcatKeepAliveTimeout() {
bind("server.tomcat.keep-alive-timeout", "30s");
assertThat(this.properties.getTomcat().getKeepAliveTimeout()).hasSeconds(30);
}

@Test
void testCustomizeTomcatKeepAliveTimeoutWithInfinite() {
bind("server.tomcat.keep-alive-timeout", "-1");
assertThat(this.properties.getTomcat().getKeepAliveTimeout().toMillis()).isEqualTo(-1);
assertThat(this.properties.getTomcat().getKeepAliveTimeout()).hasMillis(-1);
}

@Test
void customizeMaxKeepAliveRequests() {
bind("server.tomcat.max-keep-alive-requests", "-1");
assertThat(this.properties.getTomcat().getMaxKeepAliveRequests()).isEqualTo(-1);
}

@Test
void testCustomizeTomcatMinSpareThreads() {
bind("server.tomcat.threads.min-spare", "10");
Expand Down Expand Up @@ -384,6 +405,14 @@ void tomcatUseRelativeRedirectsDefaultsToFalse() {
assertThat(this.properties.getTomcat().isUseRelativeRedirects()).isFalse();
}

@Test
void tomcatMaxKeepAliveRequestsDefault() throws Exception {
AbstractEndpoint<?, ?> endpoint = (AbstractEndpoint<?, ?>) ReflectionTestUtils.getField(getDefaultProtocol(),
"endpoint");
int defaultMaxKeepAliveRequests = (int) ReflectionTestUtils.getField(endpoint, "maxKeepAliveRequests");
assertThat(this.properties.getTomcat().getMaxKeepAliveRequests()).isEqualTo(defaultMaxKeepAliveRequests);
}

@Test
void jettyThreadPoolPropertyDefaultsShouldMatchServerDefault() {
JettyServletWebServerFactory jettyFactory = new JettyServletWebServerFactory(0);
Expand Down
Expand Up @@ -56,6 +56,7 @@
* @author Andrew McGhie
* @author Rafiullah Hamedy
* @author Victor Mandujano
* @author Parviz Rozikov
*/
class TomcatWebServerFactoryCustomizerTests {

Expand Down Expand Up @@ -97,6 +98,29 @@ void customProcessorCache() {
.isEqualTo(100));
}

@Test
void customizeKeepAliveTimeout() {
bind("server.tomcat.keep-alive-timeout=30ms");
customizeAndRunServer((server) -> assertThat(
((AbstractProtocol<?>) server.getTomcat().getConnector().getProtocolHandler()).getKeepAliveTimeout())
.isEqualTo(30));
}

@Test
void customizeMaxKeepAliveRequests() {
bind("server.tomcat.max-keep-alive-requests=-1");
customizeAndRunServer((server) -> assertThat(
((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())
.getMaxKeepAliveRequests()).isEqualTo(-1));
}

@Test
void defaultMaxKeepAliveRequests() {
customizeAndRunServer((server) -> assertThat(
((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())
.getMaxKeepAliveRequests()).isEqualTo(100));
}

@Test
void unlimitedProcessorCache() {
bind("server.tomcat.processor-cache=-1");
Expand Down

0 comments on commit 91e4af2

Please sign in to comment.