();
+
public WebContentInterceptor() {
- // no restriction of HTTP methods by default,
- // in particular for use with annotated controllers
+ // No restriction of HTTP methods by default,
+ // in particular for use with annotated controllers...
super(false);
}
@@ -134,11 +136,9 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
* Overrides the default cache seconds setting of this interceptor.
* Can specify a empty {@link org.springframework.http.CacheControl} instance
* to exclude a URL path from default caching.
- *
*
Supports direct matches, e.g. a registered "/test" matches "/test",
* and a various Ant-style pattern matches, e.g. a registered "/t*" matches
* both "/test" and "/team". For details, see the AntPathMatcher javadoc.
- *
* @param cacheControl the {@code CacheControl} to use
* @param paths URL paths that will map to the given {@code CacheControl}
* @see #setCacheSeconds
@@ -151,7 +151,6 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
}
}
-
/**
* Set the PathMatcher implementation to use for matching URL paths
* against registered URL patterns, for determining cache mappings.
@@ -168,7 +167,9 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws ServletException {
+ throws ServletException {
+
+ checkRequest(request);
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
@@ -181,19 +182,19 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
if (logger.isDebugEnabled()) {
logger.debug("Applying CacheControl to [" + lookupPath + "]");
}
- checkAndPrepare(request, response, cacheControl);
+ applyCacheControl(response, cacheControl);
}
else if (cacheSeconds != null) {
if (logger.isDebugEnabled()) {
logger.debug("Applying CacheControl to [" + lookupPath + "]");
}
- checkAndPrepare(request, response, cacheSeconds);
+ applyCacheSeconds(response, cacheSeconds);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Applying default cache seconds to [" + lookupPath + "]");
}
- checkAndPrepare(request, response);
+ prepareResponse(response);
}
return true;
@@ -209,10 +210,10 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
* @see org.springframework.util.AntPathMatcher
*/
protected CacheControl lookupCacheControl(String urlPath) {
- // direct match?
+ // Direct match?
CacheControl cacheControl = this.cacheControlMappings.get(urlPath);
if (cacheControl == null) {
- // pattern match?
+ // Pattern match?
for (String registeredPath : this.cacheControlMappings.keySet()) {
if (this.pathMatcher.match(registeredPath, urlPath)) {
cacheControl = this.cacheControlMappings.get(registeredPath);
@@ -232,10 +233,10 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
* @see org.springframework.util.AntPathMatcher
*/
protected Integer lookupCacheSeconds(String urlPath) {
- // direct match?
+ // Direct match?
Integer cacheSeconds = this.cacheMappings.get(urlPath);
if (cacheSeconds == null) {
- // pattern match?
+ // Pattern match?
for (String registeredPath : this.cacheMappings.keySet()) {
if (this.pathMatcher.match(registeredPath, urlPath)) {
cacheSeconds = this.cacheMappings.get(registeredPath);
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java
index 62f96c0aac..006b0784c0 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java
@@ -138,8 +138,7 @@ import org.springframework.web.util.WebUtils;
* @see #setMethodNameResolver
* @see #setWebBindingInitializer
* @see #setSessionAttributeStore
- *
- * @deprecated in Spring 3.2 in favor of
+ * @deprecated as of Spring 3.2, in favor of
* {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter RequestMappingHandlerAdapter}
*/
@Deprecated
@@ -411,13 +410,10 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
}
if (annotatedWithSessionAttributes) {
- // Always prevent caching in case of session attribute management.
- checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers);
- // Prepare cached set of session attributes names.
+ checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
}
else {
- // Uses configured default cacheSeconds setting.
- checkAndPrepare(request, response);
+ checkAndPrepare(request, response, true);
}
// Execute invokeHandlerMethod in synchronized block if required.
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
index b310405884..96a3c40aa3 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
@@ -705,13 +705,13 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
+ checkRequest(request);
+
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
- // Always prevent caching in case of session attribute management.
- checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers);
+ applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
- // Uses configured default cacheSeconds setting.
- checkAndPrepare(request, response);
+ prepareResponse(response);
}
// Execute invokeHandlerMethod in synchronized block if required.
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java
index efac7c9f05..0fe1421148 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java
@@ -39,9 +39,7 @@ import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRange;
import org.springframework.http.MediaType;
-import org.springframework.web.cors.CorsConfiguration;
import org.springframework.http.server.ServletServerHttpRequest;
-import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
@@ -52,6 +50,8 @@ import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.context.request.ServletWebRequest;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.support.WebContentGenerator;
@@ -91,7 +91,8 @@ import org.springframework.web.servlet.support.WebContentGenerator;
* @author Arjen Poutsma
* @since 3.0.4
*/
-public class ResourceHttpRequestHandler extends WebContentGenerator implements HttpRequestHandler, InitializingBean, CorsConfigurationSource {
+public class ResourceHttpRequestHandler extends WebContentGenerator
+ implements HttpRequestHandler, InitializingBean, CorsConfigurationSource {
private static final String CONTENT_ENCODING = "Content-Encoding";
@@ -171,6 +172,12 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
this.corsConfiguration = corsConfiguration;
}
+ @Override
+ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
+ return this.corsConfiguration;
+ }
+
+
@Override
public void afterPropertiesSet() throws Exception {
if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) {
@@ -180,11 +187,6 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
initAllowedLocations();
}
- @Override
- public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
- return corsConfiguration;
- }
-
/**
* Look for a {@link org.springframework.web.servlet.resource.PathResourceResolver}
* among the {@link #getResourceResolvers() resource resolvers} and configure
@@ -207,6 +209,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
}
}
+
/**
* Processes a resource request.
*
Checks for the existence of the requested resource in the configured list of locations.
@@ -223,9 +226,10 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
- checkAndPrepare(request, response);
+ // Supported methods and required session
+ checkRequest(request);
- // check whether a matching resource exists
+ // Check whether a matching resource exists
Resource resource = getResource(request);
if (resource == null) {
logger.trace("No matching resource found - returning 404");
@@ -233,13 +237,16 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
return;
}
- // header phase
+ // Header phase
if (new ServletWebRequest(request, response).checkNotModified(resource.lastModified())) {
logger.trace("Resource not modified - returning 304");
return;
}
- // check the resource's media type
+ // Apply cache settings, if any
+ prepareResponse(response);
+
+ // Check the resource's media type
MediaType mediaType = getMediaType(resource);
if (mediaType != null) {
if (logger.isTraceEnabled()) {
@@ -252,7 +259,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
}
}
- // content phase
+ // Content phase
if (METHOD_HEAD.equals(request.getMethod())) {
setHeaders(response, resource, mediaType);
logger.trace("HEAD request - skipping content");
@@ -532,15 +539,12 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
}
private void copyRange(InputStream in, OutputStream out, long start, long end) throws IOException {
-
long skipped = in.skip(start);
-
if (skipped < start) {
throw new IOException("Skipped only " + skipped + " bytes out of " + start + " required.");
}
long bytesToCopy = end - start + 1;
-
byte buffer[] = new byte[StreamUtils.BUFFER_SIZE];
while (bytesToCopy > 0) {
int bytesRead = in.read(buffer);
@@ -561,8 +565,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
@Override
public String toString() {
- return "ResourceHttpRequestHandler [locations=" +
- getLocations() + ", resolvers=" + getResourceResolvers() + "]";
+ return "ResourceHttpRequestHandler [locations=" + getLocations() + ", resolvers=" + getResourceResolvers() + "]";
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/WebContentGenerator.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/WebContentGenerator.java
index 0f8700c4a2..86fa88c677 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/support/WebContentGenerator.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/support/WebContentGenerator.java
@@ -16,22 +16,18 @@
package org.springframework.web.servlet.support;
-import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.HashSet;
-import java.util.Locale;
import java.util.Set;
-import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
-
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.springframework.http.CacheControl;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.HttpSessionRequiredException;
-import org.springframework.http.CacheControl;
import org.springframework.web.context.support.WebApplicationObjectSupport;
/**
@@ -41,19 +37,22 @@ import org.springframework.web.context.support.WebApplicationObjectSupport;
* Can also be used for custom handlers that have their own
* {@link org.springframework.web.servlet.HandlerAdapter}.
*
- *
Supports HTTP cache control options. The usage of corresponding
- * HTTP headers can be controlled via the "setCacheSeconds" or "setCacheControl" properties.
- * As of 4.2, its default behavior changed when using only {@link #setCacheSeconds(int)}, sending
- * HTTP response headers that are more in line with current browsers and proxies implementations.
+ *
Supports HTTP cache control options. The usage of corresponding HTTP
+ * headers can be controlled via the {@link #setCacheSeconds "cacheSeconds"
+ * and {@link #setCacheControl "cacheControl"} properties.
*
- *
Reverting to the previous behavior can be easily done by using one of the nealy deprecated methods
- * {@link #setUseExpiresHeader}, {@link #setUseCacheControlHeader}, {@link #setUseCacheControlNoStore} or
- * {@link #setAlwaysMustRevalidate}.
+ *
NOTE: As of Spring 4.2, this generator's default behavior changed when
+ * using only {@link #setCacheSeconds)}, sending HTTP response headers that are in line
+ * with current browsers and proxies implementations (i.e. no HTTP 1.0 headers anymore)
+ * Reverting to the previous behavior can be easily done by using one of the newly
+ * deprecated methods {@link #setUseExpiresHeader}, {@link #setUseCacheControlHeader},
+ * {@link #setUseCacheControlNoStore} or {@link #setAlwaysMustRevalidate}.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Brian Clozel
* @see #setCacheSeconds
+ * @see #setCacheControl
* @see #setRequireSession
*/
public abstract class WebContentGenerator extends WebApplicationObjectSupport {
@@ -79,10 +78,12 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
private boolean requireSession = false;
+ private CacheControl cacheControl;
+
private int cacheSeconds = -1;
/** Use HTTP 1.0 expires header? */
- private boolean useExpiresHeader = true;
+ private boolean useExpiresHeader = false;
/** Use HTTP 1.1 cache-control header? */
private boolean useCacheControlHeader = true;
@@ -92,10 +93,6 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
private boolean alwaysMustRevalidate = false;
- private boolean usePreviousHttpCachingBehavior = false;
-
- private CacheControl cacheControl;
-
/**
* Create a new WebContentGenerator which supports
@@ -167,40 +164,60 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
/**
* Set the {@link org.springframework.http.CacheControl} instance to build
* the Cache-Control HTTP response header.
- *
* @since 4.2
*/
- public void setCacheControl(CacheControl cacheControl) {
+ public final void setCacheControl(CacheControl cacheControl) {
this.cacheControl = cacheControl;
}
/**
* Get the {@link org.springframework.http.CacheControl} instance
* that builds the Cache-Control HTTP response header.
- *
* @since 4.2
*/
- public CacheControl getCacheControl() {
- return cacheControl;
+ public final CacheControl getCacheControl() {
+ return this.cacheControl;
}
/**
- * Set whether to use the HTTP 1.0 expires header. Default is "false".
+ * Cache content for the given number of seconds, by writing
+ * cache-related HTTP headers to the response:
+ *
+ * - seconds == -1 (default value): no generation cache-related headers
+ * - seconds == 0: "Cache-Control: no-store" will prevent caching
+ * - seconds > 0: "Cache-Control: max-age=seconds" will ask to cache content
+ *
+ * For more specific needs, a custom {@link org.springframework.http.CacheControl}
+ * should be used.
+ * @see #setCacheControl
+ */
+ public final void setCacheSeconds(int seconds) {
+ this.cacheSeconds = seconds;
+ }
+
+ /**
+ * Return the number of seconds that content is cached.
+ */
+ public final int getCacheSeconds() {
+ return this.cacheSeconds;
+ }
+
+ /**
+ * Set whether to use the HTTP 1.0 expires header. Default is "false",
+ * as of 4.2.
*
Note: Cache headers will only get applied if caching is enabled
* (or explicitly prevented) for the current request.
- *
- * @deprecated in favor of {@link #setCacheSeconds} or {@link #setCacheControl}.
+ * @deprecated as of 4.2, since going forward, the HTTP 1.1 cache-control
+ * header will be required, with the HTTP 1.0 headers disappearing
*/
@Deprecated
public final void setUseExpiresHeader(boolean useExpiresHeader) {
this.useExpiresHeader = useExpiresHeader;
- this.usePreviousHttpCachingBehavior = true;
}
/**
* Return whether the HTTP 1.0 expires header is used.
- *
- * @deprecated in favor of {@link #getCacheControl}.
+ * @deprecated as of 4.2, in favor of {@link #getCacheControl()}
*/
@Deprecated
public final boolean isUseExpiresHeader() {
@@ -211,19 +228,17 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
* Set whether to use the HTTP 1.1 cache-control header. Default is "true".
*
Note: Cache headers will only get applied if caching is enabled
* (or explicitly prevented) for the current request.
- *
- * @deprecated in favor of {@link #setCacheSeconds} or {@link #setCacheControl}.
+ * @deprecated as of 4.2, since going forward, the HTTP 1.1 cache-control
+ * header will be required, with the HTTP 1.0 headers disappearing
*/
@Deprecated
public final void setUseCacheControlHeader(boolean useCacheControlHeader) {
this.useCacheControlHeader = useCacheControlHeader;
- this.usePreviousHttpCachingBehavior = true;
}
/**
* Return whether the HTTP 1.1 cache-control header is used.
- *
- * @deprecated in favor of {@link #getCacheControl}.
+ * @deprecated as of 4.2, in favor of {@link #getCacheControl()}
*/
@Deprecated
public final boolean isUseCacheControlHeader() {
@@ -233,19 +248,16 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
/**
* Set whether to use the HTTP 1.1 cache-control header value "no-store"
* when preventing caching. Default is "true".
- *
- * @deprecated in favor of {@link #setCacheSeconds} or {@link #setCacheControl}.
+ * @deprecated as of 4.2, in favor of {@link #setCacheControl}
*/
@Deprecated
public final void setUseCacheControlNoStore(boolean useCacheControlNoStore) {
this.useCacheControlNoStore = useCacheControlNoStore;
- this.usePreviousHttpCachingBehavior = true;
}
/**
* Return whether the HTTP 1.1 cache-control header value "no-store" is used.
- *
- * @deprecated in favor of {@link #getCacheControl}.
+ * @deprecated as of 4.2, in favor of {@link #getCacheControl()}
*/
@Deprecated
public final boolean isUseCacheControlNoStore() {
@@ -253,125 +265,34 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
}
/**
- * An option to add 'must-revalidate' to every Cache-Control header. This
- * may be useful with annotated controller methods, which can
- * programmatically do a lastModified calculation as described in
- * {@link WebRequest#checkNotModified(long)}. Default is "false".
- *
- * @deprecated in favor of {@link #setCacheSeconds} or {@link #setCacheControl}.
+ * An option to add 'must-revalidate' to every Cache-Control header.
+ * This may be useful with annotated controller methods, which can
+ * programmatically do a last-modified calculation as described in
+ * {@link org.springframework.web.context.request.WebRequest#checkNotModified(long)}.
+ *
Default is "false".
+ * @deprecated as of 4.2, in favor of {@link #setCacheControl}
*/
@Deprecated
- public void setAlwaysMustRevalidate(boolean mustRevalidate) {
+ public final void setAlwaysMustRevalidate(boolean mustRevalidate) {
this.alwaysMustRevalidate = mustRevalidate;
- this.usePreviousHttpCachingBehavior = true;
}
/**
* Return whether 'must-revalidate' is added to every Cache-Control header.
- *
- * @deprecated in favor of {@link #getCacheControl}.
+ * @deprecated as of 4.2, in favor of {@link #getCacheControl()}
*/
@Deprecated
- public boolean isAlwaysMustRevalidate() {
- return alwaysMustRevalidate;
- }
-
- /**
- * Cache content for the given number of seconds, by writing
- * cache-related HTTP headers to the response:
- *
- * - seconds == -1 (default value): no generation cache-related headers
- * - seconds == 0: "Cache-Control: no-store" will prevent caching
- * - seconds > 0: "Cache-Control: max-age=seconds" will ask to cache content
- *
- * For more specific needs, a custom {@link org.springframework.http.CacheControl} should be used.
- *
- * @see #setCacheControl
- */
- public final void setCacheSeconds(int seconds) {
- this.cacheSeconds = seconds;
- if (!this.usePreviousHttpCachingBehavior) {
- if (cacheSeconds > 0) {
- this.cacheControl = CacheControl.maxAge(seconds, TimeUnit.SECONDS);
- }
- else if (cacheSeconds == 0) {
- this.cacheControl = CacheControl.noStore();
- }
- }
- }
-
- /**
- * Return the number of seconds that content is cached.
- */
- public final int getCacheSeconds() {
- return this.cacheSeconds;
+ public final boolean isAlwaysMustRevalidate() {
+ return this.alwaysMustRevalidate;
}
/**
- * Check and prepare the given request and response according to the settings
- * of this generator. Checks for supported methods and a required session,
- * and applies the number of cache seconds specified for this generator.
+ * Check the given request for supported methods and a required session, if any.
* @param request current HTTP request
- * @param response current HTTP response
* @throws ServletException if the request cannot be handled because a check failed
+ * @since 4.2
*/
- protected final void checkAndPrepare(
- HttpServletRequest request, HttpServletResponse response)
- throws ServletException {
-
- checkAndPrepare(request, response, this.cacheControl);
- }
-
- /**
- * * Check and prepare the given request and response according to the settings
- * of this generator. Checks for supported methods and a required session,
- * and applies the number of cache seconds specified for this generator.
- * @param request current HTTP request
- * @param response current HTTP response
- * @param lastModified whether the underlying handler writes "Last-Modified" headers; in that case,
- * a "Cache-Control: must-revalidate" directive is set in the response.
- * @throws ServletException if the request cannot be handled because a check failed
- * @deprecated in favor of {@link #checkAndPrepare(HttpServletRequest, HttpServletResponse, CacheControl)}.
- */
- @Deprecated
- protected final void checkAndPrepare(
- HttpServletRequest request, HttpServletResponse response, boolean lastModified)
- throws ServletException {
-
- if (lastModified) {
- checkAndPrepare(request, response, this.cacheControl.mustRevalidate());
- }
- else {
- checkAndPrepare(request, response);
- }
- }
-
- protected final void checkAndPrepare(
- HttpServletRequest request, HttpServletResponse response, int cacheSeconds) throws ServletException {
-
- CacheControl cControl;
- if (cacheSeconds > 0) {
- cControl = CacheControl.maxAge(cacheSeconds, TimeUnit.SECONDS);
- }
- else if (cacheSeconds == 0) {
- cControl = CacheControl.noStore();
- }
- else {
- cControl = CacheControl.empty();
- }
- checkRequest(request);
- if (this.usePreviousHttpCachingBehavior) {
- addHttp10CacheHeaders(cacheSeconds, response);
- }
- else {
- String ccValue = cControl.getHeaderValue();
- if (ccValue != null) {
- response.setHeader(HEADER_CACHE_CONTROL, ccValue);
- }
- }
- }
-
protected final void checkRequest(HttpServletRequest request) throws ServletException {
// Check whether we should support the request method.
String method = request.getMethod();
@@ -387,46 +308,143 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
}
/**
- * Check and prepare the given request and response according to the settings
- * of this generator. Checks for supported methods and a required session
- * specified for this generator. Also applies the {@link org.springframework.http.CacheControl}
- * given as a parameter.
- * @param request current HTTP request
+ * Prepare the given response according to the settings of this generator.
+ * Applies the number of cache seconds specified for this generator.
* @param response current HTTP response
- * @param cacheControl the {@link org.springframework.http.CacheControl} to use
- * @throws ServletException if the request cannot be handled because a check failed
- *
* @since 4.2
*/
- protected final void checkAndPrepare(
- HttpServletRequest request, HttpServletResponse response, CacheControl cacheControl)
- throws ServletException {
-
- checkRequest(request);
-
- if (this.usePreviousHttpCachingBehavior) {
- addHttp10CacheHeaders(this.cacheSeconds, response);
+ protected final void prepareResponse(HttpServletResponse response) {
+ if (this.cacheControl != null) {
+ applyCacheControl(response, this.cacheControl);
}
- else if (cacheControl != null) {
- String ccValue = cacheControl.getHeaderValue();
- if (ccValue != null) {
- response.setHeader(HEADER_CACHE_CONTROL, ccValue);
- if (response.containsHeader(HEADER_PRAGMA)) {
- response.setHeader(HEADER_PRAGMA, "");
- }
+ else {
+ applyCacheSeconds(response, this.cacheSeconds);
+ }
+ }
+
+ /**
+ * Set the HTTP Cache-Control header according to the given settings.
+ * @param response current HTTP response
+ * @param cacheControl the pre-configured cache control settings
+ * @since 4.2
+ */
+ protected final void applyCacheControl(HttpServletResponse response, CacheControl cacheControl) {
+ String ccValue = cacheControl.getHeaderValue();
+ if (ccValue != null) {
+ // Set computed HTTP 1.1 Cache-Control header
+ response.setHeader(HEADER_CACHE_CONTROL, ccValue);
+
+ if (response.containsHeader(HEADER_PRAGMA)) {
+ // Reset HTTP 1.0 Pragma header if present
+ response.setHeader(HEADER_PRAGMA, "");
}
}
}
- protected final void addHttp10CacheHeaders(int cacheSeconds, HttpServletResponse response) {
+ /**
+ * Apply the given cache seconds and generate corresponding HTTP headers,
+ * i.e. allow caching for the given number of seconds in case of a positive
+ * value, prevent caching if given a 0 value, do nothing else.
+ * Does not tell the browser to revalidate the resource.
+ * @param response current HTTP response
+ * @param cacheSeconds positive number of seconds into the future that the
+ * response should be cacheable for, 0 to prevent caching
+ */
+ @SuppressWarnings("deprecation")
+ protected final void applyCacheSeconds(HttpServletResponse response, int cacheSeconds) {
+ if (this.useExpiresHeader || !this.useCacheControlHeader) {
+ // Deprecated HTTP 1.0 cache behavior, as in previous Spring versions
+ if (cacheSeconds > 0) {
+ cacheForSeconds(response, cacheSeconds);
+ }
+ else if (cacheSeconds == 0) {
+ preventCaching(response);
+ }
+ }
+ else {
+ CacheControl cControl;
+ if (cacheSeconds > 0) {
+ cControl = CacheControl.maxAge(cacheSeconds, TimeUnit.SECONDS);
+ if (this.alwaysMustRevalidate) {
+ cControl = cControl.mustRevalidate();
+ }
+ }
+ else if (cacheSeconds == 0) {
+ cControl = (this.useCacheControlNoStore ? CacheControl.noStore() : CacheControl.noCache());
+ }
+ else {
+ cControl = CacheControl.empty();
+ }
+ applyCacheControl(response, cControl);
+ }
+ }
+
+
+ /**
+ * @see #checkRequest(HttpServletRequest)
+ * @see #prepareResponse(HttpServletResponse)
+ * @deprecated as of 4.2, since the {@code lastModified} flag is effectively ignored,
+ * with a must-revalidate header only generated if explicitly configured
+ */
+ @Deprecated
+ protected final void checkAndPrepare(
+ HttpServletRequest request, HttpServletResponse response, boolean lastModified) throws ServletException {
+
+ checkRequest(request);
+ prepareResponse(response);
+ }
+
+ /**
+ * @see #checkRequest(HttpServletRequest)
+ * @see #applyCacheSeconds(HttpServletResponse, int)
+ * @deprecated as of 4.2, since the {@code lastModified} flag is effectively ignored,
+ * with a must-revalidate header only generated if explicitly configured
+ */
+ @Deprecated
+ protected final void checkAndPrepare(
+ HttpServletRequest request, HttpServletResponse response, int cacheSeconds, boolean lastModified)
+ throws ServletException {
+
+ checkRequest(request);
+ applyCacheSeconds(response, cacheSeconds);
+ }
+
+ /**
+ * Apply the given cache seconds and generate respective HTTP headers.
+ *
That is, allow caching for the given number of seconds in the
+ * case of a positive value, prevent caching if given a 0 value, else
+ * do nothing (i.e. leave caching to the client).
+ * @param response the current HTTP response
+ * @param cacheSeconds the (positive) number of seconds into the future
+ * that the response should be cacheable for; 0 to prevent caching; and
+ * a negative value to leave caching to the client.
+ * @param mustRevalidate whether the client should revalidate the resource
+ * (typically only necessary for controllers with last-modified support)
+ * @deprecated as of 4.2, in favor of {@link #applyCacheControl}
+ */
+ @Deprecated
+ protected final void applyCacheSeconds(HttpServletResponse response, int cacheSeconds, boolean mustRevalidate) {
if (cacheSeconds > 0) {
- cacheForSeconds(response, cacheSeconds, this.alwaysMustRevalidate);
+ cacheForSeconds(response, cacheSeconds, mustRevalidate);
}
else if (cacheSeconds == 0) {
preventCaching(response);
}
}
+ /**
+ * Set HTTP headers to allow caching for the given number of seconds.
+ * Does not tell the browser to revalidate the resource.
+ * @param response current HTTP response
+ * @param seconds number of seconds into the future that the response
+ * should be cacheable for
+ * @deprecated as of 4.2, in favor of {@link #applyCacheControl}
+ */
+ @Deprecated
+ protected final void cacheForSeconds(HttpServletResponse response, int seconds) {
+ cacheForSeconds(response, seconds, false);
+ }
+
/**
* Set HTTP headers to allow caching for the given number of seconds.
* Tells the browser to revalidate the resource if mustRevalidate is
@@ -436,38 +454,48 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
* should be cacheable for
* @param mustRevalidate whether the client should revalidate the resource
* (typically only necessary for controllers with last-modified support)
+ * @deprecated as of 4.2, in favor of {@link #applyCacheControl}
*/
+ @Deprecated
protected final void cacheForSeconds(HttpServletResponse response, int seconds, boolean mustRevalidate) {
if (this.useExpiresHeader) {
// HTTP 1.0 header
response.setDateHeader(HEADER_EXPIRES, System.currentTimeMillis() + seconds * 1000L);
}
+
if (this.useCacheControlHeader) {
// HTTP 1.1 header
String headerValue = "max-age=" + seconds;
- if (mustRevalidate) {
+ if (mustRevalidate || this.alwaysMustRevalidate) {
headerValue += ", must-revalidate";
}
response.setHeader(HEADER_CACHE_CONTROL, headerValue);
}
+
if (response.containsHeader(HEADER_PRAGMA)) {
+ // Reset HTTP 1.0 Pragma header if present
response.setHeader(HEADER_PRAGMA, "");
}
}
/**
* Prevent the response from being cached.
- * See {@code http://www.mnot.net/cache_docs}.
+ * Only called in HTTP 1.0 compatibility mode.
+ *
See {@code http://www.mnot.net/cache_docs}.
+ * @deprecated as of 4.2, in favor of {@link #applyCacheControl}
*/
+ @Deprecated
protected final void preventCaching(HttpServletResponse response) {
response.setHeader(HEADER_PRAGMA, "no-cache");
+
if (this.useExpiresHeader) {
- // HTTP 1.0 header
- response.setDateHeader(HEADER_EXPIRES, System.currentTimeMillis());
+ // HTTP 1.0 Expires header
+ response.setDateHeader(HEADER_EXPIRES, 1L);
}
+
if (this.useCacheControlHeader) {
- // HTTP 1.1 header: "no-cache" is the standard value,
- // "no-store" is necessary to prevent caching on FireFox.
+ // HTTP 1.1 Cache-Control header: "no-cache" is the standard value,
+ // "no-store" is necessary to prevent caching on Firefox.
response.setHeader(HEADER_CACHE_CONTROL, "no-cache");
if (this.useCacheControlNoStore) {
response.addHeader(HEADER_CACHE_CONTROL, "no-store");
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
index df2311e24c..4bb8962b7e 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
@@ -392,8 +392,6 @@ public class MvcNamespaceTests {
ResourceHttpRequestHandler.class);
assertNotNull(handler);
assertEquals(3600, handler.getCacheSeconds());
- assertThat(handler.getCacheControl().getHeaderValue(),
- Matchers.equalTo(CacheControl.maxAge(1, TimeUnit.HOURS).getHeaderValue()));
}
@Test
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistryTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistryTests.java
index d1d0df7a44..1530dc7791 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistryTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistryTests.java
@@ -90,8 +90,6 @@ public class ResourceHandlerRegistryTests {
this.registration.setCachePeriod(0);
assertEquals(0, getHandler("/resources/**").getCacheSeconds());
- assertThat(getHandler("/resources/**").getCacheControl().getHeaderValue(),
- Matchers.equalTo(CacheControl.noStore().getHeaderValue()));
}
@Test
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/WebContentInterceptorTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/WebContentInterceptorTests.java
index 273a3c64d7..a269583f9d 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/WebContentInterceptorTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/WebContentInterceptorTests.java
@@ -137,6 +137,7 @@ public class WebContentInterceptorTests {
public void http10CachingConfigAndSpecificMapping() throws Exception {
WebContentInterceptor interceptor = new WebContentInterceptor();
interceptor.setCacheSeconds(0);
+ interceptor.setUseExpiresHeader(true);
interceptor.setAlwaysMustRevalidate(true);
Properties mappings = new Properties();
mappings.setProperty("**/*.cache.html", "10");
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java
index f85c4cd9ce..7e20319b5d 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerTests.java
@@ -110,7 +110,7 @@ public class ResourceHttpRequestHandlerTests {
@Test
@SuppressWarnings("deprecation")
- public void getResourcePreviousBehaviorCache() throws Exception {
+ public void getResourceHttp10BehaviorCache() throws Exception {
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css");
this.handler.setCacheSeconds(3600);
this.handler.setUseExpiresHeader(true);
@@ -126,15 +126,17 @@ public class ResourceHttpRequestHandlerTests {
@Test
@SuppressWarnings("deprecation")
- public void getResourcePreviousBehaviorNoCache() throws Exception {
+ public void getResourceHttp10BehaviorNoCache() throws Exception {
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css");
this.handler.setCacheSeconds(0);
- this.handler.setUseCacheControlNoStore(true);
+ this.handler.setUseExpiresHeader(true);
+ this.handler.setUseCacheControlNoStore(false);
this.handler.setUseCacheControlHeader(true);
this.handler.handleRequest(this.request, this.response);
assertEquals("no-cache", this.response.getHeader("Pragma"));
- assertThat(this.response.getHeaderValues("Cache-Control"), Matchers.contains("no-cache", "no-store"));
+ assertThat(this.response.getHeaderValues("Cache-Control"), Matchers.iterableWithSize(1));
+ assertEquals("no-cache", this.response.getHeader("Cache-Control"));
assertTrue(dateHeaderAsLong("Expires") <= System.currentTimeMillis());
assertTrue(this.response.containsHeader("Last-Modified"));
assertEquals(dateHeaderAsLong("Last-Modified") / 1000, resourceLastModified("test/foo.css") / 1000);