diff options
| author | Greg Roach <fisharebest@webtrees.net> | 2019-03-06 10:34:32 +0000 |
|---|---|---|
| committer | Greg Roach <fisharebest@webtrees.net> | 2019-03-06 10:34:32 +0000 |
| commit | d250673fd02596cce82a1fbc789be57c0f4bf3fd (patch) | |
| tree | 20f32eb94c00fd78052da031b27fcc516c26f85a /vendor/symfony/http-kernel | |
| parent | 9c811d4799f06f28d9bfb1399c2ffa6bab93c682 (diff) | |
| download | webtrees-d250673fd02596cce82a1fbc789be57c0f4bf3fd.tar.gz webtrees-d250673fd02596cce82a1fbc789be57c0f4bf3fd.tar.bz2 webtrees-d250673fd02596cce82a1fbc789be57c0f4bf3fd.zip | |
Update vendor dependencies
Diffstat (limited to 'vendor/symfony/http-kernel')
7 files changed, 397 insertions, 55 deletions
diff --git a/vendor/symfony/http-kernel/DataCollector/DataCollector.php b/vendor/symfony/http-kernel/DataCollector/DataCollector.php index 14ea230f57..efe1705179 100644 --- a/vendor/symfony/http-kernel/DataCollector/DataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/DataCollector.php @@ -34,9 +34,6 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable */ private $cloner; - /** - * @internal - */ public function serialize() { $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2); @@ -45,9 +42,6 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable return $isCalledFromOverridingMethod ? $this->data : serialize($this->data); } - /** - * @internal - */ public function unserialize($data) { $this->data = \is_array($data) ? $data : unserialize($data); diff --git a/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php b/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php index 04ea44a073..323ebf2054 100644 --- a/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php @@ -133,9 +133,6 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface $this->clonesIndex = 0; } - /** - * @internal - */ public function serialize() { if ($this->clonesCount !== $this->clonesIndex) { @@ -152,9 +149,6 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface return $ser; } - /** - * @internal - */ public function unserialize($data) { $this->data = unserialize($data); diff --git a/vendor/symfony/http-kernel/EventListener/ExceptionListener.php b/vendor/symfony/http-kernel/EventListener/ExceptionListener.php index dd00797f5f..811f99bd9d 100644 --- a/vendor/symfony/http-kernel/EventListener/ExceptionListener.php +++ b/vendor/symfony/http-kernel/EventListener/ExceptionListener.php @@ -79,13 +79,12 @@ class ExceptionListener implements EventSubscriberInterface $this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', $f->getClass(), $f->getMessage(), $e->getFile(), $e->getLine())); - $wrapper = $e; - - while ($prev = $wrapper->getPrevious()) { + $prev = $e; + do { if ($exception === $wrapper = $prev) { throw $e; } - } + } while ($prev = $wrapper->getPrevious()); $prev = new \ReflectionProperty($wrapper instanceof \Exception ? \Exception::class : \Error::class, 'previous'); $prev->setAccessible(true); diff --git a/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php b/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php index 5ee09fb1a7..c01b09559a 100644 --- a/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php +++ b/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php @@ -80,7 +80,7 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer return SubRequestHandler::handle($this->kernel, $subRequest, HttpKernelInterface::SUB_REQUEST, false); } catch (\Exception $e) { // we dispatch the exception event to trigger the logging - // the response that comes back is simply ignored + // the response that comes back is ignored if (isset($options['ignore_errors']) && $options['ignore_errors'] && $this->dispatcher) { $event = new GetResponseForExceptionEvent($this->kernel, $request, HttpKernelInterface::SUB_REQUEST, $e); diff --git a/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php b/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php index 168e9564b0..862bac557d 100644 --- a/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php +++ b/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php @@ -5,10 +5,6 @@ * * (c) Fabien Potencier <fabien@symfony.com> * - * This code is partially based on the Rack-Cache library by Ryan Tomayko, - * which is released under the MIT license. - * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801) - * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ @@ -28,30 +24,69 @@ use Symfony\Component\HttpFoundation\Response; */ class ResponseCacheStrategy implements ResponseCacheStrategyInterface { - private $cacheable = true; + /** + * Cache-Control headers that are sent to the final response if they appear in ANY of the responses. + */ + private static $overrideDirectives = ['private', 'no-cache', 'no-store', 'no-transform', 'must-revalidate', 'proxy-revalidate']; + + /** + * Cache-Control headers that are sent to the final response if they appear in ALL of the responses. + */ + private static $inheritDirectives = ['public', 'immutable']; + private $embeddedResponses = 0; - private $ttls = []; - private $maxAges = []; private $isNotCacheableResponseEmbedded = false; + private $age = 0; + private $flagDirectives = [ + 'no-cache' => null, + 'no-store' => null, + 'no-transform' => null, + 'must-revalidate' => null, + 'proxy-revalidate' => null, + 'public' => null, + 'private' => null, + 'immutable' => null, + ]; + private $ageDirectives = [ + 'max-age' => null, + 's-maxage' => null, + 'expires' => null, + ]; /** * {@inheritdoc} */ public function add(Response $response) { - if (!$response->isFresh() || !$response->isCacheable()) { - $this->cacheable = false; - } else { - $maxAge = $response->getMaxAge(); - $this->ttls[] = $response->getTtl(); - $this->maxAges[] = $maxAge; + ++$this->embeddedResponses; - if (null === $maxAge) { - $this->isNotCacheableResponseEmbedded = true; + foreach (self::$overrideDirectives as $directive) { + if ($response->headers->hasCacheControlDirective($directive)) { + $this->flagDirectives[$directive] = true; } } - ++$this->embeddedResponses; + foreach (self::$inheritDirectives as $directive) { + if (false !== $this->flagDirectives[$directive]) { + $this->flagDirectives[$directive] = $response->headers->hasCacheControlDirective($directive); + } + } + + $age = $response->getAge(); + $this->age = max($this->age, $age); + + if ($this->willMakeFinalResponseUncacheable($response)) { + $this->isNotCacheableResponseEmbedded = true; + + return; + } + + $this->storeRelativeAgeDirective('max-age', $response->headers->getCacheControlDirective('max-age'), $age); + $this->storeRelativeAgeDirective('s-maxage', $response->headers->getCacheControlDirective('s-maxage') ?: $response->headers->getCacheControlDirective('max-age'), $age); + + $expires = $response->getExpires(); + $expires = null !== $expires ? $expires->format('U') - $response->getDate()->format('U') : null; + $this->storeRelativeAgeDirective('expires', $expires >= 0 ? $expires : null, 0); } /** @@ -64,33 +99,124 @@ class ResponseCacheStrategy implements ResponseCacheStrategyInterface return; } - // Remove validation related headers in order to avoid browsers using - // their own cache, because some of the response content comes from - // at least one embedded response (which likely has a different caching strategy). - if ($response->isValidateable()) { - $response->setEtag(null); - $response->setLastModified(null); + // 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). + $response->setEtag(null); + $response->setLastModified(null); + + $this->add($response); + + $response->headers->set('Age', $this->age); + + if ($this->isNotCacheableResponseEmbedded) { + $response->setExpires($response->getDate()); + + if ($this->flagDirectives['no-store']) { + $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate'); + } else { + $response->headers->set('Cache-Control', 'no-cache, must-revalidate'); + } + + return; } - if (!$response->isFresh() || !$response->isCacheable()) { - $this->cacheable = false; + $flags = array_filter($this->flagDirectives); + + if (isset($flags['must-revalidate'])) { + $flags['no-cache'] = true; } - if (!$this->cacheable) { - $response->headers->set('Cache-Control', 'no-cache, must-revalidate'); + $response->headers->set('Cache-Control', implode(', ', array_keys($flags))); - return; + $maxAge = null; + $sMaxage = null; + + if (\is_numeric($this->ageDirectives['max-age'])) { + $maxAge = $this->ageDirectives['max-age'] + $this->age; + $response->headers->addCacheControlDirective('max-age', $maxAge); } - $this->ttls[] = $response->getTtl(); - $this->maxAges[] = $response->getMaxAge(); + if (\is_numeric($this->ageDirectives['s-maxage'])) { + $sMaxage = $this->ageDirectives['s-maxage'] + $this->age; - if ($this->isNotCacheableResponseEmbedded) { - $response->headers->removeCacheControlDirective('s-maxage'); - } elseif (null !== $maxAge = min($this->maxAges)) { - $response->setSharedMaxAge($maxAge); - $response->headers->set('Age', $maxAge - min($this->ttls)); + if ($maxAge !== $sMaxage) { + $response->headers->addCacheControlDirective('s-maxage', $sMaxage); + } + } + + if (\is_numeric($this->ageDirectives['expires'])) { + $date = clone $response->getDate(); + $date->modify('+'.($this->ageDirectives['expires'] + $this->age).' seconds'); + $response->setExpires($date); + } + } + + /** + * RFC2616, Section 13.4. + * + * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 + * + * @return bool + */ + private function willMakeFinalResponseUncacheable(Response $response) + { + // 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') + ) { + return true; + } + + // Last-Modified and 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() + ) { + return false; + } + + // RFC2616: A response received with any other status code (e.g. status codes 302 and 307) + // MUST NOT be returned in a reply to a subsequent request unless there are + // cache-control directives or another header(s) that explicitly allow it. + $cacheControl = ['max-age', 's-maxage', 'must-revalidate', 'proxy-revalidate', 'public', 'private']; + foreach ($cacheControl as $key) { + if ($response->headers->hasCacheControlDirective($key)) { + return false; + } + } + + if ($response->headers->has('Expires')) { + return false; + } + + return true; + } + + /** + * Store lowest max-age/s-maxage/expires for the final response. + * + * The response might have been stored in cache a while ago. To keep things comparable, + * we have to subtract the age so that the value is normalized for an age of 0. + * + * If the value is lower than the currently stored value, we update the value, to keep a rolling + * minimal value of each instruction. If the value is NULL, the directive will not be set on the final response. + * + * @param string $directive + * @param int|null $value + * @param int $age + */ + private function storeRelativeAgeDirective($directive, $value, $age) + { + if (null === $value) { + $this->ageDirectives[$directive] = false; + } + + if (false !== $this->ageDirectives[$directive]) { + $value = $value - $age; + $this->ageDirectives[$directive] = null !== $this->ageDirectives[$directive] ? min($this->ageDirectives[$directive], $value) : $value; } - $response->setMaxAge(0); } } diff --git a/vendor/symfony/http-kernel/Kernel.php b/vendor/symfony/http-kernel/Kernel.php index c5e351ca3a..6737caee9e 100644 --- a/vendor/symfony/http-kernel/Kernel.php +++ b/vendor/symfony/http-kernel/Kernel.php @@ -73,11 +73,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.2.3'; - const VERSION_ID = 40203; + const VERSION = '4.2.4'; + const VERSION_ID = 40204; const MAJOR_VERSION = 4; const MINOR_VERSION = 2; - const RELEASE_VERSION = 3; + const RELEASE_VERSION = 4; const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '07/2019'; diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/ResponseCacheStrategyTest.php b/vendor/symfony/http-kernel/Tests/HttpCache/ResponseCacheStrategyTest.php index 6d67a17739..22cadf7129 100644 --- a/vendor/symfony/http-kernel/Tests/HttpCache/ResponseCacheStrategyTest.php +++ b/vendor/symfony/http-kernel/Tests/HttpCache/ResponseCacheStrategyTest.php @@ -237,4 +237,233 @@ class ResponseCacheStrategyTest extends TestCase $this->assertSame('60', $masterResponse->headers->getCacheControlDirective('s-maxage')); $this->assertFalse($masterResponse->isValidateable()); } + + /** + * @dataProvider cacheControlMergingProvider + */ + public function testCacheControlMerging(array $expects, array $master, array $surrogates) + { + $cacheStrategy = new ResponseCacheStrategy(); + $buildResponse = function ($config) { + $response = new Response(); + + foreach ($config as $key => $value) { + switch ($key) { + case 'age': + $response->headers->set('Age', $value); + break; + + case 'expires': + $expires = clone $response->getDate(); + $expires->modify('+'.$value.' seconds'); + $response->setExpires($expires); + break; + + case 'max-age': + $response->setMaxAge($value); + break; + + case 's-maxage': + $response->setSharedMaxAge($value); + break; + + case 'private': + $response->setPrivate(); + break; + + case 'public': + $response->setPublic(); + break; + + default: + $response->headers->addCacheControlDirective($key, $value); + } + } + + return $response; + }; + + foreach ($surrogates as $config) { + $cacheStrategy->add($buildResponse($config)); + } + + $response = $buildResponse($master); + $cacheStrategy->update($response); + + foreach ($expects as $key => $value) { + if ('expires' === $key) { + $this->assertSame($value, $response->getExpires()->format('U') - $response->getDate()->format('U')); + } elseif ('age' === $key) { + $this->assertSame($value, $response->getAge()); + } elseif (true === $value) { + $this->assertTrue($response->headers->hasCacheControlDirective($key), sprintf('Cache-Control header must have "%s" flag', $key)); + } elseif (false === $value) { + $this->assertFalse( + $response->headers->hasCacheControlDirective($key), + sprintf('Cache-Control header must NOT have "%s" flag', $key) + ); + } else { + $this->assertSame($value, $response->headers->getCacheControlDirective($key), sprintf('Cache-Control flag "%s" should be "%s"', $key, $value)); + } + } + } + + public function cacheControlMergingProvider() + { + yield 'result is public if all responses are public' => [ + ['private' => false, 'public' => true], + ['public' => true], + [ + ['public' => true], + ], + ]; + + yield 'result is private by default' => [ + ['private' => true, 'public' => false], + ['public' => true], + [ + [], + ], + ]; + + yield 'combines public and private responses' => [ + ['must-revalidate' => false, 'private' => true, 'public' => false], + ['public' => true], + [ + ['private' => true], + ], + ]; + + yield 'inherits no-cache from surrogates' => [ + ['no-cache' => true, 'public' => false], + ['public' => true], + [ + ['no-cache' => true], + ], + ]; + + yield 'inherits no-store from surrogate' => [ + ['no-store' => true, 'public' => false], + ['public' => true], + [ + ['no-store' => true], + ], + ]; + + yield 'resolve to lowest possible max-age' => [ + ['public' => false, 'private' => true, 's-maxage' => false, 'max-age' => '60'], + ['public' => true, 'max-age' => 3600], + [ + ['private' => true, 'max-age' => 60], + ], + ]; + + yield 'resolves multiple max-age' => [ + ['public' => false, 'private' => true, 's-maxage' => false, 'max-age' => '60'], + ['private' => true, 'max-age' => 100], + [ + ['private' => true, 'max-age' => 3600], + ['public' => true, 'max-age' => 60, 's-maxage' => 60], + ['private' => true, 'max-age' => 60], + ], + ]; + + yield 'merge max-age and s-maxage' => [ + ['public' => true, 's-maxage' => '60', 'max-age' => null], + ['public' => true, 's-maxage' => 3600], + [ + ['public' => true, 'max-age' => 60], + ], + ]; + + yield 'result is private when combining private responses' => [ + ['no-cache' => false, 'must-revalidate' => false, 'private' => true], + ['s-maxage' => 60, 'private' => true], + [ + ['s-maxage' => 60, 'private' => true], + ], + ]; + + yield 'result can have s-maxage and max-age' => [ + ['public' => true, 'private' => false, 's-maxage' => '60', 'max-age' => '30'], + ['s-maxage' => 100, 'max-age' => 2000], + [ + ['s-maxage' => 1000, 'max-age' => 30], + ['s-maxage' => 500, 'max-age' => 500], + ['s-maxage' => 60, 'max-age' => 1000], + ], + ]; + + yield 'does not set headers without value' => [ + ['max-age' => null, 's-maxage' => null, 'public' => null], + ['private' => true], + [ + ['private' => true], + ], + ]; + + yield 'max-age 0 is sent to the client' => [ + ['private' => true, 'max-age' => '0'], + ['max-age' => 0, 'private' => true], + [ + ['max-age' => 60, 'private' => true], + ], + ]; + + yield 'max-age is relative to age' => [ + ['max-age' => '240', 'age' => 60], + ['max-age' => 180], + [ + ['max-age' => 600, 'age' => 60], + ], + ]; + + yield 'retains lowest age of all responses' => [ + ['max-age' => '160', 'age' => 60], + ['max-age' => 600, 'age' => 60], + [ + ['max-age' => 120, 'age' => 20], + ], + ]; + + yield 'max-age can be less than age, essentially expiring the response' => [ + ['age' => 120, 'max-age' => '90'], + ['max-age' => 90, 'age' => 120], + [ + ['max-age' => 120, 'age' => 60], + ], + ]; + + yield 'max-age is 0 regardless of age' => [ + ['max-age' => '0'], + ['max-age' => 60], + [ + ['max-age' => 0, 'age' => 60], + ], + ]; + + yield 'max-age is not negative' => [ + ['max-age' => '0'], + ['max-age' => 0], + [ + ['max-age' => 0, 'age' => 60], + ], + ]; + + yield 'calculates lowest Expires header' => [ + ['expires' => 60], + ['expires' => 60], + [ + ['expires' => 120], + ], + ]; + + yield 'calculates Expires header relative to age' => [ + ['expires' => 210, 'age' => 120], + ['expires' => 90], + [ + ['expires' => 600, 'age' => '120'], + ], + ]; + } } |
