Skip to content

Commit

Permalink
Stop parsing multipart request bodies once the configured limit of fo…
Browse files Browse the repository at this point in the history
…rm fields and files has been reached

This fix is inspired by how PHP is handling it but without following the ini setting. Such setting isn't needed as the limits on files and form fields are enough.
  • Loading branch information
WyriHaximus committed Feb 19, 2023
1 parent 436d84d commit b3594f7
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
15 changes: 15 additions & 0 deletions src/Io/MultipartParser.php
Expand Up @@ -26,6 +26,13 @@ final class MultipartParser
*/
private $maxFileSize;

/**
* Based on $maxInputVars and $maxFileUploads
*
* @var int
*/
private $maxMultipartBodyParts;

/**
* ini setting "max_input_vars"
*
Expand Down Expand Up @@ -62,6 +69,7 @@ final class MultipartParser
*/
private $maxFileUploads;

private $multipartBodyPartCount = 0;
private $postCount = 0;
private $filesCount = 0;
private $emptyCount = 0;
Expand All @@ -87,6 +95,8 @@ public function __construct($uploadMaxFilesize = null, $maxFileUploads = null)

$this->uploadMaxFilesize = IniUtil::iniSizeToBytes($uploadMaxFilesize);
$this->maxFileUploads = $maxFileUploads === null ? (\ini_get('file_uploads') === '' ? 0 : (int)\ini_get('max_file_uploads')) : (int)$maxFileUploads;

$this->maxMultipartBodyParts = $this->maxInputVars + $this->maxFileUploads;
}

public function parse(ServerRequestInterface $request)
Expand All @@ -101,6 +111,7 @@ public function parse(ServerRequestInterface $request)

$request = $this->request;
$this->request = null;
$this->multipartBodyPartCount = 0;
$this->postCount = 0;
$this->filesCount = 0;
$this->emptyCount = 0;
Expand Down Expand Up @@ -128,6 +139,10 @@ private function parseBody($boundary, $buffer)
// parse one part and continue searching for next
$this->parsePart(\substr($buffer, $start, $end - $start));
$start = $end;

if (++$this->multipartBodyPartCount > $this->maxMultipartBodyParts) {
break;
}
}
}

Expand Down
27 changes: 26 additions & 1 deletion tests/Io/MultipartParserTest.php
Expand Up @@ -1026,4 +1026,29 @@ public function testPostMaxFileSizeIgnoredByFilesComingBeforeIt()
$this->assertTrue(isset($files['file4']));
$this->assertSame(UPLOAD_ERR_OK, $files['file4']->getError());
}
}

public function testWeOnlyParseTheAmountOfMultiPartChunksWeConfigured()
{
$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 .= "--$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);
}
}

0 comments on commit b3594f7

Please sign in to comment.