Skip to content

Commit dd9919b

Browse files
authored
Merge pull request #77 from mdrost/issue-76
Fix chunk header to be case-insensitive and allow leading zeros for end chunk
2 parents d70adc7 + 71e7eb2 commit dd9919b

File tree

2 files changed

+30
-15
lines changed

2 files changed

+30
-15
lines changed

src/ChunkedStreamDecoder.php

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,6 @@ protected function iterateBuffer()
8787
}
8888

8989
if ($this->nextChunkIsLength) {
90-
if (substr($this->buffer, 0, 3) === "0\r\n") {
91-
// We've reached the end of the stream
92-
$this->reachedEnd = true;
93-
$this->emit('end');
94-
$this->close();
95-
return false;
96-
}
97-
9890
$crlfPosition = strpos($this->buffer, static::CRLF);
9991
if ($crlfPosition === false && strlen($this->buffer) > 1024) {
10092
$this->emit('error', [
@@ -106,18 +98,22 @@ protected function iterateBuffer()
10698
if ($crlfPosition === false) {
10799
return false; // Chunk header hasn't completely come in yet
108100
}
109-
$this->nextChunkIsLength = false;
110101
$lengthChunk = substr($this->buffer, 0, $crlfPosition);
111102
if (strpos($lengthChunk, ';') !== false) {
112103
list($lengthChunk) = explode(';', $lengthChunk, 2);
113104
}
114105
if ($lengthChunk !== '') {
115106
$lengthChunk = ltrim($lengthChunk, "0");
116107
if ($lengthChunk === '') {
117-
$lengthChunk = "0";
108+
// We've reached the end of the stream
109+
$this->reachedEnd = true;
110+
$this->emit('end');
111+
$this->close();
112+
return false;
118113
}
119114
}
120-
if (dechex(hexdec($lengthChunk)) !== $lengthChunk) {
115+
$this->nextChunkIsLength = false;
116+
if (dechex(hexdec($lengthChunk)) !== strtolower($lengthChunk)) {
121117
$this->emit('error', [
122118
new Exception('Unable to validate "' . $lengthChunk . '" as chunk length header'),
123119
]);

tests/DecodeChunkedStreamTest.php

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ public function provideChunkedEncoding()
7373
],
7474
'end-chunk-zero-check-3' => [
7575
["00004\r\nWiki\r\n005\r\npedia\r\ne\r\n in\r\n\r\nchunks.\r\n0000\r\n\r\n"]
76+
],
77+
'uppercase-chunk' => [
78+
["4\r\nWiki\r\n5\r\npedia\r\nE\r\n in\r\n\r\nchunks.\r\n0\r\n\r\n"],
7679
]
7780
];
7881
}
@@ -130,7 +133,19 @@ public function testInvalidChunkedEncoding(array $strings)
130133
}
131134
}
132135

133-
public function testHandleEnd()
136+
public function provideZeroChunk()
137+
{
138+
return [
139+
['1-zero' => "0\r\n\r\n"],
140+
['random-zero' => str_repeat("0", rand(2, 10))."\r\n\r\n"]
141+
];
142+
}
143+
144+
/**
145+
* @test
146+
* @dataProvider provideZeroChunk
147+
*/
148+
public function testHandleEnd($zeroChunk)
134149
{
135150
$ended = false;
136151
$stream = new ThroughStream();
@@ -142,7 +157,7 @@ public function testHandleEnd()
142157
$ended = true;
143158
});
144159

145-
$stream->write("4\r\nWiki\r\n0\r\n\r\n");
160+
$stream->write("4\r\nWiki\r\n".$zeroChunk);
146161

147162
$this->assertTrue($ended);
148163
}
@@ -178,7 +193,11 @@ public function testHandleEndTrailers()
178193
$this->assertTrue($ended);
179194
}
180195

181-
public function testHandleEndEnsureNoError()
196+
/**
197+
* @test
198+
* @dataProvider provideZeroChunk
199+
*/
200+
public function testHandleEndEnsureNoError($zeroChunk)
182201
{
183202
$ended = false;
184203
$stream = new ThroughStream();
@@ -191,7 +210,7 @@ public function testHandleEndEnsureNoError()
191210
});
192211

193212
$stream->write("4\r\nWiki\r\n");
194-
$stream->write("0\r\n\r\n");
213+
$stream->write($zeroChunk);
195214
$stream->end();
196215

197216
$this->assertTrue($ended);

0 commit comments

Comments
 (0)