Esempio n. 1
0
 /**
  * Services requests for a connected client.
  *
  * Manages the server-side state for the remote client and interprets client commands.
  */
 private function handleClient(Socket $socket) : Generator
 {
     yield from log()->log(Log::INFO, 'Accepted client from %s:%d on %s:%d', $socket->getRemoteAddress(), $socket->getRemotePort(), $socket->getLocalAddress(), $socket->getLocalPort());
     // Create a new context object for this client.
     $context = new ClientContext($socket, $this->encoder, $this->accessLayer);
     try {
         // Send a welcome message.
         $welcome = new Response(200, 'Ready');
         yield from $context->writeResponse($welcome);
         // Command loop
         while ($socket->isOpen()) {
             // Parse incoming commands.
             $command = (yield from $context->readCommand());
             // Determine the command name and choose how to handle it.
             $handler = null;
             switch ($command->name()) {
                 // Mandatory commands
                 case 'CAPABILITIES':
                     $handler = $this->getHandler(handlers\CapabilitiesHandler::class);
                     break;
                 case 'HEAD':
                     $handler = $this->getHandler(handlers\HeadHandler::class);
                     break;
                 case 'HELP':
                     $handler = $this->getHandler(handlers\HelpHandler::class);
                     break;
                     // We don't advertise MODE support, but some readers need it
                 // We don't advertise MODE support, but some readers need it
                 case 'MODE':
                     $handler = $this->getHandler(handlers\ModeHandler::class);
                     break;
                 case 'STAT':
                     $handler = $this->getHandler(handlers\StatHandler::class);
                     break;
                 case 'QUIT':
                     yield from $context->writeResponse(new Response(205, 'Closing connection'));
                     break 2;
                     // stop command loop
                     // LIST commands
                 // stop command loop
                 // LIST commands
                 case 'LIST':
                     $handler = $this->getHandler(handlers\ListHandler::class);
                     break;
                     // NEWNEWS commands
                 // NEWNEWS commands
                 case 'NEWNEWS':
                     $handler = $this->getHandler(handlers\NewNewsHandler::class);
                     break;
                     // POST commands
                 // POST commands
                 case 'POST':
                     $handler = $this->getHandler(handlers\PostHandler::class);
                     break;
                     // READER commands
                 // READER commands
                 case 'ARTICLE':
                     $handler = $this->getHandler(handlers\ArticleHandler::class);
                     break;
                 case 'BODY':
                     $handler = $this->getHandler(handlers\BodyHandler::class);
                     break;
                 case 'DATE':
                     $handler = $this->getHandler(handlers\DateHandler::class);
                     break;
                 case 'GROUP':
                     $handler = $this->getHandler(handlers\GroupHandler::class);
                     break;
                 case 'LAST':
                     $handler = $this->getHandler(handlers\LastHandler::class);
                     break;
                 case 'LISTGROUP':
                     $handler = $this->getHandler(handlers\ListGroupHandler::class);
                     break;
                 case 'NEWGROUPS':
                     $handler = $this->getHandler(handlers\NewGroupsHandler::class);
                     break;
                 case 'NEXT':
                     $handler = $this->getHandler(handlers\NextHandler::class);
                     break;
             }
             // Unknown command
             if (!$handler) {
                 yield from $context->writeResponse(new Response(500, 'Unknown command'));
             } else {
                 // Execute the selected command handler.
                 try {
                     yield from $handler->handle($command, $context);
                 } catch (\Throwable $e) {
                     yield from log()->log(Log::ERROR, 'Error handling command: ' . $e);
                     yield from $context->writeResponse(new Response(502, 'Server error'));
                 }
             }
         }
     } catch (UnreadableException $e) {
         // Client disconnected.
     } catch (UnwritableException $e) {
         // Client disconnected.
     } catch (ClosedException $e) {
         // Client disconnected.
     }
     yield from log()->log(Log::INFO, 'Disconnected client from %s:%d on %s:%d', $socket->getRemoteAddress(), $socket->getRemotePort(), $socket->getLocalAddress(), $socket->getLocalPort());
     // Close the connection to the client.
     if ($socket->isOpen()) {
         $socket->close();
     }
 }
Esempio n. 2
0
 /**
  * @return int
  */
 public function getLocalPort() : int
 {
     return $this->socket->getLocalPort();
 }
Esempio n. 3
0
 /**
  * @param \Icicle\Socket\Socket $socket
  * @param int $cryptoMethod
  * @param float|int $timeout
  * @param bool $allowPersistent
  *
  * @return \Generator
  *
  * @resolve null
  */
 private function process(Socket $socket, int $cryptoMethod, float $timeout, bool $allowPersistent) : \Generator
 {
     $count = 0;
     assert(yield from $this->log->log(Log::DEBUG, 'Accepted client from %s:%d on %s:%d', $socket->getRemoteAddress(), $socket->getRemotePort(), $socket->getLocalAddress(), $socket->getLocalPort()));
     try {
         if (0 !== $cryptoMethod) {
             yield from $socket->enableCrypto($cryptoMethod, $timeout);
         }
         do {
             $request = null;
             try {
                 /** @var \Icicle\Http\Message\Request $request */
                 $request = (yield from $this->driver->readRequest($socket, $timeout));
                 ++$count;
                 /** @var \Icicle\Http\Message\Response $response */
                 $response = (yield from $this->createResponse($request, $socket));
                 assert(yield from $this->log->log(Log::DEBUG, 'Responded to request from %s:%d for %s with %d %s', $socket->getRemoteAddress(), $socket->getRemotePort(), $request->getUri(), $response->getStatusCode(), $response->getReasonPhrase()));
             } catch (TimeoutException $exception) {
                 // Request timeout.
                 if (0 < $count) {
                     assert(yield from $this->log->log(Log::DEBUG, 'Keep-alive timeout from %s:%d on %s:%d', $socket->getRemoteAddress(), $socket->getRemotePort(), $socket->getLocalAddress(), $socket->getLocalPort()));
                     return;
                     // Keep-alive timeout expired.
                 }
                 $response = (yield from $this->createErrorResponse(Response::REQUEST_TIMEOUT, $socket));
             } catch (MessageException $exception) {
                 // Bad request.
                 $response = (yield from $this->createErrorResponse($exception->getCode(), $socket));
             } catch (InvalidValueException $exception) {
                 // Invalid value in message header.
                 $response = (yield from $this->createErrorResponse(Response::BAD_REQUEST, $socket));
             } catch (ParseException $exception) {
                 // Parse error in request.
                 $response = (yield from $this->createErrorResponse(Response::BAD_REQUEST, $socket));
             }
             $response = (yield from $this->driver->buildResponse($response, $request, $timeout, $allowPersistent));
             try {
                 yield from $this->driver->writeResponse($socket, $response, $request, $timeout);
             } finally {
                 $response->getBody()->close();
             }
         } while (strtolower($response->getHeader('Connection')) === 'keep-alive');
     } catch (Throwable $exception) {
         yield from $this->log->log(Log::NOTICE, "Error when handling request from %s:%d: %s", $socket->getRemoteAddress(), $socket->getRemotePort(), $exception->getMessage());
     } finally {
         $socket->close();
     }
     assert(yield from $this->log->log(Log::DEBUG, 'Disconnected client from %s:%d on %s:%d', $socket->getRemoteAddress(), $socket->getRemotePort(), $socket->getLocalAddress(), $socket->getLocalPort()));
 }