Completed
Push — master ( 624dd7...696191 )
by Nikola
04:34
created

RateLimitMiddleware::process()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3.009

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 9
cts 10
cp 0.9
rs 9.6333
c 0
b 0
f 0
cc 3
nc 3
nop 2
crap 3.009
1
<?php
2
3
declare(strict_types=1);
4
5
namespace RateLimit\Http;
6
7
use Psr\Http\Message\ServerRequestInterface;
8
use Psr\Http\Server\MiddlewareInterface;
9
use Psr\Http\Server\RequestHandlerInterface;
10
use Psr\Http\Message\ResponseInterface;
11
use RateLimit\SilentRateLimiter;
12
use RateLimit\Status;
13
14
final class RateLimitMiddleware implements MiddlewareInterface
15
{
16
    public const HEADER_LIMIT = 'X-RateLimit-Limit';
17
    public const HEADER_REMAINING = 'X-RateLimit-Remaining';
18
    public const HEADER_RESET = 'X-RateLimit-Reset';
19
20
    /** @var SilentRateLimiter */
21
    private $rateLimiter;
22
23
    /** @var GetRate */
24
    private $getRate;
25
26
    /** @var ResolveIdentifier */
27
    private $resolveIdentifier;
28
29
    /** @var RequestHandlerInterface */
30
    private $limitExceededHandler;
31
32 4
    public function __construct(
33
        SilentRateLimiter $rateLimiter,
34
        GetRate $getRate,
35
        ResolveIdentifier $resolveIdentifier,
36
        RequestHandlerInterface $limitExceededHandler
37
    ) {
38 4
        $this->rateLimiter = $rateLimiter;
39 4
        $this->getRate = $getRate;
40 4
        $this->resolveIdentifier = $resolveIdentifier;
41 4
        $this->limitExceededHandler = $limitExceededHandler;
42 4
    }
43
44 4
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
45
    {
46 4
        $rate = $this->getRate->forRequest($request);
47
48 4
        if (null === $rate) {
49
            return $handler->handle($request);
50
        }
51
52 4
        $identifier = $this->resolveIdentifier->fromRequest($request);
53
54 4
        $status = $this->rateLimiter->limitSilently($identifier, $rate);
55
56 4
        if ($status->limitExceeded()) {
57 3
            return $this->setRateLimitHeaders($this->limitExceededHandler->handle($request), $status)
58 3
                ->withStatus(429);
59
        }
60
61 4
        return $this->setRateLimitHeaders($handler->handle($request), $status);
62
    }
63
64 4
    private function setRateLimitHeaders(ResponseInterface $response, Status $rateLimitStatus): ResponseInterface
65
    {
66
        return $response
67 4
            ->withHeader(self::HEADER_LIMIT, (string) $rateLimitStatus->getLimit())
68 4
            ->withHeader(self::HEADER_REMAINING, (string) $rateLimitStatus->getRemainingAttempts())
69 4
            ->withHeader(self::HEADER_RESET, (string) $rateLimitStatus->getResetAt()->getTimestamp());
70
    }
71
}
72