This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
symfony/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php

632 lines
21 KiB
PHP
Raw Normal View History

2010-06-23 20:42:41 +01:00
<?php
/*
* This file is part of the Symfony package.
2010-06-23 20:42:41 +01:00
*
* (c) Fabien Potencier <fabien@symfony.com>
2010-06-23 20:42:41 +01:00
*
* 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.
2010-06-23 20:42:41 +01:00
*/
namespace Symfony\Component\HttpKernel\HttpCache;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
2010-06-23 20:42:41 +01:00
/**
* Cache provides HTTP caching.
*
* @author Fabien Potencier <fabien@symfony.com>
2010-06-23 20:42:41 +01:00
*/
class HttpCache implements HttpKernelInterface
2010-06-23 20:42:41 +01:00
{
private $kernel;
private $store;
private $request;
private $esi;
private $esiCacheStrategy;
private $traces;
2010-06-23 20:42:41 +01:00
/**
* Constructor.
*
* The available options are:
*
* * debug: If true, the traces are added as a HTTP header to ease debugging
*
* * default_ttl The number of seconds that a cache entry should be considered
* fresh when no explicit freshness information is provided in
* a response. Explicit Cache-Control or Expires headers
* override this value. (default: 0)
*
* * private_headers Set of request headers that trigger "private" cache-control behavior
* on responses that don't explicitly state whether the response is
* public or private via a Cache-Control directive. (default: Authorization and Cookie)
*
* * allow_reload Specifies whether the client can force a cache reload by including a
2010-10-30 19:46:39 +01:00
* Cache-Control "no-cache" directive in the request. Set it to ``true``
* for compliance with RFC 2616. (default: false)
2010-06-23 20:42:41 +01:00
*
* * allow_revalidate Specifies whether the client can force a cache revalidate by including
2010-10-30 19:46:39 +01:00
* a Cache-Control "max-age=0" directive in the request. Set it to ``true``
* for compliance with RFC 2616. (default: false)
2010-06-23 20:42:41 +01:00
*
* * stale_while_revalidate Specifies the default number of seconds (the granularity is the second as the
* Response TTL precision is a second) during which the cache can immediately return
* a stale response while it revalidates it in the background (default: 2).
2010-10-16 11:32:57 +01:00
* This setting is overridden by the stale-while-revalidate HTTP Cache-Control
2010-06-23 20:42:41 +01:00
* extension (see RFC 5861).
*
2010-10-16 11:32:57 +01:00
* * stale_if_error Specifies the default number of seconds (the granularity is the second) during which
2010-10-30 19:46:39 +01:00
* the cache can serve a stale response when an error is encountered (default: 60).
2010-10-16 11:32:57 +01:00
* This setting is overridden by the stale-if-error HTTP Cache-Control extension
2010-06-23 20:42:41 +01:00
* (see RFC 5861).
*
2011-04-23 16:05:44 +01:00
* @param HttpKernelInterface $kernel An HttpKernelInterface instance
* @param StoreInterface $store A Store instance
* @param Esi $esi An Esi instance
* @param array $options An array of options
2010-06-23 20:42:41 +01:00
*/
2011-01-31 13:10:53 +00:00
public function __construct(HttpKernelInterface $kernel, StoreInterface $store, Esi $esi = null, array $options = array())
2010-06-23 20:42:41 +01:00
{
$this->store = $store;
$this->kernel = $kernel;
// needed in case there is a fatal error because the backend is too slow to respond
2011-01-31 13:10:53 +00:00
register_shutdown_function(array($this->store, 'cleanup'));
2010-06-23 20:42:41 +01:00
$this->options = array_merge(array(
'debug' => false,
'default_ttl' => 0,
'private_headers' => array('Authorization', 'Cookie'),
'allow_reload' => false,
'allow_revalidate' => false,
'stale_while_revalidate' => 2,
'stale_if_error' => 60,
), $options);
$this->esi = $esi;
$this->traces = array();
2010-06-23 20:42:41 +01:00
}
/**
* Returns an array of events that took place during processing of the last request.
*
* @return array An array of events
*/
public function getTraces()
{
return $this->traces;
}
/**
* Returns a log message for the events of the last request processing.
*
* @return string A log message
*/
public function getLog()
{
$log = array();
foreach ($this->traces as $request => $traces) {
$log[] = sprintf('%s: %s', $request, implode(', ', $traces));
}
return implode('; ', $log);
}
/**
* Gets the Request instance associated with the master request.
*
* @return Symfony\Component\HttpFoundation\Request A Request instance
*/
public function getRequest()
{
return $this->request;
}
/**
* Gets the Kernel instance
*
* @return Symfony\Component\HttpKernel\HttpKernelInterface An HttpKernelInterface instance
*/
public function getKernel()
{
return $this->kernel;
}
/**
* Gets the Esi instance
*
* @return Symfony\Component\HttpKernel\HttpCache\Esi An Esi instance
*/
public function getEsi()
{
return $this->esi;
}
2010-06-23 20:42:41 +01:00
/**
* {@inheritdoc}
2010-06-23 20:42:41 +01:00
*/
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
2010-06-23 20:42:41 +01:00
{
2010-10-16 11:32:57 +01:00
// FIXME: catch exceptions and implement a 500 error page here? -> in Varnish, there is a built-in error page mechanism
2010-06-23 20:42:41 +01:00
if (HttpKernelInterface::MASTER_REQUEST === $type) {
$this->traces = array();
$this->request = $request;
if (null !== $this->esi) {
$this->esiCacheStrategy = $this->esi->createCacheStrategy();
}
2010-06-23 20:42:41 +01:00
}
$path = $request->getPathInfo();
if ($qs = $request->getQueryString()) {
$path .= '?'.$qs;
}
$this->traces[$request->getMethod().' '.$path] = array();
2010-06-23 20:42:41 +01:00
2011-02-22 15:38:03 +00:00
if (!$request->isMethodSafe()) {
$response = $this->invalidate($request, $catch);
2010-06-23 20:42:41 +01:00
} elseif ($request->headers->has('expect')) {
$response = $this->pass($request, $catch);
2010-06-23 20:42:41 +01:00
} else {
$response = $this->lookup($request, $catch);
2010-06-23 20:42:41 +01:00
}
$response->isNotModified($request);
$this->restoreResponseBody($request, $response);
2010-06-23 20:42:41 +01:00
$response->setDate(new \DateTime(null, new \DateTimeZone('UTC')));
2010-06-23 20:42:41 +01:00
if (HttpKernelInterface::MASTER_REQUEST === $type && $this->options['debug']) {
$response->headers->set('X-Symfony-Cache', $this->getLog());
}
if (null !== $this->esi) {
$this->esiCacheStrategy->add($response);
if (HttpKernelInterface::MASTER_REQUEST === $type) {
$this->esiCacheStrategy->update($response);
}
}
2010-06-23 20:42:41 +01:00
return $response;
}
/**
* Forwards the Request to the backend without storing the Response in the cache.
*
* @param Request $request A Request instance
2011-04-23 16:05:44 +01:00
* @param Boolean $catch Whether to process exceptions
2010-06-23 20:42:41 +01:00
*
* @return Response A Response instance
2010-06-23 20:42:41 +01:00
*/
protected function pass(Request $request, $catch = false)
2010-06-23 20:42:41 +01:00
{
$this->record($request, 'pass');
return $this->forward($request, $catch);
2010-06-23 20:42:41 +01:00
}
/**
* Invalidates non-safe methods (like POST, PUT, and DELETE).
*
* @param Request $request A Request instance
2011-04-23 16:05:44 +01:00
* @param Boolean $catch Whether to process exceptions
2010-06-23 20:42:41 +01:00
*
* @return Response A Response instance
2010-06-23 20:42:41 +01:00
*
* @see RFC2616 13.10
*/
protected function invalidate(Request $request, $catch = false)
2010-06-23 20:42:41 +01:00
{
$response = $this->pass($request, $catch);
2010-06-23 20:42:41 +01:00
// invalidate only when the response is successful
if ($response->isSuccessful() || $response->isRedirect()) {
try {
$this->store->invalidate($request, $catch);
2010-06-23 20:42:41 +01:00
$this->record($request, 'invalidate');
} catch (\Exception $e) {
$this->record($request, 'invalidate-failed');
if ($this->options['debug']) {
throw $e;
}
}
}
return $response;
}
/**
* Lookups a Response from the cache for the given Request.
*
* When a matching cache entry is found and is fresh, it uses it as the
* response without forwarding any request to the backend. When a matching
* cache entry is found but is stale, it attempts to "validate" the entry with
* the backend using conditional GET. When no matching cache entry is found,
* it triggers "miss" processing.
*
* @param Request $request A Request instance
2011-05-30 00:25:35 +01:00
* @param Boolean $catch whether to process exceptions
2010-06-23 20:42:41 +01:00
*
* @return Response A Response instance
2010-06-23 20:42:41 +01:00
*/
protected function lookup(Request $request, $catch = false)
2010-06-23 20:42:41 +01:00
{
// if allow_reload and no-cache Cache-Control, allow a cache reload
2010-06-23 20:42:41 +01:00
if ($this->options['allow_reload'] && $request->isNoCache()) {
$this->record($request, 'reload');
return $this->fetch($request);
}
try {
$entry = $this->store->lookup($request);
} catch (\Exception $e) {
$this->record($request, 'lookup-failed');
if ($this->options['debug']) {
throw $e;
}
return $this->pass($request, $catch);
2010-06-23 20:42:41 +01:00
}
if (null === $entry) {
$this->record($request, 'miss');
return $this->fetch($request, $catch);
2010-06-23 20:42:41 +01:00
}
if (!$this->isFreshEnough($request, $entry)) {
$this->record($request, 'stale');
return $this->validate($request, $entry, $catch);
2010-06-23 20:42:41 +01:00
}
$this->record($request, 'fresh');
$entry->headers->set('Age', $entry->getAge());
return $entry;
}
/**
* Validates that a cache entry is fresh.
*
* The original request is used as a template for a conditional
* GET request with the backend.
*
* @param Request $request A Request instance
* @param Response $entry A Response instance to validate
* @param Boolean $catch Whether to process exceptions
2010-06-23 20:42:41 +01:00
*
* @return Response A Response instance
2010-06-23 20:42:41 +01:00
*/
protected function validate(Request $request, Response $entry, $catch = false)
2010-06-23 20:42:41 +01:00
{
$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 = $entry->getEtag() ? array($entry->getEtag()) : array();
2010-06-23 20:42:41 +01:00
$requestEtags = $request->getEtags();
if ($etags = array_unique(array_merge($cachedEtags, $requestEtags))) {
$subRequest->headers->set('if_none_match', implode(', ', $etags));
}
2010-06-23 20:42:41 +01:00
$response = $this->forward($subRequest, $catch, $entry);
2010-06-23 20:42:41 +01:00
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->remove('Date');
2010-06-23 20:42:41 +01:00
foreach (array('Date', 'Expires', 'Cache-Control', 'ETag', 'Last-Modified') as $name) {
2010-06-23 20:42:41 +01:00
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;
}
/**
* Forwards the Request to the backend and determines whether the response should be stored.
*
2011-03-01 17:54:51 +00:00
* This methods is triggered when the cache missed or a reload is required.
2010-06-23 20:42:41 +01:00
*
2011-04-23 16:05:44 +01:00
* @param Request $request A Request instance
* @param Boolean $catch whether to process exceptions
2010-06-23 20:42:41 +01:00
*
* @return Response A Response instance
2010-06-23 20:42:41 +01:00
*/
protected function fetch(Request $request, $catch = false)
2010-06-23 20:42:41 +01:00
{
$subRequest = clone $request;
// send no head requests because we want content
$subRequest->setMethod('get');
// avoid that the backend sends no content
made some method name changes to have a better coherence throughout the framework When an object has a "main" many relation with related "things" (objects, parameters, ...), the method names are normalized: * get() * set() * all() * replace() * remove() * clear() * isEmpty() * add() * register() * count() * keys() The classes below follow this method naming convention: * BrowserKit\CookieJar -> Cookie * BrowserKit\History -> Request * Console\Application -> Command * Console\Application\Helper\HelperSet -> HelperInterface * DependencyInjection\Container -> services * DependencyInjection\ContainerBuilder -> services * DependencyInjection\ParameterBag\ParameterBag -> parameters * DependencyInjection\ParameterBag\FrozenParameterBag -> parameters * DomCrawler\Form -> FormField * EventDispatcher\Event -> parameters * Form\FieldGroup -> Field * HttpFoundation\HeaderBag -> headers * HttpFoundation\ParameterBag -> parameters * HttpFoundation\Session -> attributes * HttpKernel\Profiler\Profiler -> DataCollectorInterface * Routing\RouteCollection -> Route * Security\Authentication\AuthenticationProviderManager -> AuthenticationProviderInterface * Templating\Engine -> HelperInterface * Translation\MessageCatalogue -> messages The usage of these methods are only allowed when it is clear that there is a main relation: * a CookieJar has many Cookies; * a Container has many services and many parameters (as services is the main relation, we use the naming convention for this relation); * a Console Input has many arguments and many options. There is no "main" relation, and so the naming convention does not apply. For many relations where the convention does not apply, the following methods must be used instead (where XXX is the name of the related thing): * get() -> getXXX() * set() -> setXXX() * all() -> getXXXs() * replace() -> setXXXs() * remove() -> removeXXX() * clear() -> clearXXX() * isEmpty() -> isEmptyXXX() * add() -> addXXX() * register() -> registerXXX() * count() -> countXXX() * keys()
2010-11-23 08:42:19 +00:00
$subRequest->headers->remove('if_modified_since');
$subRequest->headers->remove('if_none_match');
2010-06-23 20:42:41 +01:00
$response = $this->forward($subRequest, $catch);
2010-06-23 20:42:41 +01:00
if ($this->isPrivateRequest($request) && !$response->headers->hasCacheControlDirective('public')) {
2010-06-23 20:42:41 +01:00
$response->setPrivate(true);
} elseif ($this->options['default_ttl'] > 0 && null === $response->getTtl() && !$response->headers->getCacheControlDirective('must-revalidate')) {
2010-06-23 20:42:41 +01:00
$response->setTtl($this->options['default_ttl']);
}
if ($response->isCacheable()) {
$this->store($request, $response);
}
return $response;
}
/**
* Forwards the Request to the backend and returns the Response.
*
2011-04-23 16:05:44 +01:00
* @param Request $request A Request instance
* @param Boolean $catch Whether to catch exceptions or not
* @param Response $entry A Response instance (the stale entry if present, null otherwise)
2010-06-23 20:42:41 +01:00
*
* @return Response A Response instance
2010-06-23 20:42:41 +01:00
*/
protected function forward(Request $request, $catch = false, Response $entry = null)
2010-06-23 20:42:41 +01:00
{
if ($this->esi) {
$this->esi->addSurrogateEsiCapability($request);
}
// always a "master" request (as the real master request can be in cache)
$response = $this->kernel->handle($request, HttpKernelInterface::MASTER_REQUEST, $catch);
2010-06-23 20:42:41 +01:00
// FIXME: we probably need to also catch exceptions if raw === true
// we don't implement the stale-if-error on Requests, which is nonetheless part of the RFC
if (null !== $entry && in_array($response->getStatusCode(), array(500, 502, 503, 504))) {
if (null === $age = $entry->headers->getCacheControlDirective('stale-if-error')) {
2010-06-23 20:42:41 +01:00
$age = $this->options['stale_if_error'];
}
if (abs($entry->getTtl()) < $age) {
$this->record($request, 'stale-if-error');
return $entry;
}
}
$this->processResponseBody($request, $response);
return $response;
}
/**
* Checks whether the cache entry is "fresh enough" to satisfy the Request.
*
* @param Request $request A Request instance
* @param Response $entry A Response instance
2010-06-23 20:42:41 +01:00
*
* @return Boolean true if the cache entry if fresh enough, false otherwise
*/
protected function isFreshEnough(Request $request, Response $entry)
{
if (!$entry->isFresh()) {
return $this->lock($request, $entry);
}
if ($this->options['allow_revalidate'] && null !== $maxAge = $request->headers->getCacheControlDirective('max-age')) {
2010-06-23 20:42:41 +01:00
return $maxAge > 0 && $maxAge >= $entry->getAge();
}
return true;
}
/**
* Locks a Request during the call to the backend.
*
* @param Request $request A Request instance
* @param Response $entry A Response instance
2010-06-23 20:42:41 +01:00
*
* @return Boolean true if the cache entry can be returned even if it is staled, false otherwise
*/
protected function lock(Request $request, Response $entry)
{
// try to acquire a lock to call the backend
$lock = $this->store->lock($request, $entry);
// there is already another process calling the backend
if (true !== $lock) {
// check if we can serve the stale entry
if (null === $age = $entry->headers->getCacheControlDirective('stale-while-revalidate')) {
2010-06-23 20:42:41 +01:00
$age = $this->options['stale_while_revalidate'];
}
if (abs($entry->getTtl()) < $age) {
$this->record($request, 'stale-while-revalidate');
// server the stale response while there is a revalidation
return true;
2011-02-27 17:28:38 +00:00
}
2010-06-23 20:42:41 +01:00
2011-02-27 17:28:38 +00:00
// wait for the lock to be released
$wait = 0;
while (file_exists($lock) && $wait < 5000000) {
usleep($wait += 50000);
2010-06-23 20:42:41 +01:00
}
2011-02-27 17:28:38 +00:00
if ($wait < 2000000) {
// replace the current entry with the fresh one
$new = $this->lookup($request);
$entry->headers = $new->headers;
$entry->setContent($new->getContent());
$entry->setStatusCode($new->getStatusCode());
$entry->setProtocolVersion($new->getProtocolVersion());
2011-05-18 17:40:36 +01:00
foreach ($new->headers->getCookies() as $cookie) {
$entry->headers->setCookie($cookie);
}
2011-02-27 17:28:38 +00:00
} else {
// backend is slow as hell, send a 503 response (to avoid the dog pile effect)
$entry->setStatusCode(503);
$entry->setContent('503 Service Unavailable');
$entry->headers->set('Retry-After', 10);
}
return true;
2010-06-23 20:42:41 +01:00
}
// we have the lock, call the backend
return false;
}
/**
* Writes the Response to the cache.
*
* @param Request $request A Request instance
* @param Response $response A Response instance
2010-06-23 20:42:41 +01:00
*/
protected function store(Request $request, Response $response)
{
try {
$this->store->write($request, $response);
$this->record($request, 'store');
$response->headers->set('Age', $response->getAge());
} catch (\Exception $e) {
$this->record($request, 'store-failed');
if ($this->options['debug']) {
throw $e;
}
}
// now that the response is cached, release the lock
$this->store->unlock($request);
}
/**
* Restores the Response body.
*
2011-04-23 16:05:44 +01:00
* @param Request $request A Request instance
* @param Response $response A Response instance
2010-06-23 20:42:41 +01:00
*
* @return Response A Response instance
2010-06-23 20:42:41 +01:00
*/
private function restoreResponseBody(Request $request, Response $response)
2010-06-23 20:42:41 +01:00
{
if ('head' === strtolower($request->getMethod()) || 304 === $response->getStatusCode()) {
$response->setContent('');
$response->headers->remove('X-Body-Eval');
$response->headers->remove('X-Body-File');
return;
}
2010-06-23 20:42:41 +01:00
if ($response->headers->has('X-Body-Eval')) {
ob_start();
if ($response->headers->has('X-Body-File')) {
include $response->headers->get('X-Body-File');
} else {
eval('; ?>'.$response->getContent().'<?php ;');
}
$response->setContent(ob_get_clean());
made some method name changes to have a better coherence throughout the framework When an object has a "main" many relation with related "things" (objects, parameters, ...), the method names are normalized: * get() * set() * all() * replace() * remove() * clear() * isEmpty() * add() * register() * count() * keys() The classes below follow this method naming convention: * BrowserKit\CookieJar -> Cookie * BrowserKit\History -> Request * Console\Application -> Command * Console\Application\Helper\HelperSet -> HelperInterface * DependencyInjection\Container -> services * DependencyInjection\ContainerBuilder -> services * DependencyInjection\ParameterBag\ParameterBag -> parameters * DependencyInjection\ParameterBag\FrozenParameterBag -> parameters * DomCrawler\Form -> FormField * EventDispatcher\Event -> parameters * Form\FieldGroup -> Field * HttpFoundation\HeaderBag -> headers * HttpFoundation\ParameterBag -> parameters * HttpFoundation\Session -> attributes * HttpKernel\Profiler\Profiler -> DataCollectorInterface * Routing\RouteCollection -> Route * Security\Authentication\AuthenticationProviderManager -> AuthenticationProviderInterface * Templating\Engine -> HelperInterface * Translation\MessageCatalogue -> messages The usage of these methods are only allowed when it is clear that there is a main relation: * a CookieJar has many Cookies; * a Container has many services and many parameters (as services is the main relation, we use the naming convention for this relation); * a Console Input has many arguments and many options. There is no "main" relation, and so the naming convention does not apply. For many relations where the convention does not apply, the following methods must be used instead (where XXX is the name of the related thing): * get() -> getXXX() * set() -> setXXX() * all() -> getXXXs() * replace() -> setXXXs() * remove() -> removeXXX() * clear() -> clearXXX() * isEmpty() -> isEmptyXXX() * add() -> addXXX() * register() -> registerXXX() * count() -> countXXX() * keys()
2010-11-23 08:42:19 +00:00
$response->headers->remove('X-Body-Eval');
2010-06-23 20:42:41 +01:00
} elseif ($response->headers->has('X-Body-File')) {
$response->setContent(file_get_contents($response->headers->get('X-Body-File')));
} else {
return;
}
made some method name changes to have a better coherence throughout the framework When an object has a "main" many relation with related "things" (objects, parameters, ...), the method names are normalized: * get() * set() * all() * replace() * remove() * clear() * isEmpty() * add() * register() * count() * keys() The classes below follow this method naming convention: * BrowserKit\CookieJar -> Cookie * BrowserKit\History -> Request * Console\Application -> Command * Console\Application\Helper\HelperSet -> HelperInterface * DependencyInjection\Container -> services * DependencyInjection\ContainerBuilder -> services * DependencyInjection\ParameterBag\ParameterBag -> parameters * DependencyInjection\ParameterBag\FrozenParameterBag -> parameters * DomCrawler\Form -> FormField * EventDispatcher\Event -> parameters * Form\FieldGroup -> Field * HttpFoundation\HeaderBag -> headers * HttpFoundation\ParameterBag -> parameters * HttpFoundation\Session -> attributes * HttpKernel\Profiler\Profiler -> DataCollectorInterface * Routing\RouteCollection -> Route * Security\Authentication\AuthenticationProviderManager -> AuthenticationProviderInterface * Templating\Engine -> HelperInterface * Translation\MessageCatalogue -> messages The usage of these methods are only allowed when it is clear that there is a main relation: * a CookieJar has many Cookies; * a Container has many services and many parameters (as services is the main relation, we use the naming convention for this relation); * a Console Input has many arguments and many options. There is no "main" relation, and so the naming convention does not apply. For many relations where the convention does not apply, the following methods must be used instead (where XXX is the name of the related thing): * get() -> getXXX() * set() -> setXXX() * all() -> getXXXs() * replace() -> setXXXs() * remove() -> removeXXX() * clear() -> clearXXX() * isEmpty() -> isEmptyXXX() * add() -> addXXX() * register() -> registerXXX() * count() -> countXXX() * keys()
2010-11-23 08:42:19 +00:00
$response->headers->remove('X-Body-File');
2010-06-23 20:42:41 +01:00
if (!$response->headers->has('Transfer-Encoding')) {
$response->headers->set('Content-Length', strlen($response->getContent()));
}
}
protected function processResponseBody(Request $request, Response $response)
{
if (null !== $this->esi && $this->esi->needsEsiParsing($response)) {
$this->esi->process($request, $response);
}
}
/**
* Checks if the Request includes authorization or other sensitive information
* that should cause the Response to be considered private by default.
*
* @param Request $request A Request instance
2010-06-23 20:42:41 +01:00
*
* @return Boolean true if the Request is private, false otherwise
*/
private function isPrivateRequest(Request $request)
2010-06-23 20:42:41 +01:00
{
foreach ($this->options['private_headers'] as $key) {
$key = strtolower(str_replace('HTTP_', '', $key));
if ('cookie' === $key) {
if (count($request->cookies->all())) {
return true;
}
} elseif ($request->headers->has($key)) {
return true;
}
}
return false;
}
/**
* Records that an event took place.
*
2011-04-23 16:05:44 +01:00
* @param Request $request A Request instance
* @param string $event The event name
2010-06-23 20:42:41 +01:00
*/
private function record(Request $request, $event)
2010-06-23 20:42:41 +01:00
{
$path = $request->getPathInfo();
if ($qs = $request->getQueryString()) {
$path .= '?'.$qs;
}
$this->traces[$request->getMethod().' '.$path][] = $event;
2010-06-23 20:42:41 +01:00
}
}