コード例 #1
0
ファイル: Dispatcher.php プロジェクト: koolkode/k1
 public function __invoke(HttpRequest $request, HttpDriverContext $context) : \Generator
 {
     $path = \str_replace('+', '%20', $request->getRequestTarget());
     $routing = new RoutingContext($this->container, $this->compiler, $path, $request->getMethod(), $this->routable->getMiddlewares());
     $this->routeRequest($routing);
     if (!$routing->isMatch()) {
         return $routing->createNoMatchResponse();
     }
     $matches = [];
     if ($request->hasHeader('Content-Type')) {
         $type = $request->getContentType()->getMediaType();
         foreach ($routing->getMatches() as $match) {
             if ($match->handler->canConsume($type)) {
                 $matches[] = $match;
             }
         }
     } else {
         foreach ($routing->getMatches() as $match) {
             if ($match->handler->isConsumer()) {
                 continue;
             }
             $matches[] = $match;
         }
     }
     if (!$matches) {
         return $routing->createUnsupportedMediaTypeResponse();
     }
     $accept = $request->getAccept();
     $result = $matches[0];
     foreach ($accept->getMediaTypes() as $media) {
         foreach ($matches as $match) {
             foreach ($match->handler->getProducedMediaTypes() as $type) {
                 if ($media->is($type)) {
                     $result = $match;
                     break 3;
                 }
             }
         }
     }
     if (empty($result->middlewares)) {
         return yield from $this->dispatchRequest($request, $context, $result);
     }
     $next = new NextMiddleware($result->middlewares, function (HttpRequest $request) use($context, $result) {
         return yield from $this->dispatchRequest($request, $context, $result);
     }, $this->logger);
     return yield from $next($request);
 }
コード例 #2
0
ファイル: PublishFiles.php プロジェクト: koolkode/async-http
 /**
  * Check if the HTTP request matches a public file and server it as needed.
  * 
  * @param HttpRequest $request
  * @param NextMiddleware $next
  * @return HttpResponse
  */
 public function __invoke(HttpRequest $request, NextMiddleware $next) : \Generator
 {
     static $methods = [Http::HEAD, Http::GET];
     if (!\in_array($request->getMethod(), $methods, true)) {
         return yield from $next($request);
     }
     $path = '/' . \trim($request->getRequestTarget(), '/');
     if ($this->basePath !== '/') {
         if (0 !== \strpos($path, $this->basePath)) {
             return yield from $next($request);
         }
         $path = \substr($path, \strlen($this->basePath) - 1);
     }
     $file = Filesystem::normalizePath($this->directory . \substr($path, 1));
     if (0 !== \strpos($file, $this->directory)) {
         return yield from $next($request);
     }
     if (!(yield LoopConfig::currentFilesystem()->isFile($file))) {
         return yield from $next($request);
     }
     return $this->createResponse($request, $file);
 }
コード例 #3
0
ファイル: ResourceMiddleware.php プロジェクト: koolkode/k1
 /**
  * {@inheritdoc}
  */
 public function __invoke(HttpRequest $request, NextMiddleware $next) : \Generator
 {
     static $methods = [Http::HEAD => true, Http::GET => true];
     if (empty($methods[$request->getMethod()])) {
         return yield from $next($request);
     }
     $path = '/' . \trim(Uri::decode($request->getRequestTarget()), '/');
     if (0 !== \strpos($path, $this->base)) {
         return yield from $next($request);
     }
     $path = \substr($path, \strlen($this->base));
     try {
         $file = $this->locator->locatePublicFile($path);
     } catch (ResourceNotFoundException $e) {
         return yield from $next($request);
     }
     $ext = false === ($pos = \strpos($file, '.')) ? '' : \strtolower(\substr($file, $pos + 1));
     foreach ($this->processors as $processor) {
         $result = $processor($request, $file, $ext);
         if ($result instanceof \Generator) {
             $result = (yield from $result);
         }
         if ($result instanceof HttpResponse) {
             $response = $result;
             break;
         }
     }
     if (!isset($response)) {
         $response = new FileResponse($file);
     }
     if (!$response->hasHeader('Cache-Control')) {
         $response = $response->withHeader('Cache-Control', \sprintf('public, max-age=%u', $this->ttl));
         if ($request->getProtocolVersion() === '1.0') {
             $response = $response->withHeader('Expires', \gmdate(Http::DATE_RFC1123, \time() + $this->ttl));
         }
     }
     return $response;
 }
コード例 #4
0
 /**
  * Assert that an upgrade to WebSockets is possible.
  * 
  * @param HttpRequest $request
  * @param HttpResponse $response
  * @return HttpResponse when upgrading is impossible, NULL if everything's fine.
  */
 protected function assertUpgradePossible(HttpRequest $request, HttpResponse $response)
 {
     if ($request->getMethod() !== Http::METHOD_GET) {
         return $response->withStatus(Http::CODE_METHOD_NOT_ALLOWED)->withHeader('Allow', 'GET');
     }
     if ($request->getProtocolVersion() !== '1.1') {
         return $response->withStatus(Http::CODE_HTTP_VERSION_NOT_SUPPORTED);
     }
     if (!$request->hasHeader('Sec-WebSocket-Key')) {
         return $response->withStatus(Http::CODE_BAD_REQUEST, 'Missing Sec-Websocket-Key header');
     }
     if ($request->hasHeader('Sec-Websocket-Version') && !in_array('13', $request->getHeader('Sec-Websocket-Version'), true)) {
         return $response->withStatus(Http::CODE_BAD_REQUEST, 'Web socket version 13 required')->withHeader('Sec-WebSocket-Version', '13');
     }
 }
コード例 #5
0
 /**
  * Assert that the given HTTP request can be upgraded to the WebSocket protocol.
  */
 protected function assertUpgradePossible(HttpRequest $request)
 {
     if ($request->getMethod() !== Http::GET) {
         throw new StatusException(Http::METHOD_NOT_ALLOWED, 'WebSocket upgrade requires an HTTP GET request', ['Allow' => Http::GET, 'Sec-Websocket-Version' => '13']);
     }
     if (!$request->hasHeader('Sec-Websocket-Key')) {
         throw new StatusException(Http::BAD_REQUEST, 'Missing Sec-Websocket-Key HTTP header', ['Sec-Websocket-Version' => '13']);
     }
     if (!\in_array('13', $request->getHeaderTokenValues('Sec-Websocket-Version'), true)) {
         throw new StatusException(Http::BAD_REQUEST, 'Secure websocket version 13 required', ['Sec-Websocket-Version' => '13']);
     }
 }
コード例 #6
0
ファイル: Driver.php プロジェクト: koolkode/async-http
 /**
  * Check for a pre-parsed HTTP/2 connection preface.
  */
 protected function isPrefaceRequest(HttpRequest $request) : bool
 {
     if ($request->getMethod() !== 'PRI') {
         return false;
     }
     if ($request->getRequestTarget() !== '*') {
         return false;
     }
     if ($request->getProtocolVersion() !== '2.0') {
         return false;
     }
     return true;
 }
コード例 #7
0
ファイル: Driver.php プロジェクト: koolkode/async-http
 protected function sendDeferredResponse(SocketStream $socket, HttpRequest $request, HttpResponse $response, bool $nobody, bool $close) : \Generator
 {
     if ($this->logger) {
         $this->logger->info('{ip} "{method} {target} HTTP/{protocol}" {status} {size}', ['ip' => $request->getClientAddress(), 'method' => $request->getMethod(), 'target' => $request->getRequestTarget(), 'protocol' => $request->getProtocolVersion(), 'status' => $response->getStatusCode(), 'size' => '-']);
     }
     if (!$nobody) {
         $close = true;
     }
     (yield $socket->write($this->serializeHeaders($response, $close, null, $nobody, true) . "\r\n"));
     (yield $socket->flush());
     if ($nobody) {
         $response->getBody()->close(false);
         return !$close;
     }
     $watcher = null;
     $task = new Coroutine(function () use(&$watcher, $socket, $request, $response) {
         $body = $response->getBody();
         $body->start($request, $this->logger);
         $bodyStream = (yield $body->getReadableStream());
         $e = null;
         try {
             while (null !== ($chunk = (yield $bodyStream->read()))) {
                 (yield $socket->write($chunk));
             }
         } catch (StreamClosedException $e) {
             // Client disconnected from server.
         } finally {
             try {
                 $bodyStream->close();
             } finally {
                 $body->close($e ? true : false);
             }
             $watcher->cancel(new \RuntimeException());
         }
         return false;
     }, true);
     $watcher = new Coroutine(function () use($socket, $task) {
         $socket = $socket->getSocket();
         while (\is_resource($socket) && !\feof($socket)) {
             (yield new AwaitRead($socket));
         }
         $task->cancel(new StreamClosedException('Client disconnected'));
     });
     return (yield $task);
 }
コード例 #8
0
 /**
  * Check if the given response payload should be compressed.
  * 
  * @param HttpRequest $request
  * @param HttpResponse $response
  * @return bool
  */
 protected function isCompressable(HttpRequest $request, HttpResponse $response) : bool
 {
     if ($request->getMethod() === Http::HEAD) {
         return false;
     }
     if ($response->getBody() instanceof DeferredBody || Http::isResponseWithoutBody($response->getStatusCode())) {
         return false;
     }
     if ($response->hasHeader('Content-Encoding') || !$response->hasHeader('Content-Type')) {
         return false;
     }
     try {
         $media = $response->getContentType()->getMediaType();
     } catch (InvalidMediaTypeException $e) {
         return false;
     }
     if (isset($this->types[(string) $media])) {
         return true;
     }
     foreach ($media->getSubTypes() as $sub) {
         if (isset($this->subTypes[$sub])) {
             return true;
         }
     }
     return false;
 }