Skip to content

Commit c5e4c1b

Browse files
committed
Add TransferEncoding header enum
1 parent 3c85039 commit c5e4c1b

File tree

2 files changed

+181
-0
lines changed

2 files changed

+181
-0
lines changed

src/Header/TransferEncoding.php

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
3+
/**
4+
* This file is part of php-fast-forward/http-message.
5+
*
6+
* This source file is subject to the license bundled
7+
* with this source code in the file LICENSE.
8+
*
9+
* @see https://github.com/php-fast-forward/http-message
10+
*
11+
* @copyright Copyright (c) 2025 Felipe Sayão Lobato Abreu <[email protected]>
12+
* @license https://opensource.org/licenses/MIT MIT License
13+
*/
14+
15+
declare(strict_types=1);
16+
17+
/**
18+
* This file is part of php-fast-forward/http-message.
19+
*
20+
* This source file is subject to the license bundled
21+
* with this source code in the file LICENSE.
22+
*
23+
* @link https://github.com/php-fast-forward/http-message
24+
* @copyright Copyright (c) 2025 Felipe Sayão Lobato Abreu <[email protected]>
25+
* @license https://opensource.org/licenses/MIT MIT License
26+
*/
27+
28+
namespace FastForward\Http\Message\Header;
29+
30+
/**
31+
* Enum TransferEncoding.
32+
*
33+
* Represents the HTTP `Transfer-Encoding` header values.
34+
*
35+
* Transfer-Encoding is a hop-by-hop header, meaning it applies only to a
36+
* single transport-level connection and MUST NOT be stored or reused by
37+
* caches for subsequent requests or responses. The listed values indicate
38+
* which transfer codings have been applied to the message body in order to
39+
* safely move it between intermediaries.
40+
*
41+
* Implementations using this enum SHOULD ensure that the semantics
42+
* of chunked transfer-coding and any compression codings are respected
43+
* according to the relevant HTTP specifications.
44+
*
45+
* @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1
46+
* @see https://datatracker.ietf.org/doc/html/rfc7230#section-4.1
47+
*/
48+
enum TransferEncoding: string
49+
{
50+
/**
51+
* Indicates that the message body is sent as a series of chunks.
52+
*
53+
* Chunked transfer-coding is the only transfer-coding that is mandatory
54+
* for HTTP/1.1 compliance and MUST be understood by all HTTP/1.1 agents
55+
* that advertise support for `Transfer-Encoding`.
56+
*
57+
* When present, `chunked` MUST be the final transfer-coding applied to
58+
* the payload. It allows the sender to stream content without knowing
59+
* the final length in advance.
60+
*/
61+
case Chunked = 'chunked';
62+
63+
/**
64+
* A transfer-coding using the Lempel-Ziv-Welch (LZW) algorithm.
65+
*
66+
* This coding derives from the historic UNIX `compress` format. It is
67+
* largely obsolete in modern HTTP and SHOULD NOT be used for new
68+
* deployments. Many clients no longer support it due to past patent
69+
* concerns and limited practical usage.
70+
*/
71+
case Compress = 'compress';
72+
73+
/**
74+
* A transfer-coding using the zlib structure with the DEFLATE
75+
* compression algorithm.
76+
*
77+
* This coding uses the zlib framing (RFC 1950) combined with the DEFLATE
78+
* algorithm (RFC 1951). Implementations MUST take care not to confuse
79+
* this with a “raw deflate” stream without zlib framing.
80+
*/
81+
case Deflate = 'deflate';
82+
83+
/**
84+
* A transfer-coding using the Lempel-Ziv coding (LZ77) with a 32-bit CRC.
85+
*
86+
* This corresponds to the traditional `gzip` format produced by the
87+
* UNIX `gzip` program. Some legacy systems MAY also accept `x-gzip`,
88+
* but as a transfer-coding value, `gzip` itself SHOULD be preferred.
89+
*/
90+
case Gzip = 'gzip';
91+
92+
/**
93+
* Determines whether the given `Transfer-Encoding` header indicates that
94+
* chunked transfer-coding has been applied.
95+
*
96+
* The `chunked` token MAY appear as one of several comma-separated values.
97+
* This method performs a case-insensitive search for its presence. While
98+
* RFC 7230 specifies that `chunked` MUST be the final transfer-coding
99+
* when present, this method deliberately checks only for its existence to
100+
* provide a more robust, tolerant interpretation of real-world headers.
101+
*
102+
* Callers SHOULD use this method before attempting to parse a message
103+
* body as chunked data.
104+
*
105+
* @param string $transferEncodingHeader the raw `Transfer-Encoding` header value
106+
*
107+
* @return bool true if `chunked` is present (case-insensitive), false otherwise
108+
*/
109+
public static function isChunked(string $transferEncodingHeader): bool
110+
{
111+
if ('' === $transferEncodingHeader) {
112+
return false;
113+
}
114+
115+
$codings = array_map('\mb_trim', explode(',', mb_strtolower($transferEncodingHeader)));
116+
117+
return \in_array(self::Chunked->value, $codings, true);
118+
}
119+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of php-fast-forward/http-message.
7+
*
8+
* This source file is subject to the license bundled
9+
* with this source code in the file LICENSE.
10+
*
11+
* @link https://github.com/php-fast-forward/http-message
12+
* @copyright Copyright (c) 2025 Felipe Sayão Lobato Abreu <[email protected]>
13+
* @license https://opensource.org/licenses/MIT MIT License
14+
*/
15+
16+
namespace FastForward\Http\Message\Tests\Header;
17+
18+
use FastForward\Http\Message\Header\TransferEncoding;
19+
use PHPUnit\Framework\Attributes\CoversClass;
20+
use PHPUnit\Framework\Attributes\DataProvider;
21+
use PHPUnit\Framework\TestCase;
22+
23+
/**
24+
* @internal
25+
*/
26+
#[CoversClass(TransferEncoding::class)]
27+
final class TransferEncodingTest extends TestCase
28+
{
29+
#[DataProvider('providerCases')]
30+
public function testCasesHaveCorrectValues(TransferEncoding $case, string $expected): void
31+
{
32+
self::assertSame($expected, $case->value);
33+
}
34+
35+
#[DataProvider('providerIsChunked')]
36+
public function testIsChunked(string $header, bool $expected): void
37+
{
38+
self::assertSame($expected, TransferEncoding::isChunked($header));
39+
}
40+
41+
public static function providerCases(): array
42+
{
43+
return [
44+
[TransferEncoding::Chunked, 'chunked'],
45+
[TransferEncoding::Compress, 'compress'],
46+
[TransferEncoding::Deflate, 'deflate'],
47+
[TransferEncoding::Gzip, 'gzip'],
48+
];
49+
}
50+
51+
public static function providerIsChunked(): array
52+
{
53+
return [
54+
'only chunked' => ['chunked', true],
55+
'chunked last' => ['gzip, chunked', true],
56+
'case insensitive' => ['GZIP, CHUNKED', true],
57+
'with spaces' => [' gzip , chunked ', true],
58+
'not chunked' => ['gzip, deflate', false],
59+
'empty header' => ['', false],
60+
];
61+
}
62+
}

0 commit comments

Comments
 (0)