mirror of
https://0xacab.org/radar/radar-wp.git
synced 2025-04-19 14:27:30 +02:00
Initial import.
This commit is contained in:
commit
86383280c9
428 changed files with 68738 additions and 0 deletions
11
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/CacheKeyProviderInterface.php
vendored
Normal file
11
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/CacheKeyProviderInterface.php
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace Guzzle\Plugin\Cache;
|
||||
|
||||
\Guzzle\Common\Version::warn('Guzzle\Plugin\Cache\CacheKeyProviderInterface is no longer used');
|
||||
|
||||
/**
|
||||
* @deprecated This is no longer used
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
interface CacheKeyProviderInterface {}
|
353
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/CachePlugin.php
vendored
Normal file
353
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/CachePlugin.php
vendored
Normal file
|
@ -0,0 +1,353 @@
|
|||
<?php
|
||||
|
||||
namespace Guzzle\Plugin\Cache;
|
||||
|
||||
use Guzzle\Cache\CacheAdapterFactory;
|
||||
use Guzzle\Cache\CacheAdapterInterface;
|
||||
use Guzzle\Common\Event;
|
||||
use Guzzle\Common\Exception\InvalidArgumentException;
|
||||
use Guzzle\Common\Version;
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
use Guzzle\Http\Message\Response;
|
||||
use Guzzle\Cache\DoctrineCacheAdapter;
|
||||
use Guzzle\Http\Exception\CurlException;
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
/**
|
||||
* Plugin to enable the caching of GET and HEAD requests. Caching can be done on all requests passing through this
|
||||
* plugin or only after retrieving resources with cacheable response headers.
|
||||
*
|
||||
* This is a simple implementation of RFC 2616 and should be considered a private transparent proxy cache, meaning
|
||||
* authorization and private data can be cached.
|
||||
*
|
||||
* It also implements RFC 5861's `stale-if-error` Cache-Control extension, allowing stale cache responses to be used
|
||||
* when an error is encountered (such as a `500 Internal Server Error` or DNS failure).
|
||||
*/
|
||||
class CachePlugin implements EventSubscriberInterface
|
||||
{
|
||||
/** @var RevalidationInterface Cache revalidation strategy */
|
||||
protected $revalidation;
|
||||
|
||||
/** @var CanCacheStrategyInterface Object used to determine if a request can be cached */
|
||||
protected $canCache;
|
||||
|
||||
/** @var CacheStorageInterface $cache Object used to cache responses */
|
||||
protected $storage;
|
||||
|
||||
/** @var bool */
|
||||
protected $autoPurge;
|
||||
|
||||
/**
|
||||
* @param array|CacheAdapterInterface|CacheStorageInterface $options Array of options for the cache plugin,
|
||||
* cache adapter, or cache storage object.
|
||||
* - CacheStorageInterface storage: Adapter used to cache responses
|
||||
* - RevalidationInterface revalidation: Cache revalidation strategy
|
||||
* - CanCacheInterface can_cache: Object used to determine if a request can be cached
|
||||
* - bool auto_purge Set to true to automatically PURGE resources when non-idempotent
|
||||
* requests are sent to a resource. Defaults to false.
|
||||
* @throws InvalidArgumentException if no cache is provided and Doctrine cache is not installed
|
||||
*/
|
||||
public function __construct($options = null)
|
||||
{
|
||||
if (!is_array($options)) {
|
||||
if ($options instanceof CacheAdapterInterface) {
|
||||
$options = array('storage' => new DefaultCacheStorage($options));
|
||||
} elseif ($options instanceof CacheStorageInterface) {
|
||||
$options = array('storage' => $options);
|
||||
} elseif ($options) {
|
||||
$options = array('storage' => new DefaultCacheStorage(CacheAdapterFactory::fromCache($options)));
|
||||
} elseif (!class_exists('Doctrine\Common\Cache\ArrayCache')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new InvalidArgumentException('No cache was provided and Doctrine is not installed');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
$this->autoPurge = isset($options['auto_purge']) ? $options['auto_purge'] : false;
|
||||
|
||||
// Add a cache storage if a cache adapter was provided
|
||||
$this->storage = isset($options['storage'])
|
||||
? $options['storage']
|
||||
: new DefaultCacheStorage(new DoctrineCacheAdapter(new ArrayCache()));
|
||||
|
||||
if (!isset($options['can_cache'])) {
|
||||
$this->canCache = new DefaultCanCacheStrategy();
|
||||
} else {
|
||||
$this->canCache = is_callable($options['can_cache'])
|
||||
? new CallbackCanCacheStrategy($options['can_cache'])
|
||||
: $options['can_cache'];
|
||||
}
|
||||
|
||||
// Use the provided revalidation strategy or the default
|
||||
$this->revalidation = isset($options['revalidation'])
|
||||
? $options['revalidation']
|
||||
: new DefaultRevalidation($this->storage, $this->canCache);
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
'request.before_send' => array('onRequestBeforeSend', -255),
|
||||
'request.sent' => array('onRequestSent', 255),
|
||||
'request.error' => array('onRequestError', 0),
|
||||
'request.exception' => array('onRequestException', 0),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a response in cache will satisfy the request before sending
|
||||
*
|
||||
* @param Event $event
|
||||
*/
|
||||
public function onRequestBeforeSend(Event $event)
|
||||
{
|
||||
$request = $event['request'];
|
||||
$request->addHeader('Via', sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION));
|
||||
|
||||
if (!$this->canCache->canCacheRequest($request)) {
|
||||
switch ($request->getMethod()) {
|
||||
case 'PURGE':
|
||||
$this->purge($request);
|
||||
$request->setResponse(new Response(200, array(), 'purged'));
|
||||
break;
|
||||
case 'PUT':
|
||||
case 'POST':
|
||||
case 'DELETE':
|
||||
case 'PATCH':
|
||||
if ($this->autoPurge) {
|
||||
$this->purge($request);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ($response = $this->storage->fetch($request)) {
|
||||
$params = $request->getParams();
|
||||
$params['cache.lookup'] = true;
|
||||
$response->setHeader(
|
||||
'Age',
|
||||
time() - strtotime($response->getDate() ? : $response->getLastModified() ?: 'now')
|
||||
);
|
||||
// Validate that the response satisfies the request
|
||||
if ($this->canResponseSatisfyRequest($request, $response)) {
|
||||
if (!isset($params['cache.hit'])) {
|
||||
$params['cache.hit'] = true;
|
||||
}
|
||||
$request->setResponse($response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If possible, store a response in cache after sending
|
||||
*
|
||||
* @param Event $event
|
||||
*/
|
||||
public function onRequestSent(Event $event)
|
||||
{
|
||||
$request = $event['request'];
|
||||
$response = $event['response'];
|
||||
|
||||
if ($request->getParams()->get('cache.hit') === null &&
|
||||
$this->canCache->canCacheRequest($request) &&
|
||||
$this->canCache->canCacheResponse($response)
|
||||
) {
|
||||
$this->storage->cache($request, $response);
|
||||
}
|
||||
|
||||
$this->addResponseHeaders($request, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* If possible, return a cache response on an error
|
||||
*
|
||||
* @param Event $event
|
||||
*/
|
||||
public function onRequestError(Event $event)
|
||||
{
|
||||
$request = $event['request'];
|
||||
|
||||
if (!$this->canCache->canCacheRequest($request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($response = $this->storage->fetch($request)) {
|
||||
$response->setHeader(
|
||||
'Age',
|
||||
time() - strtotime($response->getLastModified() ? : $response->getDate() ?: 'now')
|
||||
);
|
||||
|
||||
if ($this->canResponseSatisfyFailedRequest($request, $response)) {
|
||||
$request->getParams()->set('cache.hit', 'error');
|
||||
$this->addResponseHeaders($request, $response);
|
||||
$event['response'] = $response;
|
||||
$event->stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If possible, set a cache response on a cURL exception
|
||||
*
|
||||
* @param Event $event
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function onRequestException(Event $event)
|
||||
{
|
||||
if (!$event['exception'] instanceof CurlException) {
|
||||
return;
|
||||
}
|
||||
|
||||
$request = $event['request'];
|
||||
if (!$this->canCache->canCacheRequest($request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($response = $this->storage->fetch($request)) {
|
||||
$response->setHeader('Age', time() - strtotime($response->getDate() ? : 'now'));
|
||||
if (!$this->canResponseSatisfyFailedRequest($request, $response)) {
|
||||
return;
|
||||
}
|
||||
$request->getParams()->set('cache.hit', 'error');
|
||||
$request->setResponse($response);
|
||||
$this->addResponseHeaders($request, $response);
|
||||
$event->stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a cache response satisfies a request's caching constraints
|
||||
*
|
||||
* @param RequestInterface $request Request to validate
|
||||
* @param Response $response Response to validate
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canResponseSatisfyRequest(RequestInterface $request, Response $response)
|
||||
{
|
||||
$responseAge = $response->calculateAge();
|
||||
$reqc = $request->getHeader('Cache-Control');
|
||||
$resc = $response->getHeader('Cache-Control');
|
||||
|
||||
// Check the request's max-age header against the age of the response
|
||||
if ($reqc && $reqc->hasDirective('max-age') &&
|
||||
$responseAge > $reqc->getDirective('max-age')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the response's max-age header
|
||||
if ($response->isFresh() === false) {
|
||||
$maxStale = $reqc ? $reqc->getDirective('max-stale') : null;
|
||||
if (null !== $maxStale) {
|
||||
if ($maxStale !== true && $response->getFreshness() < (-1 * $maxStale)) {
|
||||
return false;
|
||||
}
|
||||
} elseif ($resc && $resc->hasDirective('max-age')
|
||||
&& $responseAge > $resc->getDirective('max-age')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->revalidation->shouldRevalidate($request, $response)) {
|
||||
try {
|
||||
return $this->revalidation->revalidate($request, $response);
|
||||
} catch (CurlException $e) {
|
||||
$request->getParams()->set('cache.hit', 'error');
|
||||
return $this->canResponseSatisfyFailedRequest($request, $response);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a cache response satisfies a failed request's caching constraints
|
||||
*
|
||||
* @param RequestInterface $request Request to validate
|
||||
* @param Response $response Response to validate
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canResponseSatisfyFailedRequest(RequestInterface $request, Response $response)
|
||||
{
|
||||
$reqc = $request->getHeader('Cache-Control');
|
||||
$resc = $response->getHeader('Cache-Control');
|
||||
$requestStaleIfError = $reqc ? $reqc->getDirective('stale-if-error') : null;
|
||||
$responseStaleIfError = $resc ? $resc->getDirective('stale-if-error') : null;
|
||||
|
||||
if (!$requestStaleIfError && !$responseStaleIfError) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_numeric($requestStaleIfError) && $response->getAge() - $response->getMaxAge() > $requestStaleIfError) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_numeric($responseStaleIfError) && $response->getAge() - $response->getMaxAge() > $responseStaleIfError) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge all cache entries for a given URL
|
||||
*
|
||||
* @param string $url URL to purge
|
||||
*/
|
||||
public function purge($url)
|
||||
{
|
||||
// BC compatibility with previous version that accepted a Request object
|
||||
$url = $url instanceof RequestInterface ? $url->getUrl() : $url;
|
||||
$this->storage->purge($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the plugin's headers to a response
|
||||
*
|
||||
* @param RequestInterface $request Request
|
||||
* @param Response $response Response to add headers to
|
||||
*/
|
||||
protected function addResponseHeaders(RequestInterface $request, Response $response)
|
||||
{
|
||||
$params = $request->getParams();
|
||||
$response->setHeader('Via', sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION));
|
||||
|
||||
$lookup = ($params['cache.lookup'] === true ? 'HIT' : 'MISS') . ' from GuzzleCache';
|
||||
if ($header = $response->getHeader('X-Cache-Lookup')) {
|
||||
// Don't add duplicates
|
||||
$values = $header->toArray();
|
||||
$values[] = $lookup;
|
||||
$response->setHeader('X-Cache-Lookup', array_unique($values));
|
||||
} else {
|
||||
$response->setHeader('X-Cache-Lookup', $lookup);
|
||||
}
|
||||
|
||||
if ($params['cache.hit'] === true) {
|
||||
$xcache = 'HIT from GuzzleCache';
|
||||
} elseif ($params['cache.hit'] == 'error') {
|
||||
$xcache = 'HIT_ERROR from GuzzleCache';
|
||||
} else {
|
||||
$xcache = 'MISS from GuzzleCache';
|
||||
}
|
||||
|
||||
if ($header = $response->getHeader('X-Cache')) {
|
||||
// Don't add duplicates
|
||||
$values = $header->toArray();
|
||||
$values[] = $xcache;
|
||||
$response->setHeader('X-Cache', array_unique($values));
|
||||
} else {
|
||||
$response->setHeader('X-Cache', $xcache);
|
||||
}
|
||||
|
||||
if ($response->isFresh() === false) {
|
||||
$response->addHeader('Warning', sprintf('110 GuzzleCache/%s "Response is stale"', Version::VERSION));
|
||||
if ($params['cache.hit'] === 'error') {
|
||||
$response->addHeader('Warning', sprintf('111 GuzzleCache/%s "Revalidation failed"', Version::VERSION));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/CacheStorageInterface.php
vendored
Normal file
43
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/CacheStorageInterface.php
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Guzzle\Plugin\Cache;
|
||||
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
use Guzzle\Http\Message\Response;
|
||||
|
||||
/**
|
||||
* Interface used to cache HTTP requests
|
||||
*/
|
||||
interface CacheStorageInterface
|
||||
{
|
||||
/**
|
||||
* Get a Response from the cache for a request
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
*
|
||||
* @return null|Response
|
||||
*/
|
||||
public function fetch(RequestInterface $request);
|
||||
|
||||
/**
|
||||
* Cache an HTTP request
|
||||
*
|
||||
* @param RequestInterface $request Request being cached
|
||||
* @param Response $response Response to cache
|
||||
*/
|
||||
public function cache(RequestInterface $request, Response $response);
|
||||
|
||||
/**
|
||||
* Deletes cache entries that match a request
|
||||
*
|
||||
* @param RequestInterface $request Request to delete from cache
|
||||
*/
|
||||
public function delete(RequestInterface $request);
|
||||
|
||||
/**
|
||||
* Purge all cache entries for a given URL
|
||||
*
|
||||
* @param string $url
|
||||
*/
|
||||
public function purge($url);
|
||||
}
|
53
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/CallbackCanCacheStrategy.php
vendored
Normal file
53
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/CallbackCanCacheStrategy.php
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace Guzzle\Plugin\Cache;
|
||||
|
||||
use Guzzle\Common\Exception\InvalidArgumentException;
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
use Guzzle\Http\Message\Response;
|
||||
|
||||
/**
|
||||
* Determines if a request can be cached using a callback
|
||||
*/
|
||||
class CallbackCanCacheStrategy extends DefaultCanCacheStrategy
|
||||
{
|
||||
/** @var callable Callback for request */
|
||||
protected $requestCallback;
|
||||
|
||||
/** @var callable Callback for response */
|
||||
protected $responseCallback;
|
||||
|
||||
/**
|
||||
* @param \Closure|array|mixed $requestCallback Callable method to invoke for requests
|
||||
* @param \Closure|array|mixed $responseCallback Callable method to invoke for responses
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct($requestCallback = null, $responseCallback = null)
|
||||
{
|
||||
if ($requestCallback && !is_callable($requestCallback)) {
|
||||
throw new InvalidArgumentException('Method must be callable');
|
||||
}
|
||||
|
||||
if ($responseCallback && !is_callable($responseCallback)) {
|
||||
throw new InvalidArgumentException('Method must be callable');
|
||||
}
|
||||
|
||||
$this->requestCallback = $requestCallback;
|
||||
$this->responseCallback = $responseCallback;
|
||||
}
|
||||
|
||||
public function canCacheRequest(RequestInterface $request)
|
||||
{
|
||||
return $this->requestCallback
|
||||
? call_user_func($this->requestCallback, $request)
|
||||
: parent::canCacheRequest($request);
|
||||
}
|
||||
|
||||
public function canCacheResponse(Response $response)
|
||||
{
|
||||
return $this->responseCallback
|
||||
? call_user_func($this->responseCallback, $response)
|
||||
: parent::canCacheResponse($response);
|
||||
}
|
||||
}
|
30
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/CanCacheStrategyInterface.php
vendored
Normal file
30
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/CanCacheStrategyInterface.php
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Guzzle\Plugin\Cache;
|
||||
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
use Guzzle\Http\Message\Response;
|
||||
|
||||
/**
|
||||
* Strategy used to determine if a request can be cached
|
||||
*/
|
||||
interface CanCacheStrategyInterface
|
||||
{
|
||||
/**
|
||||
* Determine if a request can be cached
|
||||
*
|
||||
* @param RequestInterface $request Request to determine
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canCacheRequest(RequestInterface $request);
|
||||
|
||||
/**
|
||||
* Determine if a response can be cached
|
||||
*
|
||||
* @param Response $response Response to determine
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canCacheResponse(Response $response);
|
||||
}
|
46
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/DefaultCacheKeyProvider.php
vendored
Normal file
46
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/DefaultCacheKeyProvider.php
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Guzzle\Plugin\Cache;
|
||||
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
|
||||
\Guzzle\Common\Version::warn('Guzzle\Plugin\Cache\DefaultCacheKeyProvider is no longer used');
|
||||
|
||||
/**
|
||||
* @deprecated This class is no longer used
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class DefaultCacheKeyProvider implements CacheKeyProviderInterface
|
||||
{
|
||||
public function getCacheKey(RequestInterface $request)
|
||||
{
|
||||
// See if the key has already been calculated
|
||||
$key = $request->getParams()->get(self::CACHE_KEY);
|
||||
|
||||
if (!$key) {
|
||||
|
||||
$cloned = clone $request;
|
||||
$cloned->removeHeader('Cache-Control');
|
||||
|
||||
// Check to see how and if the key should be filtered
|
||||
foreach (explode(';', $request->getParams()->get(self::CACHE_KEY_FILTER)) as $part) {
|
||||
$pieces = array_map('trim', explode('=', $part));
|
||||
if (isset($pieces[1])) {
|
||||
foreach (array_map('trim', explode(',', $pieces[1])) as $remove) {
|
||||
if ($pieces[0] == 'header') {
|
||||
$cloned->removeHeader($remove);
|
||||
} elseif ($pieces[0] == 'query') {
|
||||
$cloned->getQuery()->remove($remove);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$raw = (string) $cloned;
|
||||
$key = 'GZ' . md5($raw);
|
||||
$request->getParams()->set(self::CACHE_KEY, $key)->set(self::CACHE_KEY_RAW, $raw);
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
}
|
251
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/DefaultCacheStorage.php
vendored
Normal file
251
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/DefaultCacheStorage.php
vendored
Normal file
|
@ -0,0 +1,251 @@
|
|||
<?php
|
||||
|
||||
namespace Guzzle\Plugin\Cache;
|
||||
|
||||
use Guzzle\Cache\CacheAdapterFactory;
|
||||
use Guzzle\Cache\CacheAdapterInterface;
|
||||
use Guzzle\Http\EntityBodyInterface;
|
||||
use Guzzle\Http\Message\MessageInterface;
|
||||
use Guzzle\Http\Message\Request;
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
use Guzzle\Http\Message\Response;
|
||||
|
||||
/**
|
||||
* Default cache storage implementation
|
||||
*/
|
||||
class DefaultCacheStorage implements CacheStorageInterface
|
||||
{
|
||||
/** @var string */
|
||||
protected $keyPrefix;
|
||||
|
||||
/** @var CacheAdapterInterface Cache used to store cache data */
|
||||
protected $cache;
|
||||
|
||||
/** @var int Default cache TTL */
|
||||
protected $defaultTtl;
|
||||
|
||||
/**
|
||||
* @param mixed $cache Cache used to store cache data
|
||||
* @param string $keyPrefix Provide an optional key prefix to prefix on all cache keys
|
||||
* @param int $defaultTtl Default cache TTL
|
||||
*/
|
||||
public function __construct($cache, $keyPrefix = '', $defaultTtl = 3600)
|
||||
{
|
||||
$this->cache = CacheAdapterFactory::fromCache($cache);
|
||||
$this->defaultTtl = $defaultTtl;
|
||||
$this->keyPrefix = $keyPrefix;
|
||||
}
|
||||
|
||||
public function cache(RequestInterface $request, Response $response)
|
||||
{
|
||||
$currentTime = time();
|
||||
$ttl = $request->getParams()->get('cache.override_ttl') ?: $response->getMaxAge() ?: $this->defaultTtl;
|
||||
|
||||
if ($cacheControl = $response->getHeader('Cache-Control')) {
|
||||
$stale = $cacheControl->getDirective('stale-if-error');
|
||||
$ttl += $stale == true ? $ttl : $stale;
|
||||
}
|
||||
|
||||
// Determine which manifest key should be used
|
||||
$key = $this->getCacheKey($request);
|
||||
$persistedRequest = $this->persistHeaders($request);
|
||||
$entries = array();
|
||||
|
||||
if ($manifest = $this->cache->fetch($key)) {
|
||||
// Determine which cache entries should still be in the cache
|
||||
$vary = $response->getVary();
|
||||
foreach (unserialize($manifest) as $entry) {
|
||||
// Check if the entry is expired
|
||||
if ($entry[4] < $currentTime) {
|
||||
continue;
|
||||
}
|
||||
$entry[1]['vary'] = isset($entry[1]['vary']) ? $entry[1]['vary'] : '';
|
||||
if ($vary != $entry[1]['vary'] || !$this->requestsMatch($vary, $entry[0], $persistedRequest)) {
|
||||
$entries[] = $entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Persist the response body if needed
|
||||
$bodyDigest = null;
|
||||
if ($response->getBody() && $response->getBody()->getContentLength() > 0) {
|
||||
$bodyDigest = $this->getBodyKey($request->getUrl(), $response->getBody());
|
||||
$this->cache->save($bodyDigest, (string) $response->getBody(), $ttl);
|
||||
}
|
||||
|
||||
array_unshift($entries, array(
|
||||
$persistedRequest,
|
||||
$this->persistHeaders($response),
|
||||
$response->getStatusCode(),
|
||||
$bodyDigest,
|
||||
$currentTime + $ttl
|
||||
));
|
||||
|
||||
$this->cache->save($key, serialize($entries));
|
||||
}
|
||||
|
||||
public function delete(RequestInterface $request)
|
||||
{
|
||||
$key = $this->getCacheKey($request);
|
||||
if ($entries = $this->cache->fetch($key)) {
|
||||
// Delete each cached body
|
||||
foreach (unserialize($entries) as $entry) {
|
||||
if ($entry[3]) {
|
||||
$this->cache->delete($entry[3]);
|
||||
}
|
||||
}
|
||||
$this->cache->delete($key);
|
||||
}
|
||||
}
|
||||
|
||||
public function purge($url)
|
||||
{
|
||||
foreach (array('GET', 'HEAD', 'POST', 'PUT', 'DELETE') as $method) {
|
||||
$this->delete(new Request($method, $url));
|
||||
}
|
||||
}
|
||||
|
||||
public function fetch(RequestInterface $request)
|
||||
{
|
||||
$key = $this->getCacheKey($request);
|
||||
if (!($entries = $this->cache->fetch($key))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$match = null;
|
||||
$headers = $this->persistHeaders($request);
|
||||
$entries = unserialize($entries);
|
||||
foreach ($entries as $index => $entry) {
|
||||
if ($this->requestsMatch(isset($entry[1]['vary']) ? $entry[1]['vary'] : '', $headers, $entry[0])) {
|
||||
$match = $entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Ensure that the response is not expired
|
||||
$response = null;
|
||||
if ($match[4] < time()) {
|
||||
$response = -1;
|
||||
} else {
|
||||
$response = new Response($match[2], $match[1]);
|
||||
if ($match[3]) {
|
||||
if ($body = $this->cache->fetch($match[3])) {
|
||||
$response->setBody($body);
|
||||
} else {
|
||||
// The response is not valid because the body was somehow deleted
|
||||
$response = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($response === -1) {
|
||||
// Remove the entry from the metadata and update the cache
|
||||
unset($entries[$index]);
|
||||
if ($entries) {
|
||||
$this->cache->save($key, serialize($entries));
|
||||
} else {
|
||||
$this->cache->delete($key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash a request URL into a string that returns cache metadata
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getCacheKey(RequestInterface $request)
|
||||
{
|
||||
// Allow cache.key_filter to trim down the URL cache key by removing generate query string values (e.g. auth)
|
||||
if ($filter = $request->getParams()->get('cache.key_filter')) {
|
||||
$url = $request->getUrl(true);
|
||||
foreach (explode(',', $filter) as $remove) {
|
||||
$url->getQuery()->remove(trim($remove));
|
||||
}
|
||||
} else {
|
||||
$url = $request->getUrl();
|
||||
}
|
||||
|
||||
return $this->keyPrefix . md5($request->getMethod() . ' ' . $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a cache key for a response's body
|
||||
*
|
||||
* @param string $url URL of the entry
|
||||
* @param EntityBodyInterface $body Response body
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getBodyKey($url, EntityBodyInterface $body)
|
||||
{
|
||||
return $this->keyPrefix . md5($url) . $body->getContentMd5();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether two Request HTTP header sets are non-varying
|
||||
*
|
||||
* @param string $vary Response vary header
|
||||
* @param array $r1 HTTP header array
|
||||
* @param array $r2 HTTP header array
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function requestsMatch($vary, $r1, $r2)
|
||||
{
|
||||
if ($vary) {
|
||||
foreach (explode(',', $vary) as $header) {
|
||||
$key = trim(strtolower($header));
|
||||
$v1 = isset($r1[$key]) ? $r1[$key] : null;
|
||||
$v2 = isset($r2[$key]) ? $r2[$key] : null;
|
||||
if ($v1 !== $v2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of cacheable and normalized message headers
|
||||
*
|
||||
* @param MessageInterface $message
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function persistHeaders(MessageInterface $message)
|
||||
{
|
||||
// Headers are excluded from the caching (see RFC 2616:13.5.1)
|
||||
static $noCache = array(
|
||||
'age' => true,
|
||||
'connection' => true,
|
||||
'keep-alive' => true,
|
||||
'proxy-authenticate' => true,
|
||||
'proxy-authorization' => true,
|
||||
'te' => true,
|
||||
'trailers' => true,
|
||||
'transfer-encoding' => true,
|
||||
'upgrade' => true,
|
||||
'set-cookie' => true,
|
||||
'set-cookie2' => true
|
||||
);
|
||||
|
||||
// Clone the response to not destroy any necessary headers when caching
|
||||
$headers = $message->getHeaders()->getAll();
|
||||
$headers = array_diff_key($headers, $noCache);
|
||||
// Cast the headers to a string
|
||||
$headers = array_map(function ($h) { return (string) $h; }, $headers);
|
||||
|
||||
return $headers;
|
||||
}
|
||||
}
|
32
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/DefaultCanCacheStrategy.php
vendored
Normal file
32
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/DefaultCanCacheStrategy.php
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Guzzle\Plugin\Cache;
|
||||
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
use Guzzle\Http\Message\Response;
|
||||
|
||||
/**
|
||||
* Default strategy used to determine of an HTTP request can be cached
|
||||
*/
|
||||
class DefaultCanCacheStrategy implements CanCacheStrategyInterface
|
||||
{
|
||||
public function canCacheRequest(RequestInterface $request)
|
||||
{
|
||||
// Only GET and HEAD requests can be cached
|
||||
if ($request->getMethod() != RequestInterface::GET && $request->getMethod() != RequestInterface::HEAD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Never cache requests when using no-store
|
||||
if ($request->hasHeader('Cache-Control') && $request->getHeader('Cache-Control')->hasDirective('no-store')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canCacheResponse(Response $response)
|
||||
{
|
||||
return $response->isSuccessful() && $response->canCache();
|
||||
}
|
||||
}
|
174
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/DefaultRevalidation.php
vendored
Normal file
174
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/DefaultRevalidation.php
vendored
Normal file
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
|
||||
namespace Guzzle\Plugin\Cache;
|
||||
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
use Guzzle\Http\Message\Response;
|
||||
use Guzzle\Http\Exception\BadResponseException;
|
||||
|
||||
/**
|
||||
* Default revalidation strategy
|
||||
*/
|
||||
class DefaultRevalidation implements RevalidationInterface
|
||||
{
|
||||
/** @var CacheStorageInterface Cache object storing cache data */
|
||||
protected $storage;
|
||||
|
||||
/** @var CanCacheStrategyInterface */
|
||||
protected $canCache;
|
||||
|
||||
/**
|
||||
* @param CacheStorageInterface $cache Cache storage
|
||||
* @param CanCacheStrategyInterface $canCache Determines if a message can be cached
|
||||
*/
|
||||
public function __construct(CacheStorageInterface $cache, CanCacheStrategyInterface $canCache = null)
|
||||
{
|
||||
$this->storage = $cache;
|
||||
$this->canCache = $canCache ?: new DefaultCanCacheStrategy();
|
||||
}
|
||||
|
||||
public function revalidate(RequestInterface $request, Response $response)
|
||||
{
|
||||
try {
|
||||
$revalidate = $this->createRevalidationRequest($request, $response);
|
||||
$validateResponse = $revalidate->send();
|
||||
if ($validateResponse->getStatusCode() == 200) {
|
||||
return $this->handle200Response($request, $validateResponse);
|
||||
} elseif ($validateResponse->getStatusCode() == 304) {
|
||||
return $this->handle304Response($request, $validateResponse, $response);
|
||||
}
|
||||
} catch (BadResponseException $e) {
|
||||
$this->handleBadResponse($e);
|
||||
}
|
||||
|
||||
// Other exceptions encountered in the revalidation request are ignored
|
||||
// in hopes that sending a request to the origin server will fix it
|
||||
return false;
|
||||
}
|
||||
|
||||
public function shouldRevalidate(RequestInterface $request, Response $response)
|
||||
{
|
||||
if ($request->getMethod() != RequestInterface::GET) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$reqCache = $request->getHeader('Cache-Control');
|
||||
$resCache = $response->getHeader('Cache-Control');
|
||||
|
||||
$revalidate = $request->getHeader('Pragma') == 'no-cache' ||
|
||||
($reqCache && ($reqCache->hasDirective('no-cache') || $reqCache->hasDirective('must-revalidate'))) ||
|
||||
($resCache && ($resCache->hasDirective('no-cache') || $resCache->hasDirective('must-revalidate')));
|
||||
|
||||
// Use the strong ETag validator if available and the response contains no Cache-Control directive
|
||||
if (!$revalidate && !$resCache && $response->hasHeader('ETag')) {
|
||||
$revalidate = true;
|
||||
}
|
||||
|
||||
return $revalidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a bad response when attempting to revalidate
|
||||
*
|
||||
* @param BadResponseException $e Exception encountered
|
||||
*
|
||||
* @throws BadResponseException
|
||||
*/
|
||||
protected function handleBadResponse(BadResponseException $e)
|
||||
{
|
||||
// 404 errors mean the resource no longer exists, so remove from
|
||||
// cache, and prevent an additional request by throwing the exception
|
||||
if ($e->getResponse()->getStatusCode() == 404) {
|
||||
$this->storage->delete($e->getRequest());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a request to use for revalidation
|
||||
*
|
||||
* @param RequestInterface $request Request
|
||||
* @param Response $response Response to revalidate
|
||||
*
|
||||
* @return RequestInterface returns a revalidation request
|
||||
*/
|
||||
protected function createRevalidationRequest(RequestInterface $request, Response $response)
|
||||
{
|
||||
$revalidate = clone $request;
|
||||
$revalidate->removeHeader('Pragma')->removeHeader('Cache-Control');
|
||||
|
||||
if ($response->getLastModified()) {
|
||||
$revalidate->setHeader('If-Modified-Since', $response->getLastModified());
|
||||
}
|
||||
|
||||
if ($response->getEtag()) {
|
||||
$revalidate->setHeader('If-None-Match', $response->getEtag());
|
||||
}
|
||||
|
||||
// Remove any cache plugins that might be on the request to prevent infinite recursive revalidations
|
||||
$dispatcher = $revalidate->getEventDispatcher();
|
||||
foreach ($dispatcher->getListeners() as $eventName => $listeners) {
|
||||
foreach ($listeners as $listener) {
|
||||
if (is_array($listener) && $listener[0] instanceof CachePlugin) {
|
||||
$dispatcher->removeListener($eventName, $listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $revalidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a 200 response response from revalidating. The server does not support validation, so use this response.
|
||||
*
|
||||
* @param RequestInterface $request Request that was sent
|
||||
* @param Response $validateResponse Response received
|
||||
*
|
||||
* @return bool Returns true if valid, false if invalid
|
||||
*/
|
||||
protected function handle200Response(RequestInterface $request, Response $validateResponse)
|
||||
{
|
||||
$request->setResponse($validateResponse);
|
||||
if ($this->canCache->canCacheResponse($validateResponse)) {
|
||||
$this->storage->cache($request, $validateResponse);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a 304 response and ensure that it is still valid
|
||||
*
|
||||
* @param RequestInterface $request Request that was sent
|
||||
* @param Response $validateResponse Response received
|
||||
* @param Response $response Original cached response
|
||||
*
|
||||
* @return bool Returns true if valid, false if invalid
|
||||
*/
|
||||
protected function handle304Response(RequestInterface $request, Response $validateResponse, Response $response)
|
||||
{
|
||||
static $replaceHeaders = array('Date', 'Expires', 'Cache-Control', 'ETag', 'Last-Modified');
|
||||
|
||||
// Make sure that this response has the same ETag
|
||||
if ($validateResponse->getEtag() != $response->getEtag()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Replace cached headers with any of these headers from the
|
||||
// origin server that might be more up to date
|
||||
$modified = false;
|
||||
foreach ($replaceHeaders as $name) {
|
||||
if ($validateResponse->hasHeader($name)) {
|
||||
$modified = true;
|
||||
$response->setHeader($name, $validateResponse->getHeader($name));
|
||||
}
|
||||
}
|
||||
|
||||
// Store the updated response in cache
|
||||
if ($modified && $this->canCache->canCacheResponse($response)) {
|
||||
$this->storage->cache($request, $response);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
19
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/DenyRevalidation.php
vendored
Normal file
19
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/DenyRevalidation.php
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Guzzle\Plugin\Cache;
|
||||
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
use Guzzle\Http\Message\Response;
|
||||
|
||||
/**
|
||||
* Never performs cache revalidation and just assumes the request is invalid
|
||||
*/
|
||||
class DenyRevalidation extends DefaultRevalidation
|
||||
{
|
||||
public function __construct() {}
|
||||
|
||||
public function revalidate(RequestInterface $request, Response $response)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
32
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/RevalidationInterface.php
vendored
Normal file
32
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/RevalidationInterface.php
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Guzzle\Plugin\Cache;
|
||||
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
use Guzzle\Http\Message\Response;
|
||||
|
||||
/**
|
||||
* Cache revalidation interface
|
||||
*/
|
||||
interface RevalidationInterface
|
||||
{
|
||||
/**
|
||||
* Performs a cache revalidation
|
||||
*
|
||||
* @param RequestInterface $request Request to revalidate
|
||||
* @param Response $response Response that was received
|
||||
*
|
||||
* @return bool Returns true if the request can be cached
|
||||
*/
|
||||
public function revalidate(RequestInterface $request, Response $response);
|
||||
|
||||
/**
|
||||
* Returns true if the response should be revalidated
|
||||
*
|
||||
* @param RequestInterface $request Request to check
|
||||
* @param Response $response Response to check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldRevalidate(RequestInterface $request, Response $response);
|
||||
}
|
19
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/SkipRevalidation.php
vendored
Normal file
19
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/SkipRevalidation.php
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Guzzle\Plugin\Cache;
|
||||
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
use Guzzle\Http\Message\Response;
|
||||
|
||||
/**
|
||||
* Never performs cache revalidation and just assumes the request is still ok
|
||||
*/
|
||||
class SkipRevalidation extends DefaultRevalidation
|
||||
{
|
||||
public function __construct() {}
|
||||
|
||||
public function revalidate(RequestInterface $request, Response $response)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
28
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/composer.json
vendored
Normal file
28
vendor/guzzle/plugin-cache/Guzzle/Plugin/Cache/composer.json
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "guzzle/plugin-cache",
|
||||
"description": "Guzzle HTTP cache plugin",
|
||||
"homepage": "http://guzzlephp.org/",
|
||||
"keywords": ["plugin", "guzzle"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"guzzle/http": "self.version",
|
||||
"guzzle/cache": "self.version"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": { "Guzzle\\Plugin\\Cache": "" }
|
||||
},
|
||||
"target-dir": "Guzzle/Plugin/Cache",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.7-dev"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue