Skip to content

Commit d205a8e

Browse files
committed
Ignore multipart chunks without name
1 parent 628a121 commit d205a8e

2 files changed

Lines changed: 51 additions & 33 deletions

File tree

src/Io/MultipartParser.php

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -116,36 +116,29 @@ private function parseChunk($chunk)
116116
return;
117117
}
118118

119-
if ($this->headerStartsWith($headers['content-disposition'], 'filename')) {
120-
$this->parseFile($headers, $body);
119+
if (!$this->headerContainsParameter($headers['content-disposition'], 'name')) {
121120
return;
122121
}
123122

124-
if ($this->headerStartsWith($headers['content-disposition'], 'name')) {
123+
if ($this->headerContainsParameter($headers['content-disposition'], 'filename')) {
124+
$this->parseFile($headers, $body);
125+
} else {
125126
$this->parsePost($headers, $body);
126-
return;
127127
}
128128
}
129129

130130
private function parseFile($headers, $body)
131131
{
132-
if (
133-
!$this->headerContains($headers['content-disposition'], 'name=') ||
134-
!$this->headerContains($headers['content-disposition'], 'filename=')
135-
) {
136-
return;
137-
}
138-
139132
$this->request = $this->request->withUploadedFiles($this->extractPost(
140133
$this->request->getUploadedFiles(),
141-
$this->getFieldFromHeader($headers['content-disposition'], 'name'),
134+
$this->getParameterFromHeader($headers['content-disposition'], 'name'),
142135
$this->parseUploadedFile($headers, $body)
143136
));
144137
}
145138

146139
private function parseUploadedFile($headers, $body)
147140
{
148-
$filename = $this->getFieldFromHeader($headers['content-disposition'], 'filename');
141+
$filename = $this->getParameterFromHeader($headers['content-disposition'], 'filename');
149142
$bodyLength = strlen($body);
150143

151144
// no file selected (zero size and empty filename)
@@ -217,33 +210,22 @@ private function parseHeaders($header)
217210
return $headers;
218211
}
219212

220-
private function headerStartsWith(array $header, $needle)
221-
{
222-
foreach ($header as $part) {
223-
if (strpos($part, $needle) === 0) {
224-
return true;
225-
}
226-
}
227-
228-
return false;
229-
}
230-
231-
private function headerContains(array $header, $needle)
213+
private function headerContainsParameter(array $header, $parameter)
232214
{
233215
foreach ($header as $part) {
234-
if (strpos($part, $needle) !== false) {
216+
if (strpos($part, $parameter . '=') === 0) {
235217
return true;
236218
}
237219
}
238220

239221
return false;
240222
}
241223

242-
private function getFieldFromHeader(array $header, $field)
224+
private function getParameterFromHeader(array $header, $parameter)
243225
{
244226
foreach ($header as $part) {
245-
if (strpos($part, $field) === 0) {
246-
preg_match('/' . $field . '="?(.*)"$/', $part, $matches);
227+
if (strpos($part, $parameter) === 0) {
228+
preg_match('/' . $parameter . '="?(.*)"$/', $part, $matches);
247229
return $matches[1];
248230
}
249231
}

tests/Io/MultipartParserTest.php

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,50 @@ public function testFileUpload()
197197
$this->assertSame("<?php echo 'Owner';\r\n\r\n", (string)$files['files'][2]->getStream());
198198
}
199199

200+
public function testInvalidContentDispositionMissingWillBeIgnored()
201+
{
202+
$boundary = "---------------------------5844729766471062541057622570";
203+
204+
$data = "--$boundary\r\n";
205+
$data .= "Content-Type: text/plain\r\n";
206+
$data .= "\r\n";
207+
$data .= "hello";
208+
$data .= "--$boundary--\r\n";
209+
210+
$request = new ServerRequest('POST', 'http://example.com/', array(
211+
'Content-Type' => 'multipart/mixed; boundary=' . $boundary,
212+
), $data, 1.1);
213+
214+
$parsedRequest = MultipartParser::parseRequest($request);
215+
216+
$this->assertEmpty($parsedRequest->getUploadedFiles());
217+
$this->assertEmpty($parsedRequest->getParsedBody());
218+
}
219+
220+
public function testInvalidContentDispositionWithoutNameWillBeIgnored()
221+
{
222+
$boundary = "---------------------------5844729766471062541057622570";
223+
224+
$data = "--$boundary\r\n";
225+
$data .= "Content-Disposition: form-data; something=\"key\"\r\n";
226+
$data .= "\r\n";
227+
$data .= "value";
228+
$data .= "--$boundary--\r\n";
229+
230+
$request = new ServerRequest('POST', 'http://example.com/', array(
231+
'Content-Type' => 'multipart/mixed; boundary=' . $boundary,
232+
), $data, 1.1);
233+
234+
$parsedRequest = MultipartParser::parseRequest($request);
235+
236+
$this->assertEmpty($parsedRequest->getUploadedFiles());
237+
$this->assertEmpty($parsedRequest->getParsedBody());
238+
}
239+
200240
public function testUploadEmptyFile()
201241
{
202242
$boundary = "---------------------------12758086162038677464950549563";
203243

204-
$file = base64_decode("R0lGODlhAQABAIAAAP///wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==");
205-
206244
$data = "--$boundary\r\n";
207245
$data .= "Content-Disposition: form-data; name=\"file\"; filename=\"empty\"\r\n";
208246
$data .= "Content-type: text/plain\r\n";
@@ -236,8 +274,6 @@ public function testUploadNoFile()
236274
{
237275
$boundary = "---------------------------12758086162038677464950549563";
238276

239-
$file = base64_decode("R0lGODlhAQABAIAAAP///wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==");
240-
241277
$data = "--$boundary\r\n";
242278
$data .= "Content-Disposition: form-data; name=\"file\"; filename=\"\"\r\n";
243279
$data .= "Content-type: application/octet-stream\r\n";

0 commit comments

Comments
 (0)