Skip to content

Commit 1e882ea

Browse files
committed
Limit ChunkedDecoder trailer size to avoid unbounded buffering
1 parent 796f509 commit 1e882ea

2 files changed

Lines changed: 20 additions & 0 deletions

File tree

src/Io/ChunkedDecoder.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ public function handleData($data)
158158
} elseif ($this->chunkSize === 0) {
159159
if ($positionCrlf === false) {
160160
// end chunk received, but trailer is incomplete
161+
// trailer shouldn't be bigger than 1024 bytes
162+
if (isset($this->buffer[static::MAX_CHUNK_HEADER_SIZE])) {
163+
$this->handleError(new Exception('Trailer size bigger than ' . static::MAX_CHUNK_HEADER_SIZE . ' bytes'));
164+
}
161165
return;
162166
}
163167
// end chunk received, skip all trailer data

tests/Io/ChunkedDecoderTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,22 @@ public function testEndChunkWithIncompleteTrailerWillEndOnceTrailerIsCompleted()
525525
$this->input->emit('data', ["\r\n\r\n"]);
526526
}
527527

528+
public function testEndChunkWithIncompleteTrailerIsTooBig()
529+
{
530+
$this->parser->on('data', $this->expectCallableNever());
531+
$this->parser->on('close', $this->expectCallableOnce());
532+
$this->parser->on('end', $this->expectCallableNever());
533+
$this->parser->on('error', $this->expectCallableOnce());
534+
535+
$data = '';
536+
for ($i = 0; $i < 1025; $i++) {
537+
$data .= 'a';
538+
}
539+
540+
// incomplete trailer must not be buffered without any limit
541+
$this->input->emit('data', ["0\r\n" . $data]);
542+
}
543+
528544
public function testChunkFollowedByExactlyTwoNonCrlfBytesWillErrorAndNotCauseInfiniteLoop()
529545
{
530546
$this->parser->on('data', $this->expectCallableOnceWith('ab'));

0 commit comments

Comments
 (0)