Beispiel #1
0
 /**
  * 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)));
 }
Beispiel #2
0
 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);
 }
Beispiel #3
0
 /**
  * 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));
 }
Beispiel #4
0
 /**
  * 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);
     }
 }