diff --git a/src/Server.php b/src/Server.php index a95028f0..6ad349c7 100644 --- a/src/Server.php +++ b/src/Server.php @@ -140,12 +140,14 @@ public function handleRequest(ConnectionInterface $conn, RequestInterface $reque $response = new Response($conn, $request->getProtocolVersion()); + $contentLength = 0; $stream = new CloseProtectionStream($conn); if ($request->hasHeader('Transfer-Encoding')) { $transferEncodingHeader = $request->getHeader('Transfer-Encoding'); // 'chunked' must always be the final value of 'Transfer-Encoding' according to: https://tools.ietf.org/html/rfc7230#section-3.3.1 if (strtolower(end($transferEncodingHeader)) === 'chunked') { $stream = new ChunkedDecoder($stream); + $contentLength = null; } } elseif ($request->hasHeader('Content-Length')) { $string = $request->getHeaderLine('Content-Length'); @@ -170,9 +172,9 @@ public function handleRequest(ConnectionInterface $conn, RequestInterface $reque $this->emit('request', array($request, $response)); - if ($stream instanceof LengthLimitedStream && $contentLength === 0) { - // Content-Length is 0 and won't emit further data, - // 'handleData' from LengthLimitedStream won't be called anymore + if ($contentLength === 0) { + // If Body is empty or Content-Length is 0 and won't emit further data, + // 'data' events from other streams won't be called anymore $stream->emit('end'); $stream->close(); } diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 73f29e8e..6eb4fc6f 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -100,7 +100,12 @@ public function testRequestPauseWillbeForwardedToConnection() $this->connection->expects($this->once())->method('pause'); $this->socket->emit('connection', array($this->connection)); - $data = $this->createGetRequest(); + $data = "GET / HTTP/1.1\r\n"; + $data .= "Host: example.com:80\r\n"; + $data .= "Connection: close\r\n"; + $data .= "Content-Length: 5\r\n"; + $data .= "\r\n"; + $this->connection->emit('data', array($data)); } @@ -1175,6 +1180,55 @@ public function testCloseRequestWillPauseConnection() $this->connection->emit('data', array($data)); } + public function testEndEventWillBeEmittedOnSimpleRequest() + { + $dataEvent = $this->expectCallableNever(); + $closeEvent = $this->expectCallableOnce(); + $endEvent = $this->expectCallableOnce(); + $errorEvent = $this->expectCallableNever(); + + $server = new Server($this->socket); + $server->on('request', function ($request, $response) use ($dataEvent, $closeEvent, $endEvent, $errorEvent){ + $request->on('data', $dataEvent); + $request->on('close', $closeEvent); + $request->on('end', $endEvent); + $request->on('error', $errorEvent); + }); + + $this->connection->expects($this->once())->method('pause'); + $this->connection->expects($this->never())->method('close'); + + $this->socket->emit('connection', array($this->connection)); + + $data = $this->createGetRequest(); + + $this->connection->emit('data', array($data)); + } + + public function testRequestWithoutDefinedLengthWillIgnoreDataEvent() + { + $server = new Server($this->socket); + + $dataEvent = $this->expectCallableNever(); + $endEvent = $this->expectCallableOnce(); + $closeEvent = $this->expectCallableOnce(); + $errorEvent = $this->expectCallableNever(); + + $server->on('request', function (Request $request, Response $response) use ($dataEvent, $endEvent, $closeEvent, $errorEvent) { + $request->on('data', $dataEvent); + $request->on('end', $endEvent); + $request->on('close', $closeEvent); + $request->on('error', $errorEvent); + }); + + $this->socket->emit('connection', array($this->connection)); + + $data = $this->createGetRequest(); + $data .= "hello world"; + + $this->connection->emit('data', array($data)); + } + private function createGetRequest() { $data = "GET / HTTP/1.1\r\n";