Skip to content

Commit b3594f7

Browse files
committed
Stop parsing multipart request bodies once the configured limit of form 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.
1 parent 436d84d commit b3594f7

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

src/Io/MultipartParser.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ final class MultipartParser
2626
*/
2727
private $maxFileSize;
2828

29+
/**
30+
* Based on $maxInputVars and $maxFileUploads
31+
*
32+
* @var int
33+
*/
34+
private $maxMultipartBodyParts;
35+
2936
/**
3037
* ini setting "max_input_vars"
3138
*
@@ -62,6 +69,7 @@ final class MultipartParser
6269
*/
6370
private $maxFileUploads;
6471

72+
private $multipartBodyPartCount = 0;
6573
private $postCount = 0;
6674
private $filesCount = 0;
6775
private $emptyCount = 0;
@@ -87,6 +95,8 @@ public function __construct($uploadMaxFilesize = null, $maxFileUploads = null)
8795

8896
$this->uploadMaxFilesize = IniUtil::iniSizeToBytes($uploadMaxFilesize);
8997
$this->maxFileUploads = $maxFileUploads === null ? (\ini_get('file_uploads') === '' ? 0 : (int)\ini_get('max_file_uploads')) : (int)$maxFileUploads;
98+
99+
$this->maxMultipartBodyParts = $this->maxInputVars + $this->maxFileUploads;
90100
}
91101

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

102112
$request = $this->request;
103113
$this->request = null;
114+
$this->multipartBodyPartCount = 0;
104115
$this->postCount = 0;
105116
$this->filesCount = 0;
106117
$this->emptyCount = 0;
@@ -128,6 +139,10 @@ private function parseBody($boundary, $buffer)
128139
// parse one part and continue searching for next
129140
$this->parsePart(\substr($buffer, $start, $end - $start));
130141
$start = $end;
142+
143+
if (++$this->multipartBodyPartCount > $this->maxMultipartBodyParts) {
144+
break;
145+
}
131146
}
132147
}
133148

tests/Io/MultipartParserTest.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1026,4 +1026,29 @@ public function testPostMaxFileSizeIgnoredByFilesComingBeforeIt()
10261026
$this->assertTrue(isset($files['file4']));
10271027
$this->assertSame(UPLOAD_ERR_OK, $files['file4']->getError());
10281028
}
1029-
}
1029+
1030+
public function testWeOnlyParseTheAmountOfMultiPartChunksWeConfigured()
1031+
{
1032+
$boundary = "---------------------------12758086162038677464950549563";
1033+
1034+
$chunk = "--$boundary\r\n";
1035+
$chunk .= "Content-Disposition: form-data; name=\"f\"\r\n";
1036+
$chunk .= "\r\n";
1037+
$chunk .= "u\r\n";
1038+
$data = '';
1039+
for ($i = 0; $i < 5000000; $i++) {
1040+
$data .= $chunk;
1041+
}
1042+
$data .= "--$boundary--\r\n";
1043+
1044+
$request = new ServerRequest('POST', 'http://example.com/', array(
1045+
'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
1046+
), $data, 1.1);
1047+
1048+
$parser = new MultipartParser();
1049+
$startTime = microtime(true);
1050+
$parser->parse($request);
1051+
$runTime = microtime(true) - $startTime;
1052+
$this->assertLessThan(1, $runTime);
1053+
}
1054+
}

0 commit comments

Comments
 (0)