/** * Validates that a cache entry is fresh. * * The original request is used as a template for a conditional * GET request with the backend. * * @param Symfony\Components\HttpFoundation\Request $request A Request instance * @param Symfony\Components\HttpFoundation\Response $entry A Response instance to validate * * @return Symfony\Components\HttpFoundation\Response A Response instance */ protected function validate(Request $request, $entry) { $subRequest = clone $request; // send no head requests because we want content $subRequest->setMethod('get'); // add our cached last-modified validator $subRequest->headers->set('if_modified_since', $entry->headers->get('Last-Modified')); // Add our cached etag validator to the environment. // We keep the etags from the client to handle the case when the client // has a different private valid entry which is not cached here. $cachedEtags = array($entry->getEtag()); $requestEtags = $request->getEtags(); $etags = array_unique(array_merge($cachedEtags, $requestEtags)); $subRequest->headers->set('if_none_match', $etags ? implode(', ', $etags) : ''); $response = $this->forward($subRequest, false, $entry); if (304 == $response->getStatusCode()) { $this->record($request, 'valid'); // return the response and not the cache entry if the response is valid but not cached $etag = $response->getEtag(); if ($etag && in_array($etag, $requestEtags) && !in_array($etag, $cachedEtags)) { return $response; } $entry = clone $entry; $entry->headers->delete('Date'); foreach (array('Date', 'Expires', 'Cache-Control', 'ETag', 'Last-Modified') as $name) { if ($response->headers->has($name)) { $entry->headers->set($name, $response->headers->get($name)); } } $response = $entry; } else { $this->record($request, 'invalid'); } if ($response->isCacheable()) { $this->store($request, $response); } return $response; }