Skip to content

Commit 40befa3

Browse files
authored
Add RemoveBodyMiddleware (#10)
1 parent 905256c commit 40befa3

File tree

7 files changed

+168
-3
lines changed

7 files changed

+168
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
## 1.0.1 under development
44

5-
- no changes in this release.
5+
- New #10: Add `RemoveBodyMiddleware` (@vjik)
66

77
## 1.0.0 June 04, 2025
88

9-
- Initial release.
9+
- Initial release.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ HTTP features:
2828
- [`HeadRequestMiddleware`](docs/guide/en/head-request-middleware.md) — removes body from response for `HEAD` request;
2929
- [`HttpCacheMiddleware`](docs/guide/en/http-cache-middleware.md) — implements HTTP caching using `Cache-Control`,
3030
`ETag`, and `Last-Modified` headers;
31+
- [`RemoveBodyMiddleware`](docs/guide/en/remove-body-middleware.md) — removes body from response by status code;
3132
- [`TagRequestMiddleware`](docs/guide/en/tag-request-middleware.md) — adds specific header to request, which can be used
3233
for logging or debugging purposes.
3334

docs/guide/en/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ HTTP features. All middleware implements independent functionality and doesn't i
88
- [`ForceSecureConnectionMiddleware`](force-secure-connection-middleware.md)
99
- [`HeadRequestMiddleware`](head-request-middleware.md)
1010
- [`HttpCacheMiddleware`](http-cache-middleware.md)
11+
- [`RemoveBodyMiddleware`](remove-body-middleware.md)
1112
- [`TagRequestMiddleware`](tag-request-middleware.md)
1213

docs/guide/en/head-request-middleware.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# `HeadRequestMiddleware`
22

3-
This middleware ensures that HTTP `HEAD` requests return a response without a body, as required by the HTTP specification.
3+
This middleware ensures that HTTP `HEAD` requests return a response without a body, as required by the HTTP
4+
specification.
45

56
General usage:
67

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# `RemoveBodyMiddleware`
2+
3+
This middleware removes the body from the response based on the status code. It is useful when you want to ensure that
4+
no body content is sent for certain HTTP responses, such as `204 No Content` or `304 Not Modified`.
5+
6+
General usage:
7+
8+
```php
9+
use Psr\Http\Message\StreamFactoryInterface;
10+
use Yiisoft\HttpMiddleware\RemoveBodyMiddleware;
11+
12+
/**
13+
* @var StreamFactoryInterface $streamFactory
14+
*/
15+
16+
$middleware = new RemoveBodyMiddleware($streamFactory);
17+
```
18+
19+
## Constructor parameters
20+
21+
### `$streamFactory` (required)
22+
23+
Type: `Psr\Http\Message\StreamFactoryInterface`
24+
25+
A PSR-17 stream factory used to create an empty body.
26+
27+
### `$statusCodes`
28+
29+
Type: `list<int>`
30+
31+
Default:
32+
```php
33+
[
34+
100, // Continue
35+
101, // Switching Protocols
36+
102, // Processing
37+
204, // No Content
38+
205, // Reset Content
39+
304, // Not Modified
40+
]
41+
```
42+
43+
An array of HTTP status codes for which the body should be removed.

src/RemoveBodyMiddleware.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\HttpMiddleware;
6+
7+
use Psr\Http\Message\ResponseInterface;
8+
use Psr\Http\Message\ServerRequestInterface;
9+
use Psr\Http\Message\StreamFactoryInterface;
10+
use Psr\Http\Server\MiddlewareInterface;
11+
use Psr\Http\Server\RequestHandlerInterface;
12+
13+
use function in_array;
14+
15+
/**
16+
* Removes the body from the response for specific HTTP status codes.
17+
*/
18+
final class RemoveBodyMiddleware implements MiddlewareInterface
19+
{
20+
/**
21+
* @param StreamFactoryInterface $streamFactory Factory to create a stream.
22+
* @param array $statusCodes List of HTTP status codes for which the body should be removed.
23+
*
24+
* @psalm-param list<int> $statusCodes
25+
*/
26+
public function __construct(
27+
private readonly StreamFactoryInterface $streamFactory,
28+
private readonly array $statusCodes = [
29+
100, // Continue
30+
101, // Switching Protocols
31+
102, // Processing
32+
204, // No Content
33+
205, // Reset Content
34+
304, // Not Modified
35+
],
36+
) {
37+
}
38+
39+
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
40+
{
41+
$response = $handler->handle($request);
42+
43+
return $this->shouldRemoveBody($response)
44+
? $this->removeBody($response)
45+
: $response;
46+
}
47+
48+
private function shouldRemoveBody(ResponseInterface $response): bool
49+
{
50+
return in_array($response->getStatusCode(), $this->statusCodes, true);
51+
}
52+
53+
private function removeBody(ResponseInterface $response): ResponseInterface
54+
{
55+
return $response->withBody(
56+
$this->streamFactory->createStream(),
57+
);
58+
}
59+
}

tests/RemoveBodyMiddlewareTest.php

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+
use HttpSoft\Message\Response;
6+
use HttpSoft\Message\ServerRequest;
7+
use HttpSoft\Message\StreamFactory;
8+
use PHPUnit\Framework\Attributes\TestWith;
9+
use PHPUnit\Framework\TestCase;
10+
use Yiisoft\HttpMiddleware\RemoveBodyMiddleware;
11+
use Yiisoft\HttpMiddleware\Tests\Support\FakeRequestHandler;
12+
13+
use function PHPUnit\Framework\assertSame;
14+
15+
final class RemoveBodyMiddlewareTest extends TestCase
16+
{
17+
#[TestWith([true, 200])]
18+
#[TestWith([true, 500])]
19+
#[TestWith([false, 100])]
20+
#[TestWith([false, 101])]
21+
#[TestWith([false, 102])]
22+
#[TestWith([false, 204])]
23+
#[TestWith([false, 205])]
24+
#[TestWith([false, 304])]
25+
public function testBase(bool $expectBody, int $statusCode): void
26+
{
27+
$streamFactory = new StreamFactory();
28+
$requestHandler = new FakeRequestHandler(
29+
new Response(
30+
statusCode: $statusCode,
31+
body: (new StreamFactory())->createStream('test')
32+
),
33+
);
34+
$middleware = new RemoveBodyMiddleware($streamFactory);
35+
36+
$response = $middleware->process(new ServerRequest(), $requestHandler);
37+
38+
assertSame($expectBody ? 'test' : '', (string) $response->getBody());
39+
}
40+
41+
#[TestWith([true, 200])]
42+
#[TestWith([true, 304])]
43+
#[TestWith([false, 100])]
44+
#[TestWith([false, 404])]
45+
public function testCustomStatus(bool $expectBody, int $statusCode): void
46+
{
47+
$streamFactory = new StreamFactory();
48+
$requestHandler = new FakeRequestHandler(
49+
new Response(
50+
statusCode: $statusCode,
51+
body: (new StreamFactory())->createStream('test')
52+
),
53+
);
54+
$middleware = new RemoveBodyMiddleware($streamFactory, [100, 404]);
55+
56+
$response = $middleware->process(new ServerRequest(), $requestHandler);
57+
58+
assertSame($expectBody ? 'test' : '', (string) $response->getBody());
59+
}
60+
}

0 commit comments

Comments
 (0)