Chris@0: Chris@0: * Chris@0: * This code is partially based on the Rack-Cache library by Ryan Tomayko, Chris@0: * which is released under the MIT license. Chris@0: * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801) Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\HttpKernel\HttpCache; Chris@0: Chris@0: use Symfony\Component\HttpFoundation\Response; Chris@0: Chris@0: /** Chris@0: * ResponseCacheStrategy knows how to compute the Response cache HTTP header Chris@0: * based on the different response cache headers. Chris@0: * Chris@0: * This implementation changes the master response TTL to the smallest TTL received Chris@0: * or force validation if one of the surrogates has validation cache strategy. Chris@0: * Chris@0: * @author Fabien Potencier Chris@0: */ Chris@0: class ResponseCacheStrategy implements ResponseCacheStrategyInterface Chris@0: { Chris@0: private $cacheable = true; Chris@0: private $embeddedResponses = 0; Chris@0: private $ttls = array(); Chris@0: private $maxAges = array(); Chris@0: private $isNotCacheableResponseEmbedded = false; Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function add(Response $response) Chris@0: { Chris@0: if ($response->isValidateable()) { Chris@0: $this->cacheable = false; Chris@0: } else { Chris@0: $maxAge = $response->getMaxAge(); Chris@0: $this->ttls[] = $response->getTtl(); Chris@0: $this->maxAges[] = $maxAge; Chris@0: Chris@0: if (null === $maxAge) { Chris@0: $this->isNotCacheableResponseEmbedded = true; Chris@0: } Chris@0: } Chris@0: Chris@0: ++$this->embeddedResponses; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function update(Response $response) Chris@0: { Chris@0: // if we have no embedded Response, do nothing Chris@0: if (0 === $this->embeddedResponses) { Chris@0: return; Chris@0: } Chris@0: Chris@0: // Remove validation related headers in order to avoid browsers using Chris@0: // their own cache, because some of the response content comes from Chris@0: // at least one embedded response (which likely has a different caching strategy). Chris@0: if ($response->isValidateable()) { Chris@0: $response->setEtag(null); Chris@0: $response->setLastModified(null); Chris@0: $this->cacheable = false; Chris@0: } Chris@0: Chris@0: if (!$this->cacheable) { Chris@0: $response->headers->set('Cache-Control', 'no-cache, must-revalidate'); Chris@0: Chris@0: return; Chris@0: } Chris@0: Chris@0: $this->ttls[] = $response->getTtl(); Chris@0: $this->maxAges[] = $response->getMaxAge(); Chris@0: Chris@0: if ($this->isNotCacheableResponseEmbedded) { Chris@0: $response->headers->removeCacheControlDirective('s-maxage'); Chris@0: } elseif (null !== $maxAge = min($this->maxAges)) { Chris@0: $response->setSharedMaxAge($maxAge); Chris@0: $response->headers->set('Age', $maxAge - min($this->ttls)); Chris@0: } Chris@0: $response->setMaxAge(0); Chris@0: } Chris@0: }