diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml index d64d4ae0ce7..cc9eee48c46 100644 --- a/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-autoconfigure/pom.xml @@ -160,6 +160,11 @@ HikariCP-java6 true + + org.eclipse.jetty + jetty-servlets + true + org.eclipse.jetty jetty-webapp diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/GzipFilterAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/GzipFilterAutoConfiguration.java new file mode 100644 index 00000000000..eb12a29860f --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/GzipFilterAutoConfiguration.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.web; + +import org.eclipse.jetty.servlets.GzipFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.context.embedded.FilterRegistrationBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for {@link GzipFilter}. + * + * @author Andy Wilkinson + * @since 1.2.2 + */ +@Configuration +@ConditionalOnClass(GzipFilter.class) +@EnableConfigurationProperties(GzipFilterProperties.class) +public class GzipFilterAutoConfiguration { + + @Autowired + private GzipFilterProperties properties; + + @Bean + public FilterRegistrationBean gzipFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean(new GzipFilter()); + registration.addUrlPatterns("/*"); + registration.setInitParameters(this.properties.getAsInitParameters()); + + return registration; + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/GzipFilterProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/GzipFilterProperties.java new file mode 100644 index 00000000000..473912d6cbf --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/GzipFilterProperties.java @@ -0,0 +1,226 @@ +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.web; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.jetty.servlets.GzipFilter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.http.HttpMethod; +import org.springframework.util.MimeType; +import org.springframework.util.StringUtils; + +/** + * Properties for configuring {@link GzipFilter}. + * + * @author Andy Wilkinson + * @since 1.2.2 + */ +@ConfigurationProperties(prefix = "spring.http.gzip") +public class GzipFilterProperties { + + private final Map initParameters = new HashMap(); + + /** + * Size of the output buffer in bytes. + */ + private Integer bufferSize; + + /** + * Minimum content length required for compression to occur. + */ + private Integer minGzipSize; + + /** + * The level used for deflate compression (0-9). + */ + private Integer deflateCompressionLevel; + + /** + * noWrap setting for deflate compression. + */ + private Boolean deflateNoWrap; + + /** + * Comma-separated list of HTTP methods for which compression is enabled. + */ + private List methods; + + /** + * Comma-separated list of MIME types which should be compressed. + */ + private List mimeTypes; + + /** + * Comma-separated list of user agents to exclude from compression. String.contains is + * used to determine a match against the request's User-Agent header. + */ + private String excludedAgents; + + /** + * Comma-separated list of regular expression patterns to control user agents excluded + * from compression. + */ + private String excludedAgentPatterns; + + /** + * Comma-separated list of paths to exclude from compression. Uses String.startsWith + * to determine a match against the request's path. + */ + private String excludedPaths; + + /** + * Comma-separated list of regular expression patterns to control the paths that are + * excluded from compression. + */ + private String excludedPathPatterns; + + /** + * Vary header sent on responses that may be compressed. + */ + private String vary; + + public GzipFilterProperties() { + this.addInitParameter("checkGzExists", false); + } + + public Integer getBufferSize() { + return this.bufferSize; + } + + public void setBufferSize(Integer bufferSize) { + this.addInitParameter("bufferSize", bufferSize); + this.bufferSize = bufferSize; + } + + public Integer getMinGzipSize() { + return this.minGzipSize; + } + + public void setMinGzipSize(Integer minGzipSize) { + this.addInitParameter("minGzipSize", minGzipSize); + this.minGzipSize = minGzipSize; + } + + public Integer getDeflateCompressionLevel() { + return this.deflateCompressionLevel; + } + + public void setDeflateCompressionLevel(Integer deflateCompressionLevel) { + this.addInitParameter("deflateCompressionLevel", deflateCompressionLevel); + this.deflateCompressionLevel = deflateCompressionLevel; + } + + public Boolean getDeflateNoWrap() { + return this.deflateNoWrap; + } + + public void setDeflateNoWrap(Boolean deflateNoWrap) { + this.addInitParameter("deflateNoWrap", deflateNoWrap); + this.deflateNoWrap = deflateNoWrap; + } + + public List getMethods() { + return this.methods; + } + + public void setMethods(List methods) { + this.addInitParameter("methods", + StringUtils.collectionToCommaDelimitedString(methods)); + this.methods = methods; + } + + public List getMimeTypes() { + return this.mimeTypes; + } + + public void setMimeTypes(List mimeTypes) { + this.addInitParameter("mimeTypes", + StringUtils.collectionToCommaDelimitedString(mimeTypes)); + this.mimeTypes = mimeTypes; + } + + public String getExcludedAgents() { + return this.excludedAgents; + } + + public void setExcludedAgents(String excludedAgents) { + this.addInitParameter("excludedAgents", excludedAgents); + this.excludedAgents = excludedAgents; + } + + public String getExcludedAgentPatterns() { + return this.excludedAgentPatterns; + } + + public void setExcludedAgentPatterns(String excludedAgentPatterns) { + this.addInitParameter("excludedAgentPatterns", excludedAgentPatterns); + this.excludedAgentPatterns = excludedAgentPatterns; + } + + public String getExcludedPaths() { + return this.excludedPaths; + } + + public void setExcludedPaths(String excludedPaths) { + this.addInitParameter("excludedPaths", excludedPaths); + this.excludedPaths = excludedPaths; + } + + public String getExcludedPathPatterns() { + return this.excludedPathPatterns; + } + + public void setExcludedPathPatterns(String excludedPathPatterns) { + this.addInitParameter("excludedPathPatterns", excludedPathPatterns); + this.excludedPathPatterns = excludedPathPatterns; + } + + public String getVary() { + return this.vary; + } + + public void setVary(String vary) { + this.addInitParameter("vary", vary); + this.vary = vary; + } + + Map getAsInitParameters() { + return this.initParameters; + } + + private void addInitParameter(String name, Integer value) { + if (value != null) { + this.initParameters.put(name, value.toString()); + } + } + + private void addInitParameter(String name, Boolean value) { + if (value != null) { + this.initParameters.put(name, value.toString()); + } + } + + private void addInitParameter(String name, String value) { + if (value != null) { + this.initParameters.put(name, value.toString()); + } + } + +} diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 1db59da3c74..f3f3ca601e6 100644 --- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -57,14 +57,15 @@ org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\ org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ org.springframework.boot.autoconfigure.velocity.VelocityAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ -org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\ -org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\ -org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\ +org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\ +org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\ +org.springframework.boot.autoconfigure.web.GzipFilterAutoConfiguration,\ org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\ org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\ +org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\ +org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\ -org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration # Template availability providers diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/GzipFilterAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/GzipFilterAutoConfigurationTests.java new file mode 100644 index 00000000000..ec6d0e928df --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/GzipFilterAutoConfigurationTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.web; + +import org.junit.After; +import org.junit.Test; +import org.springframework.boot.context.embedded.FilterRegistrationBean; +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; + +/** + * Tests for {@link GzipFilterAutoConfiguration} + * + * @author Andy Wilkinson + */ +public class GzipFilterAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void filterIsMappedToSlashStar() { + createAndRefreshContext(); + FilterRegistrationBean registrationBean = this.context.getBean("gzipFilter", + FilterRegistrationBean.class); + assertThat(registrationBean.getUrlPatterns(), contains("/*")); + } + + @Test + public void byDefaultCheckGzExistsIsTheOnlyInitParameter() { + createAndRefreshContext(); + FilterRegistrationBean registrationBean = this.context.getBean("gzipFilter", + FilterRegistrationBean.class); + assertThat(registrationBean.getInitParameters().size(), equalTo(1)); + assertThat(registrationBean.getInitParameters().get("checkGzExists"), + equalTo("false")); + } + + @Test + public void customInitParameterConfiguration() { + createAndRefreshContext("spring.http.gzip.bufferSize:1234", + "spring.http.gzip.minGzipSize:2345", + "spring.http.gzip.deflateCompressionLevel:5", + "spring.http.gzip.deflateNoWrap:false", + "spring.http.gzip.methods:GET,POST", + "spring.http.gzip.mimeTypes:application/foo,application/bar", + "spring.http.gzip.excludedAgents:excluded-agent-1,excluded-agent-2", + "spring.http.gzip.excludedAgentPatterns:agent-pattern-1,agent-pattern-2", + "spring.http.gzip.excludedPaths:/static/", + "spring.http.gzip.excludedPathPatterns:path-pattern", + "spring.http.gzip.vary:vary-header-value"); + FilterRegistrationBean registrationBean = this.context.getBean("gzipFilter", + FilterRegistrationBean.class); + assertThat(registrationBean.getInitParameters().size(), equalTo(12)); + assertThat(registrationBean.getInitParameters().get("checkGzExists"), + equalTo("false")); + assertThat(registrationBean.getInitParameters().get("bufferSize"), + equalTo("1234")); + assertThat(registrationBean.getInitParameters().get("minGzipSize"), + equalTo("2345")); + assertThat(registrationBean.getInitParameters().get("deflateCompressionLevel"), + equalTo("5")); + assertThat(registrationBean.getInitParameters().get("deflateNoWrap"), + equalTo("false")); + assertThat(registrationBean.getInitParameters().get("methods"), + equalTo("GET,POST")); + assertThat(registrationBean.getInitParameters().get("mimeTypes"), + equalTo("application/foo,application/bar")); + assertThat(registrationBean.getInitParameters().get("excludedAgents"), + equalTo("excluded-agent-1,excluded-agent-2")); + assertThat(registrationBean.getInitParameters().get("excludedAgentPatterns"), + equalTo("agent-pattern-1,agent-pattern-2")); + assertThat(registrationBean.getInitParameters().get("excludedPaths"), + equalTo("/static/")); + assertThat(registrationBean.getInitParameters().get("excludedPathPatterns"), + equalTo("path-pattern")); + assertThat(registrationBean.getInitParameters().get("vary"), + equalTo("vary-header-value")); + } + + private void createAndRefreshContext(String... pairs) { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, pairs); + this.context.register(GzipFilterAutoConfiguration.class); + this.context.refresh(); + } + +} diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 8699ee2fff3..2b42cc79c82 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -983,6 +983,11 @@ jetty-security ${jetty.version} + + org.eclipse.jetty + jetty-server + ${jetty.version} + org.eclipse.jetty jetty-servlet @@ -990,7 +995,7 @@ org.eclipse.jetty - jetty-server + jetty-servlets ${jetty.version}