Middleware   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 99
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 99
rs 10
eloc 24
ccs 26
cts 26
cp 1
wmc 8

6 Methods

Rating   Name   Duplication   Size   Complexity  
A process() 0 16 3
A getResponseFactory() 0 3 1
A setLimitPeriod() 0 3 1
A addHeaders() 0 6 1
A __construct() 0 5 1
A createTooManyRequestResponse() 0 3 1
1
<?php
2
namespace RazonYang\Psr\RateLimiter;
3
4
use Psr\Http\Message\ResponseFactoryInterface;
5
use Psr\Http\Message\ResponseInterface;
6
use Psr\Http\Message\ServerRequestInterface;
7
use Psr\Http\Server\MiddlewareInterface;
8
use Psr\Http\Server\RequestHandlerInterface;
9
use RazonYang\TokenBucket\ManagerInterface;
10
11
class Middleware implements MiddlewareInterface
12
{
13
    /**
14
     * @var ManagerInterface
15
     */
16
    private $manager;
17
18
    /**
19
     * @var ResponseFactoryInterface
20
     */
21
    private $responseFactory;
22
23
    /**
24
     * Returns response factory.
25
     *
26
     * @return ResponseFactoryInterface
27
     */
28 1
    protected function getResponseFactory(): ResponseFactoryInterface
29
    {
30 1
        return $this->responseFactory;
31
    }
32
33
    /**
34
     * @var \Closure $nameCallback the bucket name callback that accepts request parameter,
35
     * and returns bucket name, returns empty string for skipping rate limiting.
36
     */
37
    private $nameCallback;
38
39
    /**
40
     * @var int $limitPeriod calculates maximum count of requests during the period.
41
     */
42
    private $limitPeriod = 3600;
43
44
    /**
45
     * Sets limit period.
46
     *
47
     * @param int $period
48
     */
49 2
    public function setLimitPeriod(int $period)
50
    {
51 2
        $this->limitPeriod = $period;
52 2
    }
53
54
    /**
55
     * @param ManagerInterface $manager token bucket manager.
56
     * @param ResponseFactoryInterface $responseFactory response factory.
57
     * @param \Closure $nameCallback bucket name callback.
58
     */
59 5
    public function __construct(ManagerInterface $manager, ResponseFactoryInterface $responseFactory, \Closure $nameCallback)
60
    {
61 5
        $this->manager = $manager;
62 5
        $this->nameCallback = $nameCallback;
63 5
        $this->responseFactory = $responseFactory;
64 5
    }
65
66 2
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
67
    {
68 2
        $name = call_user_func($this->nameCallback, $request);
69 2
        if ($name === '') {
70 1
            return $handler->handle($request);
71
        }
72
        
73 1
        $consumed = $this->manager->consume($name, $remaining, $reset);
74 1
        $limit = $this->manager->getLimit($this->limitPeriod);
75 1
        if (!$consumed) {
76 1
            $response = $this->createTooManyRequestResponse();
77
        } else {
78 1
            $response = $handler->handle($request);
79
        }
80
81 1
        return $this->addHeaders($response, $limit, $remaining, $reset);
82
    }
83
84
    /**
85
     * Creates a response about too many request.
86
     *
87
     * @return ResponseInterface
88
     */
89 1
    protected function createTooManyRequestResponse(): ResponseInterface
90
    {
91 1
        return $this->responseFactory->createResponse(429, 'Too Many Requests');
92
    }
93
    
94
    /**
95
     * Adds rate limiting headers.
96
     *
97
     * @param ResponseInterface $response
98
     * @param int               $limit
99
     * @param int               $remaining
100
     * @param int               $reset
101
     *
102
     * @return ResponseInterface
103
     */
104 1
    protected function addHeaders(ResponseInterface $response, int $limit, int $remaining, int $reset): ResponseInterface
105
    {
106
        /** @var Psr\Http\Message\ResponseInterface $response */
107 1
        return $response->withHeader('X-Rate-Limit-Limit', $limit)
108 1
            ->withHeader('X-Rate-Limit-Remaining', $remaining)
109 1
            ->withHeader('X-Rate-Limit-Reset', $reset);
110
    }
111
}
112