From af118e6f3f2fd000830ec9563c72181b46b471c6 Mon Sep 17 00:00:00 2001 From: Venil Noronha Date: Sat, 9 Apr 2016 15:41:59 +0530 Subject: [PATCH 1/3] Fixes #5637 - Implemented server.maxHttpHeaderSize and server.maxHttpPostSize property configuration and marked server.tomcat.maxHttpHeaderSize deprecated. --- .../autoconfigure/web/ServerProperties.java | 178 +++++++++++++++++- 1 file changed, 174 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 aeaad83b98ae..cee8017fa241 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,9 @@ import javax.servlet.SessionTrackingMode; import javax.validation.constraints.NotNull; +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; @@ -37,6 +40,15 @@ import org.apache.coyote.AbstractProtocol; import org.apache.coyote.ProtocolHandler; import org.apache.coyote.http11.AbstractHttp11Protocol; +import org.eclipse.jetty.server.ConnectionFactory; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConfiguration.Customizer; +import org.eclipse.jetty.server.Request; +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; @@ -50,11 +62,14 @@ import org.springframework.boot.context.embedded.ServletContextInitializer; 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.context.EnvironmentAware; import org.springframework.core.Ordered; @@ -73,6 +88,7 @@ * @author Marcos Barbero * @author EddĂș MelĂ©ndez * @author Quinten De Swaef + * @author Venil Noronha */ @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties @@ -122,6 +138,16 @@ public class ServerProperties */ private String serverHeader; + /** + * Maximum size in bytes of the HTTP message header. + */ + private int maxHttpHeaderSize = 0; // bytes + + /** + * Maximum size in bytes of the HTTP post content. + */ + private int maxHttpPostSize = 0; // bytes + private Session session = new Session(); @NestedConfigurationProperty @@ -319,6 +345,22 @@ public void setServerHeader(String serverHeader) { this.serverHeader = serverHeader; } + public int getMaxHttpHeaderSize() { + return this.maxHttpHeaderSize; + } + + public void setMaxHttpHeaderSize(int maxHttpHeaderSize) { + this.maxHttpHeaderSize = maxHttpHeaderSize; + } + + public int getMaxHttpPostSize() { + return this.maxHttpPostSize; + } + + public void setMaxHttpPostSize(int maxHttpPostSize) { + this.maxHttpPostSize = maxHttpPostSize; + } + protected final boolean getOrDeduceUseForwardHeaders() { if (this.useForwardHeaders != null) { return this.useForwardHeaders; @@ -612,10 +654,23 @@ public void setMinSpareThreads(int minSpareThreads) { this.minSpareThreads = minSpareThreads; } + /** + * Get the max http header size. + * @return the max http header size. + * @deprecated in favor of {@code server.maxHttpHeaderSize} + */ + @Deprecated + @DeprecatedConfigurationProperty(replacement = "server.maxHttpHeaderSize") public int getMaxHttpHeaderSize() { return this.maxHttpHeaderSize; } + /** + * Set the max http header size. + * @param maxHttpHeaderSize the max http header size. + * @deprecated in favor of {@code server.maxHttpHeaderSize} + */ + @Deprecated public void setMaxHttpHeaderSize(int maxHttpHeaderSize) { this.maxHttpHeaderSize = maxHttpHeaderSize; } @@ -701,8 +756,14 @@ void customizeTomcat(ServerProperties serverProperties, if (this.minSpareThreads > 0) { customizeMinThreads(factory); } - if (this.maxHttpHeaderSize > 0) { - customizeMaxHttpHeaderSize(factory); + if (serverProperties.getMaxHttpHeaderSize() > 0) { + customizeMaxHttpHeaderSize(factory, serverProperties.getMaxHttpHeaderSize()); + } + else if (this.maxHttpHeaderSize > 0) { + customizeMaxHttpHeaderSize(factory, this.maxHttpHeaderSize); + } + if (serverProperties.getMaxHttpPostSize() > 0) { + customizeMaxHttpPostSize(factory, serverProperties.getMaxHttpPostSize()); } if (this.accesslog.enabled) { customizeAccessLog(factory); @@ -782,7 +843,7 @@ public void customize(Connector connector) { @SuppressWarnings("rawtypes") private void customizeMaxHttpHeaderSize( - TomcatEmbeddedServletContainerFactory factory) { + TomcatEmbeddedServletContainerFactory factory, int maxHttpHeaderSize) { factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { @Override @@ -790,13 +851,23 @@ public void customize(Connector connector) { ProtocolHandler handler = connector.getProtocolHandler(); if (handler instanceof AbstractHttp11Protocol) { AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler; - protocol.setMaxHttpHeaderSize(Tomcat.this.maxHttpHeaderSize); + protocol.setMaxHttpHeaderSize(maxHttpHeaderSize); } } }); } + private void customizeMaxHttpPostSize( + TomcatEmbeddedServletContainerFactory factory, 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()); @@ -882,6 +953,79 @@ private static class Jetty { void customizeJetty(ServerProperties serverProperties, JettyEmbeddedServletContainerFactory factory) { factory.setUseForwardHeaders(serverProperties.getOrDeduceUseForwardHeaders()); + if (serverProperties.getMaxHttpHeaderSize() > 0) { + customizeMaxHttpHeaderSize(factory, serverProperties.getMaxHttpHeaderSize()); + } + if (serverProperties.getMaxHttpPostSize() > 0) { + customizeMaxHttpPostSize(factory, serverProperties.getMaxHttpPostSize()); + } + } + + private void customizeMaxHttpHeaderSize( + JettyEmbeddedServletContainerFactory factory, int maxHttpHeaderSize) { + factory.addServerCustomizers(new JettyServerCustomizer() { + @Override + public void customize(Server server) { + JettyMaxHttpHeaderSizeCustomizer customizer = new JettyMaxHttpHeaderSizeCustomizer( + maxHttpHeaderSize); + org.eclipse.jetty.server.Connector[] connectors = server.getConnectors(); + for (org.eclipse.jetty.server.Connector connector : connectors) { + for (ConnectionFactory connectionFactory : connector + .getConnectionFactories()) { + if (connectionFactory instanceof HttpConfiguration.ConnectionFactory) { + ((HttpConfiguration.ConnectionFactory) connectionFactory) + .getHttpConfiguration().addCustomizer(customizer); + } + } + } + } + }); + } + + private void customizeMaxHttpPostSize( + JettyEmbeddedServletContainerFactory factory, 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()); + } + } + } + + }); + } + + } + + private static class JettyMaxHttpHeaderSizeCustomizer implements Customizer { + + private int headerSize; + + JettyMaxHttpHeaderSizeCustomizer(int headerSize) { + this.headerSize = headerSize; + } + + @Override + public void customize(org.eclipse.jetty.server.Connector connector, + HttpConfiguration channelConfig, Request request) { + channelConfig.setRequestHeaderSize(this.headerSize); + channelConfig.setResponseHeaderSize(this.headerSize); } } @@ -970,6 +1114,32 @@ void customizeUndertow(ServerProperties serverProperties, factory.setAccessLogPattern(this.accesslog.pattern); factory.setAccessLogEnabled(this.accesslog.enabled); factory.setUseForwardHeaders(serverProperties.getOrDeduceUseForwardHeaders()); + if (serverProperties.getMaxHttpHeaderSize() > 0) { + customizeMaxHttpHeaderSize(factory, serverProperties.getMaxHttpHeaderSize()); + } + if (serverProperties.getMaxHttpPostSize() > 0) { + customizeMaxHttpPostSize(factory, serverProperties.getMaxHttpPostSize()); + } + } + + private void customizeMaxHttpHeaderSize( + UndertowEmbeddedServletContainerFactory factory, int maxHttpHeaderSize) { + factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { + @Override + public void customize(Builder builder) { + builder.setServerOption(UndertowOptions.MAX_HEADER_SIZE, maxHttpHeaderSize); + } + }); + } + + private void customizeMaxHttpPostSize( + UndertowEmbeddedServletContainerFactory factory, int maxHttpPostSize) { + factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { + @Override + public void customize(Builder builder) { + builder.setServerOption(UndertowOptions.MAX_ENTITY_SIZE, (long) maxHttpPostSize); + } + }); } public static class Accesslog { From 16c5898ad9219c7b4f908b2dd0742b1d80cfcaf9 Mon Sep 17 00:00:00 2001 From: Venil Noronha Date: Sat, 9 Apr 2016 16:30:03 +0530 Subject: [PATCH 2/3] Marked method params final to fix Travis compilation error. --- .../boot/autoconfigure/web/ServerProperties.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 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 cee8017fa241..ccb39913bc69 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 @@ -843,7 +843,7 @@ public void customize(Connector connector) { @SuppressWarnings("rawtypes") private void customizeMaxHttpHeaderSize( - TomcatEmbeddedServletContainerFactory factory, int maxHttpHeaderSize) { + TomcatEmbeddedServletContainerFactory factory, final int maxHttpHeaderSize) { factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { @Override @@ -859,7 +859,7 @@ public void customize(Connector connector) { } private void customizeMaxHttpPostSize( - TomcatEmbeddedServletContainerFactory factory, int maxHttpPostSize) { + TomcatEmbeddedServletContainerFactory factory, final int maxHttpPostSize) { factory.addConnectorCustomizers(new TomcatConnectorCustomizer() { @Override public void customize(Connector connector) { @@ -962,7 +962,7 @@ void customizeJetty(ServerProperties serverProperties, } private void customizeMaxHttpHeaderSize( - JettyEmbeddedServletContainerFactory factory, int maxHttpHeaderSize) { + JettyEmbeddedServletContainerFactory factory, final int maxHttpHeaderSize) { factory.addServerCustomizers(new JettyServerCustomizer() { @Override public void customize(Server server) { @@ -983,7 +983,7 @@ public void customize(Server server) { } private void customizeMaxHttpPostSize( - JettyEmbeddedServletContainerFactory factory, int maxHttpPostSize) { + JettyEmbeddedServletContainerFactory factory, final int maxHttpPostSize) { factory.addServerCustomizers(new JettyServerCustomizer() { @Override @@ -1123,7 +1123,7 @@ void customizeUndertow(ServerProperties serverProperties, } private void customizeMaxHttpHeaderSize( - UndertowEmbeddedServletContainerFactory factory, int maxHttpHeaderSize) { + UndertowEmbeddedServletContainerFactory factory, final int maxHttpHeaderSize) { factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { @Override public void customize(Builder builder) { @@ -1133,7 +1133,7 @@ public void customize(Builder builder) { } private void customizeMaxHttpPostSize( - UndertowEmbeddedServletContainerFactory factory, int maxHttpPostSize) { + UndertowEmbeddedServletContainerFactory factory, final int maxHttpPostSize) { factory.addBuilderCustomizers(new UndertowBuilderCustomizer() { @Override public void customize(Builder builder) { From 634c355ca4fe7b416effdff8e33349595d80114d Mon Sep 17 00:00:00 2001 From: Venil Noronha Date: Sat, 9 Apr 2016 18:20:46 +0530 Subject: [PATCH 3/3] Updated setting of Jetty maxHttpHeaderSize. --- .../autoconfigure/web/ServerProperties.java | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 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 ccb39913bc69..e160acc96e64 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 @@ -43,8 +43,6 @@ import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConfiguration.Customizer; -import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.HandlerCollection; @@ -966,15 +964,15 @@ private void customizeMaxHttpHeaderSize( factory.addServerCustomizers(new JettyServerCustomizer() { @Override public void customize(Server server) { - JettyMaxHttpHeaderSizeCustomizer customizer = new JettyMaxHttpHeaderSizeCustomizer( - maxHttpHeaderSize); org.eclipse.jetty.server.Connector[] connectors = server.getConnectors(); for (org.eclipse.jetty.server.Connector connector : connectors) { - for (ConnectionFactory connectionFactory : connector - .getConnectionFactories()) { + for (ConnectionFactory connectionFactory : connector.getConnectionFactories()) { if (connectionFactory instanceof HttpConfiguration.ConnectionFactory) { - ((HttpConfiguration.ConnectionFactory) connectionFactory) - .getHttpConfiguration().addCustomizer(customizer); + HttpConfiguration httpConfig = + ((HttpConfiguration.ConnectionFactory) connectionFactory) + .getHttpConfiguration(); + httpConfig.setRequestHeaderSize(maxHttpHeaderSize); + httpConfig.setResponseHeaderSize(maxHttpHeaderSize); } } } @@ -1013,23 +1011,6 @@ else if (handler instanceof HandlerCollection) { } - private static class JettyMaxHttpHeaderSizeCustomizer implements Customizer { - - private int headerSize; - - JettyMaxHttpHeaderSizeCustomizer(int headerSize) { - this.headerSize = headerSize; - } - - @Override - public void customize(org.eclipse.jetty.server.Connector connector, - HttpConfiguration channelConfig, Request request) { - channelConfig.setRequestHeaderSize(this.headerSize); - channelConfig.setResponseHeaderSize(this.headerSize); - } - - } - public static class Undertow { /**