Polish
This commit is contained in:
parent
cc3aea2b69
commit
d213cc05d5
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.web;
|
package org.springframework.boot.autoconfigure.web;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -42,15 +40,6 @@ public class ResourceProperties {
|
||||||
|
|
||||||
private final Chain chain = new Chain();
|
private final Chain chain = new Chain();
|
||||||
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void setUpDefaults() {
|
|
||||||
if (this.chain.enabled == null && (this.chain.strategy.content.enabled
|
|
||||||
|| this.chain.strategy.fixed.enabled)) {
|
|
||||||
this.chain.enabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getCachePeriod() {
|
public Integer getCachePeriod() {
|
||||||
return this.cachePeriod;
|
return this.cachePeriod;
|
||||||
}
|
}
|
||||||
|
|
@ -68,7 +57,7 @@ public class ResourceProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Chain getChain() {
|
public Chain getChain() {
|
||||||
return chain;
|
return this.chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -77,8 +66,8 @@ public class ResourceProperties {
|
||||||
public static class Chain {
|
public static class Chain {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable the Spring Resource Handling chain. Disabled by default unless
|
* Enable the Spring Resource Handling chain. Disabled by default unless at least
|
||||||
* at least one strategy has been enabled.
|
* one strategy has been enabled.
|
||||||
*/
|
*/
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
|
|
||||||
|
|
@ -95,7 +84,7 @@ public class ResourceProperties {
|
||||||
private final Strategy strategy = new Strategy();
|
private final Strategy strategy = new Strategy();
|
||||||
|
|
||||||
public Boolean getEnabled() {
|
public Boolean getEnabled() {
|
||||||
return enabled;
|
return this.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnabled(boolean enabled) {
|
public void setEnabled(boolean enabled) {
|
||||||
|
|
@ -103,7 +92,7 @@ public class ResourceProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCache() {
|
public boolean isCache() {
|
||||||
return cache;
|
return this.cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCache(boolean cache) {
|
public void setCache(boolean cache) {
|
||||||
|
|
@ -111,16 +100,17 @@ public class ResourceProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Strategy getStrategy() {
|
public Strategy getStrategy() {
|
||||||
return strategy;
|
return this.strategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isHtml5AppCache() {
|
public boolean isHtml5AppCache() {
|
||||||
return html5AppCache;
|
return this.html5AppCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHtml5AppCache(boolean html5AppCache) {
|
public void setHtml5AppCache(boolean html5AppCache) {
|
||||||
this.html5AppCache = html5AppCache;
|
this.html5AppCache = html5AppCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -133,12 +123,13 @@ public class ResourceProperties {
|
||||||
private final Content content = new Content();
|
private final Content content = new Content();
|
||||||
|
|
||||||
public Fixed getFixed() {
|
public Fixed getFixed() {
|
||||||
return fixed;
|
return this.fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Content getContent() {
|
public Content getContent() {
|
||||||
return content;
|
return this.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -154,10 +145,10 @@ public class ResourceProperties {
|
||||||
/**
|
/**
|
||||||
* Comma-separated list of patterns to apply to the Version Strategy.
|
* Comma-separated list of patterns to apply to the Version Strategy.
|
||||||
*/
|
*/
|
||||||
private String[] paths = new String[]{"/**"};
|
private String[] paths = new String[] { "/**" };
|
||||||
|
|
||||||
public boolean isEnabled() {
|
public boolean isEnabled() {
|
||||||
return enabled;
|
return this.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnabled(boolean enabled) {
|
public void setEnabled(boolean enabled) {
|
||||||
|
|
@ -165,12 +156,13 @@ public class ResourceProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getPaths() {
|
public String[] getPaths() {
|
||||||
return paths;
|
return this.paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPaths(String[] paths) {
|
public void setPaths(String[] paths) {
|
||||||
this.paths = paths;
|
this.paths = paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -194,7 +186,7 @@ public class ResourceProperties {
|
||||||
private String version;
|
private String version;
|
||||||
|
|
||||||
public boolean isEnabled() {
|
public boolean isEnabled() {
|
||||||
return enabled;
|
return this.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnabled(boolean enabled) {
|
public void setEnabled(boolean enabled) {
|
||||||
|
|
@ -202,7 +194,7 @@ public class ResourceProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getPaths() {
|
public String[] getPaths() {
|
||||||
return paths;
|
return this.paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPaths(String[] paths) {
|
public void setPaths(String[] paths) {
|
||||||
|
|
@ -210,11 +202,13 @@ public class ResourceProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getVersion() {
|
public String getVersion() {
|
||||||
return version;
|
return this.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVersion(String version) {
|
public void setVersion(String version) {
|
||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.web.ResourceProperties.Strategy;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.context.web.OrderedHiddenHttpMethodFilter;
|
import org.springframework.boot.context.web.OrderedHiddenHttpMethodFilter;
|
||||||
import org.springframework.context.ResourceLoaderAware;
|
import org.springframework.context.ResourceLoaderAware;
|
||||||
|
|
@ -55,7 +56,6 @@ import org.springframework.format.Formatter;
|
||||||
import org.springframework.format.FormatterRegistry;
|
import org.springframework.format.FormatterRegistry;
|
||||||
import org.springframework.format.datetime.DateFormatter;
|
import org.springframework.format.datetime.DateFormatter;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.validation.DefaultMessageCodesResolver;
|
import org.springframework.validation.DefaultMessageCodesResolver;
|
||||||
import org.springframework.validation.MessageCodesResolver;
|
import org.springframework.validation.MessageCodesResolver;
|
||||||
|
|
@ -81,6 +81,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
import org.springframework.web.servlet.resource.AppCacheManifestTransformer;
|
import org.springframework.web.servlet.resource.AppCacheManifestTransformer;
|
||||||
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
|
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
|
||||||
|
import org.springframework.web.servlet.resource.ResourceResolver;
|
||||||
import org.springframework.web.servlet.resource.VersionResourceResolver;
|
import org.springframework.web.servlet.resource.VersionResourceResolver;
|
||||||
import org.springframework.web.servlet.view.BeanNameViewResolver;
|
import org.springframework.web.servlet.view.BeanNameViewResolver;
|
||||||
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
|
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
|
||||||
|
|
@ -260,42 +261,51 @@ public class WebMvcAutoConfiguration {
|
||||||
}
|
}
|
||||||
Integer cachePeriod = this.resourceProperties.getCachePeriod();
|
Integer cachePeriod = this.resourceProperties.getCachePeriod();
|
||||||
if (!registry.hasMappingForPattern("/webjars/**")) {
|
if (!registry.hasMappingForPattern("/webjars/**")) {
|
||||||
ResourceHandlerRegistration registration = registry.addResourceHandler("/webjars/**")
|
registerResourceChain(registry.addResourceHandler("/webjars/**")
|
||||||
.addResourceLocations("classpath:/META-INF/resources/webjars/")
|
.addResourceLocations("classpath:/META-INF/resources/webjars/")
|
||||||
.setCachePeriod(cachePeriod);
|
.setCachePeriod(cachePeriod));
|
||||||
registerResourceChain(registration);
|
|
||||||
}
|
}
|
||||||
if (!registry.hasMappingForPattern("/**")) {
|
if (!registry.hasMappingForPattern("/**")) {
|
||||||
ResourceHandlerRegistration registration = registry.addResourceHandler("/**")
|
registerResourceChain(registry.addResourceHandler("/**")
|
||||||
.addResourceLocations(RESOURCE_LOCATIONS)
|
.addResourceLocations(RESOURCE_LOCATIONS)
|
||||||
.setCachePeriod(cachePeriod);
|
.setCachePeriod(cachePeriod));
|
||||||
registerResourceChain(registration);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerResourceChain(ResourceHandlerRegistration registration) {
|
private void registerResourceChain(ResourceHandlerRegistration registration) {
|
||||||
ResourceProperties.Chain chainProperties = this.resourceProperties.getChain();
|
ResourceProperties.Chain properties = this.resourceProperties.getChain();
|
||||||
if (ObjectUtils.nullSafeEquals(chainProperties.getEnabled(), Boolean.TRUE)) {
|
if (Boolean.TRUE.equals(properties.getEnabled())
|
||||||
ResourceChainRegistration chain = registration.resourceChain(chainProperties.isCache());
|
|| properties.getStrategy().getFixed().isEnabled()
|
||||||
boolean hasFixedVersionConfigured = chainProperties.getStrategy().getFixed().isEnabled();
|
|| properties.getStrategy().getContent().isEnabled()) {
|
||||||
boolean hasContentVersionConfigured = chainProperties.getStrategy().getContent().isEnabled();
|
configureResourceChain(properties,
|
||||||
if (hasFixedVersionConfigured || hasContentVersionConfigured) {
|
registration.resourceChain(properties.isCache()));
|
||||||
VersionResourceResolver versionResourceResolver = new VersionResourceResolver();
|
|
||||||
if (hasFixedVersionConfigured) {
|
|
||||||
versionResourceResolver.addFixedVersionStrategy(
|
|
||||||
chainProperties.getStrategy().getFixed().getVersion(),
|
|
||||||
chainProperties.getStrategy().getFixed().getPaths());
|
|
||||||
}
|
}
|
||||||
if (hasContentVersionConfigured) {
|
|
||||||
versionResourceResolver.
|
|
||||||
addContentVersionStrategy(chainProperties.getStrategy().getContent().getPaths());
|
|
||||||
}
|
}
|
||||||
chain.addResolver(versionResourceResolver);
|
|
||||||
|
private void configureResourceChain(ResourceProperties.Chain properties,
|
||||||
|
ResourceChainRegistration chain) {
|
||||||
|
Strategy strategy = properties.getStrategy();
|
||||||
|
if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) {
|
||||||
|
chain.addResolver(getVersionResourceResolver(strategy));
|
||||||
}
|
}
|
||||||
if (chainProperties.isHtml5AppCache()) {
|
if (properties.isHtml5AppCache()) {
|
||||||
chain.addTransformer(new AppCacheManifestTransformer());
|
chain.addTransformer(new AppCacheManifestTransformer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResourceResolver getVersionResourceResolver(
|
||||||
|
ResourceProperties.Strategy properties) {
|
||||||
|
VersionResourceResolver resolver = new VersionResourceResolver();
|
||||||
|
if (properties.getFixed().isEnabled()) {
|
||||||
|
String version = properties.getFixed().getVersion();
|
||||||
|
String[] paths = properties.getFixed().getPaths();
|
||||||
|
resolver.addFixedVersionStrategy(version, paths);
|
||||||
|
}
|
||||||
|
if (properties.getContent().isEnabled()) {
|
||||||
|
String[] paths = properties.getContent().getPaths();
|
||||||
|
resolver.addContentVersionStrategy(paths);
|
||||||
|
}
|
||||||
|
return resolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import java.util.Map;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
|
|
@ -170,15 +171,16 @@ public class WebMvcAutoConfigurationTests {
|
||||||
@Test
|
@Test
|
||||||
public void resourceHandlerChainEnabled() throws Exception {
|
public void resourceHandlerChainEnabled() throws Exception {
|
||||||
load("spring.resources.chain.enabled:true");
|
load("spring.resources.chain.enabled:true");
|
||||||
|
|
||||||
assertThat(getResourceResolvers("/webjars/**").size(), equalTo(2));
|
assertThat(getResourceResolvers("/webjars/**").size(), equalTo(2));
|
||||||
assertThat(getResourceTransformers("/webjars/**").size(), equalTo(1));
|
assertThat(getResourceTransformers("/webjars/**").size(), equalTo(1));
|
||||||
assertThat(getResourceResolvers("/**").size(), equalTo(2));
|
assertThat(getResourceResolvers("/**").size(), equalTo(2));
|
||||||
assertThat(getResourceTransformers("/**").size(), equalTo(1));
|
assertThat(getResourceTransformers("/**").size(), equalTo(1));
|
||||||
|
assertThat(
|
||||||
assertThat(getResourceResolvers("/**"), contains(instanceOf(CachingResourceResolver.class),
|
getResourceResolvers("/**"),
|
||||||
instanceOf(PathResourceResolver.class)));
|
containsInstances(CachingResourceResolver.class,
|
||||||
assertThat(getResourceTransformers("/**"), contains(instanceOf(CachingResourceTransformer.class)));
|
PathResourceResolver.class));
|
||||||
|
assertThat(getResourceTransformers("/**"),
|
||||||
|
contains(instanceOf(CachingResourceTransformer.class)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -186,38 +188,44 @@ public class WebMvcAutoConfigurationTests {
|
||||||
load("spring.resources.chain.strategy.fixed.enabled:true",
|
load("spring.resources.chain.strategy.fixed.enabled:true",
|
||||||
"spring.resources.chain.strategy.fixed.version:test",
|
"spring.resources.chain.strategy.fixed.version:test",
|
||||||
"spring.resources.chain.strategy.fixed.paths:/**/*.js");
|
"spring.resources.chain.strategy.fixed.paths:/**/*.js");
|
||||||
|
|
||||||
assertThat(getResourceResolvers("/webjars/**").size(), equalTo(3));
|
assertThat(getResourceResolvers("/webjars/**").size(), equalTo(3));
|
||||||
assertThat(getResourceTransformers("/webjars/**").size(), equalTo(2));
|
assertThat(getResourceTransformers("/webjars/**").size(), equalTo(2));
|
||||||
assertThat(getResourceResolvers("/**").size(), equalTo(3));
|
assertThat(getResourceResolvers("/**").size(), equalTo(3));
|
||||||
assertThat(getResourceTransformers("/**").size(), equalTo(2));
|
assertThat(getResourceTransformers("/**").size(), equalTo(2));
|
||||||
|
assertThat(
|
||||||
assertThat(getResourceResolvers("/**"), contains(instanceOf(CachingResourceResolver.class),
|
getResourceResolvers("/**"),
|
||||||
instanceOf(VersionResourceResolver.class),
|
containsInstances(CachingResourceResolver.class,
|
||||||
instanceOf(PathResourceResolver.class)));
|
VersionResourceResolver.class, PathResourceResolver.class));
|
||||||
assertThat(getResourceTransformers("/**"), contains(instanceOf(CachingResourceTransformer.class),
|
assertThat(
|
||||||
instanceOf(CssLinkResourceTransformer.class)));
|
getResourceTransformers("/**"),
|
||||||
VersionResourceResolver resolver = (VersionResourceResolver) getResourceResolvers("/**").get(1);
|
containsInstances(CachingResourceTransformer.class,
|
||||||
assertThat(resolver.getStrategyMap().get("/**/*.js"), instanceOf(FixedVersionStrategy.class));
|
CssLinkResourceTransformer.class));
|
||||||
|
VersionResourceResolver resolver = (VersionResourceResolver) getResourceResolvers(
|
||||||
|
"/**").get(1);
|
||||||
|
assertThat(resolver.getStrategyMap().get("/**/*.js"),
|
||||||
|
instanceOf(FixedVersionStrategy.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resourceHandlerContentStrategyEnabled() throws Exception {
|
public void resourceHandlerContentStrategyEnabled() throws Exception {
|
||||||
load("spring.resources.chain.strategy.content.enabled:true",
|
load("spring.resources.chain.strategy.content.enabled:true",
|
||||||
"spring.resources.chain.strategy.content.paths:/**,/*.png");
|
"spring.resources.chain.strategy.content.paths:/**,/*.png");
|
||||||
|
|
||||||
assertThat(getResourceResolvers("/webjars/**").size(), equalTo(3));
|
assertThat(getResourceResolvers("/webjars/**").size(), equalTo(3));
|
||||||
assertThat(getResourceTransformers("/webjars/**").size(), equalTo(2));
|
assertThat(getResourceTransformers("/webjars/**").size(), equalTo(2));
|
||||||
assertThat(getResourceResolvers("/**").size(), equalTo(3));
|
assertThat(getResourceResolvers("/**").size(), equalTo(3));
|
||||||
assertThat(getResourceTransformers("/**").size(), equalTo(2));
|
assertThat(getResourceTransformers("/**").size(), equalTo(2));
|
||||||
|
assertThat(
|
||||||
assertThat(getResourceResolvers("/**"), contains(instanceOf(CachingResourceResolver.class),
|
getResourceResolvers("/**"),
|
||||||
instanceOf(VersionResourceResolver.class),
|
containsInstances(CachingResourceResolver.class,
|
||||||
instanceOf(PathResourceResolver.class)));
|
VersionResourceResolver.class, PathResourceResolver.class));
|
||||||
assertThat(getResourceTransformers("/**"), contains(instanceOf(CachingResourceTransformer.class),
|
assertThat(
|
||||||
instanceOf(CssLinkResourceTransformer.class)));
|
getResourceTransformers("/**"),
|
||||||
VersionResourceResolver resolver = (VersionResourceResolver) getResourceResolvers("/**").get(1);
|
containsInstances(CachingResourceTransformer.class,
|
||||||
assertThat(resolver.getStrategyMap().get("/*.png"), instanceOf(ContentVersionStrategy.class));
|
CssLinkResourceTransformer.class));
|
||||||
|
VersionResourceResolver resolver = (VersionResourceResolver) getResourceResolvers(
|
||||||
|
"/**").get(1);
|
||||||
|
assertThat(resolver.getStrategyMap().get("/*.png"),
|
||||||
|
instanceOf(ContentVersionStrategy.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -229,20 +237,24 @@ public class WebMvcAutoConfigurationTests {
|
||||||
"spring.resources.chain.strategy.fixed.version:test",
|
"spring.resources.chain.strategy.fixed.version:test",
|
||||||
"spring.resources.chain.strategy.fixed.paths:/**/*.js",
|
"spring.resources.chain.strategy.fixed.paths:/**/*.js",
|
||||||
"spring.resources.chain.html5AppCache:true");
|
"spring.resources.chain.html5AppCache:true");
|
||||||
|
|
||||||
assertThat(getResourceResolvers("/webjars/**").size(), equalTo(2));
|
assertThat(getResourceResolvers("/webjars/**").size(), equalTo(2));
|
||||||
assertThat(getResourceTransformers("/webjars/**").size(), equalTo(2));
|
assertThat(getResourceTransformers("/webjars/**").size(), equalTo(2));
|
||||||
assertThat(getResourceResolvers("/**").size(), equalTo(2));
|
assertThat(getResourceResolvers("/**").size(), equalTo(2));
|
||||||
assertThat(getResourceTransformers("/**").size(), equalTo(2));
|
assertThat(getResourceTransformers("/**").size(), equalTo(2));
|
||||||
|
assertThat(
|
||||||
assertThat(getResourceResolvers("/**"), contains(
|
getResourceResolvers("/**"),
|
||||||
instanceOf(VersionResourceResolver.class), instanceOf(PathResourceResolver.class)));
|
containsInstances(VersionResourceResolver.class,
|
||||||
assertThat(getResourceTransformers("/**"), contains(instanceOf(CssLinkResourceTransformer.class),
|
PathResourceResolver.class));
|
||||||
instanceOf(AppCacheManifestTransformer.class)));
|
assertThat(
|
||||||
|
getResourceTransformers("/**"),
|
||||||
VersionResourceResolver resolver = (VersionResourceResolver) getResourceResolvers("/**").get(0);
|
containsInstances(CssLinkResourceTransformer.class,
|
||||||
assertThat(resolver.getStrategyMap().get("/*.png"), instanceOf(ContentVersionStrategy.class));
|
AppCacheManifestTransformer.class));
|
||||||
assertThat(resolver.getStrategyMap().get("/**/*.js"), instanceOf(FixedVersionStrategy.class));
|
VersionResourceResolver resolver = (VersionResourceResolver) getResourceResolvers(
|
||||||
|
"/**").get(0);
|
||||||
|
assertThat(resolver.getStrategyMap().get("/*.png"),
|
||||||
|
instanceOf(ContentVersionStrategy.class));
|
||||||
|
assertThat(resolver.getStrategyMap().get("/**/*.js"),
|
||||||
|
instanceOf(FixedVersionStrategy.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -315,14 +327,18 @@ public class WebMvcAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<ResourceResolver> getResourceResolvers(String mapping) {
|
protected List<ResourceResolver> getResourceResolvers(String mapping) {
|
||||||
SimpleUrlHandlerMapping handler = (SimpleUrlHandlerMapping) this.context.getBean("resourceHandlerMapping");
|
SimpleUrlHandlerMapping handler = (SimpleUrlHandlerMapping) this.context
|
||||||
ResourceHttpRequestHandler resourceHandler = (ResourceHttpRequestHandler) handler.getHandlerMap().get(mapping);
|
.getBean("resourceHandlerMapping");
|
||||||
|
ResourceHttpRequestHandler resourceHandler = (ResourceHttpRequestHandler) handler
|
||||||
|
.getHandlerMap().get(mapping);
|
||||||
return resourceHandler.getResourceResolvers();
|
return resourceHandler.getResourceResolvers();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<ResourceTransformer> getResourceTransformers(String mapping) {
|
protected List<ResourceTransformer> getResourceTransformers(String mapping) {
|
||||||
SimpleUrlHandlerMapping handler = (SimpleUrlHandlerMapping) this.context.getBean("resourceHandlerMapping");
|
SimpleUrlHandlerMapping handler = (SimpleUrlHandlerMapping) this.context
|
||||||
ResourceHttpRequestHandler resourceHandler = (ResourceHttpRequestHandler) handler.getHandlerMap().get(mapping);
|
.getBean("resourceHandlerMapping");
|
||||||
|
ResourceHttpRequestHandler resourceHandler = (ResourceHttpRequestHandler) handler
|
||||||
|
.getHandlerMap().get(mapping);
|
||||||
return resourceHandler.getResourceTransformers();
|
return resourceHandler.getResourceTransformers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -440,6 +456,15 @@ public class WebMvcAutoConfigurationTests {
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
private <E> Matcher<E> containsInstances(Class<?>... types) {
|
||||||
|
Matcher[] instances = new Matcher[types.length];
|
||||||
|
for (int i = 0; i < instances.length; i++) {
|
||||||
|
instances[i] = instanceOf(types[i]);
|
||||||
|
}
|
||||||
|
return contains(instances);
|
||||||
|
}
|
||||||
|
|
||||||
private void load(String... environment) {
|
private void load(String... environment) {
|
||||||
load(null, environment);
|
load(null, environment);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -515,24 +515,37 @@ configurable period to prevent the endpoint being used in a denial of service at
|
||||||
The `endpoints.health.time-to-live` property is used to configure the caching period in
|
The `endpoints.health.time-to-live` property is used to configure the caching period in
|
||||||
milliseconds. It defaults to 1000, i.e. one second.
|
milliseconds. It defaults to 1000, i.e. one second.
|
||||||
|
|
||||||
The above-described restrictions can be enhanced, thereby allowing only authenticated users full
|
The above-described restrictions can be enhanced, thereby allowing only authenticated
|
||||||
access to the health endpoint in a secure application. To do so, set `endpoints.health.sensitive` to `true`.
|
users full access to the health endpoint in a secure application. To do so, set
|
||||||
Here's a summary of behaviour (with default `sensitive` flag value "false" indicated in bold):
|
`endpoints.health.sensitive` to `true`. Here's a summary of behavior (with default
|
||||||
|
`sensitive` flag value "`false`" indicated in bold):
|
||||||
|
|
||||||
|====
|
|====
|
||||||
|Secure | Sensitive | Unauthenticated behaviour | Authenticated behaviour
|
|Secure |Sensitive |Unauthenticated |Authenticated
|
||||||
|
|
||||||
| false | **false** | Full content | Full content
|
|false
|
||||||
|
|**false**
|
||||||
|
|Full content
|
||||||
|
|Full content
|
||||||
|
|
||||||
| false | true | Status only | Full content
|
|false
|
||||||
|
|true
|
||||||
|
|Status only
|
||||||
|
|Full content
|
||||||
|
|
||||||
| true | **false** | Status only | Full content
|
|true
|
||||||
|
|**false**
|
||||||
| true | true | No content | Full content
|
|Status only
|
||||||
|
|Full content
|
||||||
|
|
||||||
|
|true
|
||||||
|
|true
|
||||||
|
|No content
|
||||||
|
|Full content
|
||||||
|====
|
|====
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[production-ready-jmx]]
|
[[production-ready-jmx]]
|
||||||
== Monitoring and management over JMX
|
== Monitoring and management over JMX
|
||||||
Java Management Extensions (JMX) provide a standard mechanism to monitor and manage
|
Java Management Extensions (JMX) provide a standard mechanism to monitor and manage
|
||||||
|
|
|
||||||
|
|
@ -1205,7 +1205,8 @@ supported right now, but can be with custom template macros/helpers and the use
|
||||||
|
|
||||||
When loading resources dynamically with, for example, a JavaScript module loader, renaming
|
When loading resources dynamically with, for example, a JavaScript module loader, renaming
|
||||||
files is not an option. That's why other strategies are also supported and can be combined.
|
files is not an option. That's why other strategies are also supported and can be combined.
|
||||||
A "fixed" strategy will add a static version string in the URL, without changing the file name:
|
A "fixed" strategy will add a static version string in the URL, without changing the file
|
||||||
|
name:
|
||||||
|
|
||||||
[source,properties,indent=0,subs="verbatim,quotes,attributes"]
|
[source,properties,indent=0,subs="verbatim,quotes,attributes"]
|
||||||
----
|
----
|
||||||
|
|
@ -1231,6 +1232,7 @@ and in Spring Framework's {spring-reference}/#mvc-config-static-resources[refere
|
||||||
====
|
====
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[boot-features-spring-mvc-template-engines]]
|
[[boot-features-spring-mvc-template-engines]]
|
||||||
==== Template engines
|
==== Template engines
|
||||||
As well as REST web services, you can also use Spring MVC to serve dynamic HTML content.
|
As well as REST web services, you can also use Spring MVC to serve dynamic HTML content.
|
||||||
|
|
|
||||||
|
|
@ -68,14 +68,10 @@ public class SampleJetty8ApplicationTests {
|
||||||
HttpHeaders requestHeaders = new HttpHeaders();
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
requestHeaders.set("Accept-Encoding", "gzip");
|
requestHeaders.set("Accept-Encoding", "gzip");
|
||||||
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
|
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
|
||||||
|
|
||||||
RestTemplate restTemplate = new TestRestTemplate();
|
RestTemplate restTemplate = new TestRestTemplate();
|
||||||
|
|
||||||
ResponseEntity<byte[]> entity = restTemplate.exchange("http://localhost:"
|
ResponseEntity<byte[]> entity = restTemplate.exchange("http://localhost:"
|
||||||
+ this.port, HttpMethod.GET, requestEntity, byte[].class);
|
+ this.port, HttpMethod.GET, requestEntity, byte[].class);
|
||||||
|
|
||||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
|
||||||
GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(
|
GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(
|
||||||
entity.getBody()));
|
entity.getBody()));
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -68,14 +68,10 @@ public class SampleJetty93ApplicationTests {
|
||||||
HttpHeaders requestHeaders = new HttpHeaders();
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
requestHeaders.set("Accept-Encoding", "gzip");
|
requestHeaders.set("Accept-Encoding", "gzip");
|
||||||
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
|
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
|
||||||
|
|
||||||
RestTemplate restTemplate = new TestRestTemplate();
|
RestTemplate restTemplate = new TestRestTemplate();
|
||||||
|
|
||||||
ResponseEntity<byte[]> entity = restTemplate.exchange("http://localhost:"
|
ResponseEntity<byte[]> entity = restTemplate.exchange("http://localhost:"
|
||||||
+ this.port, HttpMethod.GET, requestEntity, byte[].class);
|
+ this.port, HttpMethod.GET, requestEntity, byte[].class);
|
||||||
|
|
||||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
|
||||||
GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(
|
GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(
|
||||||
entity.getBody()));
|
entity.getBody()));
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -66,14 +66,10 @@ public class SampleTomcatApplicationTests {
|
||||||
HttpHeaders requestHeaders = new HttpHeaders();
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
requestHeaders.set("Accept-Encoding", "gzip");
|
requestHeaders.set("Accept-Encoding", "gzip");
|
||||||
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
|
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
|
||||||
|
|
||||||
RestTemplate restTemplate = new TestRestTemplate();
|
RestTemplate restTemplate = new TestRestTemplate();
|
||||||
|
|
||||||
ResponseEntity<byte[]> entity = restTemplate.exchange("http://localhost:"
|
ResponseEntity<byte[]> entity = restTemplate.exchange("http://localhost:"
|
||||||
+ this.port, HttpMethod.GET, requestEntity, byte[].class);
|
+ this.port, HttpMethod.GET, requestEntity, byte[].class);
|
||||||
|
|
||||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
|
||||||
GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(
|
GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(
|
||||||
entity.getBody()));
|
entity.getBody()));
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -70,14 +70,10 @@ public class SampleUndertowApplicationTests {
|
||||||
HttpHeaders requestHeaders = new HttpHeaders();
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
requestHeaders.set("Accept-Encoding", "gzip");
|
requestHeaders.set("Accept-Encoding", "gzip");
|
||||||
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
|
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
|
||||||
|
|
||||||
RestTemplate restTemplate = new TestRestTemplate();
|
RestTemplate restTemplate = new TestRestTemplate();
|
||||||
|
|
||||||
ResponseEntity<byte[]> entity = restTemplate.exchange("http://localhost:"
|
ResponseEntity<byte[]> entity = restTemplate.exchange("http://localhost:"
|
||||||
+ this.port, HttpMethod.GET, requestEntity, byte[].class);
|
+ this.port, HttpMethod.GET, requestEntity, byte[].class);
|
||||||
|
|
||||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
|
||||||
GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(
|
GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(
|
||||||
entity.getBody()));
|
entity.getBody()));
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,7 @@ public abstract class AbstractConfigurableEmbeddedServletContainer implements
|
||||||
return this.compression;
|
return this.compression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setCompression(Compression compression) {
|
public void setCompression(Compression compression) {
|
||||||
this.compression = compression;
|
this.compression = compression;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,14 +155,14 @@ public class JettyEmbeddedServletContainerFactory extends
|
||||||
}
|
}
|
||||||
|
|
||||||
private HandlerWrapper createGzipHandler() {
|
private HandlerWrapper createGzipHandler() {
|
||||||
if (ClassUtils.isPresent(GZIP_HANDLER_JETTY_9_2, getClass().getClassLoader())) {
|
ClassLoader classLoader = getClass().getClassLoader();
|
||||||
|
if (ClassUtils.isPresent(GZIP_HANDLER_JETTY_9_2, classLoader)) {
|
||||||
return new Jetty92GzipHandlerFactory().createGzipHandler(getCompression());
|
return new Jetty92GzipHandlerFactory().createGzipHandler(getCompression());
|
||||||
}
|
}
|
||||||
else if (ClassUtils.isPresent(GZIP_HANDLER_JETTY_8, getClass().getClassLoader())) {
|
if (ClassUtils.isPresent(GZIP_HANDLER_JETTY_8, getClass().getClassLoader())) {
|
||||||
return new Jetty8GzipHandlerFactory().createGzipHandler(getCompression());
|
return new Jetty8GzipHandlerFactory().createGzipHandler(getCompression());
|
||||||
}
|
}
|
||||||
else if (ClassUtils
|
if (ClassUtils.isPresent(GZIP_HANDLER_JETTY_9_3, getClass().getClassLoader())) {
|
||||||
.isPresent(GZIP_HANDLER_JETTY_9_3, getClass().getClassLoader())) {
|
|
||||||
return new Jetty93GzipHandlerFactory().createGzipHandler(getCompression());
|
return new Jetty93GzipHandlerFactory().createGzipHandler(getCompression());
|
||||||
}
|
}
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
|
|
@ -579,19 +579,17 @@ public class JettyEmbeddedServletContainerFactory extends
|
||||||
@Override
|
@Override
|
||||||
public HandlerWrapper createGzipHandler(Compression compression) {
|
public HandlerWrapper createGzipHandler(Compression compression) {
|
||||||
try {
|
try {
|
||||||
Class<?> gzipHandlerClass = ClassUtils.forName(GZIP_HANDLER_JETTY_8,
|
Class<?> handlerClass = ClassUtils.forName(GZIP_HANDLER_JETTY_8,
|
||||||
getClass().getClassLoader());
|
getClass().getClassLoader());
|
||||||
HandlerWrapper gzipHandler = (HandlerWrapper) gzipHandlerClass
|
HandlerWrapper handler = (HandlerWrapper) handlerClass.newInstance();
|
||||||
.newInstance();
|
ReflectionUtils.findMethod(handlerClass, "setMinGzipSize", int.class)
|
||||||
ReflectionUtils.findMethod(gzipHandlerClass, "setMinGzipSize", int.class)
|
.invoke(handler, compression.getMinResponseSize());
|
||||||
.invoke(gzipHandler, compression.getMinResponseSize());
|
ReflectionUtils.findMethod(handlerClass, "setMimeTypes", Set.class)
|
||||||
ReflectionUtils.findMethod(gzipHandlerClass, "setMimeTypes", Set.class)
|
.invoke(handler,
|
||||||
.invoke(gzipHandler,
|
|
||||||
new HashSet<String>(Arrays.asList(compression
|
new HashSet<String>(Arrays.asList(compression
|
||||||
.getMimeTypes())));
|
.getMimeTypes())));
|
||||||
return gzipHandler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new RuntimeException("Failed to configure Jetty 8 gzip handler", ex);
|
throw new RuntimeException("Failed to configure Jetty 8 gzip handler", ex);
|
||||||
}
|
}
|
||||||
|
|
@ -608,7 +606,6 @@ public class JettyEmbeddedServletContainerFactory extends
|
||||||
gzipHandler.setMimeTypes(new HashSet<String>(Arrays.asList(compression
|
gzipHandler.setMimeTypes(new HashSet<String>(Arrays.asList(compression
|
||||||
.getMimeTypes())));
|
.getMimeTypes())));
|
||||||
return gzipHandler;
|
return gzipHandler;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -618,18 +615,16 @@ public class JettyEmbeddedServletContainerFactory extends
|
||||||
@Override
|
@Override
|
||||||
public HandlerWrapper createGzipHandler(Compression compression) {
|
public HandlerWrapper createGzipHandler(Compression compression) {
|
||||||
try {
|
try {
|
||||||
Class<?> gzipHandlerClass = ClassUtils.forName(GZIP_HANDLER_JETTY_9_3,
|
Class<?> handlerClass = ClassUtils.forName(GZIP_HANDLER_JETTY_9_3,
|
||||||
getClass().getClassLoader());
|
getClass().getClassLoader());
|
||||||
HandlerWrapper gzipHandler = (HandlerWrapper) gzipHandlerClass
|
HandlerWrapper handler = (HandlerWrapper) handlerClass.newInstance();
|
||||||
.newInstance();
|
ReflectionUtils.findMethod(handlerClass, "setMinGzipSize", int.class)
|
||||||
ReflectionUtils.findMethod(gzipHandlerClass, "setMinGzipSize", int.class)
|
.invoke(handler, compression.getMinResponseSize());
|
||||||
.invoke(gzipHandler, compression.getMinResponseSize());
|
ReflectionUtils.findMethod(handlerClass, "setIncludedMimeTypes",
|
||||||
ReflectionUtils.findMethod(gzipHandlerClass, "setIncludedMimeTypes",
|
String[].class).invoke(handler,
|
||||||
String[].class).invoke(gzipHandler,
|
|
||||||
new Object[] { compression.getMimeTypes() });
|
new Object[] { compression.getMimeTypes() });
|
||||||
return gzipHandler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new RuntimeException("Failed to configure Jetty 9.3 gzip handler",
|
throw new RuntimeException("Failed to configure Jetty 9.3 gzip handler",
|
||||||
ex);
|
ex);
|
||||||
|
|
@ -637,4 +632,5 @@ public class JettyEmbeddedServletContainerFactory extends
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ import org.apache.coyote.http11.AbstractHttp11JsseProtocol;
|
||||||
import org.apache.coyote.http11.AbstractHttp11Protocol;
|
import org.apache.coyote.http11.AbstractHttp11Protocol;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
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;
|
||||||
|
|
@ -233,10 +234,7 @@ public class TomcatEmbeddedServletContainerFactory extends
|
||||||
int port = (getPort() >= 0 ? getPort() : 0);
|
int port = (getPort() >= 0 ? getPort() : 0);
|
||||||
connector.setPort(port);
|
connector.setPort(port);
|
||||||
if (connector.getProtocolHandler() instanceof AbstractProtocol) {
|
if (connector.getProtocolHandler() instanceof AbstractProtocol) {
|
||||||
if (getAddress() != null) {
|
customizeProtocol((AbstractProtocol<?>) connector.getProtocolHandler());
|
||||||
((AbstractProtocol<?>) connector.getProtocolHandler())
|
|
||||||
.setAddress(getAddress());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (getUriEncoding() != null) {
|
if (getUriEncoding() != null) {
|
||||||
connector.setURIEncoding(getUriEncoding());
|
connector.setURIEncoding(getUriEncoding());
|
||||||
|
|
@ -247,30 +245,41 @@ public class TomcatEmbeddedServletContainerFactory extends
|
||||||
connector.setProperty("bindOnInit", "false");
|
connector.setProperty("bindOnInit", "false");
|
||||||
|
|
||||||
if (getSsl() != null && getSsl().isEnabled()) {
|
if (getSsl() != null && getSsl().isEnabled()) {
|
||||||
Assert.state(
|
customizeSsl(connector);
|
||||||
connector.getProtocolHandler() instanceof AbstractHttp11JsseProtocol,
|
}
|
||||||
|
if (getCompression() != null && getCompression().getEnabled()) {
|
||||||
|
customizeCompression(connector);
|
||||||
|
}
|
||||||
|
for (TomcatConnectorCustomizer customizer : this.tomcatConnectorCustomizers) {
|
||||||
|
customizer.customize(connector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void customizeProtocol(AbstractProtocol<?> protocol) {
|
||||||
|
if (getAddress() != null) {
|
||||||
|
protocol.setAddress(getAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void customizeSsl(Connector connector) {
|
||||||
|
ProtocolHandler handler = connector.getProtocolHandler();
|
||||||
|
Assert.state(handler instanceof AbstractHttp11JsseProtocol,
|
||||||
"To use SSL, the connector's protocol handler must be an "
|
"To use SSL, the connector's protocol handler must be an "
|
||||||
+ "AbstractHttp11JsseProtocol subclass");
|
+ "AbstractHttp11JsseProtocol subclass");
|
||||||
configureSsl((AbstractHttp11JsseProtocol<?>) connector.getProtocolHandler(),
|
configureSsl((AbstractHttp11JsseProtocol<?>) handler, getSsl());
|
||||||
getSsl());
|
|
||||||
connector.setScheme("https");
|
connector.setScheme("https");
|
||||||
connector.setSecure(true);
|
connector.setSecure(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getCompression() != null && getCompression().getEnabled()) {
|
private void customizeCompression(Connector connector) {
|
||||||
ProtocolHandler handler = connector.getProtocolHandler();
|
ProtocolHandler handler = connector.getProtocolHandler();
|
||||||
if (handler instanceof AbstractHttp11Protocol) {
|
if (handler instanceof AbstractHttp11Protocol) {
|
||||||
@SuppressWarnings("rawtypes")
|
AbstractHttp11Protocol<?> protocol = (AbstractHttp11Protocol<?>) handler;
|
||||||
AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler;
|
Compression compression = getCompression();
|
||||||
protocol.setCompression("on");
|
protocol.setCompression("on");
|
||||||
protocol.setCompressionMinSize(getCompression().getMinResponseSize());
|
protocol.setCompressionMinSize(compression.getMinResponseSize());
|
||||||
protocol.setCompressableMimeTypes(StringUtils
|
protocol.setCompressableMimeTypes(StringUtils
|
||||||
.arrayToCommaDelimitedString(getCompression().getMimeTypes()));
|
.arrayToCommaDelimitedString(compression.getMimeTypes()));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (TomcatConnectorCustomizer customizer : this.tomcatConnectorCustomizers) {
|
|
||||||
customizer.customize(connector);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -123,11 +123,9 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
|
||||||
return servletHandler;
|
return servletHandler;
|
||||||
}
|
}
|
||||||
ContentEncodingRepository encodingRepository = new ContentEncodingRepository();
|
ContentEncodingRepository encodingRepository = new ContentEncodingRepository();
|
||||||
|
|
||||||
Predicate mimeAndSizePredicate = Predicates.and(Predicates
|
Predicate mimeAndSizePredicate = Predicates.and(Predicates
|
||||||
.maxContentSize(this.compression.getMinResponseSize()), Predicates
|
.maxContentSize(this.compression.getMinResponseSize()), Predicates
|
||||||
.or(new CompressibleMimeTypePredicate(this.compression.getMimeTypes())));
|
.or(new CompressibleMimeTypePredicate(this.compression.getMimeTypes())));
|
||||||
|
|
||||||
encodingRepository.addEncodingHandler("gzip", new GzipEncodingProvider(), 50,
|
encodingRepository.addEncodingHandler("gzip", new GzipEncodingProvider(), 50,
|
||||||
mimeAndSizePredicate);
|
mimeAndSizePredicate);
|
||||||
return new EncodingHandler(encodingRepository).setNext(servletHandler);
|
return new EncodingHandler(encodingRepository).setNext(servletHandler);
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import java.nio.charset.Charset;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
@ -530,18 +531,31 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void compression() throws Exception {
|
public void compression() throws Exception {
|
||||||
assertTrue(internalTestCompression(10000, null));
|
assertTrue(doTestCompression(10000, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noCompressionForSmallResponse() throws Exception {
|
public void noCompressionForSmallResponse() throws Exception {
|
||||||
assertFalse(internalTestCompression(100, null));
|
assertFalse(doTestCompression(100, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noCompressionForMimeType() throws Exception {
|
public void noCompressionForMimeType() throws Exception {
|
||||||
assertFalse(internalTestCompression(10000, new String[] { "text/html",
|
String[] mimeTypes = new String[] { "text/html", "text/xml", "text/css" };
|
||||||
"text/xml", "text/css" }));
|
assertFalse(doTestCompression(10000, mimeTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean doTestCompression(int contentSize, String[] mimeTypes)
|
||||||
|
throws Exception {
|
||||||
|
String testContent = setUpFactoryForCompression(contentSize, mimeTypes);
|
||||||
|
TestGzipInputStreamFactory inputStreamFactory = new TestGzipInputStreamFactory();
|
||||||
|
Map<String, InputStreamFactory> contentDecoderMap = singletonMap("gzip",
|
||||||
|
(InputStreamFactory) inputStreamFactory);
|
||||||
|
String response = getResponse(getLocalUrl("/test.txt"),
|
||||||
|
new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create()
|
||||||
|
.setContentDecoderRegistry(contentDecoderMap).build()));
|
||||||
|
assertThat(response, equalTo(testContent));
|
||||||
|
return inputStreamFactory.wasCompressionUsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String setUpFactoryForCompression(int contentSize, String[] mimeTypes)
|
protected String setUpFactoryForCompression(int contentSize, String[] mimeTypes)
|
||||||
|
|
@ -549,9 +563,7 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
|
||||||
char[] chars = new char[contentSize];
|
char[] chars = new char[contentSize];
|
||||||
Arrays.fill(chars, 'F');
|
Arrays.fill(chars, 'F');
|
||||||
String testContent = new String(chars);
|
String testContent = new String(chars);
|
||||||
|
|
||||||
AbstractEmbeddedServletContainerFactory factory = getFactory();
|
AbstractEmbeddedServletContainerFactory factory = getFactory();
|
||||||
|
|
||||||
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());
|
||||||
|
|
@ -561,47 +573,11 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
|
||||||
compression.setMimeTypes(mimeTypes);
|
compression.setMimeTypes(mimeTypes);
|
||||||
}
|
}
|
||||||
factory.setCompression(compression);
|
factory.setCompression(compression);
|
||||||
|
|
||||||
this.container = factory.getEmbeddedServletContainer();
|
this.container = factory.getEmbeddedServletContainer();
|
||||||
this.container.start();
|
this.container.start();
|
||||||
return testContent;
|
return testContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean internalTestCompression(int contentSize, String[] mimeTypes)
|
|
||||||
throws Exception {
|
|
||||||
String testContent = setUpFactoryForCompression(contentSize, mimeTypes);
|
|
||||||
|
|
||||||
class TestGzipInputStreamFactory implements InputStreamFactory {
|
|
||||||
|
|
||||||
final AtomicBoolean requested = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream create(InputStream instream) throws IOException {
|
|
||||||
if (this.requested.get()) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"On deflated InputStream already requested");
|
|
||||||
}
|
|
||||||
this.requested.set(true);
|
|
||||||
return new GZIPInputStream(instream);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
TestGzipInputStreamFactory gzipTestInputStreamFactory = new TestGzipInputStreamFactory();
|
|
||||||
|
|
||||||
String response = getResponse(
|
|
||||||
getLocalUrl("/test.txt"),
|
|
||||||
new HttpComponentsClientHttpRequestFactory(HttpClientBuilder
|
|
||||||
.create()
|
|
||||||
.setContentDecoderRegistry(
|
|
||||||
singletonMap("gzip",
|
|
||||||
(InputStreamFactory) gzipTestInputStreamFactory))
|
|
||||||
.build()));
|
|
||||||
assertThat(response, equalTo(testContent));
|
|
||||||
boolean wasCompressionUsed = gzipTestInputStreamFactory.requested.get();
|
|
||||||
return wasCompressionUsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addTestTxtFile(AbstractEmbeddedServletContainerFactory factory)
|
private void addTestTxtFile(AbstractEmbeddedServletContainerFactory factory)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
FileCopyUtils.copy("test",
|
FileCopyUtils.copy("test",
|
||||||
|
|
@ -678,6 +654,26 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TestGzipInputStreamFactory implements InputStreamFactory {
|
||||||
|
|
||||||
|
private final AtomicBoolean requested = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream create(InputStream instream) throws IOException {
|
||||||
|
if (this.requested.get()) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"On deflated InputStream already requested");
|
||||||
|
}
|
||||||
|
this.requested.set(true);
|
||||||
|
return new GZIPInputStream(instream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean wasCompressionUsed() {
|
||||||
|
return this.requested.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
private static class InitCountingServlet extends GenericServlet {
|
private static class InitCountingServlet extends GenericServlet {
|
||||||
|
|
||||||
|
|
@ -696,6 +692,7 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
|
||||||
public int getInitCount() {
|
public int getInitCount() {
|
||||||
return this.initCount;
|
return this.initCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,16 +191,13 @@ public class JettyEmbeddedServletContainerFactoryTests extends
|
||||||
char[] chars = new char[contentSize];
|
char[] chars = new char[contentSize];
|
||||||
Arrays.fill(chars, 'F');
|
Arrays.fill(chars, 'F');
|
||||||
final String testContent = new String(chars);
|
final String testContent = new String(chars);
|
||||||
|
|
||||||
AbstractEmbeddedServletContainerFactory factory = getFactory();
|
AbstractEmbeddedServletContainerFactory factory = getFactory();
|
||||||
|
|
||||||
Compression compression = new Compression();
|
Compression compression = new Compression();
|
||||||
compression.setEnabled(true);
|
compression.setEnabled(true);
|
||||||
if (mimeTypes != null) {
|
if (mimeTypes != null) {
|
||||||
compression.setMimeTypes(mimeTypes);
|
compression.setMimeTypes(mimeTypes);
|
||||||
}
|
}
|
||||||
factory.setCompression(compression);
|
factory.setCompression(compression);
|
||||||
|
|
||||||
this.container = factory.getEmbeddedServletContainer(new ServletRegistrationBean(
|
this.container = factory.getEmbeddedServletContainer(new ServletRegistrationBean(
|
||||||
new HttpServlet() {
|
new HttpServlet() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue