Skip to content

Commit a64fda1

Browse files
authored
Merge pull request #16 from Flowpack/task/extractPublicCacheHeadersIntoSeperateComponent
TASK: Make caching behavior opt-in via `X-FullPageCache-EnableFusionAutoconfiguration` http header
2 parents af5682c + d7e9df0 commit a64fda1

6 files changed

Lines changed: 67 additions & 28 deletions

File tree

Classes/Middleware/CacheHeaderMiddleware.php renamed to Classes/Middleware/FusionAutoconfigurationMiddleware.php

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
use Flowpack\FullPageCache\Aspects\ContentCacheAspect;
1212
use Flowpack\FullPageCache\Cache\MetadataAwareStringFrontend;
1313

14-
class CacheHeaderMiddleware implements MiddlewareInterface
14+
class FusionAutoconfigurationMiddleware implements MiddlewareInterface
1515
{
16+
public const HEADER_ENABLED = 'X-FullPageCache-EnableFusionAutoconfiguration';
1617

1718
/**
1819
* @Flow\Inject
@@ -32,41 +33,24 @@ class CacheHeaderMiddleware implements MiddlewareInterface
3233
*/
3334
protected $enabled;
3435

35-
/**
36-
* @var boolean
37-
* @Flow\InjectConfiguration(path="maxPublicCacheTime")
38-
*/
39-
protected $maxPublicCacheTime;
40-
4136
public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
4237
{
4338
if (!$this->enabled || !$request->hasHeader(RequestCacheMiddleware::HEADER_ENABLED)) {
44-
return $next->handle($request);
39+
return $next->handle($request)->withoutHeader(self::HEADER_ENABLED);
4540
}
4641

4742
$response = $next->handle($request);
4843

49-
list($hasUncachedSegments, $tags, $lifetime) = $this->getFusionCacheInformations();
50-
51-
if ($response->hasHeader('Set-Cookie') || $hasUncachedSegments) {
44+
if (!$response->hasHeader(self::HEADER_ENABLED)) {
5245
return $response;
46+
} else {
47+
$response = $response->withoutHeader(self::HEADER_ENABLED);
5348
}
5449

55-
$publicLifetime = 0;
56-
if ($this->maxPublicCacheTime > 0) {
57-
if ($lifetime > 0 && $lifetime < $this->maxPublicCacheTime) {
58-
$publicLifetime = $lifetime;
59-
} else {
60-
$publicLifetime = $this->maxPublicCacheTime;
61-
}
62-
}
50+
list($hasUncachedSegments, $tags, $lifetime) = $this->getFusionCacheInformations();
6351

64-
if ($publicLifetime > 0) {
65-
$entryContentHash = md5($response->getBody()->getContents());
66-
$response->getBody()->rewind();
67-
$response = $response
68-
->withHeader('ETag', '"' . $entryContentHash . '"')
69-
->withHeader('CacheControl', 'public, max-age=' . $publicLifetime);
52+
if ($response->hasHeader('Set-Cookie') || $hasUncachedSegments) {
53+
return $response;
7054
}
7155

7256
$response = $response

Classes/Middleware/RequestCacheMiddleware.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ class RequestCacheMiddleware implements MiddlewareInterface
5252
*/
5353
protected $ignoredCookieParams;
5454

55+
/**
56+
* @var boolean
57+
* @Flow\InjectConfiguration(path="maxPublicCacheTime")
58+
*/
59+
protected $maxPublicCacheTime;
60+
5561
public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
5662
{
5763
if (!$this->enabled) {
@@ -82,6 +88,23 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
8288
->withoutHeader(self::HEADER_LIFTIME)
8389
->withoutHeader(self::HEADER_TAGS);
8490

91+
$publicLifetime = 0;
92+
if ($this->maxPublicCacheTime > 0) {
93+
if ($lifetime > 0 && $lifetime < $this->maxPublicCacheTime) {
94+
$publicLifetime = $lifetime;
95+
} else {
96+
$publicLifetime = $this->maxPublicCacheTime;
97+
}
98+
}
99+
100+
if ($publicLifetime > 0) {
101+
$entryContentHash = md5($response->getBody()->getContents());
102+
$response->getBody()->rewind();
103+
$response = $response
104+
->withHeader('ETag', '"' . $entryContentHash . '"')
105+
->withHeader('Cache-Control', 'public, max-age=' . $publicLifetime);
106+
}
107+
85108
$this->cacheFrontend->set($entryIdentifier,[ 'timestamp' => time(), 'response' => str($response) ], $tags, $lifetime);
86109
$response->getBody()->rewind();
87110
return $response->withHeader(self::HEADER_INFO, 'MISS: ' . $entryIdentifier);

Configuration/Objects.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Flowpack\FullPageCache\Middleware\CacheHeaderMiddleware:
1+
Flowpack\FullPageCache\Middleware\FusionAutoconfigurationMiddleware:
22
properties:
33
contentCache:
44
object:

Configuration/Settings.yaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ Neos:
3838
'fullPageRequestCache':
3939
middleware: 'Flowpack\FullPageCache\Middleware\RequestCacheMiddleware'
4040
position: 'after trustedProxies'
41-
'fullPageCacheHeader':
42-
middleware: 'Flowpack\FullPageCache\Middleware\CacheHeaderMiddleware'
41+
'fullPageCacheFusionAutoconfiguration':
42+
middleware: 'Flowpack\FullPageCache\Middleware\FusionAutoconfigurationMiddleware'
4343
position: 'after fullPageRequestCache'
44+
Neos:
45+
fusion:
46+
autoInclude:
47+
Flowpack.FullPageCache: true

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,26 @@ Flowpack:
4747

4848
You can also move the cache backend to something faster if available, to improve performance even more.
4949

50+
How it works
51+
------------
52+
53+
The package defines two http middlewares:
54+
55+
- `RequestCacheMiddleware`: If a request is cacheable the cache is asked first and only if no response is found the
56+
request is passed down the middleware chain. The cache lifetime and tags are determined from the
57+
`X-FullPageCache-Enabled`, `X-FullPageCache-Lifetime` and `X-FullPageCache-Tags` that are set by upstream middlewares
58+
or controllers. Additionally the middleware adds `ETag` and `Cache-Control` Headers taking the lifetime and setting
59+
`maxPublicCacheTime` into account.
60+
61+
- `FusionAutoconfigurationMiddleware`: Connects to the fusion cache and extracts tags plus the allowed lifetime which is then
62+
stored in the response headers `X-FullPageCache-Enabled`, `X-FullPageCache-Lifetime` and `X-FullPageCache-Tags`.
63+
This component is only active if the header `X-FullPageCache-EnableFusionAutoconfiguration` is present in the response
64+
which is set automatically for `Neos.Neos:Page`.
65+
66+
Custom controllers that want to control the caching behavior directly can set the headers `X-FullPageCache-Enabled`,
67+
`X-FullPageCache-Lifetime` and `X-FullPageCache-Tags` directly while fusion based controllers can enable the autoconfiguration
68+
by setting the header `X-FullPageCache-EnableFusionAutoconfiguration`.
69+
5070
Warning
5171
-------
5272

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
prototype(Neos.Neos:Page) {
2+
httpResponseHead {
3+
headers {
4+
'X-FullPageCache-EnableFusionAutoconfiguration' = ''
5+
'X-FullPageCache-EnableFusionAutoconfiguration'.@if.isEnabled = ${Configuration.setting('Flowpack.FullPageCache.enabled') == true}
6+
}
7+
}
8+
}

0 commit comments

Comments
 (0)