Skip to content

Commit a7d25e6

Browse files
mpdudepilif
authored andcommitted
Apply stale-while-revalidate also for responses without a validator
Due to its name, the stale-while-revalidate Cache-Control extension might suggest that it only applies to revalidation requests. However, looking at https://tools.ietf.org/html/rfc5861#section-3... > The stale-while-revalidate Cache-Control Extension > When present in an HTTP response, the stale-while-revalidate > Cache-Control extension indicates that caches MAY serve the > response in which it appears after it becomes stale, up to the > indicated number of seconds. > stale-while-revalidate = "stale-while-revalidate" "=" delta-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). There is no reason why a cache should not also return a stale response while a complete re-fetch happens in the background (just what would happen if validation fails). This makes a difference if, for example, a resource has `Cache-Control: public, max-age=30, stale-while-revalidate=30` set and no additional Last-Modified or ETag headers. Co-Authored-By: Philip Hofstetter <phofstetter@sensational.ch
1 parent 9e6f5eb commit a7d25e6

File tree

2 files changed

+23
-14
lines changed

2 files changed

+23
-14
lines changed

src/CacheMiddleware.php

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -164,25 +164,28 @@ function (ResponseInterface $response) use ($request) {
164164
return new FulfilledPromise(
165165
$cacheEntry->getResponse()->withHeader(static::HEADER_CACHE_INFO, static::HEADER_CACHE_HIT)
166166
);
167-
} elseif ($staleResponse
168-
|| ($maxStaleCache !== null && $cacheEntry->getStaleAge() <= $maxStaleCache)
167+
} elseif ($cacheEntry->staleWhileValidate()
168+
&& ($maxStaleCache === null || $cacheEntry->getStaleAge() <= $maxStaleCache)
169169
) {
170-
// Staled cache!
170+
/*
171+
* The cached response indicated that it may be served stale while background revalidation (or fetch)
172+
* occurs, and the client did not limit maximum staleness. (https://tools.ietf.org/html/rfc5861#section-3)
173+
*
174+
* Return the cached, stale response; initiate deferred revalidation/re-fetch.
175+
*/
176+
static::addReValidationRequest(
177+
static::getRequestWithReValidationHeader($request, $cacheEntry),
178+
$this->cacheStorage,
179+
$cacheEntry
180+
);
181+
171182
return new FulfilledPromise(
172-
$cacheEntry->getResponse()->withHeader(static::HEADER_CACHE_INFO, static::HEADER_CACHE_HIT)
183+
$cacheEntry->getResponse()
184+
->withHeader(self::HEADER_CACHE_INFO, self::HEADER_CACHE_STALE)
173185
);
174186
} elseif ($cacheEntry->hasValidationInformation() && !$onlyFromCache) {
175187
// Re-validation header
176188
$request = static::getRequestWithReValidationHeader($request, $cacheEntry);
177-
178-
if ($cacheEntry->staleWhileValidate()) {
179-
static::addReValidationRequest($request, $this->cacheStorage, $cacheEntry);
180-
181-
return new FulfilledPromise(
182-
$cacheEntry->getResponse()
183-
->withHeader(static::HEADER_CACHE_INFO, static::HEADER_CACHE_STALE)
184-
);
185-
}
186189
}
187190
} else {
188191
$cacheEntry = null;

tests/ResponseCacheControlTest.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ protected function setUp(): void
3030
case '/2s-complex':
3131
return new FulfilledPromise(
3232
(new Response())
33-
->withAddedHeader('Cache-Control', 'invalid-token="yes", max-age=2, stale-while-revalidate=60')
33+
->withAddedHeader('Cache-Control', 'invalid-token="yes", max-age=2, stale-while-revalidate=3')
3434
);
3535
case '/no-store':
3636
return new FulfilledPromise(
@@ -91,8 +91,14 @@ public function testMaxAgeComplexHeader()
9191

9292
sleep(3);
9393

94+
$response = $this->client->get('http://test.com/2s-complex');
95+
$this->assertEquals(CacheMiddleware::HEADER_CACHE_STALE, $response->getHeaderLine(CacheMiddleware::HEADER_CACHE_INFO));
96+
97+
sleep(4);
98+
9499
$response = $this->client->get('http://test.com/2s-complex');
95100
$this->assertEquals(CacheMiddleware::HEADER_CACHE_MISS, $response->getHeaderLine(CacheMiddleware::HEADER_CACHE_INFO));
101+
96102
}
97103

98104
public function testNoStoreHeader()

0 commit comments

Comments
 (0)