Skip to content

Commit 8c281d4

Browse files
committed
Fix ignoring invalid/incomplete parts
1 parent 7c790ef commit 8c281d4

2 files changed

Lines changed: 113 additions & 3 deletions

File tree

src/Io/MultipartParser.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,13 @@ private function parseBuffer()
105105

106106
private function parseChunk($chunk)
107107
{
108-
if ($chunk === '') {
108+
$pos = strpos($chunk, "\r\n\r\n");
109+
if ($pos === false) {
109110
return;
110111
}
111112

112-
list ($header, $body) = explode("\r\n\r\n", $chunk, 2);
113-
$headers = $this->parseHeaders($header);
113+
$headers = $this->parseHeaders((string)substr($chunk, 0, $pos));
114+
$body = (string)substr($chunk, $pos + 4);
114115

115116
if (!isset($headers['content-disposition'])) {
116117
return;

tests/Io/MultipartParserTest.php

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,93 @@ public function testFileUpload()
379379
$this->assertSame("<?php echo 'Owner';\r\n\r\n", (string)$files['files'][2]->getStream());
380380
}
381381

382+
public function testInvalidDoubleContentDispositionUsesLast()
383+
{
384+
$boundary = "---------------------------5844729766471062541057622570";
385+
386+
$data = "--$boundary\r\n";
387+
$data .= "Content-Disposition: form-data; name=\"ignored\"\r\n";
388+
$data .= "Content-Disposition: form-data; name=\"key\"\r\n";
389+
$data .= "\r\n";
390+
$data .= "value\r\n";
391+
$data .= "--$boundary--\r\n";
392+
393+
$request = new ServerRequest('POST', 'http://example.com/', array(
394+
'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
395+
), $data, 1.1);
396+
397+
$parsedRequest = MultipartParser::parseRequest($request);
398+
399+
$this->assertEmpty($parsedRequest->getUploadedFiles());
400+
$this->assertSame(
401+
array(
402+
'key' => 'value'
403+
),
404+
$parsedRequest->getParsedBody()
405+
);
406+
}
407+
408+
public function testInvalidMissingNewlineAfterValueDoesNotMatter()
409+
{
410+
$boundary = "---------------------------5844729766471062541057622570";
411+
412+
$data = "--$boundary\r\n";
413+
$data .= "Content-Disposition: form-data; name=\"key\"\r\n";
414+
$data .= "\r\n";
415+
$data .= "value";
416+
$data .= "--$boundary--\r\n";
417+
418+
$request = new ServerRequest('POST', 'http://example.com/', array(
419+
'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
420+
), $data, 1.1);
421+
422+
$parsedRequest = MultipartParser::parseRequest($request);
423+
424+
$this->assertEmpty($parsedRequest->getUploadedFiles());
425+
$this->assertSame(
426+
array(
427+
'key' => 'value'
428+
),
429+
$parsedRequest->getParsedBody()
430+
);
431+
}
432+
433+
public function testInvalidMissingValueWillBeIgnored()
434+
{
435+
$boundary = "---------------------------5844729766471062541057622570";
436+
437+
$data = "--$boundary\r\n";
438+
$data .= "Content-Disposition: form-data; name=\"key\"\r\n";
439+
$data .= "\r\n";
440+
$data .= "--$boundary--\r\n";
441+
442+
$request = new ServerRequest('POST', 'http://example.com/', array(
443+
'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
444+
), $data, 1.1);
445+
446+
$parsedRequest = MultipartParser::parseRequest($request);
447+
448+
$this->assertEmpty($parsedRequest->getUploadedFiles());
449+
$this->assertEmpty($parsedRequest->getParsedBody());
450+
}
451+
452+
public function testInvalidMissingValueAndEndBoundaryWillBeIgnored()
453+
{
454+
$boundary = "---------------------------5844729766471062541057622570";
455+
456+
$data = "--$boundary\r\n";
457+
$data .= "Content-Disposition: form-data; name=\"key\"\r\n";
458+
459+
$request = new ServerRequest('POST', 'http://example.com/', array(
460+
'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
461+
), $data, 1.1);
462+
463+
$parsedRequest = MultipartParser::parseRequest($request);
464+
465+
$this->assertEmpty($parsedRequest->getUploadedFiles());
466+
$this->assertEmpty($parsedRequest->getParsedBody());
467+
}
468+
382469
public function testInvalidContentDispositionMissingWillBeIgnored()
383470
{
384471
$boundary = "---------------------------5844729766471062541057622570";
@@ -419,6 +506,28 @@ public function testInvalidContentDispositionWithoutNameWillBeIgnored()
419506
$this->assertEmpty($parsedRequest->getParsedBody());
420507
}
421508

509+
public function testInvalidMissingEndBoundaryWillBeIgnored()
510+
{
511+
$boundary = "---------------------------5844729766471062541057622570";
512+
513+
$data = "--$boundary\r\n";
514+
$data .= "Content-Disposition: form-data; name=\"key\"\r\n";
515+
$data .= "\r\n";
516+
$data .= "value\r\n";
517+
518+
$request = new ServerRequest('POST', 'http://example.com/', array(
519+
'Content-Type' => 'multipart/mixed; boundary=' . $boundary,
520+
), $data, 1.1);
521+
522+
$parsedRequest = MultipartParser::parseRequest($request);
523+
524+
$this->assertEmpty($parsedRequest->getUploadedFiles());
525+
$this->assertSame(
526+
null,
527+
$parsedRequest->getParsedBody()
528+
);
529+
}
530+
422531
public function testInvalidUploadFileWithoutContentTypeUsesNullValue()
423532
{
424533
$boundary = "---------------------------12758086162038677464950549563";

0 commit comments

Comments
 (0)