/** * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable|null $next * @return ResponseInterface * @throws InternalServerError * @throws TooManyRequests */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null) { // Get resource $endpoint = $request->getAttribute($this->requestAttribName, null); if (is_null($endpoint)) { throw new InternalServerError('Rate Limit could not find a matched endpoint from the router. ' . 'Make sure the requestAttribName is correct.'); } // Check what bucket to use if (array_key_exists($endpoint, $this->buckets)) { $this->bucket = $this->buckets[$endpoint]; } elseif (array_key_exists('default', $this->buckets)) { $this->bucket = $this->buckets['default']; } else { // No bucket configured throw new InternalServerError('Rate Limit needs at least one (default) bucket to work.'); } // Check for cache if ($this->cache instanceof NullCache) { // Throw error since we don't have anywhere to save the data throw new InternalServerError('Rate Limit needs a cache to work.'); } // Get identifier and check it it's null if (null === ($this->identifier = $this->getIdentifier($request))) { // No identifier found $this->container['log']->warning('Request (ID: ' . $response->getHeaderLine('Uuid') . ') made but without ' . 'the ' . $this->identifierHeader . ' header. Please note that the request was executed as normal.'); // Call next middleware if one is set return $next($request, $response, $next); } // Sanitize the endpoint name(space) a little bit $endpoint = preg_replace("/[^a-zA-Z0-9]+/", "", $endpoint); // Get saved data from cache $this->bucket->remainingTokens = $this->cache->get('rateLimit' . $endpoint . $this->identifier); $this->bucket->updated = $this->cache->get('rateLimitUpdated' . $endpoint . $this->identifier); // Refill tokens $this->refillTokens(); // Check if there are enough tokens left $this->checkTokens(); // Set headers $response = $this->setHeaders($response); // Save to cache $this->cache->set('rateLimit' . $endpoint . $this->identifier, $this->bucket->remainingTokens); $this->cache->set('rateLimitUpdated' . $endpoint . $this->identifier, $this->bucket->updated); // Call next middleware if one is set return $next($request, $response, $next); }
/** * Add a match to the cache for later use, this makes it * easier for the router to find a match the next time the * same request uri i requested since the router checks in the * cache before it tries to find a match in the route table. * * @param $requestUri */ protected function addToCache($requestUri) { // we found our match, stop looking for more and add to cache if cache is configured if ($this->cache instanceof Cache) { // prepare info to be saved to cache $toCache = ['matchedRoute' => $this->matchedRoute, 'matchedEndpoint' => $this->matchedEndpoint, 'params' => $this->params]; // check if we have any routes saved if ($cachedRoutes = $this->cache->get('routeMiddlewareRoutes')) { // add this route to cache $cachedRoutes[$requestUri] = $toCache; } else { // no routes found in cache, this is the first one we save $cachedRoutes = [$requestUri => $toCache]; } // save to cache $this->cache->set('routeMiddlewareRoutes', $cachedRoutes); } }