Update dependencies

This commit is contained in:
Chris Hunt
2024-02-16 21:36:54 +00:00
parent 22d7a59e59
commit d52ae0d3c3
9569 changed files with 460443 additions and 282416 deletions

View File

@@ -29,13 +29,15 @@ use Symfony\Component\HttpKernel\TerminableInterface;
*/
class HttpCache implements HttpKernelInterface, TerminableInterface
{
private $kernel;
private $store;
private $request;
private $surrogate;
private $surrogateCacheStrategy;
private $options = [];
private $traces = [];
public const BODY_EVAL_BOUNDARY_LENGTH = 24;
private HttpKernelInterface $kernel;
private StoreInterface $store;
private Request $request;
private ?SurrogateInterface $surrogate;
private ?ResponseCacheStrategyInterface $surrogateCacheStrategy = null;
private array $options = [];
private array $traces = [];
/**
* Constructor.
@@ -60,6 +62,9 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
* on responses that don't explicitly state whether the response is
* public or private via a Cache-Control directive. (default: Authorization and Cookie)
*
* * skip_response_headers Set of response headers that are never cached even if a response is cacheable (public).
* (default: Set-Cookie)
*
* * allow_reload Specifies whether the client can force a cache reload by including a
* Cache-Control "no-cache" directive in the request. Set it to ``true``
* for compliance with RFC 2616. (default: false)
@@ -78,26 +83,33 @@ 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 = [])
public function __construct(HttpKernelInterface $kernel, StoreInterface $store, ?SurrogateInterface $surrogate = null, array $options = [])
{
$this->store = $store;
$this->kernel = $kernel;
$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,
'default_ttl' => 0,
'private_headers' => ['Authorization', 'Cookie'],
'skip_response_headers' => ['Set-Cookie'],
'allow_reload' => false,
'allow_revalidate' => false,
'stale_while_revalidate' => 2,
'stale_if_error' => 60,
'trace_level' => 'none',
'trace_header' => 'X-Symfony-Cache',
'terminate_on_cache_hit' => true,
], $options);
if (!isset($options['trace_level'])) {
@@ -107,25 +119,21 @@ 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;
}
private function addTraces(Response $response)
private function addTraces(Response $response): void
{
$traceString = null;
@@ -144,10 +152,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 +165,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 +182,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) {
@@ -246,10 +243,19 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
}
/**
* {@inheritdoc}
* @return void
*/
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 +265,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 +278,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 +324,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 +370,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 +431,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;
@@ -469,11 +465,9 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
*
* @return Response
*/
protected function forward(Request $request, bool $catch = false, Response $entry = null)
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 +517,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 +533,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 +552,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);
@@ -603,13 +595,24 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
/**
* Writes the Response to the cache.
*
* @return void
*
* @throws \Exception
*/
protected function store(Request $request, Response $response)
{
try {
$this->store->write($request, $response);
$restoreHeaders = [];
foreach ($this->options['skip_response_headers'] as $header) {
if (!$response->headers->has($header)) {
continue;
}
$restoreHeaders[$header] = $response->headers->all($header);
$response->headers->remove($header);
}
$this->store->write($request, $response);
$this->record($request, 'store');
$response->headers->set('Age', $response->getAge());
@@ -619,6 +622,10 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
if ($this->options['debug']) {
throw $e;
}
} finally {
foreach ($restoreHeaders as $header => $values) {
$response->headers->set($header, $values);
}
}
// now that the response is cached, release the lock
@@ -628,15 +635,25 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
/**
* Restores the Response body.
*/
private function restoreResponseBody(Request $request, Response $response)
private function restoreResponseBody(Request $request, Response $response): void
{
if ($response->headers->has('X-Body-Eval')) {
\assert(self::BODY_EVAL_BOUNDARY_LENGTH === 24);
ob_start();
if ($response->headers->has('X-Body-File')) {
include $response->headers->get('X-Body-File');
} else {
eval('; ?>'.$response->getContent().'<?php ;');
$content = $response->getContent();
$boundary = substr($content, 0, 24);
$j = strpos($content, $boundary, 24);
echo substr($content, 24, $j - 24);
$i = $j + 24;
while (false !== $j = strpos($content, $boundary, $i)) {
[$uri, $alt, $ignoreErrors, $part] = explode("\n", substr($content, $i, $j - $i), 4);
$i = $j + 24;
echo $this->surrogate->handle($this, $uri, $alt, $ignoreErrors);
echo $part;
}
$response->setContent(ob_get_clean());
@@ -657,9 +674,12 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
$response->headers->remove('X-Body-File');
}
/**
* @return void
*/
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);
}
}
@@ -688,7 +708,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
/**
* Records that an event took place.
*/
private function record(Request $request, string $event)
private function record(Request $request, string $event): void
{
$this->traces[$this->getTraceKey($request)][] = $event;
}
@@ -713,12 +733,13 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
private function mayServeStaleWhileRevalidate(Response $entry): bool
{
$timeout = $entry->headers->getCacheControlDirective('stale-while-revalidate');
$timeout ??= $this->options['stale_while_revalidate'];
if (null === $timeout) {
$timeout = $this->options['stale_while_revalidate'];
}
$age = $entry->getAge();
$maxAge = $entry->getMaxAge() ?? 0;
$ttl = $maxAge - $age;
return abs($entry->getTtl() ?? 0) < $timeout;
return abs($ttl) < $timeout;
}
/**