diff --git a/spring-web/src/main/java/org/springframework/http/CacheControl.java b/spring-web/src/main/java/org/springframework/http/CacheControl.java index a291e7ae7e..2685661798 100644 --- a/spring-web/src/main/java/org/springframework/http/CacheControl.java +++ b/spring-web/src/main/java/org/springframework/http/CacheControl.java @@ -65,6 +65,10 @@ public class CacheControl { private boolean proxyRevalidate = false; + private long staleWhileRevalidate = -1; + + private long staleIfError = -1; + private long sMaxAge = -1; @@ -207,6 +211,36 @@ public class CacheControl { return this; } + /** + * Add an "stale-while-revalidate" directive. + *

This directive indicates that caches MAY serve the response in + * which it appears after it becomes stale, up to the indicated number of seconds. + * If a cached response is served stale due to the presence of this extension, + * the cache SHOULD attempt to revalidate it while still serving stale responses (i.e., without blocking). + * @param staleWhileRevalidate the maximum time the response should be used while being revalidated + * @param unit the time unit of the {@code sMaxAge} argument + * @return {@code this}, to facilitate method chaining + * @see rfc5861 section 3 + */ + public CacheControl staleWhileRevalidate(long staleWhileRevalidate, TimeUnit unit) { + this.staleWhileRevalidate = unit.toSeconds(staleWhileRevalidate); + return this; + } + + /** + * Add an "stale-if-error" directive. + *

This directive indicates that that when an error is encountered, a cached stale response MAY be used to satisfy + * the request, regardless of other freshness information.. + * @param staleIfError the maximum time the response should be used when errors are encountered + * @param unit the time unit of the {@code sMaxAge} argument + * @return {@code this}, to facilitate method chaining + * @see rfc5861 section 4 + */ + public CacheControl staleIfError(long staleIfError, TimeUnit unit) { + this.staleIfError = unit.toSeconds(staleIfError); + return this; + } + /** * Return the "Cache-Control" header value. @@ -241,6 +275,13 @@ public class CacheControl { if (this.sMaxAge != -1) { appendDirective(ccValue, "s-maxage=" + Long.toString(this.sMaxAge)); } + if(this.staleIfError != -1) { + appendDirective(ccValue, "stale-if-error=" + Long.toString(this.staleIfError)); + } + if(this.staleWhileRevalidate != -1) { + appendDirective(ccValue, "stale-while-revalidate=" + Long.toString(this.staleWhileRevalidate)); + } + String ccHeaderValue = ccValue.toString(); return (StringUtils.hasText(ccHeaderValue) ? ccHeaderValue : null); } diff --git a/spring-web/src/test/java/org/springframework/http/CacheControlTests.java b/spring-web/src/test/java/org/springframework/http/CacheControlTests.java index 43de2c0b43..b3c38bc64e 100644 --- a/spring-web/src/test/java/org/springframework/http/CacheControlTests.java +++ b/spring-web/src/test/java/org/springframework/http/CacheControlTests.java @@ -63,4 +63,17 @@ public class CacheControlTests { CacheControl cc = CacheControl.noStore(); assertThat(cc.getHeaderValue(), Matchers.equalTo("no-store")); } + + @Test + public void staleIfError() throws Exception { + CacheControl cc = CacheControl.maxAge(1, TimeUnit.HOURS).staleIfError(2, TimeUnit.HOURS); + assertThat(cc.getHeaderValue(), Matchers.equalTo("max-age=3600, stale-if-error=7200")); + } + + @Test + public void staleWhileRevalidate() throws Exception { + CacheControl cc = CacheControl.maxAge(1, TimeUnit.HOURS).staleWhileRevalidate(2, TimeUnit.HOURS); + assertThat(cc.getHeaderValue(), Matchers.equalTo("max-age=3600, stale-while-revalidate=7200")); + } + }