protected function createSocketChannel($socket, int $chunkSize, int $length = null) : Channel { $size = (int) \max(1, \ceil(65535 / $chunkSize)); return Channel::fromGenerator($size, function (Channel $channel) use($socket, $length, $chunkSize) { $reader = new SocketReader($socket); $remaining = $length ?? \PHP_INT_MAX; try { while ($remaining && null !== ($chunk = (yield $reader->readBuffer(\min($remaining, $chunkSize))))) { $remaining -= \strlen($chunk); (yield $channel->send($chunk)); } } finally { $reader->dispose(); } }); }
/** * {@inheritdoc} */ public function channel(int $chunkSize = 4096, int $length = null) : Channel { return Channel::fromGenerator(16, function (Channel $channel) use($chunkSize, $length) { (yield $this->executor->execute(function () use($channel, $chunkSize, $length) { $remaining = $length ?? \PHP_INT_MAX; while ($remaining && null !== ($chunk = (yield $this->stream->readBuffer(\min($remaining, $chunkSize))))) { $remaining -= \strlen($chunk); (yield $channel->send($chunk)); } })); }); }
/** * {@inheritdoc} */ public function channel(int $chunkSize = 4096, int $length = null) : Channel { $size = (int) \max(1, \ceil($this->readBufferSize / $chunkSize)); return Channel::fromGenerator($size, function (Channel $channel) use($chunkSize, $length) { $remaining = $length ?? \PHP_INT_MAX; while ($remaining && null !== ($chunk = (yield $this->readBuffer(\min($remaining, $chunkSize))))) { $remaining -= \strlen($chunk); (yield $channel->send($chunk)); } }); }
/** * {@inheritdoc} */ public function handleConnection(HttpDriverContext $context, SocketStream $socket, callable $action) : Awaitable { return new Coroutine(function () use($context, $socket, $action) { $remotePeer = $socket->getRemoteAddress(); $upgraded = false; if ($this->logger) { $this->logger->debug('Accepted new HTTP/1 connection from {peer}', ['peer' => $remotePeer]); } try { $request = (yield from $this->parseNextRequest($context, $socket)); if ($request->getProtocolVersion() !== '1.0' && $request->hasHeader('Host')) { try { yield from $this->upgradeConnection($context, $socket, $request, $action, $upgraded); if ($upgraded) { return; } } catch (\Throwable $e) { return yield from $this->sendErrorResponse($socket, $request, $e); } } $tokens = $request->getHeaderTokenValues('Connection'); if (\in_array('upgrade', $tokens, true)) { foreach ($tokens as $i => $token) { if ($token === 'keep-alive') { unset($tokens[$i]); } } // Ensure connections with an upgrade token in the connection header are not pipelined / persistent. $request = $request->withHeader('Connection', \implode(', ', \array_merge($tokens, ['close']))); } $pipeline = Channel::fromGenerator(10, function (Channel $channel) use($socket, $request, $context) { yield from $this->parseIncomingRequests($context, $socket, $channel, $request); }); try { while (null !== ($next = (yield $pipeline->receive()))) { if (!(yield from $this->processRequest($context, $socket, $action, $upgraded, ...$next))) { break; } } $pipeline->close(); } catch (\Throwable $e) { $pipeline->close($e); } } finally { try { $socket->close(); } finally { if ($this->logger && !$upgraded) { $this->logger->debug('Closed HTTP/1 connection to {peer}', ['peer' => $remotePeer]); } } } }); }