/** * Assemble an HTTP request from received FCGI params. */ protected function buildRequest() : HttpRequest { static $extra = ['CONTENT_TYPE' => 'Content-Type', 'CONTENT_LENGTH' => 'Content-Length', 'CONTENT_MD5' => 'Content-MD5']; $uri = \strtolower($this->params['REQUEST_SCHEME'] ?? 'http') . '://'; $uri .= $this->params['HTTP_HOST'] ?? $this->context->getPeerName(); if (!empty($this->params['SERVER_PORT'])) { $uri .= ':' . (int) $this->params['SERVER_PORT']; } $uri = Uri::parse($uri . '/' . \ltrim($this->params['REQUEST_URI'] ?? '', '/')); $request = new HttpRequest($uri, $this->params['REQUEST_METHOD'] ?? Http::GET, [], '1.1'); foreach ($this->params as $k => $v) { if ('HTTP_' === \substr($k, 0, 5)) { switch ($k) { case 'HTTP_TRANSFER_ENCODING': case 'HTTP_CONTENT_ENCODING': case 'HTTP_KEEP_ALIVE': // Skip these headers... break; default: $request = $request->withAddedHeader(\str_replace('_', '-', \substr($k, 5)), (string) $v); } } } foreach ($extra as $k => $v) { if (isset($this->params[$k])) { $request = $request->withHeader($v, $this->params[$k]); } } $addresses = [$this->conn->getRemoteAddress()]; if (isset($this->params['REMOTE_ADDR'])) { $addresses = \array_merge([$this->params['REMOTE_ADDR']], $addresses); } $request = $request->withAddress(...$addresses); $request = $request->withAttribute(HttpDriverContext::class, $this->context); return $request->withBody(new StreamBody(new ReadableChannelStream($this->body))); }
protected function dispatchRequest(HttpRequest $request, HttpDriverContext $context, RouteMatch $match) : \Generator { // TODO: Add support for param converters. $ref = $match->handler->getReflection(); $args = []; foreach ($ref->getParameters() as $param) { if (isset($match->params[$param->name])) { $args[] = $match->params[$param->name]; continue; } $type = $param->getClass(); if ($type) { switch ($type->name) { case HttpRequest::class: $args[] = $request; continue 2; case PathParams::class: $args[] = new PathParams($match->params); continue 2; } foreach ($this->compiler->getBodyReaders() as $reader) { if ($reader->isSupported($type)) { $args[] = (yield from $reader->readBody($request, $type)); continue 2; } } $args[] = $this->container->get($type->name, $param->isOptional()); } else { if (!$param->isOptional()) { throw new StatusException(Http::CONFLICT, \sprintf('Missing action param "%s"', $param->name)); } $args[] = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null; } } $result = $match->handler->getAction()(...$args); if ($result instanceof \Generator) { $result = (yield from $result); } $type = \is_object($result) ? \get_class($result) : \gettype($result); foreach ($this->compiler->getBodyWriters() as $writer) { $response = $writer->createResponse($request, $result); if ($response instanceof \Generator) { $response = (yield from $response); } if ($response !== null) { return $response; } } return $context->respond($request, $result); }
/** * Process the given HTTP request and generate and send an appropriate response to the client. */ protected function processRequest(HttpDriverContext $context, Connection $conn, callable $action, Stream $stream, HttpRequest $request) : \Generator { $next = new NextMiddleware($context->getMiddlewares(), function (HttpRequest $request) use($context, $action) { $response = $action($request, $context); if ($response instanceof \Generator) { $response = (yield from $response); } return $context->respond($request, $response); }, $this->logger); $response = (yield from $next($request)); $response = $response->withHeader('Date', \gmdate(Http::DATE_RFC1123)); (yield $stream->sendResponse($request, $response)); }
/** * 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); } }