This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Concat\Http\Middleware; |
||
4 | |||
5 | use Psr\Http\Message\ResponseInterface; |
||
6 | use Psr\Http\Message\RequestInterface; |
||
7 | use Psr\Log\LoggerInterface; |
||
8 | use Psr\Log\LogLevel; |
||
9 | |||
10 | /** |
||
11 | * Guzzle middleware which delays requests if they exceed a rate allowance. |
||
12 | */ |
||
13 | class RateLimiter |
||
14 | { |
||
15 | /** |
||
16 | * @var RateLimitProvider |
||
17 | */ |
||
18 | protected $provider; |
||
19 | |||
20 | /** |
||
21 | * @var LoggerInterface |
||
22 | */ |
||
23 | protected $logger; |
||
24 | |||
25 | /** |
||
26 | * @var string|callable Constant or callable that accepts a Response. |
||
27 | */ |
||
28 | protected $logLevel; |
||
29 | |||
30 | /** |
||
31 | * Creates a callable middleware rate limiter. |
||
32 | * |
||
33 | * @param RateLimitProvider $provider A rate data provider. |
||
34 | * @param LoggerInterface $logger |
||
35 | */ |
||
36 | 7 | public function __construct( |
|
37 | RateLimitProvider $provider, |
||
38 | LoggerInterface $logger = null |
||
39 | ) { |
||
40 | 7 | $this->provider = $provider; |
|
41 | 7 | $this->logger = $logger; |
|
42 | 7 | } |
|
43 | |||
44 | /** |
||
45 | * Delays and logs the request then sets the allowance for the next request. |
||
46 | * |
||
47 | * @param callable $handler |
||
48 | * @return \Closure |
||
49 | */ |
||
50 | 3 | public function __invoke(callable $handler) |
|
51 | { |
||
52 | return function (RequestInterface $request, $options) use ($handler) { |
||
53 | |||
54 | // Amount of time to delay the request by |
||
55 | 3 | $delay = $this->getDelay($request); |
|
56 | |||
57 | 3 | if ($delay > 0) { |
|
58 | 3 | $this->delay($delay); |
|
59 | 3 | $this->log($request, $delay); |
|
60 | 3 | } |
|
61 | |||
62 | // Sets the time when this request is being made, |
||
63 | // which allows calculation of allowance later on. |
||
64 | 3 | $this->provider->setLastRequestTime($request); |
|
65 | |||
66 | // Set the allowance when the response was received |
||
67 | 3 | return $handler($request, $options)->then($this->setAllowance()); |
|
68 | 3 | }; |
|
69 | } |
||
70 | |||
71 | /** |
||
72 | * Logs a request which is being delayed by a specified amount of time. |
||
73 | * |
||
74 | * @param RequestInterface $request The request being delayed. |
||
75 | * @param float $delay The amount of time that the request is delayed for. |
||
0 ignored issues
–
show
|
|||
76 | */ |
||
77 | 3 | protected function log(RequestInterface $request, $delay) |
|
78 | { |
||
79 | 3 | if (isset($this->logger)) { |
|
80 | 3 | $level = $this->getLogLevel($request); |
|
81 | 3 | $message = $this->getLogMessage($request, $delay); |
|
82 | 3 | $context = compact('request', 'delay'); |
|
83 | |||
84 | 3 | $this->logger->log($level, $message, $context); |
|
85 | 3 | } |
|
86 | 3 | } |
|
87 | |||
88 | /** |
||
89 | * Formats a request and delay time as a log message. |
||
90 | * |
||
91 | * @param RequestInterface $request The request being logged. |
||
92 | * @param float $delay The amount of time that the request is delayed for. |
||
93 | * |
||
94 | * @return string Log message |
||
95 | */ |
||
96 | 3 | protected function getLogMessage(RequestInterface $request, $delay) |
|
97 | { |
||
98 | 3 | return vsprintf("[%s] %s %s was delayed by {$delay} seconds", [ |
|
99 | 3 | gmdate("d/M/Y:H:i:s O"), |
|
100 | 3 | $request->getMethod(), |
|
101 | 3 | $request->getUri() |
|
102 | 3 | ]); |
|
103 | } |
||
104 | |||
105 | /** |
||
106 | * Returns the default log level. |
||
107 | * |
||
108 | * @return string LogLevel |
||
109 | */ |
||
110 | 1 | protected function getDefaultLogLevel() |
|
111 | { |
||
112 | 1 | return LogLevel::DEBUG; |
|
113 | } |
||
114 | |||
115 | /** |
||
116 | * Sets the log level to use, which can be either a string or a callable |
||
117 | * that accepts a response (which could be null). A log level could also |
||
118 | * be null, which indicates that the default log level should be used. |
||
119 | * |
||
120 | * @param string|callable|null |
||
121 | */ |
||
122 | 2 | public function setLogLevel($logLevel) |
|
123 | { |
||
124 | 2 | $this->logLevel = $logLevel; |
|
125 | 2 | } |
|
126 | |||
127 | /** |
||
128 | * Returns a log level for a given request. |
||
129 | * |
||
130 | * @param RequestInterface $request The request being logged. |
||
131 | * @return string LogLevel |
||
132 | */ |
||
133 | 3 | protected function getLogLevel(RequestInterface $request) |
|
134 | { |
||
135 | 3 | if (!$this->logLevel) { |
|
136 | 1 | return $this->getDefaultLogLevel(); |
|
137 | } |
||
138 | |||
139 | 2 | if (is_callable($this->logLevel)) { |
|
140 | 1 | return call_user_func($this->logLevel, $request); |
|
141 | } |
||
142 | |||
143 | 1 | return (string) $this->logLevel; |
|
144 | } |
||
145 | |||
146 | /** |
||
147 | * Returns the delay duration for the given request (in seconds). |
||
148 | * |
||
149 | * @param RequestInterface $request Request to get the delay duration for. |
||
150 | * |
||
151 | * @return float The delay duration (in seconds). |
||
152 | */ |
||
153 | 4 | protected function getDelay(RequestInterface $request) |
|
154 | { |
||
155 | 4 | $lastRequestTime = $this->provider->getLastRequestTime($request); |
|
156 | 4 | $requestAllowance = $this->provider->getRequestAllowance($request); |
|
157 | 4 | $requestTime = $this->provider->getRequestTime($request); |
|
158 | |||
159 | // If lastRequestTime is null or false, the max will be 0. |
||
160 | 4 | return max(0, $requestAllowance - ($requestTime - $lastRequestTime)); |
|
161 | } |
||
162 | |||
163 | /** |
||
164 | * Delays the given request by an amount of seconds. This method supports microsecond |
||
0 ignored issues
–
show
|
|||
165 | * precision as well as integer seconds, ie. both microtime(true) or time() |
||
166 | * |
||
167 | * @param float $seconds The amount of time (in seconds) to delay by. |
||
168 | * |
||
169 | * @codeCoverageIgnore |
||
170 | */ |
||
171 | protected function delay($seconds) |
||
172 | { |
||
173 | $floor = floor($seconds); |
||
174 | $micro = max(0, floor(($seconds - $floor) * 1000000)); |
||
175 | |||
176 | sleep($floor); |
||
177 | usleep($micro); |
||
178 | } |
||
179 | |||
180 | /** |
||
181 | * Returns a callable handler which allows the provider to set the request |
||
182 | * allowance for the next request, using the current response. |
||
183 | * |
||
184 | * @return \Closure Handler to set request allowance on the rate provider. |
||
185 | */ |
||
186 | protected function setAllowance() |
||
187 | { |
||
188 | 3 | return function (ResponseInterface $response) { |
|
189 | 3 | $this->provider->setRequestAllowance($response); |
|
190 | 3 | return $response; |
|
191 | 3 | }; |
|
192 | } |
||
193 | } |
||
194 |
Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.