From a98e3f048183528a0e99c3894e24e03873916166 Mon Sep 17 00:00:00 2001 From: Lars Grefer Date: Fri, 8 Mar 2019 01:30:55 +0100 Subject: [PATCH] Migrate CacheControl to use java.time.Duration for durations --- .../springframework/http/CacheControl.java | 95 +++++++++++++++---- .../http/CacheControlTests.java | 25 +++++ 2 files changed, 102 insertions(+), 18 deletions(-) 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 58437c4f11..9137e72f60 100644 --- a/spring-web/src/main/java/org/springframework/http/CacheControl.java +++ b/spring-web/src/main/java/org/springframework/http/CacheControl.java @@ -16,6 +16,7 @@ package org.springframework.http; +import java.time.Duration; import java.util.concurrent.TimeUnit; import org.springframework.lang.Nullable; @@ -50,7 +51,8 @@ import org.springframework.util.StringUtils; */ public class CacheControl { - private long maxAge = -1; + @Nullable + private Duration maxAge = null; private boolean noCache = false; @@ -66,12 +68,14 @@ public class CacheControl { private boolean proxyRevalidate = false; - private long staleWhileRevalidate = -1; + @Nullable + private Duration staleWhileRevalidate = null; - private long staleIfError = -1; - - private long sMaxAge = -1; + @Nullable + private Duration staleIfError = null; + @Nullable + private Duration sMaxAge = null; /** * Create an empty CacheControl instance. @@ -106,8 +110,25 @@ public class CacheControl { * @see rfc7234 section 5.2.2.8 */ public static CacheControl maxAge(long maxAge, TimeUnit unit) { + return maxAge(Duration.ofSeconds(unit.toSeconds(maxAge))); + } + + /** + * Add a "max-age=" directive. + *

This directive is well suited for publicly caching resources, knowing that + * they won't change within the configured amount of time. Additional directives + * can be also used, in case resources shouldn't be cached ({@link #cachePrivate()}) + * or transformed ({@link #noTransform()}) by shared caches. + *

In order to prevent caches to reuse the cached response even when it has + * become stale (i.e. the "max-age" delay is passed), the "must-revalidate" + * directive should be set ({@link #mustRevalidate()} + * @param maxAge the maximum time the response should be cached + * @return {@code this}, to facilitate method chaining + * @see rfc7234 section 5.2.2.8 + */ + public static CacheControl maxAge(Duration maxAge) { CacheControl cc = new CacheControl(); - cc.maxAge = unit.toSeconds(maxAge); + cc.maxAge = maxAge; return cc; } @@ -216,7 +237,19 @@ public class CacheControl { * @see rfc7234 section 5.2.2.9 */ public CacheControl sMaxAge(long sMaxAge, TimeUnit unit) { - this.sMaxAge = unit.toSeconds(sMaxAge); + return sMaxAge(Duration.ofSeconds(unit.toSeconds(sMaxAge))); + } + + /** + * Add an "s-maxage" directive. + *

This directive indicates that, in shared caches, the maximum age specified + * by this directive overrides the maximum age specified by other directives. + * @param sMaxAge the maximum time the response should be cached + * @return {@code this}, to facilitate method chaining + * @see rfc7234 section 5.2.2.9 + */ + public CacheControl sMaxAge(Duration sMaxAge) { + this.sMaxAge = sMaxAge; return this; } @@ -233,7 +266,22 @@ public class CacheControl { * @see rfc5861 section 3 */ public CacheControl staleWhileRevalidate(long staleWhileRevalidate, TimeUnit unit) { - this.staleWhileRevalidate = unit.toSeconds(staleWhileRevalidate); + return staleWhileRevalidate(Duration.ofSeconds(unit.toSeconds(staleWhileRevalidate))); + } + + /** + * Add a "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 + * @return {@code this}, to facilitate method chaining + * @see rfc5861 section 3 + */ + public CacheControl staleWhileRevalidate(Duration staleWhileRevalidate) { + this.staleWhileRevalidate = staleWhileRevalidate; return this; } @@ -247,10 +295,21 @@ public class CacheControl { * @see rfc5861 section 4 */ public CacheControl staleIfError(long staleIfError, TimeUnit unit) { - this.staleIfError = unit.toSeconds(staleIfError); - return this; + return staleIfError(Duration.ofSeconds(unit.toSeconds(staleIfError))); } + /** + * Add a "stale-if-error" directive. + *

This directive indicates 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 + * @return {@code this}, to facilitate method chaining + * @see rfc5861 section 4 + */ + public CacheControl staleIfError(Duration staleIfError) { + this.staleIfError = staleIfError; + return this; + } /** * Return the "Cache-Control" header value, if any. @@ -268,8 +327,8 @@ public class CacheControl { */ private String toHeaderValue() { StringBuilder headerValue = new StringBuilder(); - if (this.maxAge != -1) { - appendDirective(headerValue, "max-age=" + this.maxAge); + if (this.maxAge != null) { + appendDirective(headerValue, "max-age=" + this.maxAge.getSeconds()); } if (this.noCache) { appendDirective(headerValue, "no-cache"); @@ -292,14 +351,14 @@ public class CacheControl { if (this.proxyRevalidate) { appendDirective(headerValue, "proxy-revalidate"); } - if (this.sMaxAge != -1) { - appendDirective(headerValue, "s-maxage=" + this.sMaxAge); + if (this.sMaxAge != null) { + appendDirective(headerValue, "s-maxage=" + this.sMaxAge.getSeconds()); } - if (this.staleIfError != -1) { - appendDirective(headerValue, "stale-if-error=" + this.staleIfError); + if (this.staleIfError != null) { + appendDirective(headerValue, "stale-if-error=" + this.staleIfError.getSeconds()); } - if (this.staleWhileRevalidate != -1) { - appendDirective(headerValue, "stale-while-revalidate=" + this.staleWhileRevalidate); + if (this.staleWhileRevalidate != null) { + appendDirective(headerValue, "stale-while-revalidate=" + this.staleWhileRevalidate.getSeconds()); } return headerValue.toString(); } 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 2111d2f1f6..2e50699a35 100644 --- a/spring-web/src/test/java/org/springframework/http/CacheControlTests.java +++ b/spring-web/src/test/java/org/springframework/http/CacheControlTests.java @@ -21,6 +21,7 @@ import org.junit.Test; import static org.junit.Assert.*; +import java.time.Duration; import java.util.concurrent.TimeUnit; /** @@ -40,6 +41,12 @@ public class CacheControlTests { assertThat(cc.getHeaderValue(), Matchers.equalTo("max-age=3600")); } + @Test + public void maxAge_duration() throws Exception { + CacheControl cc = CacheControl.maxAge(Duration.ofHours(1)); + assertThat(cc.getHeaderValue(), Matchers.equalTo("max-age=3600")); + } + @Test public void maxAgeAndDirectives() throws Exception { CacheControl cc = CacheControl.maxAge(3600, TimeUnit.SECONDS).cachePublic().noTransform(); @@ -52,6 +59,12 @@ public class CacheControlTests { assertThat(cc.getHeaderValue(), Matchers.equalTo("max-age=3600, s-maxage=1800")); } + @Test + public void maxAgeAndSMaxAge_duration() throws Exception { + CacheControl cc = CacheControl.maxAge(Duration.ofHours(1)).sMaxAge(Duration.ofMinutes(30)); + assertThat(cc.getHeaderValue(), Matchers.equalTo("max-age=3600, s-maxage=1800")); + } + @Test public void noCachePrivate() throws Exception { CacheControl cc = CacheControl.noCache().cachePrivate(); @@ -70,10 +83,22 @@ public class CacheControlTests { assertThat(cc.getHeaderValue(), Matchers.equalTo("max-age=3600, stale-if-error=7200")); } + @Test + public void staleIfError_duration() throws Exception { + CacheControl cc = CacheControl.maxAge(Duration.ofHours(1)).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")); } + @Test + public void staleWhileRevalidate_duration() throws Exception { + CacheControl cc = CacheControl.maxAge(Duration.ofHours(1)).staleWhileRevalidate(2, TimeUnit.HOURS); + assertThat(cc.getHeaderValue(), Matchers.equalTo("max-age=3600, stale-while-revalidate=7200")); + } + }