sonarrradarrplexorganizrnginxdashboardmuximuxlandingpagestartpagelandinghtpcserverhomepagesabnzbdheimdallembycouchpotatonzbgetbookmarkapplication-dashboard
		
		
		
		
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							241 lines
						
					
					
						
							7.1 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							241 lines
						
					
					
						
							7.1 KiB
						
					
					
				
								<?php
							 | 
						|
								
							 | 
						|
								declare(strict_types=1);
							 | 
						|
								
							 | 
						|
								/*
							 | 
						|
								 * This file is part of Cache Plugin.
							 | 
						|
								 *
							 | 
						|
								 * (c) Graham Campbell <graham@alt-three.com>
							 | 
						|
								 *
							 | 
						|
								 * For the full copyright and license information, please view the LICENSE
							 | 
						|
								 * file that was distributed with this source code.
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								namespace GrahamCampbell\CachePlugin;
							 | 
						|
								
							 | 
						|
								use Exception;
							 | 
						|
								use Http\Client\Common\Plugin;
							 | 
						|
								use Http\Client\Common\Plugin\Cache\Generator\CacheKeyGenerator;
							 | 
						|
								use Http\Client\Common\Plugin\Cache\Generator\HeaderCacheKeyGenerator;
							 | 
						|
								use Http\Client\Common\Plugin\Exception\RewindStreamException;
							 | 
						|
								use Http\Client\Common\Plugin\VersionBridgePlugin;
							 | 
						|
								use Http\Message\StreamFactory;
							 | 
						|
								use Psr\Cache\CacheItemInterface;
							 | 
						|
								use Psr\Cache\CacheItemPoolInterface;
							 | 
						|
								use Psr\Http\Message\RequestInterface;
							 | 
						|
								use Psr\Http\Message\ResponseInterface;
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * This is the response cache plugin class.
							 | 
						|
								 *
							 | 
						|
								 * @author Tobias Nyholm <tobias.nyholm@gmail.com>
							 | 
						|
								 * @author Graham Campbell <graham@alt-three.com>
							 | 
						|
								 */
							 | 
						|
								class CachePlugin implements Plugin
							 | 
						|
								{
							 | 
						|
								    use VersionBridgePlugin;
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * The cache item pool instance.
							 | 
						|
								     *
							 | 
						|
								     * @var \Psr\Cache\CacheItemPoolInterface
							 | 
						|
								     */
							 | 
						|
								    protected $pool;
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * The steam factory instance.
							 | 
						|
								     *
							 | 
						|
								     * @var \Http\Message\StreamFactory
							 | 
						|
								     */
							 | 
						|
								    protected $streamFactory;
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * The cache key generator instance.
							 | 
						|
								     *
							 | 
						|
								     * @var \Http\Client\Common\Plugin\Cache\Generator\CacheKeyGenerator
							 | 
						|
								     */
							 | 
						|
								    protected $generator;
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * The cache lifetime in seconds.
							 | 
						|
								     *
							 | 
						|
								     * @var int
							 | 
						|
								     */
							 | 
						|
								    protected $lifetime;
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Create a new cache plugin.
							 | 
						|
								     *
							 | 
						|
								     * @param \Psr\Cache\CacheItemPoolInterface                                 $pool
							 | 
						|
								     * @param \Http\Message\StreamFactory                                       $streamFactory
							 | 
						|
								     * @param \Http\Client\Common\Plugin\Cache\Generator\CacheKeyGenerator|null $generator
							 | 
						|
								     * @param int|null                                                          $lifetime
							 | 
						|
								     *
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    public function __construct(CacheItemPoolInterface $pool, StreamFactory $streamFactory, CacheKeyGenerator $generator = null, int $lifetime = null)
							 | 
						|
								    {
							 | 
						|
								        $this->pool = $pool;
							 | 
						|
								        $this->streamFactory = $streamFactory;
							 | 
						|
								        $this->generator = $generator ?: new HeaderCacheKeyGenerator(['Authorization', 'Cookie', 'Accept', 'Content-type']);
							 | 
						|
								        $this->lifetime = $lifetime ?: 3600 * 48;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Handle the request and return the response coming from the next callable.
							 | 
						|
								     *
							 | 
						|
								     * @param \Psr\Http\Message\RequestInterface $request
							 | 
						|
								     * @param callable                           $next
							 | 
						|
								     * @param callable                           $first
							 | 
						|
								     *
							 | 
						|
								     * @return \Http\Promise\Promise
							 | 
						|
								     */
							 | 
						|
								    protected function doHandleRequest(RequestInterface $request, callable $next, callable $first)
							 | 
						|
								    {
							 | 
						|
								        $method = strtoupper($request->getMethod());
							 | 
						|
								        // If the request not is cachable, move to $next
							 | 
						|
								        if (!in_array($method, ['GET', 'HEAD'], true)) {
							 | 
						|
								            return $next($request);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $cacheItem = $this->createCacheItem($request);
							 | 
						|
								
							 | 
						|
								        if ($cacheItem->isHit() && ($etag = $this->getETag($cacheItem))) {
							 | 
						|
								            $request = $request->withHeader('If-None-Match', $etag);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return $next($request)->then(function (ResponseInterface $response) use ($cacheItem) {
							 | 
						|
								            if (304 === $response->getStatusCode()) {
							 | 
						|
								                if (!$cacheItem->isHit()) {
							 | 
						|
								                    // We do not have the item in cache. This plugin did not
							 | 
						|
								                    // add If-None-Match headers. Return the response.
							 | 
						|
								                    return $response;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // The cached response we have is still valid
							 | 
						|
								                $cacheItem->set($cacheItem->get())->expiresAfter($this->lifetime);
							 | 
						|
								                $this->pool->save($cacheItem);
							 | 
						|
								
							 | 
						|
								                return $this->createResponseFromCacheItem($cacheItem);
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            if ($this->isCacheable($response)) {
							 | 
						|
								                $bodyStream = $response->getBody();
							 | 
						|
								                $body = $bodyStream->__toString();
							 | 
						|
								                if ($bodyStream->isSeekable()) {
							 | 
						|
								                    $bodyStream->rewind();
							 | 
						|
								                } else {
							 | 
						|
								                    $response = $response->withBody($this->streamFactory->createStream($body));
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                $cacheItem
							 | 
						|
								                    ->expiresAfter($this->lifetime)
							 | 
						|
								                    ->set([
							 | 
						|
								                        'response' => $response,
							 | 
						|
								                        'body'     => $body,
							 | 
						|
								                        'etag'     => $response->getHeader('ETag'),
							 | 
						|
								                    ]);
							 | 
						|
								                $this->pool->save($cacheItem);
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            return $response;
							 | 
						|
								        });
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Create a cache item for a request.
							 | 
						|
								     *
							 | 
						|
								     * @param \Psr\Http\Message\RequestInterface $request
							 | 
						|
								     *
							 | 
						|
								     * @return \Psr\Cache\CacheItemInterface
							 | 
						|
								     */
							 | 
						|
								    protected function createCacheItem(RequestInterface $request)
							 | 
						|
								    {
							 | 
						|
								        $key = sha1($this->generator->generate($request));
							 | 
						|
								
							 | 
						|
								        return $this->pool->getItem($key);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Verify that we can cache this response.
							 | 
						|
								     *
							 | 
						|
								     * @param \Psr\Http\Message\ResponseInterface $response
							 | 
						|
								     *
							 | 
						|
								     * @return bool
							 | 
						|
								     */
							 | 
						|
								    protected function isCacheable(ResponseInterface $response)
							 | 
						|
								    {
							 | 
						|
								        if (!in_array($response->getStatusCode(), [200, 203, 300, 301, 302, 404, 410])) {
							 | 
						|
								            return false;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return !$this->getCacheControlDirective($response, 'no-cache');
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Get the value of a parameter in the cache control header.
							 | 
						|
								     *
							 | 
						|
								     * @param \Psr\Http\Message\ResponseInterface $response
							 | 
						|
								     * @param string                              $name
							 | 
						|
								     *
							 | 
						|
								     * @return bool|string
							 | 
						|
								     */
							 | 
						|
								    protected function getCacheControlDirective(ResponseInterface $response, string $name)
							 | 
						|
								    {
							 | 
						|
								        foreach ($response->getHeader('Cache-Control') as $header) {
							 | 
						|
								            if (preg_match(sprintf('|%s=?([0-9]+)?|i', $name), $header, $matches)) {
							 | 
						|
								                // return the value for $name if it exists
							 | 
						|
								                if (isset($matches[1])) {
							 | 
						|
								                    return $matches[1];
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                return true;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return false;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Create a response from a cache item.
							 | 
						|
								     *
							 | 
						|
								     * @param \Psr\Cache\CacheItemInterface $cacheItem
							 | 
						|
								     *
							 | 
						|
								     * @return \Psr\Http\Message\ResponseInterface
							 | 
						|
								     */
							 | 
						|
								    protected function createResponseFromCacheItem(CacheItemInterface $cacheItem)
							 | 
						|
								    {
							 | 
						|
								        $data = $cacheItem->get();
							 | 
						|
								
							 | 
						|
								        $response = $data['response'];
							 | 
						|
								        $stream = $this->streamFactory->createStream($data['body']);
							 | 
						|
								
							 | 
						|
								        try {
							 | 
						|
								            $stream->rewind();
							 | 
						|
								        } catch (Exception $e) {
							 | 
						|
								            throw new RewindStreamException('Cannot rewind stream.', 0, $e);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $response = $response->withBody($stream);
							 | 
						|
								
							 | 
						|
								        return $response;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Get the ETag from the cached response.
							 | 
						|
								     *
							 | 
						|
								     * @param \Psr\Cache\CacheItemInterface $cacheItem
							 | 
						|
								     *
							 | 
						|
								     * @return string|null
							 | 
						|
								     */
							 | 
						|
								    protected function getETag(CacheItemInterface $cacheItem)
							 | 
						|
								    {
							 | 
						|
								        $data = $cacheItem->get();
							 | 
						|
								
							 | 
						|
								        foreach ($data['etag'] as $etag) {
							 | 
						|
								            if (!empty($etag)) {
							 | 
						|
								                return $etag;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 |