Skip to content

Commit f937d89

Browse files
committed
feat: add http error middleware
1 parent 80f250b commit f937d89

File tree

2 files changed

+239
-0
lines changed

2 files changed

+239
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright (c) 2024 Kai Sassnowski
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*
11+
* @see https://github.com/roach-php/roach
12+
*/
13+
14+
namespace RoachPHP\Downloader\Middleware;
15+
16+
use Psr\Log\LoggerInterface;
17+
use RoachPHP\Http\Response;
18+
use RoachPHP\Support\Configurable;
19+
20+
final class HttpErrorMiddleware implements ResponseMiddlewareInterface
21+
{
22+
use Configurable;
23+
24+
public function __construct(private readonly LoggerInterface $logger)
25+
{
26+
}
27+
28+
public function handleResponse(Response $response): Response
29+
{
30+
$status = $response->getStatus();
31+
32+
if (200 <= $status && 300 > $status) {
33+
return $response;
34+
}
35+
36+
/** @var array<int, int> $allowedStatus */
37+
$allowedStatus = $this->option('handleStatus');
38+
39+
if (\in_array($status, $allowedStatus, true)) {
40+
return $response;
41+
}
42+
43+
$this->logger->info(
44+
'[HttpErrorMiddleware] Dropping unsuccessful response',
45+
[
46+
'uri' => $response->getRequest()->getUri(),
47+
'status' => $status,
48+
],
49+
);
50+
51+
return $response->drop('Unallowed HTTP status: ' . $status);
52+
}
53+
54+
private function defaultOptions(): array
55+
{
56+
return [
57+
'handleStatus' => [],
58+
];
59+
}
60+
}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright (c) 2024 Kai Sassnowski
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*
11+
* @see https://github.com/roach-php/roach
12+
*/
13+
14+
namespace RoachPHP\Tests\Downloader\Middleware;
15+
16+
use PHPUnit\Framework\Attributes\DataProvider;
17+
use PHPUnit\Framework\TestCase;
18+
use RoachPHP\Downloader\Middleware\HttpErrorMiddleware;
19+
use RoachPHP\Testing\Concerns\InteractsWithRequestsAndResponses;
20+
use RoachPHP\Testing\FakeLogger;
21+
22+
/**
23+
* @internal
24+
*/
25+
final class HttpErrorMiddlewareTest extends TestCase
26+
{
27+
use InteractsWithRequestsAndResponses;
28+
29+
private HttpErrorMiddleware $middleware;
30+
31+
private FakeLogger $logger;
32+
33+
protected function setUp(): void
34+
{
35+
$this->logger = new FakeLogger();
36+
$this->middleware = new HttpErrorMiddleware($this->logger);
37+
}
38+
39+
public static function successfulHTTPStatus(): \Generator
40+
{
41+
yield from [
42+
[200],
43+
[201],
44+
[202],
45+
[203],
46+
[204],
47+
[205],
48+
[206],
49+
[207],
50+
[208],
51+
];
52+
}
53+
54+
public static function unsuccessfulHTTPStatus(): \Generator
55+
{
56+
yield from [
57+
[100],
58+
[101],
59+
[102],
60+
[103],
61+
[300],
62+
[301],
63+
[302],
64+
[303],
65+
[304],
66+
[305],
67+
[306],
68+
[307],
69+
[308],
70+
[400],
71+
[401],
72+
[402],
73+
[403],
74+
[404],
75+
[405],
76+
[406],
77+
[407],
78+
[408],
79+
[409],
80+
[410],
81+
[411],
82+
[412],
83+
[413],
84+
[414],
85+
[415],
86+
[416],
87+
[417],
88+
[418],
89+
[421],
90+
[422],
91+
[423],
92+
[424],
93+
[425],
94+
[426],
95+
[428],
96+
[429],
97+
[431],
98+
[451],
99+
[500],
100+
[501],
101+
[502],
102+
[503],
103+
[504],
104+
[505],
105+
[506],
106+
[507],
107+
[508],
108+
[510],
109+
[511],
110+
];
111+
}
112+
113+
#[DataProvider('successfulHTTPStatus')]
114+
public function testAllowResponseWithSuccessfulHTTPStatus(int $status): void
115+
{
116+
$response = $this->makeResponse(status: $status);
117+
$this->middleware->configure([]);
118+
119+
$result = $this->middleware->handleResponse($response);
120+
121+
self::assertSame($result, $response);
122+
self::assertFalse($result->wasDropped());
123+
}
124+
125+
#[DataProvider('unsuccessfulHTTPStatus')]
126+
public function testDropResponseWithNonSuccessfulHTTPStatus(int $status): void
127+
{
128+
$response = $this->makeResponse(status: $status);
129+
$this->middleware->configure([]);
130+
131+
$result = $this->middleware->handleResponse($response);
132+
133+
self::assertNotSame($result, $response);
134+
self::assertTrue($result->wasDropped());
135+
}
136+
137+
public function testLogDroppedResponses(): void
138+
{
139+
$request = $this->makeRequest('https://example.com');
140+
$response = $this->makeResponse(request: $request, status: 400);
141+
$this->middleware->configure([]);
142+
143+
$this->middleware->handleResponse($response);
144+
145+
self::assertTrue(
146+
$this->logger->messageWasLogged(
147+
'info',
148+
'[HttpErrorMiddleware] Dropping unsuccessful response',
149+
['uri' => 'https://example.com', 'status' => 400],
150+
),
151+
);
152+
}
153+
154+
public function testDontLogAllowedResponses(): void
155+
{
156+
$response = $this->makeResponse(status: 200);
157+
$this->middleware->configure([]);
158+
159+
$this->middleware->handleResponse($response);
160+
161+
self::assertFalse(
162+
$this->logger->messageWasLogged(
163+
'info',
164+
'[AllowedHttpStatusMiddleware] Dropping response with unallowed HTTP status',
165+
),
166+
);
167+
}
168+
169+
public function testAllowResponsesWithCustomAllowedStatuses(): void
170+
{
171+
$response = $this->makeResponse(status: 404);
172+
$this->middleware->configure(['handleStatus' => [404]]);
173+
174+
$result = $this->middleware->handleResponse($response);
175+
176+
self::assertSame($result, $response);
177+
self::assertFalse($result->wasDropped());
178+
}
179+
}

0 commit comments

Comments
 (0)