Ejemplo n.º 1
0
 /**
  * {@inheritdoc}
  */
 public function send(HttpRequest $request) : Awaitable
 {
     if (!$request->hasHeader('User-Agent')) {
         $request = $request->withHeader('User-Agent', $this->userAgent);
     }
     $invoke = \Closure::bind(function (HttpRequest $request) {
         $next = new NextMiddleware($this->middlewares, function (HttpRequest $request) {
             return \array_shift($this->responses);
         });
         return new Coroutine($next($request));
     }, $this, HttpClient::class);
     return $invoke($request);
 }
Ejemplo n.º 2
0
 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);
 }
Ejemplo n.º 3
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');
     }
 }
Ejemplo n.º 4
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']);
     }
 }
Ejemplo n.º 5
0
 /**
  * Send the given HTTP request and fetch the HTTP response from the server.
  * 
  * @param HttpRequest $request The request to be sent (body will be closed after it has been sent).
  * @return HttpResponse The HTTP response as returned by the target server.
  */
 public function send(HttpRequest $request) : Awaitable
 {
     if (!$request->hasHeader('User-Agent')) {
         $request = $request->withHeader('User-Agent', $this->userAgent);
     }
     $next = new NextMiddleware($this->middlewares, function (HttpRequest $request) {
         $connecting = new \SplObjectStorage();
         $uri = $request->getUri();
         foreach ($this->connectors as $connector) {
             if (!$connector->isRequestSupported($request)) {
                 continue;
             }
             $context = (yield $connector->getConnectorContext($uri));
             if ($context->connected) {
                 foreach ($connecting as $conn) {
                     $connecting[$conn]->dispose();
                 }
                 return (yield $connector->send($context, $request));
             }
             $connecting[$connector] = $context;
         }
         try {
             $socket = (yield $this->connectSocket($request->getUri()));
             $meta = $socket->getMetadata();
             try {
                 $connector = $this->chooseConnector($request, \trim($meta['crypto']['alpn_protocol'] ?? ''), $meta);
             } catch (\Throwable $e) {
                 $socket->close();
                 throw $e;
             }
             $context = $connecting[$connector];
             $context->socket = $socket;
             $connecting->detach($connector);
             return (yield $connector->send($context, $request));
         } finally {
             foreach ($connecting as $conn) {
                 $connecting[$conn]->dispose();
             }
         }
     }, $this->logger);
     return new Coroutine($next($request));
 }
Ejemplo n.º 6
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);
     }
 }
Ejemplo n.º 7
0
 /**
  * Get all known hop IP addresses as provided by an HTTP proxy.
  * 
  * @param HttpRequest $request
  * @return array
  */
 public function getAddresses(HttpRequest $request) : array
 {
     $addresses = [];
     foreach ($this->addressHeaders as $name) {
         if ($request->hasHeader($name)) {
             foreach ($request->getHeaderTokenValues($name, false) as $ip) {
                 $addresses[] = $ip;
             }
         }
     }
     return $addresses;
 }