Skip to content

Commit

Permalink
Merge pull request #491 from WyriHaximus-labs/1.x-improve-multipart-l…
Browse files Browse the repository at this point in the history
…imits-test

Improve multipart limits test
  • Loading branch information
clue committed Apr 14, 2023
2 parents 9681f76 + 2942434 commit 5d2df79
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 13 deletions.
14 changes: 8 additions & 6 deletions src/Io/MultipartParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ final class MultipartParser
private $postCount = 0;
private $filesCount = 0;
private $emptyCount = 0;
private $cursor = 0;

/**
* @param int|string|null $uploadMaxFilesize
Expand Down Expand Up @@ -112,6 +113,7 @@ public function parse(ServerRequestInterface $request)
$request = $this->request;
$this->request = null;
$this->multipartBodyPartCount = 0;
$this->cursor = 0;
$this->postCount = 0;
$this->filesCount = 0;
$this->emptyCount = 0;
Expand All @@ -125,20 +127,20 @@ private function parseBody($boundary, $buffer)
$len = \strlen($boundary);

// ignore everything before initial boundary (SHOULD be empty)
$start = \strpos($buffer, $boundary . "\r\n");
$this->cursor = \strpos($buffer, $boundary . "\r\n");

while ($start !== false) {
while ($this->cursor !== false) {
// search following boundary (preceded by newline)
// ignore last if not followed by boundary (SHOULD end with "--")
$start += $len + 2;
$end = \strpos($buffer, "\r\n" . $boundary, $start);
$this->cursor += $len + 2;
$end = \strpos($buffer, "\r\n" . $boundary, $this->cursor);
if ($end === false) {
break;
}

// parse one part and continue searching for next
$this->parsePart(\substr($buffer, $start, $end - $start));
$start = $end;
$this->parsePart(\substr($buffer, $this->cursor, $end - $this->cursor));
$this->cursor = $end;

if (++$this->multipartBodyPartCount > $this->maxMultipartBodyParts) {
break;
Expand Down
29 changes: 22 additions & 7 deletions tests/Io/MultipartParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1029,26 +1029,41 @@ public function testPostMaxFileSizeIgnoredByFilesComingBeforeIt()

public function testWeOnlyParseTheAmountOfMultiPartChunksWeConfigured()
{
$chunkCount = 5000000;
$boundary = "---------------------------12758086162038677464950549563";

$chunk = "--$boundary\r\n";
$chunk .= "Content-Disposition: form-data; name=\"f\"\r\n";
$chunk .= "\r\n";
$chunk .= "u\r\n";
$data = '';
for ($i = 0; $i < 5000000; $i++) {
$data .= $chunk;
}
$data .= str_repeat($chunk, $chunkCount);
$data .= "--$boundary--\r\n";

$request = new ServerRequest('POST', 'http://example.com/', array(
'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
), $data, 1.1);

$parser = new MultipartParser();
$startTime = microtime(true);
$parser->parse($request);
$runTime = microtime(true) - $startTime;
$this->assertLessThan(1, $runTime);

$reflectecClass = new \ReflectionClass('\React\Http\Io\MultipartParser');
$requestProperty = $reflectecClass->getProperty('request');
$requestProperty->setAccessible(true);
$cursorProperty = $reflectecClass->getProperty('cursor');
$cursorProperty->setAccessible(true);
$multipartBodyPartCountProperty = $reflectecClass->getProperty('multipartBodyPartCount');
$multipartBodyPartCountProperty->setAccessible(true);
$maxMultipartBodyPartsProperty = $reflectecClass->getProperty('maxMultipartBodyParts');
$maxMultipartBodyPartsProperty->setAccessible(true);
$parseBodyMethod = $reflectecClass->getMethod('parseBody');
$parseBodyMethod->setAccessible(true);

$this->assertSame(0, $cursorProperty->getValue($parser));

$requestProperty->setValue($parser, $request);
$parseBodyMethod->invoke($parser, '--' . $boundary, $data);

$this->assertSame(strlen(str_repeat($chunk, $multipartBodyPartCountProperty->getValue($parser))), $cursorProperty->getValue($parser) + 2);
$this->assertSame($multipartBodyPartCountProperty->getValue($parser), $maxMultipartBodyPartsProperty->getValue($parser) + 1);
}
}

0 comments on commit 5d2df79

Please sign in to comment.