Skip to content

Commit

Permalink
Merge pull request #37 from nstdio/stale-if-error
Browse files Browse the repository at this point in the history
feat(cache): Add support for stale-if-error Cache-Control extension.
  • Loading branch information
nstdio authored Mar 18, 2022
2 parents cf63a81 + a42139f commit 3835742
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ long maxAge() {
return maxAge;
}

long staleFor() {
return age(MILLISECONDS) - maxAge;
}

long requestTime() {
return requestTimeMs;
}
Expand Down
26 changes: 23 additions & 3 deletions src/main/java/io/github/nstdio/http/ext/CachingInterceptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static io.github.nstdio.http.ext.Headers.HEADER_IF_MODIFIED_SINCE;
import static io.github.nstdio.http.ext.Headers.HEADER_IF_NONE_MATCH;
import static io.github.nstdio.http.ext.Responses.gatewayTimeoutResponse;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.stream.Collectors.toList;
import static lombok.Lombok.sneakyThrow;

Expand Down Expand Up @@ -210,9 +211,28 @@ private boolean isFresh(RequestContext ctx, Cache.CacheEntry entry) {

private <T> HttpResponse<T> possiblyCached(RequestContext ctx, Cache.CacheEntry entry, HttpResponse<T> r) {
CacheEntryMetadata metadata = entry != null ? entry.metadata() : null;
if (metadata != null && r.statusCode() == 304) {
metadata.update(r.headers(), ctx.requestTimeLong(), ctx.responseTimeLong());
return createCachedResponse(ctx, entry);
if (metadata != null) {
switch (r.statusCode()) {
case 304: {
metadata.update(r.headers(), ctx.requestTimeLong(), ctx.responseTimeLong());
return createCachedResponse(ctx, entry);
}
case 500:
case 502:
case 503:
case 504: {
long staleIfError = Math.max(
ctx.cacheControl().staleIfError(MILLISECONDS),
metadata.responseCacheControl().staleIfError(MILLISECONDS)
);

if (staleIfError > metadata.staleFor()) {
return createCachedResponse(ctx, entry);
}

break;
}
}
}

return r;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@

package io.github.nstdio.http.ext;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.created;
import static com.github.tomakehurst.wiremock.client.WireMock.delete;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.matching;
import static com.github.tomakehurst.wiremock.client.WireMock.noContent;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.put;
Expand All @@ -35,6 +37,7 @@
import static io.github.nstdio.http.ext.Headers.HEADER_CACHE_CONTROL;
import static io.github.nstdio.http.ext.Headers.HEADER_DATE;
import static io.github.nstdio.http.ext.Headers.HEADER_ETAG;
import static io.github.nstdio.http.ext.Headers.HEADER_IF_MODIFIED_SINCE;
import static io.github.nstdio.http.ext.Headers.HEADER_IF_NONE_MATCH;
import static io.github.nstdio.http.ext.Headers.HEADER_LAST_MODIFIED;
import static io.github.nstdio.http.ext.Headers.toRFC1123;
Expand Down Expand Up @@ -587,9 +590,39 @@ default void shouldWorkWithPathSubscriber(@TempDir Path tempDir) throws Exceptio
Assertions.assertThat(r2Path).exists().hasContent(body);
}

/**
* https://datatracker.ietf.org/doc/html/rfc5861#section-4
*/
@Test
@Disabled("https://datatracker.ietf.org/doc/html/rfc5861#section-4")
default void shouldRespectStaleIfError() {
default void shouldRespectStaleIfError() throws Exception {
//given
var clock = FixedRateTickClock.of(clock(), Duration.ofSeconds(1));
var client = client(clock);
var bodyHandler = ofString();
var urlPattern = urlEqualTo(path());

stubFor(get(urlPattern)
.willReturn(ok()
.withHeader(HEADER_CACHE_CONTROL, "max-age=1,stale-if-error=10")
.withBody("abc")
)
);
stubFor(get(urlPattern)
.withHeader(HEADER_IF_MODIFIED_SINCE, matching(".+"))
.willReturn(aResponse().withStatus(500))
);

//when
var r1 = client.send(requestBuilder().build(), bodyHandler);
var r2 = await().until(() -> client.send(requestBuilder().header("Cache-Control", "stale-if-error=4").build(), bodyHandler), isCached());
var r3 = await().until(() -> client.send(requestBuilder().header("Cache-Control", "stale-if-error=100").build(), bodyHandler), isCached());
var r4 = client.send(requestBuilder().header("Cache-Control", "stale-if-error=1").build(), bodyHandler);

//then
assertThat(r1).isNotCached().hasBody("abc");
assertThat(r2).isCached().hasBody("abc");
assertThat(r3).isCached().hasBody("abc");
assertThat(r4).isNotCached().hasStatusCode(500);
}

@Test
Expand Down

0 comments on commit 3835742

Please sign in to comment.