package and depencies

This commit is contained in:
RafficMohammed
2023-01-08 02:57:24 +05:30
parent d5332eb421
commit 1d54b8bc7f
4309 changed files with 193331 additions and 172289 deletions

View File

@@ -40,18 +40,13 @@ abstract class AbstractSurrogate implements SurrogateInterface
/**
* Returns a new cache strategy instance.
*
* @return ResponseCacheStrategyInterface
*/
public function createCacheStrategy()
public function createCacheStrategy(): ResponseCacheStrategyInterface
{
return new ResponseCacheStrategy();
}
/**
* {@inheritdoc}
*/
public function hasSurrogateCapability(Request $request)
public function hasSurrogateCapability(Request $request): bool
{
if (null === $value = $request->headers->get('Surrogate-Capability')) {
return false;
@@ -60,9 +55,6 @@ abstract class AbstractSurrogate implements SurrogateInterface
return str_contains($value, sprintf('%s/1.0', strtoupper($this->getName())));
}
/**
* {@inheritdoc}
*/
public function addSurrogateCapability(Request $request)
{
$current = $request->headers->get('Surrogate-Capability');
@@ -71,10 +63,7 @@ abstract class AbstractSurrogate implements SurrogateInterface
$request->headers->set('Surrogate-Capability', $current ? $current.', '.$new : $new);
}
/**
* {@inheritdoc}
*/
public function needsParsing(Response $response)
public function needsParsing(Response $response): bool
{
if (!$control = $response->headers->get('Surrogate-Control')) {
return false;
@@ -85,10 +74,7 @@ abstract class AbstractSurrogate implements SurrogateInterface
return (bool) preg_match($pattern, $control);
}
/**
* {@inheritdoc}
*/
public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors)
public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors): string
{
$subRequest = Request::create($uri, Request::METHOD_GET, [], $cache->getRequest()->cookies->all(), [], $cache->getRequest()->server->all());

View File

@@ -27,14 +27,11 @@ use Symfony\Component\HttpFoundation\Response;
*/
class Esi extends AbstractSurrogate
{
public function getName()
public function getName(): string
{
return 'esi';
}
/**
* {@inheritdoc}
*/
public function addSurrogateControl(Response $response)
{
if (str_contains($response->getContent(), '<esi:include')) {
@@ -42,10 +39,7 @@ class Esi extends AbstractSurrogate
}
}
/**
* {@inheritdoc}
*/
public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = '')
public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = ''): string
{
$html = sprintf('<esi:include src="%s"%s%s />',
$uri,
@@ -60,10 +54,7 @@ class Esi extends AbstractSurrogate
return $html;
}
/**
* {@inheritdoc}
*/
public function process(Request $request, Response $response)
public function process(Request $request, Response $response): Response
{
$type = $response->headers->get('Content-Type');
if (empty($type)) {

View File

@@ -29,13 +29,13 @@ use Symfony\Component\HttpKernel\TerminableInterface;
*/
class HttpCache implements HttpKernelInterface, TerminableInterface
{
private $kernel;
private $store;
private $request;
private $surrogate;
private $surrogateCacheStrategy;
private $options = [];
private $traces = [];
private HttpKernelInterface $kernel;
private StoreInterface $store;
private Request $request;
private ?SurrogateInterface $surrogate;
private ?ResponseCacheStrategyInterface $surrogateCacheStrategy = null;
private array $options = [];
private array $traces = [];
/**
* Constructor.
@@ -78,6 +78,11 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
* the cache can serve a stale response when an error is encountered (default: 60).
* This setting is overridden by the stale-if-error HTTP Cache-Control extension
* (see RFC 5861).
*
* * terminate_on_cache_hit Specifies if the kernel.terminate event should be dispatched even when the cache
* was hit (default: true).
* Unless your application needs to process events on cache hits, it is recommended
* to set this to false to avoid having to bootstrap the Symfony framework on a cache hit.
*/
public function __construct(HttpKernelInterface $kernel, StoreInterface $store, SurrogateInterface $surrogate = null, array $options = [])
{
@@ -86,7 +91,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
$this->surrogate = $surrogate;
// needed in case there is a fatal error because the backend is too slow to respond
register_shutdown_function([$this->store, 'cleanup']);
register_shutdown_function($this->store->cleanup(...));
$this->options = array_merge([
'debug' => false,
@@ -98,6 +103,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
'stale_if_error' => 60,
'trace_level' => 'none',
'trace_header' => 'X-Symfony-Cache',
'terminate_on_cache_hit' => true,
], $options);
if (!isset($options['trace_level'])) {
@@ -107,20 +113,16 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
/**
* Gets the current store.
*
* @return StoreInterface
*/
public function getStore()
public function getStore(): StoreInterface
{
return $this->store;
}
/**
* Returns an array of events that took place during processing of the last request.
*
* @return array
*/
public function getTraces()
public function getTraces(): array
{
return $this->traces;
}
@@ -144,10 +146,8 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
/**
* Returns a log message for the events of the last request processing.
*
* @return string
*/
public function getLog()
public function getLog(): string
{
$log = [];
foreach ($this->traces as $request => $traces) {
@@ -159,20 +159,16 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
/**
* Gets the Request instance associated with the main request.
*
* @return Request
*/
public function getRequest()
public function getRequest(): Request
{
return $this->request;
}
/**
* Gets the Kernel instance.
*
* @return HttpKernelInterface
*/
public function getKernel()
public function getKernel(): HttpKernelInterface
{
return $this->kernel;
}
@@ -180,19 +176,14 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
/**
* Gets the Surrogate instance.
*
* @return SurrogateInterface
*
* @throws \LogicException
*/
public function getSurrogate()
public function getSurrogate(): SurrogateInterface
{
return $this->surrogate;
}
/**
* {@inheritdoc}
*/
public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true)
public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response
{
// FIXME: catch exceptions and implement a 500 error page here? -> in Varnish, there is a built-in error page mechanism
if (HttpKernelInterface::MAIN_REQUEST === $type) {
@@ -245,11 +236,17 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
return $response;
}
/**
* {@inheritdoc}
*/
public function terminate(Request $request, Response $response)
{
// Do not call any listeners in case of a cache hit.
// This ensures identical behavior as if you had a separate
// reverse caching proxy such as Varnish and the like.
if ($this->options['terminate_on_cache_hit']) {
trigger_deprecation('symfony/http-kernel', '6.2', 'Setting "terminate_on_cache_hit" to "true" is deprecated and will be changed to "false" in Symfony 7.0.');
} elseif (\in_array('fresh', $this->traces[$this->getTraceKey($request)] ?? [], true)) {
return;
}
if ($this->getKernel() instanceof TerminableInterface) {
$this->getKernel()->terminate($request, $response);
}
@@ -259,10 +256,8 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
* Forwards the Request to the backend without storing the Response in the cache.
*
* @param bool $catch Whether to process exceptions
*
* @return Response
*/
protected function pass(Request $request, bool $catch = false)
protected function pass(Request $request, bool $catch = false): Response
{
$this->record($request, 'pass');
@@ -274,13 +269,11 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
*
* @param bool $catch Whether to process exceptions
*
* @return Response
*
* @throws \Exception
*
* @see RFC2616 13.10
*/
protected function invalidate(Request $request, bool $catch = false)
protected function invalidate(Request $request, bool $catch = false): Response
{
$response = $this->pass($request, $catch);
@@ -322,11 +315,9 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
*
* @param bool $catch Whether to process exceptions
*
* @return Response
*
* @throws \Exception
*/
protected function lookup(Request $request, bool $catch = false)
protected function lookup(Request $request, bool $catch = false): Response
{
try {
$entry = $this->store->lookup($request);
@@ -370,10 +361,8 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
* GET request with the backend.
*
* @param bool $catch Whether to process exceptions
*
* @return Response
*/
protected function validate(Request $request, Response $entry, bool $catch = false)
protected function validate(Request $request, Response $entry, bool $catch = false): Response
{
$subRequest = clone $request;
@@ -433,10 +422,8 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
* stores it in the cache if is cacheable.
*
* @param bool $catch Whether to process exceptions
*
* @return Response
*/
protected function fetch(Request $request, bool $catch = false)
protected function fetch(Request $request, bool $catch = false): Response
{
$subRequest = clone $request;
@@ -471,9 +458,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
*/
protected function forward(Request $request, bool $catch = false, Response $entry = null)
{
if ($this->surrogate) {
$this->surrogate->addSurrogateCapability($request);
}
$this->surrogate?->addSurrogateCapability($request);
// always a "master" request (as the real master request can be in cache)
$response = SubRequestHandler::handle($this->kernel, $request, HttpKernelInterface::MAIN_REQUEST, $catch);
@@ -523,7 +508,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
Anyway, a client that received a message without a "Date" header MUST add it.
*/
if (!$response->headers->has('Date')) {
$response->setDate(\DateTime::createFromFormat('U', time()));
$response->setDate(\DateTimeImmutable::createFromFormat('U', time()));
}
$this->processResponseBody($request, $response);
@@ -539,10 +524,8 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
/**
* Checks whether the cache entry is "fresh enough" to satisfy the Request.
*
* @return bool
*/
protected function isFreshEnough(Request $request, Response $entry)
protected function isFreshEnough(Request $request, Response $entry): bool
{
if (!$entry->isFresh()) {
return $this->lock($request, $entry);
@@ -560,7 +543,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
*
* @return bool true if the cache entry can be returned even if it is staled, false otherwise
*/
protected function lock(Request $request, Response $entry)
protected function lock(Request $request, Response $entry): bool
{
// try to acquire a lock to call the backend
$lock = $this->store->lock($request);
@@ -659,7 +642,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
protected function processResponseBody(Request $request, Response $response)
{
if (null !== $this->surrogate && $this->surrogate->needsParsing($response)) {
if ($this->surrogate?->needsParsing($response)) {
$this->surrogate->process($request, $response);
}
}
@@ -713,10 +696,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
private function mayServeStaleWhileRevalidate(Response $entry): bool
{
$timeout = $entry->headers->getCacheControlDirective('stale-while-revalidate');
if (null === $timeout) {
$timeout = $this->options['stale_while_revalidate'];
}
$timeout ??= $this->options['stale_while_revalidate'];
return abs($entry->getTtl() ?? 0) < $timeout;
}

View File

@@ -34,10 +34,11 @@ class ResponseCacheStrategy implements ResponseCacheStrategyInterface
*/
private const INHERIT_DIRECTIVES = ['public', 'immutable'];
private $embeddedResponses = 0;
private $isNotCacheableResponseEmbedded = false;
private $age = 0;
private $flagDirectives = [
private int $embeddedResponses = 0;
private bool $isNotCacheableResponseEmbedded = false;
private int $age = 0;
private \DateTimeInterface|null|false $lastModified = null;
private array $flagDirectives = [
'no-cache' => null,
'no-store' => null,
'no-transform' => null,
@@ -47,15 +48,12 @@ class ResponseCacheStrategy implements ResponseCacheStrategyInterface
'private' => null,
'immutable' => null,
];
private $ageDirectives = [
private array $ageDirectives = [
'max-age' => null,
's-maxage' => null,
'expires' => null,
];
/**
* {@inheritdoc}
*/
public function add(Response $response)
{
++$this->embeddedResponses;
@@ -90,11 +88,13 @@ class ResponseCacheStrategy implements ResponseCacheStrategyInterface
$expires = $response->getExpires();
$expires = null !== $expires ? (int) $expires->format('U') - (int) $response->getDate()->format('U') : null;
$this->storeRelativeAgeDirective('expires', $expires >= 0 ? $expires : null, 0, $isHeuristicallyCacheable);
if (false !== $this->lastModified) {
$lastModified = $response->getLastModified();
$this->lastModified = $lastModified ? max($this->lastModified, $lastModified) : false;
}
}
/**
* {@inheritdoc}
*/
public function update(Response $response)
{
// if we have no embedded Response, do nothing
@@ -102,17 +102,16 @@ class ResponseCacheStrategy implements ResponseCacheStrategyInterface
return;
}
// Remove validation related headers of the master response,
// because some of the response content comes from at least
// one embedded response (which likely has a different caching strategy).
// Remove Etag since it cannot be merged from embedded responses.
$response->setEtag(null);
$response->setLastModified(null);
$this->add($response);
$response->headers->set('Age', $this->age);
if ($this->isNotCacheableResponseEmbedded) {
$response->setLastModified(null);
if ($this->flagDirectives['no-store']) {
$response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate');
} else {
@@ -122,6 +121,8 @@ class ResponseCacheStrategy implements ResponseCacheStrategyInterface
return;
}
$response->setLastModified($this->lastModified ?: null);
$flags = array_filter($this->flagDirectives);
if (isset($flags['must-revalidate'])) {
@@ -162,17 +163,14 @@ class ResponseCacheStrategy implements ResponseCacheStrategyInterface
// RFC2616: A response received with a status code of 200, 203, 300, 301 or 410
// MAY be stored by a cache […] unless a cache-control directive prohibits caching.
if ($response->headers->hasCacheControlDirective('no-cache')
|| $response->headers->getCacheControlDirective('no-store')
|| $response->headers->hasCacheControlDirective('no-store')
) {
return true;
}
// Last-Modified and Etag headers cannot be merged, they render the response uncacheable
// Etag headers cannot be merged, they render the response uncacheable
// by default (except if the response also has max-age etc.).
if (\in_array($response->getStatusCode(), [200, 203, 300, 301, 410])
&& null === $response->getLastModified()
&& null === $response->getEtag()
) {
if (null === $response->getEtag() && \in_array($response->getStatusCode(), [200, 203, 300, 301, 410])) {
return false;
}

View File

@@ -21,17 +21,11 @@ use Symfony\Component\HttpFoundation\Response;
*/
class Ssi extends AbstractSurrogate
{
/**
* {@inheritdoc}
*/
public function getName()
public function getName(): string
{
return 'ssi';
}
/**
* {@inheritdoc}
*/
public function addSurrogateControl(Response $response)
{
if (str_contains($response->getContent(), '<!--#include')) {
@@ -39,18 +33,12 @@ class Ssi extends AbstractSurrogate
}
}
/**
* {@inheritdoc}
*/
public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = '')
public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = ''): string
{
return sprintf('<!--#include virtual="%s" -->', $uri);
}
/**
* {@inheritdoc}
*/
public function process(Request $request, Response $response)
public function process(Request $request, Response $response): Response
{
$type = $response->headers->get('Content-Type');
if (empty($type)) {

View File

@@ -26,9 +26,9 @@ class Store implements StoreInterface
{
protected $root;
/** @var \SplObjectStorage<Request, string> */
private $keyCache;
private \SplObjectStorage $keyCache;
/** @var array<string, resource> */
private $locks = [];
private array $locks = [];
/**
* @throws \RuntimeException
@@ -61,7 +61,7 @@ class Store implements StoreInterface
*
* @return bool|string true if the lock is acquired, the path to the current lock otherwise
*/
public function lock(Request $request)
public function lock(Request $request): bool|string
{
$key = $this->getCacheKey($request);
@@ -88,7 +88,7 @@ class Store implements StoreInterface
*
* @return bool False if the lock file does not exist or cannot be unlocked, true otherwise
*/
public function unlock(Request $request)
public function unlock(Request $request): bool
{
$key = $this->getCacheKey($request);
@@ -103,7 +103,7 @@ class Store implements StoreInterface
return false;
}
public function isLocked(Request $request)
public function isLocked(Request $request): bool
{
$key = $this->getCacheKey($request);
@@ -125,10 +125,8 @@ class Store implements StoreInterface
/**
* Locates a cached Response for the Request provided.
*
* @return Response|null
*/
public function lookup(Request $request)
public function lookup(Request $request): ?Response
{
$key = $this->getCacheKey($request);
@@ -167,11 +165,9 @@ class Store implements StoreInterface
* Existing entries are read and any that match the response are removed. This
* method calls write with the new list of cache entries.
*
* @return string
*
* @throws \RuntimeException
*/
public function write(Request $request, Response $response)
public function write(Request $request, Response $response): string
{
$key = $this->getCacheKey($request);
$storedEnv = $this->persistRequest($request);
@@ -227,12 +223,10 @@ class Store implements StoreInterface
/**
* Returns content digest for $response.
*
* @return string
*/
protected function generateContentDigest(Response $response)
protected function generateContentDigest(Response $response): string
{
return 'en'.hash('sha256', $response->getContent());
return 'en'.hash('xxh128', $response->getContent());
}
/**
@@ -309,7 +303,7 @@ class Store implements StoreInterface
*
* @return bool true if the URL exists with either HTTP or HTTPS scheme and has been purged, false otherwise
*/
public function purge(string $url)
public function purge(string $url): bool
{
$http = preg_replace('#^https:#', 'http:', $url);
$https = preg_replace('#^http:#', 'https:', $url);
@@ -418,10 +412,8 @@ class Store implements StoreInterface
* If the same URI can have more than one representation, based on some
* headers, use a Vary header to indicate them, and each representation will
* be stored independently under the same cache key.
*
* @return string
*/
protected function generateCacheKey(Request $request)
protected function generateCacheKey(Request $request): string
{
return 'md'.hash('sha256', $request->getUri());
}

View File

@@ -26,10 +26,8 @@ interface StoreInterface
{
/**
* Locates a cached Response for the Request provided.
*
* @return Response|null
*/
public function lookup(Request $request);
public function lookup(Request $request): ?Response;
/**
* Writes a cache entry to the store for the given Request and Response.
@@ -39,7 +37,7 @@ interface StoreInterface
*
* @return string The key under which the response is stored
*/
public function write(Request $request, Response $response);
public function write(Request $request, Response $response): string;
/**
* Invalidates all cache entries that match the request.
@@ -51,28 +49,28 @@ interface StoreInterface
*
* @return bool|string true if the lock is acquired, the path to the current lock otherwise
*/
public function lock(Request $request);
public function lock(Request $request): bool|string;
/**
* Releases the lock for the given Request.
*
* @return bool False if the lock file does not exist or cannot be unlocked, true otherwise
*/
public function unlock(Request $request);
public function unlock(Request $request): bool;
/**
* Returns whether or not a lock exists.
*
* @return bool true if lock exists, false otherwise
*/
public function isLocked(Request $request);
public function isLocked(Request $request): bool;
/**
* Purges data for the given URL.
*
* @return bool true if the URL exists and has been purged, false otherwise
*/
public function purge(string $url);
public function purge(string $url): bool;
/**
* Cleanups storage.

View File

@@ -18,24 +18,18 @@ interface SurrogateInterface
{
/**
* Returns surrogate name.
*
* @return string
*/
public function getName();
public function getName(): string;
/**
* Returns a new cache strategy instance.
*
* @return ResponseCacheStrategyInterface
*/
public function createCacheStrategy();
public function createCacheStrategy(): ResponseCacheStrategyInterface;
/**
* Checks that at least one surrogate has Surrogate capability.
*
* @return bool
*/
public function hasSurrogateCapability(Request $request);
public function hasSurrogateCapability(Request $request): bool;
/**
* Adds Surrogate-capability to the given Request.
@@ -51,37 +45,29 @@ interface SurrogateInterface
/**
* Checks that the Response needs to be parsed for Surrogate tags.
*
* @return bool
*/
public function needsParsing(Response $response);
public function needsParsing(Response $response): bool;
/**
* Renders a Surrogate tag.
*
* @param string $alt An alternate URI
* @param string $comment A comment to add as an esi:include tag
*
* @return string
*/
public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = '');
public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = ''): string;
/**
* Replaces a Response Surrogate tags with the included resource content.
*
* @return Response
*/
public function process(Request $request, Response $response);
public function process(Request $request, Response $response): Response;
/**
* Handles a Surrogate from the cache.
*
* @param string $alt An alternative URI
*
* @return string
*
* @throws \RuntimeException
* @throws \Exception
*/
public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors);
public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors): string;
}