From 5893c2efa6b2e8e41d30dcec54f2666ffbacfece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Fri, 17 Feb 2017 00:51:18 +0100 Subject: [PATCH 1/2] Send HTTP status code 400 for invalid requests --- src/Server.php | 26 +++++++++++++++++++++++--- tests/ServerTest.php | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/Server.php b/src/Server.php index 6762d6b9..3a68a914 100644 --- a/src/Server.php +++ b/src/Server.php @@ -84,10 +84,14 @@ public function handleConnection(ConnectionInterface $conn) }); $conn->on('data', $listener); - $parser->on('error', function() use ($conn, $listener, $that) { - // TODO: return 400 response + $parser->on('error', function(\Exception $e) use ($conn, $listener, $that) { $conn->removeListener('data', $listener); - $that->emit('error', func_get_args()); + $that->emit('error', array($e)); + + $that->writeError( + $conn, + 400 + ); }); } @@ -123,4 +127,20 @@ public function handleRequest(ConnectionInterface $conn, Request $request) $this->emit('request', array($request, $response)); } + + /** @internal */ + public function writeError(ConnectionInterface $conn, $code) + { + $message = 'Error ' . $code; + if (isset(ResponseCodes::$statusTexts[$code])) { + $message .= ': ' . ResponseCodes::$statusTexts[$code]; + } + + $response = new Response($conn); + $response->writeHead($code, array( + 'Content-Length' => strlen($message), + 'Content-Type' => 'text/plain' + )); + $response->end($message); + } } diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 0b934da3..305bb31a 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -206,7 +206,6 @@ public function testParserErrorEmitted() { $error = null; $server = new Server($this->socket); - $server->on('headers', $this->expectCallableNever()); $server->on('error', function ($message) use (&$error) { $error = $message; }); @@ -218,7 +217,38 @@ public function testParserErrorEmitted() $this->connection->emit('data', array($data)); $this->assertInstanceOf('OverflowException', $error); - $this->connection->expects($this->never())->method('write'); + } + + public function testRequestInvalidWillEmitErrorAndSendErrorResponse() + { + $error = null; + $server = new Server($this->socket); + $server->on('error', function ($message) use (&$error) { + $error = $message; + }); + + $buffer = ''; + + $this->connection + ->expects($this->any()) + ->method('write') + ->will( + $this->returnCallback( + function ($data) use (&$buffer) { + $buffer .= $data; + } + ) + ); + + $this->socket->emit('connection', array($this->connection)); + + $data = "bad request\r\n\r\n"; + $this->connection->emit('data', array($data)); + + $this->assertInstanceOf('InvalidArgumentException', $error); + + $this->assertContains("HTTP/1.1 400 Bad Request\r\n", $buffer); + $this->assertContains("\r\n\r\nError 400: Bad Request", $buffer); } private function createGetRequest() From 65433b391be99dfa9352792d7b8d9dd0878c3df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Sat, 18 Feb 2017 01:22:44 +0100 Subject: [PATCH 2/2] Documentation for invalid request messages --- README.md | 9 +++++++++ src/Server.php | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/README.md b/README.md index aefcd2b9..88549055 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,15 @@ $http->on('request', function (Request $request, Response $response) { See also [`Request`](#request) and [`Response`](#response) for more details. +If a client sends an invalid request message, it will emit an `error` event, +send an HTTP error response to the client and close the connection: + +```php +$http->on('error', function (Exception $e) { + echo 'Error: ' . $e->getMessage() . PHP_EOL; +}); +``` + ### Request The `Request` class is responsible for streaming the incoming request body diff --git a/src/Server.php b/src/Server.php index 3a68a914..7ff523c1 100644 --- a/src/Server.php +++ b/src/Server.php @@ -28,6 +28,15 @@ * * See also [`Request`](#request) and [`Response`](#response) for more details. * + * If a client sends an invalid request message, it will emit an `error` event, + * send an HTTP error response to the client and close the connection: + * + * ```php + * $http->on('error', function (Exception $e) { + * echo 'Error: ' . $e->getMessage() . PHP_EOL; + * }); + * ``` + * * @see Request * @see Response */