Skip to content

Commit 7108b38

Browse files
authored
Merge pull request #206 from clue-labs/parse-requests
Stricter check for invalid request-line in HTTP requests
2 parents 2dda18c + 952298c commit 7108b38

File tree

2 files changed

+36
-8
lines changed

2 files changed

+36
-8
lines changed

src/RequestHeaderParser.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,30 @@ public function feed($data)
4646

4747
if (false !== $endOfHeader) {
4848
try {
49-
$this->parseAndEmitRequest();
49+
$this->parseAndEmitRequest($endOfHeader);
5050
} catch (Exception $exception) {
5151
$this->emit('error', array($exception));
5252
}
5353
$this->removeAllListeners();
5454
}
5555
}
5656

57-
private function parseAndEmitRequest()
57+
private function parseAndEmitRequest($endOfHeader)
5858
{
59-
list($request, $bodyBuffer) = $this->parseRequest($this->buffer);
59+
$request = $this->parseRequest((string)substr($this->buffer, 0, $endOfHeader));
60+
$bodyBuffer = isset($this->buffer[$endOfHeader + 4]) ? substr($this->buffer, $endOfHeader + 4) : '';
6061
$this->emit('headers', array($request, $bodyBuffer));
6162
}
6263

63-
private function parseRequest($data)
64+
private function parseRequest($headers)
6465
{
65-
list($headers, $bodyBuffer) = explode("\r\n\r\n", $data, 2);
66+
// additional, stricter safe-guard for request line
67+
// because request parser doesn't properly cope with invalid ones
68+
if (!preg_match('#^[^ ]+ [^ ]+ HTTP/\d\.\d#m', $headers)) {
69+
throw new \InvalidArgumentException('Unable to parse invalid request-line');
70+
}
71+
72+
$lines = explode("\r\n", $headers);
6673

6774
// parser does not support asterisk-form and authority-form
6875
// remember original target and temporarily replace and re-apply below
@@ -213,6 +220,6 @@ private function parseRequest($data)
213220
// always sanitize Host header because it contains critical routing information
214221
$request = $request->withUri($request->getUri()->withUserInfo('u')->withUserInfo(''));
215222

216-
return array($request, $bodyBuffer);
223+
return $request;
217224
}
218225
}

tests/RequestHeaderParserTest.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ public function testHeaderOverflowShouldNotEmitErrorWhenDataExceedsMaxHeaderSize
176176
$this->assertSame($body, $bodyBuffer);
177177
}
178178

179-
public function testGuzzleRequestParseException()
179+
public function testInvalidEmptyRequestHeadersParseException()
180180
{
181181
$error = null;
182182

@@ -192,7 +192,28 @@ public function testGuzzleRequestParseException()
192192
$parser->feed("\r\n\r\n");
193193

194194
$this->assertInstanceOf('InvalidArgumentException', $error);
195-
$this->assertSame('Invalid message', $error->getMessage());
195+
$this->assertSame('Unable to parse invalid request-line', $error->getMessage());
196+
$this->assertSame(0, count($parser->listeners('headers')));
197+
$this->assertSame(0, count($parser->listeners('error')));
198+
}
199+
200+
public function testInvalidMalformedRequestLineParseException()
201+
{
202+
$error = null;
203+
204+
$parser = new RequestHeaderParser();
205+
$parser->on('headers', $this->expectCallableNever());
206+
$parser->on('error', function ($message) use (&$error) {
207+
$error = $message;
208+
});
209+
210+
$this->assertSame(1, count($parser->listeners('headers')));
211+
$this->assertSame(1, count($parser->listeners('error')));
212+
213+
$parser->feed("GET /\r\n\r\n");
214+
215+
$this->assertInstanceOf('InvalidArgumentException', $error);
216+
$this->assertSame('Unable to parse invalid request-line', $error->getMessage());
196217
$this->assertSame(0, count($parser->listeners('headers')));
197218
$this->assertSame(0, count($parser->listeners('error')));
198219
}

0 commit comments

Comments
 (0)