From 6007d7efc1b505c1ff19e28a3795de6699c13fb8 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Mon, 30 May 2016 10:48:28 -0700 Subject: [PATCH 1/2] Allow connection timeout to be configured via the environment Closes gh-6072 --- .../autoconfigure/web/ServerProperties.java | 62 +++++++++++++++++-- .../appendix-application-properties.adoc | 1 + 2 files changed, 59 insertions(+), 4 deletions(-) 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 ee720c8fb0..396c473c60 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 @@ -30,6 +30,7 @@ import javax.servlet.SessionCookieConfig; import javax.servlet.SessionTrackingMode; import javax.validation.constraints.NotNull; +import io.undertow.Undertow; import io.undertow.Undertow.Builder; import io.undertow.UndertowOptions; import org.apache.catalina.Context; @@ -43,6 +44,7 @@ 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.ServerConnector; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.HandlerWrapper; @@ -145,6 +147,13 @@ public class ServerProperties */ private int maxHttpPostSize = 0; // bytes + /** + * The number of milliseconds connectors 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 int connectionTimeout = -1; + private Session session = new Session(); @NestedConfigurationProperty @@ -366,6 +375,14 @@ public class ServerProperties return (platform == null ? false : platform.isUsingForwardHeaders()); } + public int getConnectionTimeout() { + return connectionTimeout; + } + + public void setConnectionTimeout(final int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + public ErrorProperties getError() { return this.error; } @@ -769,6 +786,16 @@ public class ServerProperties if (getUriEncoding() != null) { factory.setUriEncoding(getUriEncoding()); } + customizeConnectionTimeout(serverProperties, factory); + } + + private void customizeConnectionTimeout(final ServerProperties serverProperties, final TomcatEmbeddedServletContainerFactory factory) { + for (Connector connector : factory.getAdditionalTomcatConnectors()) { + if (connector.getProtocolHandler() instanceof AbstractProtocol) { + final AbstractProtocol handler = (AbstractProtocol) connector.getProtocolHandler(); + handler.setConnectionTimeout(serverProperties.getConnectionTimeout()); + } + } } private void customizeBackgroundProcessorDelay( @@ -978,8 +1005,8 @@ public class ServerProperties this.selectors = selectors; } - void customizeJetty(ServerProperties serverProperties, - JettyEmbeddedServletContainerFactory factory) { + void customizeJetty(final ServerProperties serverProperties, + JettyEmbeddedServletContainerFactory factory) { factory.setUseForwardHeaders(serverProperties.getOrDeduceUseForwardHeaders()); if (this.acceptors != null) { factory.setAcceptors(this.acceptors); @@ -994,6 +1021,22 @@ public class ServerProperties if (serverProperties.getMaxHttpPostSize() > 0) { customizeMaxHttpPostSize(factory, serverProperties.getMaxHttpPostSize()); } + + customizeConnectionTimeout(serverProperties, factory); + } + private void customizeConnectionTimeout(final ServerProperties serverProperties, + final JettyEmbeddedServletContainerFactory factory) { + factory.addServerCustomizers(new JettyServerCustomizer() { + @Override + public void customize(final Server server) { + for (org.eclipse.jetty.server.Connector connector : server.getConnectors()) { + if (connector instanceof ServerConnector) { + ServerConnector serverConnector = (ServerConnector) connector; + serverConnector.setIdleTimeout(serverProperties.getConnectionTimeout()); + } + } + } + }); } private void customizeMaxHttpHeaderSize( @@ -1149,8 +1192,8 @@ public class ServerProperties return this.accesslog; } - void customizeUndertow(ServerProperties serverProperties, - UndertowEmbeddedServletContainerFactory factory) { + void customizeUndertow(final ServerProperties serverProperties, + UndertowEmbeddedServletContainerFactory factory) { if (this.bufferSize != null) { factory.setBufferSize(this.bufferSize); } @@ -1183,6 +1226,17 @@ public class ServerProperties if (serverProperties.getMaxHttpPostSize() > 0) { customizeMaxHttpPostSize(factory, serverProperties.getMaxHttpPostSize()); } + + customizeConnectionTimeout(serverProperties, factory); + } + private void customizeConnectionTimeout(final ServerProperties serverProperties, + final UndertowEmbeddedServletContainerFactory factory) { + factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { + @Override + public void customize(Builder builder) { + builder.setSocketOption(UndertowOptions.NO_REQUEST_TIMEOUT, serverProperties.getConnectionTimeout()); + } + }); } private void customizeMaxHttpHeaderSize( diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index e0d915265c..e13e386df1 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -166,6 +166,7 @@ content into your application; rather pick only the properties that you need. server.server-header= # Value to use for the Server response header (no header is sent if empty) server.servlet-path=/ # Path of the main dispatcher servlet. server.use-forward-headers= # If X-Forwarded-* headers should be applied to the HttpRequest. + server.connectionTimeout=-1 # The number of milliseconds connectors will wait for another HTTP request before closing the connection. server.session.cookie.comment= # Comment for the session cookie. server.session.cookie.domain= # Domain for the session cookie. server.session.cookie.http-only= # "HttpOnly" flag for the session cookie. From 94ba6bdae26d14cba04fb960fdd6c58b3e789946 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 27 Jun 2016 16:55:40 +0100 Subject: [PATCH 2/2] =?UTF-8?q?Polish=20=E2=80=9CAllow=20connection=20time?= =?UTF-8?q?out=20to=20be=20configured=20via=20the=20environment=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Preserve default connection timeout when server.connection-timeout has not been set - Apply standard coding conventions and formatting See gh-6072 --- .../autoconfigure/web/ServerProperties.java | 70 ++++++++++++------- .../appendix-application-properties.adoc | 1 + 2 files changed, 44 insertions(+), 27 deletions(-) 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 396c473c60..c4f978ec54 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 @@ -30,7 +30,6 @@ import javax.servlet.SessionCookieConfig; import javax.servlet.SessionTrackingMode; import javax.validation.constraints.NotNull; -import io.undertow.Undertow; import io.undertow.Undertow.Builder; import io.undertow.UndertowOptions; import org.apache.catalina.Context; @@ -40,11 +39,11 @@ 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.ServerConnector; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.HandlerWrapper; @@ -148,11 +147,11 @@ public class ServerProperties private int maxHttpPostSize = 0; // bytes /** - * The number of milliseconds connectors 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. + * Time in milliseconds that connectors will wait for another HTTP request before + * closing the connection. When not set, the connector's container-specific default + * will be used. Use a value of -1 to indicate no (i.e. infinite) timeout. */ - private int connectionTimeout = -1; + private Integer connectionTimeout; private Session session = new Session(); @@ -375,11 +374,11 @@ public class ServerProperties return (platform == null ? false : platform.isUsingForwardHeaders()); } - public int getConnectionTimeout() { - return connectionTimeout; + public Integer getConnectionTimeout() { + return this.connectionTimeout; } - public void setConnectionTimeout(final int connectionTimeout) { + public void setConnectionTimeout(Integer connectionTimeout) { this.connectionTimeout = connectionTimeout; } @@ -786,14 +785,19 @@ public class ServerProperties if (getUriEncoding() != null) { factory.setUriEncoding(getUriEncoding()); } - customizeConnectionTimeout(serverProperties, factory); + if (serverProperties.getConnectionTimeout() != null) { + customizeConnectionTimeout(factory, + serverProperties.getConnectionTimeout()); + } } - private void customizeConnectionTimeout(final ServerProperties serverProperties, final TomcatEmbeddedServletContainerFactory factory) { + private void customizeConnectionTimeout( + TomcatEmbeddedServletContainerFactory factory, int connectionTimeout) { for (Connector connector : factory.getAdditionalTomcatConnectors()) { if (connector.getProtocolHandler() instanceof AbstractProtocol) { - final AbstractProtocol handler = (AbstractProtocol) connector.getProtocolHandler(); - handler.setConnectionTimeout(serverProperties.getConnectionTimeout()); + AbstractProtocol handler = (AbstractProtocol) connector + .getProtocolHandler(); + handler.setConnectionTimeout(connectionTimeout); } } } @@ -1006,7 +1010,7 @@ public class ServerProperties } void customizeJetty(final ServerProperties serverProperties, - JettyEmbeddedServletContainerFactory factory) { + JettyEmbeddedServletContainerFactory factory) { factory.setUseForwardHeaders(serverProperties.getOrDeduceUseForwardHeaders()); if (this.acceptors != null) { factory.setAcceptors(this.acceptors); @@ -1022,17 +1026,23 @@ public class ServerProperties customizeMaxHttpPostSize(factory, serverProperties.getMaxHttpPostSize()); } - customizeConnectionTimeout(serverProperties, factory); + if (serverProperties.getConnectionTimeout() != null) { + customizeConnectionTimeout(factory, + serverProperties.getConnectionTimeout()); + } } - private void customizeConnectionTimeout(final ServerProperties serverProperties, - final JettyEmbeddedServletContainerFactory factory) { + + private void customizeConnectionTimeout( + JettyEmbeddedServletContainerFactory factory, + final int connectionTimeout) { factory.addServerCustomizers(new JettyServerCustomizer() { @Override - public void customize(final Server server) { - for (org.eclipse.jetty.server.Connector connector : server.getConnectors()) { - if (connector instanceof ServerConnector) { - ServerConnector serverConnector = (ServerConnector) connector; - serverConnector.setIdleTimeout(serverProperties.getConnectionTimeout()); + public void customize(Server server) { + for (org.eclipse.jetty.server.Connector connector : server + .getConnectors()) { + if (connector instanceof AbstractConnector) { + ((AbstractConnector) connector) + .setIdleTimeout(connectionTimeout); } } } @@ -1193,7 +1203,7 @@ public class ServerProperties } void customizeUndertow(final ServerProperties serverProperties, - UndertowEmbeddedServletContainerFactory factory) { + UndertowEmbeddedServletContainerFactory factory) { if (this.bufferSize != null) { factory.setBufferSize(this.bufferSize); } @@ -1227,14 +1237,20 @@ public class ServerProperties customizeMaxHttpPostSize(factory, serverProperties.getMaxHttpPostSize()); } - customizeConnectionTimeout(serverProperties, factory); + if (serverProperties.getConnectionTimeout() != null) { + customizeConnectionTimeout(factory, + serverProperties.getConnectionTimeout()); + } } - private void customizeConnectionTimeout(final ServerProperties serverProperties, - final UndertowEmbeddedServletContainerFactory factory) { + + private void customizeConnectionTimeout( + UndertowEmbeddedServletContainerFactory factory, + final int connectionTimeout) { factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { @Override public void customize(Builder builder) { - builder.setSocketOption(UndertowOptions.NO_REQUEST_TIMEOUT, serverProperties.getConnectionTimeout()); + builder.setSocketOption(UndertowOptions.NO_REQUEST_TIMEOUT, + connectionTimeout); } }); } diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index e13e386df1..3341165842 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -149,6 +149,7 @@ content into your application; rather pick only the properties that you need. server.compression.excluded-user-agents= # List of user-agents to exclude from compression. server.compression.mime-types= # Comma-separated list of MIME types that should be compressed. For instance `text/html,text/css,application/json` server.compression.min-response-size= # Minimum response size that is required for compression to be performed. For instance 2048 + server.connection-timeout= # Time in milliseconds that connectors will wait for another HTTP request before closing the connection. When not set, the connector's container-specific default will be used. Use a value of -1 to indicate no (i.e. infinite) timeout. server.context-parameters.*= # Servlet context init parameters. For instance `server.context-parameters.a=alpha` server.context-path= # Context path of the application. server.display-name=application # Display name of the application.