Skip to content
Permalink
Browse files

Relax SPR-13867 changes for ResourceHttpRequestHandler

Prior to this change, SPR-13867 made sure that any class extending
WebContentGenerator would not overwrite existing HTTP "Cache-Control"
response headers - set by a filter, a Controller handler, etc.

This caused issues with resource handling, since specifying a cache
configuration there would not overwrite default headers set by filters,
for example by Spring Security.

This commit restricts the previous changes to the
RequestMappingHandlerAdapter, in order to avoid overwriting header set
by a filter or a Controller handler in those cases.

Issue: SPR-14005
Cherry-picked from 50bcd67
  • Loading branch information
bclozel committed Mar 2, 2016
1 parent 8a44560 commit 0ef90df1204069edb5f39b9707fb81231ff86495
@@ -743,11 +743,13 @@ protected ModelAndView handleInternal(HttpServletRequest request,
mav = invokeHandlerMethod(request, response, handlerMethod);
}

if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}

return mav;
@@ -887,7 +889,7 @@ private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) t
}
List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
// Global methods first
for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache .entrySet()) {
for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache.entrySet()) {
if (entry.getKey().isApplicableToBeanType(handlerType)) {
Object bean = entry.getKey().resolveBean();
for (Method method : entry.getValue()) {
@@ -71,7 +71,7 @@

private static final String HEADER_EXPIRES = "Expires";

private static final String HEADER_CACHE_CONTROL = "Cache-Control";
protected static final String HEADER_CACHE_CONTROL = "Cache-Control";


/** Set of supported HTTP methods */
@@ -330,16 +330,14 @@ protected final void prepareResponse(HttpServletResponse response) {
* @since 4.2
*/
protected final void applyCacheControl(HttpServletResponse response, CacheControl cacheControl) {
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
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, "");
}
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, "");
}
}
}
@@ -355,32 +353,30 @@ protected final void applyCacheControl(HttpServletResponse response, CacheContro
*/
@SuppressWarnings("deprecation")
protected final void applyCacheSeconds(HttpServletResponse response, int cacheSeconds) {
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
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);
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 {
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);
cControl = CacheControl.empty();
}
applyCacheControl(response, cControl);
}
}

@@ -503,6 +503,17 @@ public void writeContentInputStreamThrowingNullPointerException() throws Excepti
assertEquals(0, this.response.getContentLength());
}

// SPR-14005
@Test
public void doOverwriteExistingCacheControlHeaders() throws Exception {
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css");
this.response.setHeader("Cache-Control", "no-store");

this.handler.handleRequest(this.request, this.response);

assertEquals("max-age=3600", this.response.getHeader("Cache-Control"));
}


private long dateHeaderAsLong(String responseHeaderName) throws Exception {
return dateFormat.parse(this.response.getHeader(responseHeaderName)).getTime();

0 comments on commit 0ef90df

Please sign in to comment.
You can’t perform that action at this time.