From 9a89475a4694af29c2ea9b74b59a598bdbd9ff4a Mon Sep 17 00:00:00 2001 From: Mateusz Drost Date: Sun, 19 Mar 2017 02:43:41 +0100 Subject: [PATCH 1/2] Allow chunk size to be encoded with uppercase hexadecimal digits --- src/ChunkedStreamDecoder.php | 2 +- tests/DecodeChunkedStreamTest.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ChunkedStreamDecoder.php b/src/ChunkedStreamDecoder.php index c3d8de6..0c49db8 100644 --- a/src/ChunkedStreamDecoder.php +++ b/src/ChunkedStreamDecoder.php @@ -117,7 +117,7 @@ protected function iterateBuffer() $lengthChunk = "0"; } } - if (dechex(hexdec($lengthChunk)) !== $lengthChunk) { + if (dechex(hexdec($lengthChunk)) !== strtolower($lengthChunk)) { $this->emit('error', [ new Exception('Unable to validate "' . $lengthChunk . '" as chunk length header'), ]); diff --git a/tests/DecodeChunkedStreamTest.php b/tests/DecodeChunkedStreamTest.php index 6276529..41e28e4 100644 --- a/tests/DecodeChunkedStreamTest.php +++ b/tests/DecodeChunkedStreamTest.php @@ -73,6 +73,9 @@ public function provideChunkedEncoding() ], 'end-chunk-zero-check-3' => [ ["00004\r\nWiki\r\n005\r\npedia\r\ne\r\n in\r\n\r\nchunks.\r\n0000\r\n\r\n"] + ], + 'uppercase-chunk' => [ + ["4\r\nWiki\r\n5\r\npedia\r\nE\r\n in\r\n\r\nchunks.\r\n0\r\n\r\n"], ] ]; } From 71e7eb229f63f01132cfedb5d6ee8682b9555e27 Mon Sep 17 00:00:00 2001 From: Mateusz Drost Date: Sun, 19 Mar 2017 02:47:05 +0100 Subject: [PATCH 2/2] Allow terminating chunk to has variable number of zeros --- src/ChunkedStreamDecoder.php | 16 ++++++---------- tests/DecodeChunkedStreamTest.php | 24 ++++++++++++++++++++---- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/ChunkedStreamDecoder.php b/src/ChunkedStreamDecoder.php index 0c49db8..1402077 100644 --- a/src/ChunkedStreamDecoder.php +++ b/src/ChunkedStreamDecoder.php @@ -87,14 +87,6 @@ protected function iterateBuffer() } if ($this->nextChunkIsLength) { - if (substr($this->buffer, 0, 3) === "0\r\n") { - // We've reached the end of the stream - $this->reachedEnd = true; - $this->emit('end'); - $this->close(); - return false; - } - $crlfPosition = strpos($this->buffer, static::CRLF); if ($crlfPosition === false && strlen($this->buffer) > 1024) { $this->emit('error', [ @@ -106,7 +98,6 @@ protected function iterateBuffer() if ($crlfPosition === false) { return false; // Chunk header hasn't completely come in yet } - $this->nextChunkIsLength = false; $lengthChunk = substr($this->buffer, 0, $crlfPosition); if (strpos($lengthChunk, ';') !== false) { list($lengthChunk) = explode(';', $lengthChunk, 2); @@ -114,9 +105,14 @@ protected function iterateBuffer() if ($lengthChunk !== '') { $lengthChunk = ltrim($lengthChunk, "0"); if ($lengthChunk === '') { - $lengthChunk = "0"; + // We've reached the end of the stream + $this->reachedEnd = true; + $this->emit('end'); + $this->close(); + return false; } } + $this->nextChunkIsLength = false; if (dechex(hexdec($lengthChunk)) !== strtolower($lengthChunk)) { $this->emit('error', [ new Exception('Unable to validate "' . $lengthChunk . '" as chunk length header'), diff --git a/tests/DecodeChunkedStreamTest.php b/tests/DecodeChunkedStreamTest.php index 41e28e4..435dc00 100644 --- a/tests/DecodeChunkedStreamTest.php +++ b/tests/DecodeChunkedStreamTest.php @@ -133,7 +133,19 @@ public function testInvalidChunkedEncoding(array $strings) } } - public function testHandleEnd() + public function provideZeroChunk() + { + return [ + ['1-zero' => "0\r\n\r\n"], + ['random-zero' => str_repeat("0", rand(2, 10))."\r\n\r\n"] + ]; + } + + /** + * @test + * @dataProvider provideZeroChunk + */ + public function testHandleEnd($zeroChunk) { $ended = false; $stream = new ThroughStream(); @@ -145,7 +157,7 @@ public function testHandleEnd() $ended = true; }); - $stream->write("4\r\nWiki\r\n0\r\n\r\n"); + $stream->write("4\r\nWiki\r\n".$zeroChunk); $this->assertTrue($ended); } @@ -181,7 +193,11 @@ public function testHandleEndTrailers() $this->assertTrue($ended); } - public function testHandleEndEnsureNoError() + /** + * @test + * @dataProvider provideZeroChunk + */ + public function testHandleEndEnsureNoError($zeroChunk) { $ended = false; $stream = new ThroughStream(); @@ -194,7 +210,7 @@ public function testHandleEndEnsureNoError() }); $stream->write("4\r\nWiki\r\n"); - $stream->write("0\r\n\r\n"); + $stream->write($zeroChunk); $stream->end(); $this->assertTrue($ended);