Skip to content

Migrate CacheControl to use java.time.Duration for durations #22545

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 77 additions & 18 deletions spring-web/src/main/java/org/springframework/http/CacheControl.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.http;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

import org.springframework.lang.Nullable;
Expand Down Expand Up @@ -50,7 +51,8 @@
*/
public class CacheControl {

private long maxAge = -1;
@Nullable
private Duration maxAge = null;

private boolean noCache = false;

Expand All @@ -66,12 +68,14 @@ public class CacheControl {

private boolean proxyRevalidate = false;

private long staleWhileRevalidate = -1;

private long staleIfError = -1;
@Nullable
private Duration staleWhileRevalidate = null;

private long sMaxAge = -1;
@Nullable
private Duration staleIfError = null;

@Nullable
private Duration sMaxAge = null;

/**
* Create an empty CacheControl instance.
Expand Down Expand Up @@ -106,8 +110,25 @@ public static CacheControl empty() {
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.8">rfc7234 section 5.2.2.8</a>
*/
public static CacheControl maxAge(long maxAge, TimeUnit unit) {
return maxAge(Duration.ofSeconds(unit.toSeconds(maxAge)));
}

/**
* Add a "max-age=" directive.
* <p>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.
* <p>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 <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.8">rfc7234 section 5.2.2.8</a>
*/
public static CacheControl maxAge(Duration maxAge) {
CacheControl cc = new CacheControl();
cc.maxAge = unit.toSeconds(maxAge);
cc.maxAge = maxAge;
return cc;
}

Expand Down Expand Up @@ -216,7 +237,19 @@ public CacheControl proxyRevalidate() {
* @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.9">rfc7234 section 5.2.2.9</a>
*/
public CacheControl sMaxAge(long sMaxAge, TimeUnit unit) {
this.sMaxAge = unit.toSeconds(sMaxAge);
return sMaxAge(Duration.ofSeconds(unit.toSeconds(sMaxAge)));
}

/**
* Add an "s-maxage" directive.
* <p>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 <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2.9">rfc7234 section 5.2.2.9</a>
*/
public CacheControl sMaxAge(Duration sMaxAge) {
this.sMaxAge = sMaxAge;
return this;
}

Expand All @@ -233,7 +266,22 @@ public CacheControl sMaxAge(long sMaxAge, TimeUnit unit) {
* @see <a href="https://tools.ietf.org/html/rfc5861#section-3">rfc5861 section 3</a>
*/
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.
* <p>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 <a href="https://tools.ietf.org/html/rfc5861#section-3">rfc5861 section 3</a>
*/
public CacheControl staleWhileRevalidate(Duration staleWhileRevalidate) {
this.staleWhileRevalidate = staleWhileRevalidate;
return this;
}

Expand All @@ -247,10 +295,21 @@ public CacheControl staleWhileRevalidate(long staleWhileRevalidate, TimeUnit uni
* @see <a href="https://tools.ietf.org/html/rfc5861#section-4">rfc5861 section 4</a>
*/
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.
* <p>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 <a href="https://tools.ietf.org/html/rfc5861#section-4">rfc5861 section 4</a>
*/
public CacheControl staleIfError(Duration staleIfError) {
this.staleIfError = staleIfError;
return this;
}

/**
* Return the "Cache-Control" header value, if any.
Expand All @@ -268,8 +327,8 @@ public String getHeaderValue() {
*/
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");
Expand All @@ -292,14 +351,14 @@ private String toHeaderValue() {
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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import static org.junit.Assert.*;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

/**
Expand All @@ -40,6 +41,12 @@ public void maxAge() throws Exception {
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();
Expand All @@ -52,6 +59,12 @@ public void maxAgeAndSMaxAge() throws Exception {
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();
Expand All @@ -70,10 +83,22 @@ public void staleIfError() throws Exception {
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"));
}

}