Aggiornato Composer

This commit is contained in:
Paolo A
2024-05-17 12:24:19 +00:00
parent 4ac62108b5
commit ec201d75b2
2238 changed files with 38684 additions and 59785 deletions

View File

@@ -95,7 +95,7 @@ abstract class AbstractSurrogate implements SurrogateInterface
try {
$response = $cache->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true);
if (!$response->isSuccessful()) {
if (!$response->isSuccessful() && Response::HTTP_NOT_MODIFIED !== $response->getStatusCode()) {
throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %d).', $subRequest->getUri(), $response->getStatusCode()));
}
@@ -133,4 +133,15 @@ abstract class AbstractSurrogate implements SurrogateInterface
$response->headers->set('Surrogate-Control', preg_replace(sprintf('#content="%s/1.0",\s*#', $upperName), '', $value));
}
}
protected static function generateBodyEvalBoundary(): string
{
static $cookie;
$cookie = hash('md5', $cookie ?? $cookie = random_bytes(16), true);
$boundary = base64_encode($cookie);
\assert(HttpCache::BODY_EVAL_BOUNDARY_LENGTH === \strlen($boundary));
return $boundary;
}
}

View File

@@ -45,7 +45,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 = '')
{
$html = sprintf('<esi:include src="%s"%s%s />',
$uri,
@@ -80,8 +80,8 @@ class Esi extends AbstractSurrogate
$content = preg_replace('#<esi\:remove>.*?</esi\:remove>#s', '', $content);
$content = preg_replace('#<esi\:comment[^>]+>#s', '', $content);
$boundary = self::generateBodyEvalBoundary();
$chunks = preg_split('#<esi\:include\s+(.*?)\s*(?:/|</esi\:include)>#', $content, -1, \PREG_SPLIT_DELIM_CAPTURE);
$chunks[0] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[0]);
$i = 1;
while (isset($chunks[$i])) {
@@ -95,16 +95,10 @@ class Esi extends AbstractSurrogate
throw new \RuntimeException('Unable to process an ESI tag without a "src" attribute.');
}
$chunks[$i] = sprintf('<?php echo $this->surrogate->handle($this, %s, %s, %s) ?>'."\n",
var_export($options['src'], true),
var_export($options['alt'] ?? '', true),
isset($options['onerror']) && 'continue' === $options['onerror'] ? 'true' : 'false'
);
++$i;
$chunks[$i] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[$i]);
++$i;
$chunks[$i] = $boundary.$options['src']."\n".($options['alt'] ?? '')."\n".('continue' === ($options['onerror'] ?? ''))."\n";
$i += 2;
}
$content = implode('', $chunks);
$content = $boundary.implode('', $chunks).$boundary;
$response->setContent($content);
$response->headers->set('X-Body-Eval', 'ESI');

View File

@@ -29,6 +29,8 @@ use Symfony\Component\HttpKernel\TerminableInterface;
*/
class HttpCache implements HttpKernelInterface, TerminableInterface
{
public const BODY_EVAL_BOUNDARY_LENGTH = 24;
private $kernel;
private $store;
private $request;
@@ -79,7 +81,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
* This setting is overridden by the stale-if-error HTTP Cache-Control extension
* (see RFC 5861).
*/
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;
@@ -469,7 +471,7 @@ 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);
@@ -631,12 +633,22 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
private function restoreResponseBody(Request $request, Response $response)
{
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());
@@ -718,7 +730,11 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
$timeout = $this->options['stale_while_revalidate'];
}
return abs($entry->getTtl()) < $timeout;
$age = $entry->getAge();
$maxAge = $entry->getMaxAge() ?? 0;
$ttl = $maxAge - $age;
return abs($ttl) < $timeout;
}
/**

View File

@@ -147,7 +147,7 @@ class ResponseCacheStrategy implements ResponseCacheStrategyInterface
if (is_numeric($this->ageDirectives['expires'])) {
$date = clone $response->getDate();
$date->modify('+'.($this->ageDirectives['expires'] + $this->age).' seconds');
$date = $date->modify('+'.($this->ageDirectives['expires'] + $this->age).' seconds');
$response->setExpires($date);
}
}

View File

@@ -42,7 +42,7 @@ 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 = '')
{
return sprintf('<!--#include virtual="%s" -->', $uri);
}
@@ -64,9 +64,8 @@ class Ssi extends AbstractSurrogate
// we don't use a proper XML parser here as we can have SSI tags in a plain text response
$content = $response->getContent();
$boundary = self::generateBodyEvalBoundary();
$chunks = preg_split('#<!--\#include\s+(.*?)\s*-->#', $content, -1, \PREG_SPLIT_DELIM_CAPTURE);
$chunks[0] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[0]);
$i = 1;
while (isset($chunks[$i])) {
@@ -80,14 +79,10 @@ class Ssi extends AbstractSurrogate
throw new \RuntimeException('Unable to process an SSI tag without a "virtual" attribute.');
}
$chunks[$i] = sprintf('<?php echo $this->surrogate->handle($this, %s, \'\', false) ?>'."\n",
var_export($options['virtual'], true)
);
++$i;
$chunks[$i] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[$i]);
++$i;
$chunks[$i] = $boundary.$options['virtual']."\n\n\n";
$i += 2;
}
$content = implode('', $chunks);
$content = $boundary.implode('', $chunks).$boundary;
$response->setContent($content);
$response->headers->set('X-Body-Eval', 'SSI');

View File

@@ -29,17 +29,28 @@ class Store implements StoreInterface
private $keyCache;
/** @var array<string, resource> */
private $locks = [];
private $options;
/**
* Constructor.
*
* The available options are:
*
* * private_headers Set of response headers that should not be stored
* when a response is cached. (default: Set-Cookie)
*
* @throws \RuntimeException
*/
public function __construct(string $root)
public function __construct(string $root, array $options = [])
{
$this->root = $root;
if (!is_dir($this->root) && !@mkdir($this->root, 0777, true) && !is_dir($this->root)) {
throw new \RuntimeException(sprintf('Unable to create the store directory (%s).', $this->root));
}
$this->keyCache = new \SplObjectStorage();
$this->options = array_merge([
'private_headers' => ['Set-Cookie'],
], $options);
}
/**
@@ -186,7 +197,7 @@ class Store implements StoreInterface
if ($this->getPath($digest) !== $response->headers->get('X-Body-File')) {
throw new \RuntimeException('X-Body-File and X-Content-Digest do not match.');
}
// Everything seems ok, omit writing content to disk
// Everything seems ok, omit writing content to disk
} else {
$digest = $this->generateContentDigest($response);
$response->headers->set('X-Content-Digest', $digest);
@@ -216,6 +227,10 @@ class Store implements StoreInterface
$headers = $this->persistResponse($response);
unset($headers['age']);
foreach ($this->options['private_headers'] as $h) {
unset($headers[strtolower($h)]);
}
array_unshift($entries, [$storedEnv, $headers]);
if (!$this->save($key, serialize($entries))) {
@@ -460,15 +475,25 @@ class Store implements StoreInterface
/**
* Restores a Response from the HTTP headers and body.
*/
private function restoreResponse(array $headers, string $path = null): Response
private function restoreResponse(array $headers, ?string $path = null): ?Response
{
$status = $headers['X-Status'][0];
unset($headers['X-Status']);
$content = null;
if (null !== $path) {
$headers['X-Body-File'] = [$path];
unset($headers['x-body-file']);
if ($headers['X-Body-Eval'] ?? $headers['x-body-eval'] ?? false) {
$content = file_get_contents($path);
\assert(HttpCache::BODY_EVAL_BOUNDARY_LENGTH === 24);
if (48 > \strlen($content) || substr($content, -24) !== substr($content, 0, 24)) {
return null;
}
}
}
return new Response($path, $status, $headers);
return new Response($content, $status, $headers);
}
}

View File

@@ -59,12 +59,12 @@ interface SurrogateInterface
/**
* Renders a Surrogate tag.
*
* @param string $alt An alternate URI
* @param string $comment A comment to add as an esi:include tag
* @param string|null $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 = '');
/**
* Replaces a Response Surrogate tags with the included resource content.