/** * Dispatch the given HTTP request to the given action. */ protected function processRequest(HttpDriverContext $context, SocketStream $socket, callable $action, bool &$upgraded, HttpRequest $request, bool $close) : \Generator { static $remove = ['Keep-Alive', 'Content-Length', 'Transfer-Encoding']; // No need for TCP_NODELAY as the connection will be closed anyways flushing the last chunk without delay. if ($close) { $socket->setTcpNoDelay(false); } try { if ($request->getProtocolVersion() == '1.1' && !$request->hasHeader('Host')) { throw new StatusException(Http::BAD_REQUEST, 'Missing HTTP Host header'); } foreach ($remove as $name) { $request = $request->withoutHeader($name); } $next = new NextMiddleware($context->getMiddlewares(), function (HttpRequest $request) use($context, $action) { $response = $action($request, $context->withPrependedResponder(function (HttpRequest $request, $result) { return $this->upgradeResult($request, $result); })); if ($response instanceof \Generator) { $response = (yield from $response); } if (!$response instanceof HttpResponse) { $response = $this->upgradeResult($request, $response); } return $context->respond($request, $response); }, $this->logger); $response = (yield from $next($request)); $handler = $response->getAttribute(UpgradeResultHandler::class); if ($handler instanceof UpgradeResultHandler) { $upgraded = true; return yield from $this->upgradeResultConnection($handler, $socket, $request, $response); } return yield from $this->sendResponse($socket, $request, $response, $close); } catch (\Throwable $e) { return yield from $this->sendErrorResponse($socket, $request, $e); } }