diff --git a/NoPrivateNetworkHttpClient.php b/NoPrivateNetworkHttpClient.php index 7bfe24d..ee74642 100644 --- a/NoPrivateNetworkHttpClient.php +++ b/NoPrivateNetworkHttpClient.php @@ -56,8 +56,20 @@ public function request(string $method, string $url, array $options = []): Respo $subnets = $this->subnets; - $options['on_progress'] = function (int $dlNow, int $dlSize, array $info) use ($onProgress, $subnets): void { + $options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use ($onProgress, $subnets): void { + static $lastUrl = ''; static $lastPrimaryIp = ''; + + if ($info['url'] !== $lastUrl) { + $host = trim(parse_url($info['url'], PHP_URL_HOST) ?: '', '[]'); + + if ($host && IpUtils::checkIp($host, $subnets ?? IpUtils::PRIVATE_SUBNETS)) { + throw new TransportException(sprintf('Host "%s" is blocked for "%s".', $host, $info['url'])); + } + + $lastUrl = $info['url']; + } + if ($info['primary_ip'] !== $lastPrimaryIp) { if ($info['primary_ip'] && IpUtils::checkIp($info['primary_ip'], $subnets ?? IpUtils::PRIVATE_SUBNETS)) { throw new TransportException(sprintf('IP "%s" is blocked for "%s".', $info['primary_ip'], $info['url'])); diff --git a/Tests/NoPrivateNetworkHttpClientTest.php b/Tests/NoPrivateNetworkHttpClientTest.php index 4fce894..ffd12ca 100644 --- a/Tests/NoPrivateNetworkHttpClientTest.php +++ b/Tests/NoPrivateNetworkHttpClientTest.php @@ -65,10 +65,10 @@ public static function getExcludeData(): array /** * @dataProvider getExcludeData */ - public function testExclude(string $ipAddr, $subnets, bool $mustThrow) + public function testExcludeByIp(string $ipAddr, $subnets, bool $mustThrow) { $content = 'foo'; - $url = sprintf('http://%s/', 0 < substr_count($ipAddr, ':') ? sprintf('[%s]', $ipAddr) : $ipAddr); + $url = sprintf('http://%s/', strtr($ipAddr, '.:', '--')); if ($mustThrow) { $this->expectException(TransportException::class); @@ -85,6 +85,29 @@ public function testExclude(string $ipAddr, $subnets, bool $mustThrow) } } + /** + * @dataProvider getExcludeData + */ + public function testExcludeByHost(string $ipAddr, $subnets, bool $mustThrow) + { + $content = 'foo'; + $url = sprintf('http://%s/', str_contains($ipAddr, ':') ? sprintf('[%s]', $ipAddr) : $ipAddr); + + if ($mustThrow) { + $this->expectException(TransportException::class); + $this->expectExceptionMessage(sprintf('Host "%s" is blocked for "%s".', $ipAddr, $url)); + } + + $previousHttpClient = $this->getHttpClientMock($url, $ipAddr, $content); + $client = new NoPrivateNetworkHttpClient($previousHttpClient, $subnets); + $response = $client->request('GET', $url); + + if (!$mustThrow) { + $this->assertEquals($content, $response->getContent()); + $this->assertEquals(200, $response->getStatusCode()); + } + } + public function testCustomOnProgressCallback() { $ipAddr = '104.26.14.6';