mirror of
https://github.com/FriendsOfSymfony/FOSHttpCache.git
synced 2026-03-23 22:42:18 +01:00
Merge branch 'prefix-invalidation' into 3.x
This commit is contained in:
@@ -6,6 +6,11 @@ See also the [GitHub releases page](https://github.com/FriendsOfSymfony/FOSHttpC
|
||||
3.x
|
||||
===
|
||||
|
||||
3.2.0
|
||||
-----
|
||||
|
||||
* Added support for prefix invalidation, a special case of banning for cloudflare enterprise.
|
||||
|
||||
3.1.2
|
||||
-----
|
||||
|
||||
|
||||
@@ -19,18 +19,19 @@ Supported invalidation methods
|
||||
Not all clients support all :ref:`invalidation methods <invalidation methods>`.
|
||||
This table provides of methods supported by each proxy client:
|
||||
|
||||
============= ======= ======= ======= ======= =======
|
||||
Client Purge Refresh Ban Tagging Clear
|
||||
============= ======= ======= ======= ======= =======
|
||||
Varnish ✓ ✓ ✓ ✓
|
||||
Fastly ✓ ✓ ✓ ✓
|
||||
============= ======= ======= ======= ======= ========= =======
|
||||
Client Purge Refresh Ban Tagging Prefix(*) Clear
|
||||
============= ======= ======= ======= ======= ========= =======
|
||||
Varnish ✓ ✓ ✓ ✓ ✓
|
||||
Fastly ✓ ✓ ✓ ✓
|
||||
NGINX ✓ ✓
|
||||
Symfony Cache ✓ ✓ ✓ (1) ✓ (1)
|
||||
Cloudflare ✓ ✓ (2) ✓
|
||||
Noop ✓ ✓ ✓ ✓ ✓
|
||||
Multiplexer ✓ ✓ ✓ ✓ ✓
|
||||
============= ======= ======= ======= ======= =======
|
||||
Symfony Cache ✓ ✓ ✓ (1) ✓ (1)
|
||||
Cloudflare ✓ ✓ (2) ✓ (2) ✓
|
||||
Noop ✓ ✓ ✓ ✓ ✓ ✓
|
||||
Multiplexer ✓ ✓ ✓ ✓ ✓ ✓
|
||||
============= ======= ======= ======= ======= ========= =======
|
||||
|
||||
| (*): A limited version of Ban, that allows to invalidate by the beginning of a path
|
||||
| (1): Only when using `Toflar Psr6Store`_.
|
||||
| (2): Only available with `Cloudflare Enterprise`_.
|
||||
|
||||
@@ -357,7 +358,7 @@ the HttpDispatcher is not available for Cloudflare)::
|
||||
Cloudflare supports different cache purge methods depending on your account.
|
||||
All Cloudflare accounts support purging the cache by URL and clearing all
|
||||
cache items. You need a `Cloudflare Enterprise`_ account to purge by cache
|
||||
tags.
|
||||
tags or prefixes.
|
||||
|
||||
Zone identifier
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -18,6 +18,7 @@ use FOS\HttpCache\Exception\ProxyUnreachableException;
|
||||
use FOS\HttpCache\Exception\UnsupportedProxyOperationException;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\BanCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\ClearCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\PrefixCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\PurgeCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\RefreshCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\TagCapable;
|
||||
@@ -216,6 +217,20 @@ class CacheInvalidator
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function invalidatePrefixes(array $prefixes): static
|
||||
{
|
||||
if (!$this->cache instanceof PrefixCapable) {
|
||||
throw UnsupportedProxyOperationException::cacheDoesNotImplement('Prefixes');
|
||||
}
|
||||
if (!$prefixes) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->cache->invalidatePrefixes($prefixes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate URLs based on a regular expression for the URI, an optional
|
||||
* content type and optional limit to certain hosts.
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace FOS\HttpCache\ProxyClient;
|
||||
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\ClearCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\PrefixCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\PurgeCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\TagCapable;
|
||||
use Psr\Http\Message\RequestFactoryInterface;
|
||||
@@ -27,7 +28,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
*
|
||||
* @author Simon Jones <simon@studio24.net>
|
||||
*/
|
||||
class Cloudflare extends HttpProxyClient implements ClearCapable, PurgeCapable, TagCapable
|
||||
class Cloudflare extends HttpProxyClient implements ClearCapable, PrefixCapable, PurgeCapable, TagCapable
|
||||
{
|
||||
/**
|
||||
* @see https://api.cloudflare.com/#getting-started-endpoints
|
||||
@@ -87,6 +88,32 @@ class Cloudflare extends HttpProxyClient implements ClearCapable, PurgeCapable,
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* URL prefix only available with Cloudflare enterprise plans.
|
||||
*
|
||||
* The prefixes need to include the domain name, but not the protocol, e.g. "www.example.com/path"
|
||||
*
|
||||
* @see https://developers.cloudflare.com/api/resources/cache/methods/purge/
|
||||
*/
|
||||
public function invalidatePrefixes(array $prefixes): static
|
||||
{
|
||||
if (!$prefixes) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->queueRequest(
|
||||
'POST',
|
||||
sprintf(self::API_ENDPOINT.'/zones/%s/purge_cache', $this->options['zone_identifier']),
|
||||
[],
|
||||
false,
|
||||
json_encode(['prefixes' => $prefixes], JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://api.cloudflare.com/#zone-purge-files-by-url
|
||||
* @see https://developers.cloudflare.com/cache/how-to/purge-cache#purge-by-single-file-by-url For details on headers you can pass to clear the cache correctly
|
||||
|
||||
28
src/ProxyClient/Invalidation/PrefixCapable.php
Normal file
28
src/ProxyClient/Invalidation/PrefixCapable.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the FOSHttpCache package.
|
||||
*
|
||||
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace FOS\HttpCache\ProxyClient\Invalidation;
|
||||
|
||||
use FOS\HttpCache\ProxyClient\ProxyClient;
|
||||
|
||||
/**
|
||||
* An HTTP cache that supports invalidation by a prefix, that is, removing
|
||||
* or expiring objects from the cache starting with the given string or strings.
|
||||
*/
|
||||
interface PrefixCapable extends ProxyClient
|
||||
{
|
||||
/**
|
||||
* Remove/Expire cache objects based on URL prefixes.
|
||||
*
|
||||
* @param string[] $prefixes Prefixed objects that should be removed/expired from the cache. An empty prefix list should be ignored.
|
||||
*/
|
||||
public function invalidatePrefixes(array $prefixes): static;
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace FOS\HttpCache\ProxyClient;
|
||||
use FOS\HttpCache\Exception\InvalidArgumentException;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\BanCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\ClearCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\PrefixCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\PurgeCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\RefreshCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\TagCapable;
|
||||
@@ -23,7 +24,7 @@ use FOS\HttpCache\ProxyClient\Invalidation\TagCapable;
|
||||
*
|
||||
* @author Emanuele Panzeri <thepanz@gmail.com>
|
||||
*/
|
||||
class MultiplexerClient implements BanCapable, PurgeCapable, RefreshCapable, TagCapable, ClearCapable
|
||||
class MultiplexerClient implements BanCapable, PrefixCapable, PurgeCapable, RefreshCapable, TagCapable, ClearCapable
|
||||
{
|
||||
/**
|
||||
* @var ProxyClient[]
|
||||
@@ -93,6 +94,21 @@ class MultiplexerClient implements BanCapable, PurgeCapable, RefreshCapable, Tag
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards prefix invalidation request to all clients.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function invalidatePrefixes(array $prefixes): static
|
||||
{
|
||||
if (!$prefixes) {
|
||||
return $this;
|
||||
}
|
||||
$this->invoke(PrefixCapable::class, 'invalidatePrefixes', [$prefixes]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards to all clients.
|
||||
*
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace FOS\HttpCache\ProxyClient;
|
||||
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\BanCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\ClearCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\PrefixCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\PurgeCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\RefreshCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\TagCapable;
|
||||
@@ -26,7 +27,7 @@ use FOS\HttpCache\ProxyClient\Invalidation\TagCapable;
|
||||
*
|
||||
* @author Gavin Staniforth <gavin@gsdev.me>
|
||||
*/
|
||||
class Noop implements ProxyClient, BanCapable, PurgeCapable, RefreshCapable, TagCapable, ClearCapable
|
||||
class Noop implements ProxyClient, BanCapable, PrefixCapable, PurgeCapable, RefreshCapable, TagCapable, ClearCapable
|
||||
{
|
||||
public function ban(array $headers): static
|
||||
{
|
||||
@@ -43,6 +44,11 @@ class Noop implements ProxyClient, BanCapable, PurgeCapable, RefreshCapable, Tag
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function invalidatePrefixes(array $prefixes): static
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function purge(string $url, array $headers = []): static
|
||||
{
|
||||
return $this;
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace FOS\HttpCache\ProxyClient;
|
||||
|
||||
use FOS\HttpCache\Exception\InvalidArgumentException;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\BanCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\PrefixCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\PurgeCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\RefreshCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\TagCapable;
|
||||
@@ -36,7 +37,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
*
|
||||
* @author David de Boer <david@driebit.nl>
|
||||
*/
|
||||
class Varnish extends HttpProxyClient implements BanCapable, PurgeCapable, RefreshCapable, TagCapable
|
||||
class Varnish extends HttpProxyClient implements BanCapable, PrefixCapable, PurgeCapable, RefreshCapable, TagCapable
|
||||
{
|
||||
public const HTTP_METHOD_BAN = 'BAN';
|
||||
|
||||
@@ -127,6 +128,22 @@ class Varnish extends HttpProxyClient implements BanCapable, PurgeCapable, Refre
|
||||
return $this->ban($headers);
|
||||
}
|
||||
|
||||
public function invalidatePrefixes(array $prefixes): static
|
||||
{
|
||||
if (!$prefixes) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
foreach ($prefixes as $prefix) {
|
||||
$parts = explode('/', $prefix, 2);
|
||||
$host = $parts[0];
|
||||
$path = isset($parts[1]) ? '/'.$parts[1] : '/';
|
||||
$this->banPath($path, null, $host);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function purge(string $url, array $headers = []): static
|
||||
{
|
||||
$this->queueRequest(self::HTTP_METHOD_PURGE, $url, $headers);
|
||||
|
||||
@@ -71,6 +71,28 @@ class CloudflareTest extends TestCase
|
||||
$cloudflare->invalidateTags(['tag-one', 'tag-two']);
|
||||
}
|
||||
|
||||
public function testInvalidatePrefixesPurge(): void
|
||||
{
|
||||
$cloudflare = $this->getProxyClient();
|
||||
|
||||
$this->httpDispatcher->shouldReceive('invalidate')->once()->with(
|
||||
\Mockery::on(
|
||||
function (RequestInterface $request) {
|
||||
$this->assertEquals('POST', $request->getMethod());
|
||||
$this->assertEquals('Bearer '.self::AUTH_TOKEN, current($request->getHeader('Authorization')));
|
||||
$this->assertEquals(sprintf('/client/v4/zones/%s/purge_cache', self::ZONE_IDENTIFIER), $request->getRequestTarget());
|
||||
|
||||
$this->assertEquals('{"prefixes":["example.com/one/","example.com/two/"]}', $request->getBody()->getContents());
|
||||
|
||||
return true;
|
||||
}
|
||||
),
|
||||
false
|
||||
);
|
||||
|
||||
$cloudflare->invalidatePrefixes(['example.com/one/', 'example.com/two/']);
|
||||
}
|
||||
|
||||
public function testPurge(): void
|
||||
{
|
||||
$cloudflare = $this->getProxyClient();
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace FOS\HttpCache\Tests\Unit\ProxyClient;
|
||||
use FOS\HttpCache\Exception\InvalidArgumentException;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\BanCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\ClearCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\PrefixCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\PurgeCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\RefreshCapable;
|
||||
use FOS\HttpCache\ProxyClient\Invalidation\TagCapable;
|
||||
@@ -103,6 +104,21 @@ class MultiplexerClientTest extends TestCase
|
||||
$this->assertSame($multiplexer, $multiplexer->invalidateTags($tags));
|
||||
}
|
||||
|
||||
public function testInvalidatePrefixes(): void
|
||||
{
|
||||
$prefixes = ['example.com/one/', 'example.com/two/'];
|
||||
|
||||
$mockClient = \Mockery::mock(PrefixCapable::class)
|
||||
->shouldReceive('invalidatePrefixes')
|
||||
->once()
|
||||
->with($prefixes)
|
||||
->getMock();
|
||||
|
||||
$multiplexer = new MultiplexerClient([$mockClient]);
|
||||
|
||||
$this->assertSame($multiplexer, $multiplexer->invalidatePrefixes($prefixes));
|
||||
}
|
||||
|
||||
public function testRefresh(): void
|
||||
{
|
||||
$url = 'example.com';
|
||||
|
||||
@@ -33,6 +33,11 @@ class NoopTest extends TestCase
|
||||
$this->assertSame($this->noop, $this->noop->invalidateTags(['tag123']));
|
||||
}
|
||||
|
||||
public function testInvalidatePrefixes(): void
|
||||
{
|
||||
$this->assertSame($this->noop, $this->noop->invalidatePrefixes(['example.com/one/']));
|
||||
}
|
||||
|
||||
public function testBanPath(): void
|
||||
{
|
||||
$this->assertSame($this->noop, $this->noop->banPath('/123'));
|
||||
|
||||
@@ -236,4 +236,23 @@ class VarnishTest extends TestCase
|
||||
|
||||
$varnish->refresh('/fresh');
|
||||
}
|
||||
|
||||
public function testInvalidatePrefixes(): void
|
||||
{
|
||||
$varnish = new Varnish($this->httpDispatcher);
|
||||
$this->httpDispatcher->shouldReceive('invalidate')->once()->with(
|
||||
\Mockery::on(
|
||||
function (RequestInterface $request) {
|
||||
$this->assertEquals('BAN', $request->getMethod());
|
||||
$this->assertEquals('example.org', $request->getHeaderLine('X-Host'));
|
||||
$this->assertEquals('/one/', $request->getHeaderLine('X-Url'));
|
||||
$this->assertEquals('.*', $request->getHeaderLine('X-Content-Type'));
|
||||
|
||||
return true;
|
||||
}
|
||||
),
|
||||
false
|
||||
);
|
||||
$varnish->invalidatePrefixes(['example.org/one/']);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user