Skip to content

Commit b0599c1

Browse files
[HttpClient] Fix bindto for IPv6 addresses
1 parent 69ff299 commit b0599c1

File tree

6 files changed

+36
-20
lines changed

6 files changed

+36
-20
lines changed

src/Symfony/Component/HttpClient/CurlHttpClient.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ public function request(string $method, string $url, array $options = []): Respo
274274
if (file_exists($options['bindto'])) {
275275
$curlopts[\CURLOPT_UNIX_SOCKET_PATH] = $options['bindto'];
276276
} elseif (!str_starts_with($options['bindto'], 'if!') && preg_match('/^(.*):(\d+)$/', $options['bindto'], $matches)) {
277-
$curlopts[\CURLOPT_INTERFACE] = $matches[1];
277+
$curlopts[\CURLOPT_INTERFACE] = trim($matches[1], '[]');
278278
$curlopts[\CURLOPT_LOCALPORT] = $matches[2];
279279
} else {
280280
$curlopts[\CURLOPT_INTERFACE] = $options['bindto'];

src/Symfony/Component/HttpClient/NativeHttpClient.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,9 @@ private static function dnsResolve($host, NativeClientState $multi, array &$info
334334
$info['debug'] .= "* Hostname was NOT found in DNS cache\n";
335335
$now = microtime(true);
336336

337-
if (!$ip = gethostbynamel($host)) {
337+
if ('[' === $host[0] && ']' === $host[-1] && filter_var(substr($host, 1, -1), \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
338+
$ip = [$host];
339+
} elseif (!$ip = gethostbynamel($host)) {
338340
throw new TransportException(sprintf('Could not resolve host "%s".', $host));
339341
}
340342

src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,6 @@ protected function getHttpClient(string $testCase): HttpClientInterface
3737
return new CurlHttpClient(['verify_peer' => false, 'verify_host' => false], 6, 50);
3838
}
3939

40-
public function testBindToPort()
41-
{
42-
$client = $this->getHttpClient(__FUNCTION__);
43-
$response = $client->request('GET', 'http://localhost:8057', ['bindto' => '127.0.0.1:9876']);
44-
$response->getStatusCode();
45-
46-
$r = new \ReflectionProperty($response, 'handle');
47-
$r->setAccessible(true);
48-
49-
$curlInfo = curl_getinfo($r->getValue($response));
50-
51-
self::assertSame('127.0.0.1', $curlInfo['local_ip']);
52-
self::assertSame(9876, $curlInfo['local_port']);
53-
}
54-
5540
public function testTimeoutIsNotAFatalError()
5641
{
5742
if ('\\' === \DIRECTORY_SEPARATOR) {

src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
case 'REQUEST_METHOD':
2626
case 'PHP_AUTH_USER':
2727
case 'PHP_AUTH_PW':
28+
case 'REMOTE_ADDR':
29+
case 'REMOTE_PORT':
2830
$vars[$k] = $v;
2931
}
3032
}

src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public static function tearDownAfterClass(): void
3636
{
3737
TestHttpServer::stop(8067);
3838
TestHttpServer::stop(8077);
39+
TestHttpServer::stop(8087);
3940
}
4041

4142
abstract protected function getHttpClient(string $testCase): HttpClientInterface;
@@ -1152,4 +1153,30 @@ public function testWithOptions()
11521153
$response = $client2->request('GET', '/');
11531154
$this->assertSame(200, $response->getStatusCode());
11541155
}
1156+
1157+
public function testBindToPort()
1158+
{
1159+
$client = $this->getHttpClient(__FUNCTION__);
1160+
$response = $client->request('GET', 'http://localhost:8057', ['bindto' => '127.0.0.1:9876']);
1161+
$response->getStatusCode();
1162+
1163+
$vars = $response->toArray();
1164+
1165+
self::assertSame('127.0.0.1', $vars['REMOTE_ADDR']);
1166+
self::assertSame('9876', $vars['REMOTE_PORT']);
1167+
}
1168+
1169+
public function testBindToPortV6()
1170+
{
1171+
TestHttpServer::start(8087, '[::1]');
1172+
1173+
$client = $this->getHttpClient(__FUNCTION__);
1174+
$response = $client->request('GET', 'http://[::1]:8087', ['bindto' => '[::1]:9876']);
1175+
$response->getStatusCode();
1176+
1177+
$vars = $response->toArray();
1178+
1179+
self::assertSame('::1', $vars['REMOTE_ADDR']);
1180+
self::assertSame('9876', $vars['REMOTE_PORT']);
1181+
}
11551182
}

src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class TestHttpServer
2121
/**
2222
* @return Process
2323
*/
24-
public static function start(int $port = 8057)
24+
public static function start(int $port = 8057, $ip = '127.0.0.1')
2525
{
2626
if (isset(self::$process[$port])) {
2727
self::$process[$port]->stop();
@@ -32,14 +32,14 @@ public static function start(int $port = 8057)
3232
}
3333

3434
$finder = new PhpExecutableFinder();
35-
$process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:'.$port]));
35+
$process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', $ip.':'.$port]));
3636
$process->setWorkingDirectory(__DIR__.'/Fixtures/web');
3737
$process->start();
3838
self::$process[$port] = $process;
3939

4040
do {
4141
usleep(50000);
42-
} while (!@fopen('http://127.0.0.1:'.$port, 'r'));
42+
} while (!@fopen('http://'.$ip.':'.$port, 'r'));
4343

4444
return $process;
4545
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy