/** * Connects to an NNTP server. */ public static function connect(string $host, int $port = 119, array $options = []) : Generator { // Connect to the remote host. $socket = (yield from Dns\connect($host, $port, $options)); // Encoder for encoding and decoding the protocol. $encoder = new Rfc3977Encoder(); // Create the client object. $client = new static($socket, $encoder); // The server should respond with a welcome message. $response = (yield from $encoder->readResponse($socket)); // A 201 response code means posting is not allowed. if ($response->code() === 201) { $client->postingAllowed = false; } // Get the server capabilities. yield from $client->getServerCapabilities(); // Set reader client mode if necessary. if ($client->hasCapability('MODE-READER') || !$client->hasCapability('READER')) { yield from $client->sendCommand(new Command('MODE READER')); } // Enable encryption if supported. if ($client->hasCapability('STARTTLS')) { yield from $client->sendCommand(new Command('STARTTLS')); yield from $socket->enableCrypto(STREAM_CRYPTO_METHOD_ANY_CLIENT); } return $client; }
/** * @coroutine * * @param \Icicle\Http\Message\Request $request * @param mixed[] $options * * @return \Generator * * @resolve \Icicle\Http\Message\Response */ public function send(Request $request, array $options = []) : \Generator { $timeout = isset($options['timeout']) ? (double) $options['timeout'] : self::DEFAULT_TIMEOUT; $cryptoMethod = isset($options['crypto_method']) ? (int) $options['crypto_method'] : self::DEFAULT_CRYPTO_METHOD; $request = $request->withHeader('Connection', 'close'); $count = 0; try { do { $uri = $request->getUri(); $host = $uri->getHost(); $port = $uri->getPort(); if ('' === $host || 0 === $port) { throw new InvalidArgumentError('Request URI must have a host and port.'); } /** @var \Icicle\Socket\Socket $socket */ $socket = (yield from Dns\connect($uri->getHost(), $uri->getPort(), $options)); if ($uri->getScheme() === 'https') { yield from $socket->enableCrypto($cryptoMethod, $timeout); } /** @var \Icicle\Http\Message\Response $response */ $response = (yield from $this->requester->send($socket, $request, $options)); if ($this->follow) { switch ($response->getStatusCode()) { case Response::SEE_OTHER: $request = $request->withMethod($request->getMethod() === 'HEAD' ? 'HEAD' : 'GET'); // No break. // No break. case Response::MOVED_PERMANENTLY: case Response::FOUND: case Response::TEMPORARY_REDIRECT: case Response::PERMANENT_REDIRECT: $socket->close(); // Close original connection. if (++$count > $this->maxRedirects) { throw new RedirectException(sprintf('Too many redirects encountered (max redirects: %d).', $this->maxRedirects)); } if (!$response->hasHeader('Location')) { throw new RedirectException('No Location header found in redirect response.'); } $request = $request->withUri(new BasicUri($response->getHeader('Location'))); $response = null; // Let's go around again! } } } while (null === $response); } finally { $request->getBody()->close(); } return $response; }