public function fetch(RequestInterface $request)
    {
        /** @var int|null $maxAge */
        $maxAge = null;

        if ($request->hasHeader('Cache-Control')) {
            $reqCacheControl = new KeyValueHttpHeader($request->getHeader('Cache-Control'));
            if ($reqCacheControl->has('no-cache')) {
                // Can't return cache
                return null;
            }

            $maxAge = $reqCacheControl->get('max-age', null);
        } elseif ($request->hasHeader('Pragma')) {
            $pragma = new KeyValueHttpHeader($request->getHeader('Pragma'));
            if ($pragma->has('no-cache')) {
                // Can't return cache
                return null;
            }
        }

        $cache = $this->storage->fetch($this->getCacheKey($request));
        if ($cache !== null) {
            $varyHeaders = $cache->getVaryHeaders();

            // vary headers exist from a previous response, check if we have a cache that matches those headers
            if (!$varyHeaders->isEmpty()) {
                $cache = $this->storage->fetch($this->getCacheKey($request, $varyHeaders));

                if (!$cache) {
                    return null;
                }
            }

            if ((string)$cache->getOriginalRequest()->getUri() !== (string)$request->getUri()) {
                return null;
            }

            if ($maxAge !== null) {
                if ($cache->getAge() > $maxAge) {
                    // Cache entry is too old for the request requirements!
                    return null;
                }
            }

            if (!$cache->isVaryEquals($request)) {
                return null;
            }
        }

        return $cache;
    }