Skip to content

Commit

Permalink
Merge pull request #25815 from parviz-93
Browse files Browse the repository at this point in the history
* gh-25815:
  Polish "Add config props for keep-alive timeout and max keep-alive reqs"
  Add config props for keep-alive timeout and max keep-alive reqs

Closes gh-25815
  • Loading branch information
wilkinsona committed Apr 6, 2021
2 parents dc6b5ba + 1994219 commit e731462
Show file tree
Hide file tree
Showing 4 changed files with 114 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,19 @@ public static class Tomcat {
*/
private int processorCache = 200;

/**
* Time to wait for another HTTP request before the connection is closed. When not
* set the connectionTimeout is used. When set to -1 there will be no timeout.
*/
private Duration keepAliveTimeout;

/**
* Maximum number of HTTP requests that can be pipelined before the connection is
* closed. When set to 0 or 1, keep-alive and pipelining are disabled. When set to
* -1, an unlimited number of pipelined or keep-alive requests is allowed.
*/
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 +512,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,31 @@ 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", "200");
assertThat(this.properties.getTomcat().getMaxKeepAliveRequests()).isEqualTo(200);
}

@Test
void customizeMaxKeepAliveRequestsWithInfinite() {
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 +411,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 customKeepAliveTimeout() {
bind("server.tomcat.keep-alive-timeout=30ms");
customizeAndRunServer((server) -> assertThat(
((AbstractProtocol<?>) server.getTomcat().getConnector().getProtocolHandler()).getKeepAliveTimeout())
.isEqualTo(30));
}

@Test
void customMaxKeepAliveRequests() {
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 e731462

Please sign in to comment.