Replace GzipFilter and Tomcat compression with general purpose approach
Closes gh-3296
This commit is contained in:
parent
dde194e2b9
commit
00d594dcda
|
|
@ -200,11 +200,6 @@
|
||||||
<artifactId>HikariCP-java6</artifactId>
|
<artifactId>HikariCP-java6</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-servlets</artifactId>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-webapp</artifactId>
|
<artifactId>jetty-webapp</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
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
|
|
||||||
@ConditionalOnProperty(prefix = "spring.http.gzip", name = "enabled", matchIfMissing = true)
|
|
||||||
public FilterRegistrationBean gzipFilter() {
|
|
||||||
FilterRegistrationBean registration = new FilterRegistrationBean(new GzipFilter());
|
|
||||||
registration.addUrlPatterns("/*");
|
|
||||||
registration.setInitParameters(this.properties.getAsInitParameters());
|
|
||||||
|
|
||||||
return registration;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,242 +0,0 @@
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
* @author Stephane Nicoll
|
|
||||||
* @since 1.2.2
|
|
||||||
*/
|
|
||||||
@ConfigurationProperties(prefix = "spring.http.gzip")
|
|
||||||
public class GzipFilterProperties {
|
|
||||||
|
|
||||||
private final Map<String, String> initParameters = new HashMap<String, String>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Size of the output buffer in bytes.
|
|
||||||
*/
|
|
||||||
private Integer bufferSize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimum content length required for compression to occur.
|
|
||||||
*/
|
|
||||||
private Integer minGzipSize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<HttpMethod> methods;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comma-separated list of MIME types which should be compressed.
|
|
||||||
*/
|
|
||||||
private List<MimeType> mimeTypes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comma-separated list of MIME types to exclude from compression.
|
|
||||||
*/
|
|
||||||
private List<MimeType> excludedMimeTypes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 excludeAgentPatterns;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comma-separated list of paths to exclude from compression. Uses String.startsWith
|
|
||||||
* to determine a match against the request's path.
|
|
||||||
*/
|
|
||||||
private String excludePaths;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comma-separated list of regular expression patterns to control the paths that are
|
|
||||||
* excluded from compression.
|
|
||||||
*/
|
|
||||||
private String excludePathPatterns;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<HttpMethod> getMethods() {
|
|
||||||
return this.methods;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMethods(List<HttpMethod> methods) {
|
|
||||||
this.addInitParameter("methods",
|
|
||||||
StringUtils.collectionToCommaDelimitedString(methods));
|
|
||||||
this.methods = methods;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<MimeType> getMimeTypes() {
|
|
||||||
return this.mimeTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMimeTypes(List<MimeType> mimeTypes) {
|
|
||||||
this.addInitParameter("mimeTypes",
|
|
||||||
StringUtils.collectionToCommaDelimitedString(mimeTypes));
|
|
||||||
this.mimeTypes = mimeTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<MimeType> getExcludedMimeTypes() {
|
|
||||||
return this.excludedMimeTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExcludedMimeTypes(List<MimeType> excludedMimeTypes) {
|
|
||||||
this.addInitParameter("excludedMimeTypes",
|
|
||||||
StringUtils.collectionToCommaDelimitedString(excludedMimeTypes));
|
|
||||||
this.excludedMimeTypes = excludedMimeTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExcludedAgents() {
|
|
||||||
return this.excludedAgents;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExcludedAgents(String excludedAgents) {
|
|
||||||
this.addInitParameter("excludedAgents", excludedAgents);
|
|
||||||
this.excludedAgents = excludedAgents;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExcludeAgentPatterns() {
|
|
||||||
return this.excludeAgentPatterns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExcludeAgentPatterns(String excludeAgentPatterns) {
|
|
||||||
this.addInitParameter("excludeAgentPatterns", excludeAgentPatterns);
|
|
||||||
this.excludeAgentPatterns = excludeAgentPatterns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExcludePaths() {
|
|
||||||
return this.excludePaths;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExcludePaths(String excludePaths) {
|
|
||||||
this.addInitParameter("excludePaths", excludePaths);
|
|
||||||
this.excludePaths = excludePaths;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExcludePathPatterns() {
|
|
||||||
return this.excludePathPatterns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExcludePathPatterns(String excludePathPatterns) {
|
|
||||||
this.addInitParameter("excludePathPatterns", excludePathPatterns);
|
|
||||||
this.excludePathPatterns = excludePathPatterns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVary() {
|
|
||||||
return this.vary;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVary(String vary) {
|
|
||||||
this.addInitParameter("vary", vary);
|
|
||||||
this.vary = vary;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -31,8 +31,7 @@ import org.apache.catalina.valves.RemoteIpValve;
|
||||||
import org.apache.coyote.AbstractProtocol;
|
import org.apache.coyote.AbstractProtocol;
|
||||||
import org.apache.coyote.ProtocolHandler;
|
import org.apache.coyote.ProtocolHandler;
|
||||||
import org.apache.coyote.http11.AbstractHttp11Protocol;
|
import org.apache.coyote.http11.AbstractHttp11Protocol;
|
||||||
import org.springframework.boot.context.embedded.AbstractConfigurableEmbeddedServletContainer;
|
import org.springframework.boot.context.embedded.Compression;
|
||||||
import org.springframework.boot.context.embedded.AbstractConfigurableEmbeddedServletContainer.CompressionProperties;
|
|
||||||
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
|
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
|
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor;
|
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor;
|
||||||
|
|
@ -101,7 +100,8 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
|
||||||
|
|
||||||
private final Undertow undertow = new Undertow();
|
private final Undertow undertow = new Undertow();
|
||||||
|
|
||||||
private CompressionProperties compression = new CompressionProperties();
|
@NestedConfigurationProperty
|
||||||
|
private Compression compression = new Compression();
|
||||||
|
|
||||||
@NestedConfigurationProperty
|
@NestedConfigurationProperty
|
||||||
private JspServlet jspServlet;
|
private JspServlet jspServlet;
|
||||||
|
|
@ -124,7 +124,7 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
|
||||||
return this.undertow;
|
return this.undertow;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompressionProperties getCompression() {
|
public Compression getCompression() {
|
||||||
return this.compression;
|
return this.compression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -247,9 +247,8 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
|
||||||
if (getJspServlet() != null) {
|
if (getJspServlet() != null) {
|
||||||
container.setJspServlet(getJspServlet());
|
container.setJspServlet(getJspServlet());
|
||||||
}
|
}
|
||||||
if (container instanceof AbstractConfigurableEmbeddedServletContainer) {
|
if (getCompression() != null) {
|
||||||
((AbstractConfigurableEmbeddedServletContainer) container)
|
container.setCompression(getCompression());
|
||||||
.setCompression(getCompression());
|
|
||||||
}
|
}
|
||||||
if (container instanceof TomcatEmbeddedServletContainerFactory) {
|
if (container instanceof TomcatEmbeddedServletContainerFactory) {
|
||||||
getTomcat()
|
getTomcat()
|
||||||
|
|
@ -359,19 +358,6 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
|
||||||
*/
|
*/
|
||||||
private String uriEncoding;
|
private String uriEncoding;
|
||||||
|
|
||||||
/**
|
|
||||||
* Controls response compression. Acceptable values are "off" to disable
|
|
||||||
* compression, "on" to enable compression of responses over 2048 bytes, "force"
|
|
||||||
* to force response compression, or an integer value to enable compression of
|
|
||||||
* responses with content length that is at least that value.
|
|
||||||
*/
|
|
||||||
private String compression = "off";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comma-separated list of MIME types for which compression is used.
|
|
||||||
*/
|
|
||||||
private String compressableMimeTypes = "text/html,text/xml,text/plain";
|
|
||||||
|
|
||||||
public int getMaxThreads() {
|
public int getMaxThreads() {
|
||||||
return this.maxThreads;
|
return this.maxThreads;
|
||||||
}
|
}
|
||||||
|
|
@ -420,22 +406,6 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
|
||||||
this.accessLogPattern = accessLogPattern;
|
this.accessLogPattern = accessLogPattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCompressableMimeTypes() {
|
|
||||||
return this.compressableMimeTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCompressableMimeTypes(String compressableMimeTypes) {
|
|
||||||
this.compressableMimeTypes = compressableMimeTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCompression() {
|
|
||||||
return this.compression;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCompression(String compression) {
|
|
||||||
this.compression = compression;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getInternalProxies() {
|
public String getInternalProxies() {
|
||||||
return this.internalProxies;
|
return this.internalProxies;
|
||||||
}
|
}
|
||||||
|
|
@ -496,7 +466,6 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
|
||||||
if (this.maxHttpHeaderSize > 0) {
|
if (this.maxHttpHeaderSize > 0) {
|
||||||
customizeMaxHttpHeaderSize(factory);
|
customizeMaxHttpHeaderSize(factory);
|
||||||
}
|
}
|
||||||
customizeCompression(factory);
|
|
||||||
if (this.accessLogEnabled) {
|
if (this.accessLogEnabled) {
|
||||||
customizeAccessLog(factory);
|
customizeAccessLog(factory);
|
||||||
}
|
}
|
||||||
|
|
@ -565,33 +534,6 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void customizeCompression(TomcatEmbeddedServletContainerFactory factory) {
|
|
||||||
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void customize(Connector connector) {
|
|
||||||
ProtocolHandler handler = connector.getProtocolHandler();
|
|
||||||
if (handler instanceof AbstractHttp11Protocol) {
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler;
|
|
||||||
protocol.setCompression(coerceCompression(Tomcat.this.compression));
|
|
||||||
protocol.setCompressableMimeTypes(Tomcat.this.compressableMimeTypes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String coerceCompression(String compression) {
|
|
||||||
if ("true".equalsIgnoreCase(compression)) {
|
|
||||||
return "on";
|
|
||||||
}
|
|
||||||
if ("false".equalsIgnoreCase(compression)) {
|
|
||||||
return "off";
|
|
||||||
}
|
|
||||||
return compression;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void customizeAccessLog(TomcatEmbeddedServletContainerFactory factory) {
|
private void customizeAccessLog(TomcatEmbeddedServletContainerFactory factory) {
|
||||||
AccessLogValve valve = new AccessLogValve();
|
AccessLogValve valve = new AccessLogValve();
|
||||||
String accessLogPattern = getAccessLogPattern();
|
String accessLogPattern = getAccessLogPattern();
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,6 @@ org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
|
||||||
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
|
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
|
||||||
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
|
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
|
||||||
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
|
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
|
||||||
org.springframework.boot.autoconfigure.web.GzipFilterAutoConfiguration,\
|
|
||||||
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
|
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
|
||||||
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
|
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
|
||||||
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
|
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
|
||||||
|
|
|
||||||
|
|
@ -1,123 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.hamcrest.Matchers.is;
|
|
||||||
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.excludedMimeTypes:application/biz",
|
|
||||||
"spring.http.gzip.excludedAgents:excluded-agent-1,excluded-agent-2",
|
|
||||||
"spring.http.gzip.excludeAgentPatterns:agent-pattern-1,agent-pattern-2",
|
|
||||||
"spring.http.gzip.excludePaths:/static/",
|
|
||||||
"spring.http.gzip.excludePathPatterns:path-pattern",
|
|
||||||
"spring.http.gzip.vary:vary-header-value");
|
|
||||||
FilterRegistrationBean registrationBean = this.context.getBean("gzipFilter",
|
|
||||||
FilterRegistrationBean.class);
|
|
||||||
assertThat(registrationBean.getInitParameters().size(), equalTo(13));
|
|
||||||
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("excludedMimeTypes"),
|
|
||||||
equalTo("application/biz"));
|
|
||||||
assertThat(registrationBean.getInitParameters().get("excludedAgents"),
|
|
||||||
equalTo("excluded-agent-1,excluded-agent-2"));
|
|
||||||
assertThat(registrationBean.getInitParameters().get("excludeAgentPatterns"),
|
|
||||||
equalTo("agent-pattern-1,agent-pattern-2"));
|
|
||||||
assertThat(registrationBean.getInitParameters().get("excludePaths"),
|
|
||||||
equalTo("/static/"));
|
|
||||||
assertThat(registrationBean.getInitParameters().get("excludePathPatterns"),
|
|
||||||
equalTo("path-pattern"));
|
|
||||||
assertThat(registrationBean.getInitParameters().get("vary"),
|
|
||||||
equalTo("vary-header-value"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void filterCanBeDisabled() {
|
|
||||||
createAndRefreshContext("spring.http.gzip.enabled:false");
|
|
||||||
assertThat(this.context.getBeanNamesForType(FilterRegistrationBean.class).length,
|
|
||||||
is(equalTo(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createAndRefreshContext(String... pairs) {
|
|
||||||
this.context = new AnnotationConfigApplicationContext();
|
|
||||||
EnvironmentTestUtils.addEnvironment(this.context, pairs);
|
|
||||||
this.context.register(GzipFilterAutoConfiguration.class);
|
|
||||||
this.context.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -23,21 +23,16 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.apache.catalina.Valve;
|
import org.apache.catalina.Valve;
|
||||||
import org.apache.catalina.valves.RemoteIpValve;
|
import org.apache.catalina.valves.RemoteIpValve;
|
||||||
import org.apache.coyote.http11.AbstractHttp11Protocol;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.MutablePropertyValues;
|
import org.springframework.beans.MutablePropertyValues;
|
||||||
import org.springframework.boot.bind.RelaxedDataBinder;
|
import org.springframework.boot.bind.RelaxedDataBinder;
|
||||||
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
|
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
|
||||||
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer;
|
|
||||||
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
import static org.hamcrest.core.IsInstanceOf.instanceOf;
|
import static org.hamcrest.core.IsInstanceOf.instanceOf;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
@ -106,18 +101,6 @@ public class ServerPropertiesTests {
|
||||||
.getInternalProxies());
|
.getInternalProxies());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCompressionBinding() throws Exception {
|
|
||||||
Map<String, String> map = new HashMap<String, String>();
|
|
||||||
map.put("server.compression.enabled", "true");
|
|
||||||
map.put("server.compression.mimeTypes", "foo/bar");
|
|
||||||
map.put("server.compression.minSize", "228");
|
|
||||||
bindProperties(map);
|
|
||||||
assertTrue(this.properties.getCompression().isEnabled());
|
|
||||||
assertEquals("foo/bar", this.properties.getCompression().getMimeTypes());
|
|
||||||
assertEquals(228, this.properties.getCompression().getMinSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomizeTomcat() throws Exception {
|
public void testCustomizeTomcat() throws Exception {
|
||||||
ConfigurableEmbeddedServletContainer factory = mock(ConfigurableEmbeddedServletContainer.class);
|
ConfigurableEmbeddedServletContainer factory = mock(ConfigurableEmbeddedServletContainer.class);
|
||||||
|
|
@ -243,72 +226,9 @@ public class ServerPropertiesTests {
|
||||||
assertEquals("192.168.0.1", remoteIpValve.getInternalProxies());
|
assertEquals("192.168.0.1", remoteIpValve.getInternalProxies());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void customTomcatCompression() throws Exception {
|
|
||||||
assertThat("on", is(equalTo(configureCompression("on"))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void disableTomcatCompressionWithYaml() throws Exception {
|
|
||||||
// YAML interprets "off" as false, check that it's mapped back to off
|
|
||||||
assertThat("off", is(equalTo(configureCompression("faLSe"))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void enableTomcatCompressionWithYaml() throws Exception {
|
|
||||||
// YAML interprets "on" as true, check that it's mapped back to on
|
|
||||||
assertThat("on", is(equalTo(configureCompression("trUE"))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void customTomcatCompressableMimeTypes() throws Exception {
|
|
||||||
Map<String, String> map = new HashMap<String, String>();
|
|
||||||
map.put("server.port", "0");
|
|
||||||
map.put("server.tomcat.compressableMimeTypes", "application/foo");
|
|
||||||
bindProperties(map);
|
|
||||||
|
|
||||||
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
|
|
||||||
this.properties.customize(factory);
|
|
||||||
|
|
||||||
TomcatEmbeddedServletContainer container = (TomcatEmbeddedServletContainer) factory
|
|
||||||
.getEmbeddedServletContainer();
|
|
||||||
|
|
||||||
try {
|
|
||||||
AbstractHttp11Protocol<?> protocol = (AbstractHttp11Protocol<?>) container
|
|
||||||
.getTomcat().getConnector().getProtocolHandler();
|
|
||||||
assertEquals("application/foo", protocol.getCompressableMimeTypes());
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
container.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bindProperties(Map<String, String> map) {
|
private void bindProperties(Map<String, String> map) {
|
||||||
new RelaxedDataBinder(this.properties, "server").bind(new MutablePropertyValues(
|
new RelaxedDataBinder(this.properties, "server").bind(new MutablePropertyValues(
|
||||||
map));
|
map));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String configureCompression(String compression) {
|
|
||||||
Map<String, String> map = new HashMap<String, String>();
|
|
||||||
map.put("server.port", "0");
|
|
||||||
// YAML interprets "on" as true
|
|
||||||
map.put("server.tomcat.compression", compression);
|
|
||||||
bindProperties(map);
|
|
||||||
|
|
||||||
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
|
|
||||||
this.properties.customize(factory);
|
|
||||||
|
|
||||||
TomcatEmbeddedServletContainer container = (TomcatEmbeddedServletContainer) factory
|
|
||||||
.getEmbeddedServletContainer();
|
|
||||||
|
|
||||||
try {
|
|
||||||
AbstractHttp11Protocol<?> protocol = (AbstractHttp11Protocol<?>) container
|
|
||||||
.getTomcat().getConnector().getProtocolHandler();
|
|
||||||
return protocol.getCompression();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
container.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,9 @@ content into your application; rather pick only the properties that you need.
|
||||||
server.port=8080
|
server.port=8080
|
||||||
server.address= # bind to a specific NIC
|
server.address= # bind to a specific NIC
|
||||||
server.session-timeout= # session timeout in seconds
|
server.session-timeout= # session timeout in seconds
|
||||||
|
server.compression.enabled=false # if response compression is enabled
|
||||||
|
server.compression.mime-types=text/html,text/xml,text/plain,text/css # comma-separated list of MIME types that should be compressed
|
||||||
|
server.compression.min-response-size=2048 # minimum response size that is required for compression to be performed
|
||||||
server.context-parameters.*= # Servlet context init parameters, e.g. server.context-parameters.a=alpha
|
server.context-parameters.*= # Servlet context init parameters, e.g. server.context-parameters.a=alpha
|
||||||
server.context-path= # the context path, defaults to '/'
|
server.context-path= # the context path, defaults to '/'
|
||||||
server.jsp-servlet.class-name=org.apache.jasper.servlet.JspServlet # The class name of the JSP servlet
|
server.jsp-servlet.class-name=org.apache.jasper.servlet.JspServlet # The class name of the JSP servlet
|
||||||
|
|
@ -89,8 +92,6 @@ content into your application; rather pick only the properties that you need.
|
||||||
server.ssl.trust-store-type=
|
server.ssl.trust-store-type=
|
||||||
server.tomcat.access-log-pattern= # log pattern of the access log
|
server.tomcat.access-log-pattern= # log pattern of the access log
|
||||||
server.tomcat.access-log-enabled=false # is access logging enabled
|
server.tomcat.access-log-enabled=false # is access logging enabled
|
||||||
server.tomcat.compression=off # is compression enabled (off, on, or an integer content length limit)
|
|
||||||
server.tomcat.compressable-mime-types=text/html,text/xml,text/plain # comma-separated list of mime types that Tomcat will compress
|
|
||||||
server.tomcat.internal-proxies=10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|\\
|
server.tomcat.internal-proxies=10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|\\
|
||||||
192\\.168\\.\\d{1,3}\\.\\d{1,3}|\\
|
192\\.168\\.\\d{1,3}\\.\\d{1,3}|\\
|
||||||
169\\.254\\.\\d{1,3}\\.\\d{1,3}|\\
|
169\\.254\\.\\d{1,3}\\.\\d{1,3}|\\
|
||||||
|
|
@ -156,21 +157,6 @@ content into your application; rather pick only the properties that you need.
|
||||||
# HTTP message conversion
|
# HTTP message conversion
|
||||||
spring.http.converters.preferred-json-mapper= # the preferred JSON mapper to use for HTTP message conversion. Set to "gson" to force the use of Gson when both it and Jackson are on the classpath.
|
spring.http.converters.preferred-json-mapper= # the preferred JSON mapper to use for HTTP message conversion. Set to "gson" to force the use of Gson when both it and Jackson are on the classpath.
|
||||||
|
|
||||||
# HTTP response compression ({sc-spring-boot-autoconfigure}/web/GzipFilterProperties.{sc-ext}[GzipFilterProperties])
|
|
||||||
spring.http.gzip.buffer-size= # size of the output buffer in bytes
|
|
||||||
spring.http.gzip.deflate-compression-level= # the level used for deflate compression (0-9)
|
|
||||||
spring.http.gzip.deflate-no-wrap= # noWrap setting for deflate compression (true or false)
|
|
||||||
spring.http.gzip.enabled=true # enable gzip filter support
|
|
||||||
spring.http.gzip.excluded-agents= # comma-separated list of user agents to exclude from compression
|
|
||||||
spring.http.gzip.exclude-agent-patterns= # comma-separated list of regular expression patterns to control user agents excluded from compression
|
|
||||||
spring.http.gzip.exclude-paths= # comma-separated list of paths to exclude from compression
|
|
||||||
spring.http.gzip.exclude-path-patterns= # comma-separated list of regular expression patterns to control the paths that are excluded from compression
|
|
||||||
spring.http.gzip.methods= # comma-separated list of HTTP methods for which compression is enabled
|
|
||||||
spring.http.gzip.mime-types= # comma-separated list of MIME types which should be compressed
|
|
||||||
spring.http.gzip.excluded-mime-types= # comma-separated list of MIME types to exclude from compression
|
|
||||||
spring.http.gzip.min-gzip-size= # minimum content length required for compression to occur
|
|
||||||
spring.http.gzip.vary= # Vary header to be sent on responses that may be compressed
|
|
||||||
|
|
||||||
# JACKSON ({sc-spring-boot-autoconfigure}/jackson/JacksonProperties.{sc-ext}[JacksonProperties])
|
# JACKSON ({sc-spring-boot-autoconfigure}/jackson/JacksonProperties.{sc-ext}[JacksonProperties])
|
||||||
spring.jackson.date-format= # Date format string (e.g. yyyy-MM-dd HH:mm:ss), or a fully-qualified date format class name (e.g. com.fasterxml.jackson.databind.util.ISO8601DateFormat)
|
spring.jackson.date-format= # Date format string (e.g. yyyy-MM-dd HH:mm:ss), or a fully-qualified date format class name (e.g. com.fasterxml.jackson.databind.util.ISO8601DateFormat)
|
||||||
spring.jackson.property-naming-strategy= # One of the constants on Jackson's PropertyNamingStrategy (e.g. CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) or the fully-qualified class name of a PropertyNamingStrategy subclass
|
spring.jackson.property-naming-strategy= # One of the constants on Jackson's PropertyNamingStrategy (e.g. CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) or the fully-qualified class name of a PropertyNamingStrategy subclass
|
||||||
|
|
|
||||||
|
|
@ -834,53 +834,27 @@ not required.
|
||||||
|
|
||||||
[[how-to-enable-http-response-compression]]
|
[[how-to-enable-http-response-compression]]
|
||||||
=== Enable HTTP response compression
|
=== Enable HTTP response compression
|
||||||
Spring Boot provides two mechanisms for enabling compression of HTTP compression; one
|
HTTP response compression is supported by Jetty, Tomcat, and Undertow. It can be enabled
|
||||||
that is Tomcat-specific and another that uses a filter and works with Jetty, Tomcat,
|
via `application.properties`:
|
||||||
and Undertow.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[how-to-enable-http-response-compression-tomcat]]
|
|
||||||
==== Enable Tomcat's HTTP response compression
|
|
||||||
Tomcat provides built-in support for HTTP response compression. It is disabled by
|
|
||||||
default, but can easily be enabled via `application.properties`:
|
|
||||||
|
|
||||||
[source,properties,indent=0,subs="verbatim,quotes,attributes"]
|
[source,properties,indent=0,subs="verbatim,quotes,attributes"]
|
||||||
----
|
----
|
||||||
server.tomcat.compression=on
|
server.compression.enabled=true
|
||||||
----
|
----
|
||||||
|
|
||||||
When set to `on` Tomcat will compress responses with a length that is at least 2048
|
By default, responses must be at least 2048 bytes in length for compression to be
|
||||||
bytes. This limit can be configured by specifying an integer value rather than `on`,
|
performed. This can be configured using the `server.compression.min-response-size`
|
||||||
e.g.:
|
property.
|
||||||
|
|
||||||
[source,properties,indent=0,subs="verbatim,quotes,attributes"]
|
By default, responses will only be compressed if their content type is one of the
|
||||||
----
|
following:
|
||||||
server.tomcat.compression=4096
|
|
||||||
----
|
|
||||||
|
|
||||||
By default Tomcat will only compress responses with certain MIME types
|
- `text/html`
|
||||||
(`text/html`, `text/xml`, and `text/plain`). You can customize this using the
|
- `text/xml`
|
||||||
`server.tomcat.compressableMimeTypes` property, e.g.:
|
- `text/plain`
|
||||||
|
- `text/css`
|
||||||
|
|
||||||
[source,properties,indent=0,subs="verbatim,quotes,attributes"]
|
This can be configured using the `server.compression.mime-types` property.
|
||||||
----
|
|
||||||
server.tomcat.compressableMimeTypes=application/json,application/xml
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[how-to-enable-http-compression-gzip-filter]]
|
|
||||||
==== Enable HTTP response compression using GzipFilter
|
|
||||||
If you're using Jetty or Undertow, or you want more sophisticated control over
|
|
||||||
HTTP response compression, Spring Boot provides auto-configuration for Jetty's
|
|
||||||
`GzipFilter`. While this filter is part of Jetty, it's compatible with Tomcat
|
|
||||||
and Undertow as well. To enable the filter, simply add a dependency on
|
|
||||||
`org.eclipse.jetty:jetty-servlets` to your application.
|
|
||||||
|
|
||||||
`GzipFilter` can be configured using the `spring.http.gzip.*` properties. See
|
|
||||||
{sc-spring-boot-autoconfigure}/web/GzipFilterProperties.{sc-ext}[`GzipFilterProperties`]
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,10 @@ public class WarPackagingTests {
|
||||||
"tomcat-embed-websocket-"));
|
"tomcat-embed-websocket-"));
|
||||||
|
|
||||||
private static final Set<String> JETTY_EXPECTED_IN_WEB_INF_LIB_PROVIDED = new HashSet<String>(
|
private static final Set<String> JETTY_EXPECTED_IN_WEB_INF_LIB_PROVIDED = new HashSet<String>(
|
||||||
Arrays.asList("spring-boot-starter-jetty-", "jetty-util-", "javax.servlet-",
|
Arrays.asList("spring-boot-starter-jetty-", "jetty-continuation",
|
||||||
"jetty-io-", "jetty-http-", "jetty-server-", "jetty-security-",
|
"jetty-util-", "javax.servlet-", "jetty-io-", "jetty-http-",
|
||||||
"jetty-servlet-", "jetty-webapp-", "websocket-api",
|
"jetty-server-", "jetty-security-", "jetty-servlet-",
|
||||||
|
"jetty-servlets", "jetty-webapp-", "websocket-api",
|
||||||
"javax.annotation-api", "jetty-plus", "javax-websocket-server-impl-",
|
"javax.annotation-api", "jetty-plus", "javax-websocket-server-impl-",
|
||||||
"asm-", "javax.websocket-api-", "asm-tree-", "asm-commons-",
|
"asm-", "javax.websocket-api-", "asm-tree-", "asm-commons-",
|
||||||
"websocket-common-", "jetty-annotations-",
|
"websocket-common-", "jetty-annotations-",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
server.compression.enabled: true
|
||||||
|
server.compression.min-response-size: 1
|
||||||
|
|
@ -16,17 +16,26 @@
|
||||||
|
|
||||||
package sample.jetty;
|
package sample.jetty;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.test.IntegrationTest;
|
import org.springframework.boot.test.IntegrationTest;
|
||||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||||
import org.springframework.boot.test.TestRestTemplate;
|
import org.springframework.boot.test.TestRestTemplate;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
import org.springframework.test.context.web.WebAppConfiguration;
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
|
@ -34,6 +43,7 @@ import static org.junit.Assert.assertEquals;
|
||||||
* Basic integration tests for demo application.
|
* Basic integration tests for demo application.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
|
* @author Andy Wilkinson
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@SpringApplicationConfiguration(classes = SampleJettyApplication.class)
|
@SpringApplicationConfiguration(classes = SampleJettyApplication.class)
|
||||||
|
|
@ -53,4 +63,28 @@ public class SampleJettyApplicationTests {
|
||||||
assertEquals("Hello World", entity.getBody());
|
assertEquals("Hello World", entity.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompression() throws Exception {
|
||||||
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
|
requestHeaders.set("Accept-Encoding", "gzip");
|
||||||
|
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
|
||||||
|
|
||||||
|
RestTemplate restTemplate = new TestRestTemplate();
|
||||||
|
|
||||||
|
ResponseEntity<byte[]> entity = restTemplate.exchange("http://localhost:"
|
||||||
|
+ this.port, HttpMethod.GET, requestEntity, byte[].class);
|
||||||
|
|
||||||
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
|
||||||
|
GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(
|
||||||
|
entity.getBody()));
|
||||||
|
try {
|
||||||
|
assertEquals("Hello World",
|
||||||
|
StreamUtils.copyToString(inflater, Charset.forName("UTF-8")));
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
inflater.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
server.compression.enabled: true
|
||||||
|
server.compression.min-response-size: 1
|
||||||
|
|
@ -16,25 +16,34 @@
|
||||||
|
|
||||||
package sample.jetty8;
|
package sample.jetty8;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.test.IntegrationTest;
|
import org.springframework.boot.test.IntegrationTest;
|
||||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||||
import org.springframework.boot.test.TestRestTemplate;
|
import org.springframework.boot.test.TestRestTemplate;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
import org.springframework.test.context.web.WebAppConfiguration;
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import sample.jetty8.SampleJetty8Application;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic integration tests for demo application.
|
* Basic integration tests for demo application.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
|
* @author Andy Wilkinson
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@SpringApplicationConfiguration(classes = SampleJetty8Application.class)
|
@SpringApplicationConfiguration(classes = SampleJetty8Application.class)
|
||||||
|
|
@ -54,4 +63,28 @@ public class SampleJetty8ApplicationTests {
|
||||||
assertEquals("Hello World", entity.getBody());
|
assertEquals("Hello World", entity.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompression() throws Exception {
|
||||||
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
|
requestHeaders.set("Accept-Encoding", "gzip");
|
||||||
|
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
|
||||||
|
|
||||||
|
RestTemplate restTemplate = new TestRestTemplate();
|
||||||
|
|
||||||
|
ResponseEntity<byte[]> entity = restTemplate.exchange("http://localhost:"
|
||||||
|
+ this.port, HttpMethod.GET, requestEntity, byte[].class);
|
||||||
|
|
||||||
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
|
||||||
|
GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(
|
||||||
|
entity.getBody()));
|
||||||
|
try {
|
||||||
|
assertEquals("Hello World",
|
||||||
|
StreamUtils.copyToString(inflater, Charset.forName("UTF-8")));
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
inflater.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
server.compression.enabled: true
|
||||||
|
server.compression.min-response-size: 1
|
||||||
|
|
@ -16,16 +16,25 @@
|
||||||
|
|
||||||
package sample.tomcat;
|
package sample.tomcat;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||||
import org.springframework.boot.test.TestRestTemplate;
|
import org.springframework.boot.test.TestRestTemplate;
|
||||||
import org.springframework.boot.test.WebIntegrationTest;
|
import org.springframework.boot.test.WebIntegrationTest;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
|
@ -33,6 +42,7 @@ import static org.junit.Assert.assertEquals;
|
||||||
* Basic integration tests for demo application.
|
* Basic integration tests for demo application.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
|
* @author Andy Wilkinson
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@SpringApplicationConfiguration(classes = SampleTomcatApplication.class)
|
@SpringApplicationConfiguration(classes = SampleTomcatApplication.class)
|
||||||
|
|
@ -51,4 +61,28 @@ public class SampleTomcatApplicationTests {
|
||||||
assertEquals("Hello World", entity.getBody());
|
assertEquals("Hello World", entity.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompression() throws Exception {
|
||||||
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
|
requestHeaders.set("Accept-Encoding", "gzip");
|
||||||
|
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
|
||||||
|
|
||||||
|
RestTemplate restTemplate = new TestRestTemplate();
|
||||||
|
|
||||||
|
ResponseEntity<byte[]> entity = restTemplate.exchange("http://localhost:"
|
||||||
|
+ this.port, HttpMethod.GET, requestEntity, byte[].class);
|
||||||
|
|
||||||
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
|
||||||
|
GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(
|
||||||
|
entity.getBody()));
|
||||||
|
try {
|
||||||
|
assertEquals("Hello World",
|
||||||
|
StreamUtils.copyToString(inflater, Charset.forName("UTF-8")));
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
inflater.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
server.undertow.access-log-enabled=true
|
server.undertow.access-log-enabled=true
|
||||||
server.undertow.access-log-dir=target/logs
|
server.undertow.access-log-dir=target/logs
|
||||||
server.undertow.access-log-pattern=combined
|
server.undertow.access-log-pattern=combined
|
||||||
|
server.compression.enabled=true
|
||||||
|
server.compression.min-response-size=1
|
||||||
|
|
@ -16,17 +16,26 @@
|
||||||
|
|
||||||
package sample.undertow;
|
package sample.undertow;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.test.IntegrationTest;
|
import org.springframework.boot.test.IntegrationTest;
|
||||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||||
import org.springframework.boot.test.TestRestTemplate;
|
import org.springframework.boot.test.TestRestTemplate;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
import org.springframework.test.context.web.WebAppConfiguration;
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
|
@ -56,6 +65,30 @@ public class SampleUndertowApplicationTests {
|
||||||
assertOkResponse("/async", "async: Hello World");
|
assertOkResponse("/async", "async: Hello World");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompression() throws Exception {
|
||||||
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
|
requestHeaders.set("Accept-Encoding", "gzip");
|
||||||
|
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
|
||||||
|
|
||||||
|
RestTemplate restTemplate = new TestRestTemplate();
|
||||||
|
|
||||||
|
ResponseEntity<byte[]> entity = restTemplate.exchange("http://localhost:"
|
||||||
|
+ this.port, HttpMethod.GET, requestEntity, byte[].class);
|
||||||
|
|
||||||
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
|
||||||
|
GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(
|
||||||
|
entity.getBody()));
|
||||||
|
try {
|
||||||
|
assertEquals("Hello World",
|
||||||
|
StreamUtils.copyToString(inflater, Charset.forName("UTF-8")));
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
inflater.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void assertOkResponse(String path, String body) {
|
private void assertOkResponse(String path, String body) {
|
||||||
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
|
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
|
||||||
"http://localhost:" + this.port + path, String.class);
|
"http://localhost:" + this.port + path, String.class);
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,10 @@
|
||||||
<main.basedir>${basedir}/../..</main.basedir>
|
<main.basedir>${basedir}/../..</main.basedir>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-servlets</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-webapp</artifactId>
|
<artifactId>jetty-webapp</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import java.util.Arrays;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
@ -36,6 +35,7 @@ import org.springframework.util.ClassUtils;
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
* @author Ivan Sopov
|
||||||
* @see AbstractEmbeddedServletContainerFactory
|
* @see AbstractEmbeddedServletContainerFactory
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractConfigurableEmbeddedServletContainer implements
|
public abstract class AbstractConfigurableEmbeddedServletContainer implements
|
||||||
|
|
@ -68,7 +68,7 @@ public abstract class AbstractConfigurableEmbeddedServletContainer implements
|
||||||
|
|
||||||
private JspServlet jspServlet = new JspServlet();
|
private JspServlet jspServlet = new JspServlet();
|
||||||
|
|
||||||
private CompressionProperties compression;
|
private Compression compression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link AbstractConfigurableEmbeddedServletContainer} instance.
|
* Create a new {@link AbstractConfigurableEmbeddedServletContainer} instance.
|
||||||
|
|
@ -281,11 +281,11 @@ public abstract class AbstractConfigurableEmbeddedServletContainer implements
|
||||||
return this.jspServlet;
|
return this.jspServlet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompressionProperties getCompression() {
|
public Compression getCompression() {
|
||||||
return this.compression;
|
return this.compression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCompression(CompressionProperties compression) {
|
public void setCompression(Compression compression) {
|
||||||
this.compression = compression;
|
this.compression = compression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -317,44 +317,4 @@ public abstract class AbstractConfigurableEmbeddedServletContainer implements
|
||||||
.getClassLoader());
|
.getClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CompressionProperties {
|
|
||||||
private boolean enabled = false;
|
|
||||||
private String mimeTypes = "text/html,text/xml,text/plain,text/css";
|
|
||||||
private int minSize = 2048;
|
|
||||||
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnabled(boolean enabled) {
|
|
||||||
this.enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMimeTypes() {
|
|
||||||
return mimeTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMimeTypes(String mimeTypes) {
|
|
||||||
this.mimeTypes = mimeTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMinSize() {
|
|
||||||
return minSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMinSize(int minSize) {
|
|
||||||
this.minSize = minSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getMimeTypesList() {
|
|
||||||
List<String> mimeTypesList = new ArrayList<String>();
|
|
||||||
StringTokenizer tok = new StringTokenizer(mimeTypes, ",", false);
|
|
||||||
while (tok.hasMoreTokens()) {
|
|
||||||
mimeTypesList.add(tok.nextToken());
|
|
||||||
}
|
|
||||||
return mimeTypesList;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* 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.context.embedded;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple container-independent abstraction for compression configuration.
|
||||||
|
*
|
||||||
|
* @author Ivan Sopov
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
* @since 1.3.0
|
||||||
|
*/
|
||||||
|
public class Compression {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If response compression is enabled.
|
||||||
|
*/
|
||||||
|
private boolean enabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comma-separated list of MIME types that should be compressed.
|
||||||
|
*/
|
||||||
|
private String[] mimeTypes = new String[] { "text/html", "text/xml", "text/plain",
|
||||||
|
"text/css" };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimum response size that is required for compression to be performed
|
||||||
|
*/
|
||||||
|
private int minResponseSize = 2048;
|
||||||
|
|
||||||
|
public boolean getEnabled() {
|
||||||
|
return this.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getMimeTypes() {
|
||||||
|
return this.mimeTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMimeTypes(String[] mimeTypes) {
|
||||||
|
this.mimeTypes = mimeTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinResponseSize() {
|
||||||
|
return this.minResponseSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinResponseSize(int minSize) {
|
||||||
|
this.minResponseSize = minSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -170,4 +170,11 @@ public interface ConfigurableEmbeddedServletContainer {
|
||||||
*/
|
*/
|
||||||
void setJspServlet(JspServlet jspServlet);
|
void setJspServlet(JspServlet jspServlet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the compression configuration that will be applied to the container's default
|
||||||
|
* connector.
|
||||||
|
* @param compression the compression configuration
|
||||||
|
*/
|
||||||
|
void setCompression(Compression compression);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,14 @@ package org.springframework.boot.context.embedded.jetty;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpVersion;
|
import org.eclipse.jetty.http.HttpVersion;
|
||||||
import org.eclipse.jetty.http.MimeTypes;
|
import org.eclipse.jetty.http.MimeTypes;
|
||||||
|
|
@ -42,6 +43,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
|
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
|
||||||
import org.eclipse.jetty.servlet.ServletHolder;
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
import org.eclipse.jetty.servlet.ServletMapping;
|
import org.eclipse.jetty.servlet.ServletMapping;
|
||||||
|
import org.eclipse.jetty.servlets.gzip.GzipHandler;
|
||||||
import org.eclipse.jetty.util.resource.JarResource;
|
import org.eclipse.jetty.util.resource.JarResource;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
|
|
@ -49,6 +51,7 @@ import org.eclipse.jetty.webapp.AbstractConfiguration;
|
||||||
import org.eclipse.jetty.webapp.Configuration;
|
import org.eclipse.jetty.webapp.Configuration;
|
||||||
import org.eclipse.jetty.webapp.WebAppContext;
|
import org.eclipse.jetty.webapp.WebAppContext;
|
||||||
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
|
||||||
|
import org.springframework.boot.context.embedded.Compression;
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
|
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
|
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
|
||||||
|
|
@ -84,6 +87,12 @@ import org.springframework.util.StringUtils;
|
||||||
public class JettyEmbeddedServletContainerFactory extends
|
public class JettyEmbeddedServletContainerFactory extends
|
||||||
AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware {
|
AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware {
|
||||||
|
|
||||||
|
private static final String GZIP_HANDLER_JETTY_9_2 = "org.eclipse.jetty.servlets.gzip.GzipHandler";
|
||||||
|
|
||||||
|
private static final String GZIP_HANDLER_JETTY_8 = "org.eclipse.jetty.server.handler.GzipHandler";
|
||||||
|
|
||||||
|
private static final String GZIP_HANDLER_JETTY_9_3 = "org.eclipse.jetty.server.handler.gzip.GzipHandler";
|
||||||
|
|
||||||
private List<Configuration> configurations = new ArrayList<Configuration>();
|
private List<Configuration> configurations = new ArrayList<Configuration>();
|
||||||
|
|
||||||
private List<JettyServerCustomizer> jettyServerCustomizers = new ArrayList<JettyServerCustomizer>();
|
private List<JettyServerCustomizer> jettyServerCustomizers = new ArrayList<JettyServerCustomizer>();
|
||||||
|
|
@ -116,12 +125,6 @@ public class JettyEmbeddedServletContainerFactory extends
|
||||||
super(contextPath, port);
|
super(contextPath, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String[] GZIP_HANDLER_CLASSNAMES = new String[] {
|
|
||||||
"org.eclipse.jetty.servlets.gzip.GzipHandler", // Jetty 9.2
|
|
||||||
"org.eclipse.jetty.server.handler.gzip.GzipHandler", // Jetty 9.3
|
|
||||||
"org.eclipse.jetty.server.handler.GzipHandler" // Jetty 8
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EmbeddedServletContainer getEmbeddedServletContainer(
|
public EmbeddedServletContainer getEmbeddedServletContainer(
|
||||||
ServletContextInitializer... initializers) {
|
ServletContextInitializer... initializers) {
|
||||||
|
|
@ -129,8 +132,10 @@ public class JettyEmbeddedServletContainerFactory extends
|
||||||
int port = (getPort() >= 0 ? getPort() : 0);
|
int port = (getPort() >= 0 ? getPort() : 0);
|
||||||
Server server = new Server(new InetSocketAddress(getAddress(), port));
|
Server server = new Server(new InetSocketAddress(getAddress(), port));
|
||||||
configureWebAppContext(context, initializers);
|
configureWebAppContext(context, initializers);
|
||||||
if (getCompression() != null && getCompression().isEnabled()) {
|
if (getCompression() != null && getCompression().getEnabled()) {
|
||||||
setupGzipHandler(context, server);
|
HandlerWrapper gzipHandler = createGzipHandler();
|
||||||
|
gzipHandler.setHandler(context);
|
||||||
|
server.setHandler(gzipHandler);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
server.setHandler(context);
|
server.setHandler(context);
|
||||||
|
|
@ -149,50 +154,19 @@ public class JettyEmbeddedServletContainerFactory extends
|
||||||
return getJettyEmbeddedServletContainer(server);
|
return getJettyEmbeddedServletContainer(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupGzipHandler(JettyEmbeddedWebAppContext context, Server server)
|
private HandlerWrapper createGzipHandler() {
|
||||||
throws LinkageError {
|
if (ClassUtils.isPresent(GZIP_HANDLER_JETTY_9_2, getClass().getClassLoader())) {
|
||||||
boolean done = false;
|
return new Jetty92GzipHandlerFactory().createGzipHandler(getCompression());
|
||||||
for (String gzipHandlerClassName : GZIP_HANDLER_CLASSNAMES) {
|
|
||||||
if (ClassUtils.isPresent(gzipHandlerClassName, null)) {
|
|
||||||
try {
|
|
||||||
Class<?> gzipHandlerClass = ClassUtils.forName(gzipHandlerClassName,
|
|
||||||
null);
|
|
||||||
|
|
||||||
HandlerWrapper gzipHandler = (HandlerWrapper) gzipHandlerClass
|
|
||||||
.newInstance();
|
|
||||||
gzipHandler.setHandler(context);
|
|
||||||
|
|
||||||
Method minGzipSizeMethod = ReflectionUtils.findMethod(
|
|
||||||
gzipHandlerClass, "setMinGzipSize", int.class);
|
|
||||||
minGzipSizeMethod.invoke(gzipHandler, getCompression().getMinSize());
|
|
||||||
|
|
||||||
Method mimeTypesMethod = ReflectionUtils.findMethod(gzipHandlerClass,
|
|
||||||
"setMimeTypes", String.class);
|
|
||||||
if (mimeTypesMethod != null) {
|
|
||||||
// Jetty 8 & Jety 9.2
|
|
||||||
mimeTypesMethod.invoke(gzipHandler, getCompression()
|
|
||||||
.getMimeTypes());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Jetty 9.3
|
|
||||||
mimeTypesMethod = ReflectionUtils.findMethod(gzipHandlerClass,
|
|
||||||
"setIncludedMimeTypes", String[].class);
|
|
||||||
List<String> mimeTypes = getCompression().getMimeTypesList();
|
|
||||||
mimeTypesMethod.invoke(gzipHandler,
|
|
||||||
(Object) mimeTypes.toArray(new String[mimeTypes.size()]));
|
|
||||||
}
|
|
||||||
server.setHandler(gzipHandler);
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!done) {
|
else if (ClassUtils.isPresent(GZIP_HANDLER_JETTY_8, getClass().getClassLoader())) {
|
||||||
throw new IllegalStateException("Jetty GzipHandler is not in classpath");
|
return new Jetty8GzipHandlerFactory().createGzipHandler(getCompression());
|
||||||
}
|
}
|
||||||
|
else if (ClassUtils
|
||||||
|
.isPresent(GZIP_HANDLER_JETTY_9_3, getClass().getClassLoader())) {
|
||||||
|
return new Jetty93GzipHandlerFactory().createGzipHandler(getCompression());
|
||||||
|
}
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Compression is enabled, but GzipHandler is not on the classpath");
|
||||||
}
|
}
|
||||||
|
|
||||||
private SslServerConnectorFactory getSslServerConnectorFactory() {
|
private SslServerConnectorFactory getSslServerConnectorFactory() {
|
||||||
|
|
@ -594,4 +568,73 @@ public class JettyEmbeddedServletContainerFactory extends
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private interface GzipHandlerFactory {
|
||||||
|
|
||||||
|
HandlerWrapper createGzipHandler(Compression compression);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Jetty8GzipHandlerFactory implements GzipHandlerFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerWrapper createGzipHandler(Compression compression) {
|
||||||
|
try {
|
||||||
|
Class<?> gzipHandlerClass = ClassUtils.forName(GZIP_HANDLER_JETTY_8,
|
||||||
|
getClass().getClassLoader());
|
||||||
|
HandlerWrapper gzipHandler = (HandlerWrapper) gzipHandlerClass
|
||||||
|
.newInstance();
|
||||||
|
ReflectionUtils.findMethod(gzipHandlerClass, "setMinGzipSize", int.class)
|
||||||
|
.invoke(gzipHandler, compression.getMinResponseSize());
|
||||||
|
ReflectionUtils.findMethod(gzipHandlerClass, "setMimeTypes", Set.class)
|
||||||
|
.invoke(gzipHandler,
|
||||||
|
new HashSet<String>(Arrays.asList(compression
|
||||||
|
.getMimeTypes())));
|
||||||
|
return gzipHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new RuntimeException("Failed to configure Jetty 8 gzip handler", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Jetty92GzipHandlerFactory implements GzipHandlerFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerWrapper createGzipHandler(Compression compression) {
|
||||||
|
GzipHandler gzipHandler = new GzipHandler();
|
||||||
|
gzipHandler.setMinGzipSize(compression.getMinResponseSize());
|
||||||
|
gzipHandler.setMimeTypes(new HashSet<String>(Arrays.asList(compression
|
||||||
|
.getMimeTypes())));
|
||||||
|
return gzipHandler;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Jetty93GzipHandlerFactory implements GzipHandlerFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerWrapper createGzipHandler(Compression compression) {
|
||||||
|
try {
|
||||||
|
Class<?> gzipHandlerClass = ClassUtils.forName(GZIP_HANDLER_JETTY_9_3,
|
||||||
|
getClass().getClassLoader());
|
||||||
|
HandlerWrapper gzipHandler = (HandlerWrapper) gzipHandlerClass
|
||||||
|
.newInstance();
|
||||||
|
ReflectionUtils.findMethod(gzipHandlerClass, "setMinGzipSize", int.class)
|
||||||
|
.invoke(gzipHandler, compression.getMinResponseSize());
|
||||||
|
ReflectionUtils.findMethod(gzipHandlerClass, "setIncludedMimeTypes",
|
||||||
|
String[].class).invoke(gzipHandler,
|
||||||
|
new Object[] { compression.getMimeTypes() });
|
||||||
|
return gzipHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new RuntimeException("Failed to configure Jetty 9.3 gzip handler",
|
||||||
|
ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -257,14 +257,15 @@ public class TomcatEmbeddedServletContainerFactory extends
|
||||||
connector.setSecure(true);
|
connector.setSecure(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getCompression() != null && getCompression().isEnabled()) {
|
if (getCompression() != null && getCompression().getEnabled()) {
|
||||||
ProtocolHandler handler = connector.getProtocolHandler();
|
ProtocolHandler handler = connector.getProtocolHandler();
|
||||||
if (handler instanceof AbstractHttp11Protocol) {
|
if (handler instanceof AbstractHttp11Protocol) {
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler;
|
AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler;
|
||||||
protocol.setCompression("on");
|
protocol.setCompression("on");
|
||||||
protocol.setCompressionMinSize(getCompression().getMinSize());
|
protocol.setCompressionMinSize(getCompression().getMinResponseSize());
|
||||||
protocol.setCompressableMimeTypes(getCompression().getMimeTypes());
|
protocol.setCompressableMimeTypes(StringUtils
|
||||||
|
.arrayToCommaDelimitedString(getCompression().getMimeTypes()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,14 @@ package org.springframework.boot.context.embedded.undertow;
|
||||||
import io.undertow.Handlers;
|
import io.undertow.Handlers;
|
||||||
import io.undertow.Undertow;
|
import io.undertow.Undertow;
|
||||||
import io.undertow.Undertow.Builder;
|
import io.undertow.Undertow.Builder;
|
||||||
import io.undertow.attribute.ConstantExchangeAttribute;
|
|
||||||
import io.undertow.attribute.ExchangeAttribute;
|
|
||||||
import io.undertow.attribute.ResponseHeaderAttribute;
|
|
||||||
import io.undertow.predicate.Predicate;
|
import io.undertow.predicate.Predicate;
|
||||||
import io.undertow.predicate.Predicates;
|
import io.undertow.predicate.Predicates;
|
||||||
import io.undertow.server.HttpHandler;
|
import io.undertow.server.HttpHandler;
|
||||||
|
import io.undertow.server.HttpServerExchange;
|
||||||
import io.undertow.server.handlers.encoding.ContentEncodingRepository;
|
import io.undertow.server.handlers.encoding.ContentEncodingRepository;
|
||||||
import io.undertow.server.handlers.encoding.EncodingHandler;
|
import io.undertow.server.handlers.encoding.EncodingHandler;
|
||||||
import io.undertow.server.handlers.encoding.GzipEncodingProvider;
|
import io.undertow.server.handlers.encoding.GzipEncodingProvider;
|
||||||
import io.undertow.servlet.api.DeploymentManager;
|
import io.undertow.servlet.api.DeploymentManager;
|
||||||
import io.undertow.util.HttpString;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
|
|
@ -40,10 +37,12 @@ import javax.servlet.ServletException;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.boot.context.embedded.AbstractConfigurableEmbeddedServletContainer.CompressionProperties;
|
import org.springframework.boot.context.embedded.Compression;
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
|
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
|
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.util.MimeType;
|
||||||
|
import org.springframework.util.MimeTypeUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
|
@ -70,15 +69,14 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
|
||||||
|
|
||||||
private final boolean autoStart;
|
private final boolean autoStart;
|
||||||
|
|
||||||
private final CompressionProperties compression;
|
private final Compression compression;
|
||||||
|
|
||||||
private Undertow undertow;
|
private Undertow undertow;
|
||||||
|
|
||||||
private boolean started = false;
|
private boolean started = false;
|
||||||
|
|
||||||
public UndertowEmbeddedServletContainer(Builder builder, DeploymentManager manager,
|
public UndertowEmbeddedServletContainer(Builder builder, DeploymentManager manager,
|
||||||
String contextPath, int port, boolean autoStart,
|
String contextPath, int port, boolean autoStart, Compression compression) {
|
||||||
CompressionProperties compression) {
|
|
||||||
this.builder = builder;
|
this.builder = builder;
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.contextPath = contextPath;
|
this.contextPath = contextPath;
|
||||||
|
|
@ -113,33 +111,26 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpHandler getContextHandler(HttpHandler servletHandler) {
|
private HttpHandler getContextHandler(HttpHandler servletHandler) {
|
||||||
if (compression != null && compression.isEnabled()) {
|
HttpHandler contextHandler = configurationCompressionIfNecessary(servletHandler);
|
||||||
ContentEncodingRepository encodingRepository = new ContentEncodingRepository();
|
|
||||||
|
|
||||||
List<String> mimeTypes = compression.getMimeTypesList();
|
|
||||||
Predicate[] mimePredicates = new Predicate[mimeTypes.size()];
|
|
||||||
ResponseHeaderAttribute mimeHeader = new ResponseHeaderAttribute(
|
|
||||||
new HttpString(HttpHeaders.CONTENT_TYPE));
|
|
||||||
for (int i = 0; i < mimeTypes.size(); i++) {
|
|
||||||
mimePredicates[i] = Predicates.equals(new ExchangeAttribute[] {
|
|
||||||
mimeHeader, new ConstantExchangeAttribute(mimeTypes.get(i)) });
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Predicate mimeAndSizePredicate = Predicates.and(
|
|
||||||
Predicates.maxContentSize(compression.getMinSize()),
|
|
||||||
Predicates.or(mimePredicates));
|
|
||||||
|
|
||||||
encodingRepository.addEncodingHandler("gzip", new GzipEncodingProvider(), 50,
|
|
||||||
mimeAndSizePredicate);
|
|
||||||
servletHandler = new EncodingHandler(encodingRepository)
|
|
||||||
.setNext(servletHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isEmpty(this.contextPath)) {
|
if (StringUtils.isEmpty(this.contextPath)) {
|
||||||
|
return contextHandler;
|
||||||
|
}
|
||||||
|
return Handlers.path().addPrefixPath(this.contextPath, contextHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpHandler configurationCompressionIfNecessary(HttpHandler servletHandler) {
|
||||||
|
if (this.compression == null || !this.compression.getEnabled()) {
|
||||||
return servletHandler;
|
return servletHandler;
|
||||||
}
|
}
|
||||||
return Handlers.path().addPrefixPath(this.contextPath, servletHandler);
|
ContentEncodingRepository encodingRepository = new ContentEncodingRepository();
|
||||||
|
|
||||||
|
Predicate mimeAndSizePredicate = Predicates.and(Predicates
|
||||||
|
.maxContentSize(this.compression.getMinResponseSize()), Predicates
|
||||||
|
.or(new CompressibleMimeTypePredicate(this.compression.getMimeTypes())));
|
||||||
|
|
||||||
|
encodingRepository.addEncodingHandler("gzip", new GzipEncodingProvider(), 50,
|
||||||
|
mimeAndSizePredicate);
|
||||||
|
return new EncodingHandler(encodingRepository).setNext(servletHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPortsDescription() {
|
private String getPortsDescription() {
|
||||||
|
|
@ -250,4 +241,32 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class CompressibleMimeTypePredicate implements Predicate {
|
||||||
|
|
||||||
|
private final List<MimeType> mimeTypes;
|
||||||
|
|
||||||
|
CompressibleMimeTypePredicate(String[] mimeTypes) {
|
||||||
|
this.mimeTypes = new ArrayList<MimeType>(mimeTypes.length);
|
||||||
|
for (String mimeTypeString : mimeTypes) {
|
||||||
|
this.mimeTypes.add(MimeTypeUtils.parseMimeType(mimeTypeString));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean resolve(HttpServerExchange value) {
|
||||||
|
String contentType = value.getResponseHeaders().getFirst(
|
||||||
|
HttpHeaders.CONTENT_TYPE);
|
||||||
|
if (contentType != null) {
|
||||||
|
for (MimeType mimeType : this.mimeTypes) {
|
||||||
|
if (mimeType.isCompatibleWith(MimeTypeUtils
|
||||||
|
.parseMimeType(contentType))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
import org.junit.rules.TemporaryFolder;
|
import org.junit.rules.TemporaryFolder;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
import org.springframework.boot.context.embedded.AbstractConfigurableEmbeddedServletContainer.CompressionProperties;
|
|
||||||
import org.springframework.boot.context.embedded.Ssl.ClientAuth;
|
import org.springframework.boot.context.embedded.Ssl.ClientAuth;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
@ -541,10 +540,11 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noCompressionForMimeType() throws Exception {
|
public void noCompressionForMimeType() throws Exception {
|
||||||
assertFalse(internalTestCompression(10000, "text/html,text/xml,text/css"));
|
assertFalse(internalTestCompression(10000, new String[] { "text/html",
|
||||||
|
"text/xml", "text/css" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String setupFactoryForCompression(int contentSize, String mimeTypes)
|
protected String setUpFactoryForCompression(int contentSize, String[] mimeTypes)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
char[] chars = new char[contentSize];
|
char[] chars = new char[contentSize];
|
||||||
Arrays.fill(chars, 'F');
|
Arrays.fill(chars, 'F');
|
||||||
|
|
@ -555,7 +555,7 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
|
||||||
FileCopyUtils.copy(testContent,
|
FileCopyUtils.copy(testContent,
|
||||||
new FileWriter(this.temporaryFolder.newFile("test.txt")));
|
new FileWriter(this.temporaryFolder.newFile("test.txt")));
|
||||||
factory.setDocumentRoot(this.temporaryFolder.getRoot());
|
factory.setDocumentRoot(this.temporaryFolder.getRoot());
|
||||||
CompressionProperties compression = new CompressionProperties();
|
Compression compression = new Compression();
|
||||||
compression.setEnabled(true);
|
compression.setEnabled(true);
|
||||||
if (mimeTypes != null) {
|
if (mimeTypes != null) {
|
||||||
compression.setMimeTypes(mimeTypes);
|
compression.setMimeTypes(mimeTypes);
|
||||||
|
|
@ -567,9 +567,9 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
|
||||||
return testContent;
|
return testContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean internalTestCompression(int contentSize, String mimeTypes)
|
private boolean internalTestCompression(int contentSize, String[] mimeTypes)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
String testContent = setupFactoryForCompression(contentSize, mimeTypes);
|
String testContent = setUpFactoryForCompression(contentSize, mimeTypes);
|
||||||
|
|
||||||
class TestGzipInputStreamFactory implements InputStreamFactory {
|
class TestGzipInputStreamFactory implements InputStreamFactory {
|
||||||
|
|
||||||
|
|
@ -577,11 +577,11 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream create(InputStream instream) throws IOException {
|
public InputStream create(InputStream instream) throws IOException {
|
||||||
if (requested.get()) {
|
if (this.requested.get()) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"On deflated InputStream already requested");
|
"On deflated InputStream already requested");
|
||||||
}
|
}
|
||||||
requested.set(true);
|
this.requested.set(true);
|
||||||
return new GZIPInputStream(instream);
|
return new GZIPInputStream(instream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,9 +40,9 @@ import org.junit.Test;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
|
||||||
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactoryTests;
|
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactoryTests;
|
||||||
|
import org.springframework.boot.context.embedded.Compression;
|
||||||
import org.springframework.boot.context.embedded.ServletRegistrationBean;
|
import org.springframework.boot.context.embedded.ServletRegistrationBean;
|
||||||
import org.springframework.boot.context.embedded.Ssl;
|
import org.springframework.boot.context.embedded.Ssl;
|
||||||
import org.springframework.boot.context.embedded.AbstractConfigurableEmbeddedServletContainer.CompressionProperties;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
@ -185,8 +185,8 @@ public class JettyEmbeddedServletContainerFactoryTests extends
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
// work-around for Jetty issue - https://bugs.eclipse.org/bugs/show_bug.cgi?id=470646
|
// Workaround for Jetty issue - https://bugs.eclipse.org/bugs/show_bug.cgi?id=470646
|
||||||
protected String setupFactoryForCompression(final int contentSize, String mimeTypes)
|
protected String setUpFactoryForCompression(final int contentSize, String[] mimeTypes)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
char[] chars = new char[contentSize];
|
char[] chars = new char[contentSize];
|
||||||
Arrays.fill(chars, 'F');
|
Arrays.fill(chars, 'F');
|
||||||
|
|
@ -194,7 +194,7 @@ public class JettyEmbeddedServletContainerFactoryTests extends
|
||||||
|
|
||||||
AbstractEmbeddedServletContainerFactory factory = getFactory();
|
AbstractEmbeddedServletContainerFactory factory = getFactory();
|
||||||
|
|
||||||
CompressionProperties compression = new CompressionProperties();
|
Compression compression = new Compression();
|
||||||
compression.setEnabled(true);
|
compression.setEnabled(true);
|
||||||
if (mimeTypes != null) {
|
if (mimeTypes != null) {
|
||||||
compression.setMimeTypes(mimeTypes);
|
compression.setMimeTypes(mimeTypes);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue