Completed
Push — master ( 6be743...cd47ee )
by Nikola
09:43
created

RateLimitMiddleware::getIdentifier()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace RateLimit\Middleware;
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\Rate;
12
use RateLimit\SilentRateLimiter;
13
use RateLimit\Status;
14
15
final class RateLimitMiddleware implements MiddlewareInterface
16
{
17
    public const HEADER_LIMIT = 'X-RateLimit-Limit';
18
    public const HEADER_REMAINING = 'X-RateLimit-Remaining';
19
    public const HEADER_RESET = 'X-RateLimit-Reset';
20
21
    /** @var SilentRateLimiter */
22
    private $rateLimiter;
23
24
    /** @var string */
25
    private $endpointName;
26
27
    /** @var Rate */
28
    private $rate;
29
30
    /** @var ResolveUserIdentity */
31
    private $resolveUserIdentity;
32
33
    /** @var RequestHandlerInterface */
34
    private $limitExceededHandler;
35
36
    public function __construct(
37
        SilentRateLimiter $rateLimiter,
38
        string $endpointName,
39
        Rate $rate,
40
        ResolveUserIdentity $resolveUserIdentity,
41
        RequestHandlerInterface $limitExceededHandler
42
    ) {
43
        $this->rateLimiter = $rateLimiter;
44
        $this->endpointName = $endpointName;
45
        $this->rate = $rate;
46
        $this->resolveUserIdentity = $resolveUserIdentity;
47
        $this->limitExceededHandler = $limitExceededHandler;
48
    }
49
50
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
51
    {
52
        $identifier = $this->getIdentifier($request);
53
54
        $status = $this->rateLimiter->limitSilently($identifier, $this->rate);
55
56
        $response = $status->limitExceeded()
57
            ? $this->limitExceededHandler->handle($request)->withStatus(429)
58
            : $handler->handle($request);
59
60
        return $this->setRateLimitHeaders($response, $status);
61
    }
62
63
    private function getIdentifier(ServerRequestInterface $request): string
64
    {
65
        $userIdentity = $this->resolveUserIdentity->fromRequest($request);
66
67
        return trim("{$this->endpointName}:$userIdentity", ':');
68
    }
69
70
    private function setRateLimitHeaders(ResponseInterface $response, Status $rateLimitStatus): ResponseInterface
71
    {
72
        return $response
73
            ->withHeader(self::HEADER_LIMIT, (string) $rateLimitStatus->getLimit())
74
            ->withHeader(self::HEADER_REMAINING, (string) $rateLimitStatus->getRemainingAttempts())
75
            ->withHeader(self::HEADER_RESET, (string) $rateLimitStatus->getResetAt()->getTimestamp());
76
    }
77
}
78