Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c30d91a

Browse filesBrowse files
Merge branch '6.4' into 7.1
* 6.4: [HttpClient] Resolve hostnames in NoPrivateNetworkHttpClient [security-http] Check owner of persisted remember-me cookie
2 parents 90ab2a4 + cb4073c commit c30d91a
Copy full SHA for c30d91a
Expand file treeCollapse file tree

10 files changed

+78
-15
lines changed

‎HttpOptions.php

Copy file name to clipboardExpand all lines: HttpOptions.php
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ public function buffer(bool $buffer): static
166166
}
167167

168168
/**
169+
* @param callable(int, int, array, \Closure|null=):void $callback
170+
*
169171
* @return $this
170172
*/
171173
public function setOnProgress(callable $callback): static

‎NativeHttpClient.php

Copy file name to clipboardExpand all lines: NativeHttpClient.php
+10-2Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,15 @@ public function request(string $method, string $url, array $options = []): Respo
137137

138138
if ($onProgress = $options['on_progress']) {
139139
$maxDuration = 0 < $options['max_duration'] ? $options['max_duration'] : \INF;
140-
$onProgress = static function (...$progress) use ($onProgress, &$info, $maxDuration) {
140+
$multi = $this->multi;
141+
$resolve = static function (string $host, ?string $ip = null) use ($multi): ?string {
142+
if (null !== $ip) {
143+
$multi->dnsCache[$host] = $ip;
144+
}
145+
146+
return $multi->dnsCache[$host] ?? null;
147+
};
148+
$onProgress = static function (...$progress) use ($onProgress, &$info, $maxDuration, $resolve) {
141149
if ($info['total_time'] >= $maxDuration) {
142150
throw new TransportException(sprintf('Max duration was reached for "%s".', implode('', $info['url'])));
143151
}
@@ -156,7 +164,7 @@ public function request(string $method, string $url, array $options = []): Respo
156164
$lastProgress = $progress ?: $lastProgress;
157165
}
158166

159-
$onProgress($lastProgress[0], $lastProgress[1], $progressInfo);
167+
$onProgress($lastProgress[0], $lastProgress[1], $progressInfo, $resolve);
160168
};
161169
} elseif (0 < $options['max_duration']) {
162170
$maxDuration = $options['max_duration'];

‎NoPrivateNetworkHttpClient.php

Copy file name to clipboardExpand all lines: NoPrivateNetworkHttpClient.php
+15-2Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,27 @@ public function request(string $method, string $url, array $options = []): Respo
5656

5757
$subnets = $this->subnets;
5858

59-
$options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use ($onProgress, $subnets): void {
59+
$options['on_progress'] = static function (int $dlNow, int $dlSize, array $info, ?\Closure $resolve = null) use ($onProgress, $subnets): void {
6060
static $lastUrl = '';
6161
static $lastPrimaryIp = '';
6262

6363
if ($info['url'] !== $lastUrl) {
6464
$host = trim(parse_url($info['url'], PHP_URL_HOST) ?: '', '[]');
65+
$resolve ??= static fn () => null;
66+
67+
if (($ip = $host)
68+
&& !filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)
69+
&& !filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)
70+
&& !$ip = $resolve($host)
71+
) {
72+
if ($ip = @(dns_get_record($host, \DNS_A)[0]['ip'] ?? null)) {
73+
$resolve($host, $ip);
74+
} elseif ($ip = @(dns_get_record($host, \DNS_AAAA)[0]['ipv6'] ?? null)) {
75+
$resolve($host, '['.$ip.']');
76+
}
77+
}
6578

66-
if ($host && IpUtils::checkIp($host, $subnets ?? IpUtils::PRIVATE_SUBNETS)) {
79+
if ($ip && IpUtils::checkIp($ip, $subnets ?? IpUtils::PRIVATE_SUBNETS)) {
6780
throw new TransportException(sprintf('Host "%s" is blocked for "%s".', $host, $info['url']));
6881
}
6982

‎Response/AmpResponse.php

Copy file name to clipboardExpand all lines: Response/AmpResponse.php
+9-2Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,17 @@ public function __construct(
9090
$info['max_duration'] = $options['max_duration'];
9191
$info['debug'] = '';
9292

93+
$resolve = static function (string $host, ?string $ip = null) use ($multi): ?string {
94+
if (null !== $ip) {
95+
$multi->dnsCache[$host] = $ip;
96+
}
97+
98+
return $multi->dnsCache[$host] ?? null;
99+
};
93100
$onProgress = $options['on_progress'] ?? static function () {};
94-
$onProgress = $this->onProgress = static function () use (&$info, $onProgress) {
101+
$onProgress = $this->onProgress = static function () use (&$info, $onProgress, $resolve) {
95102
$info['total_time'] = microtime(true) - $info['start_time'];
96-
$onProgress((int) $info['size_download'], ((int) (1 + $info['download_content_length']) ?: 1) - 1, (array) $info);
103+
$onProgress((int) $info['size_download'], ((int) (1 + $info['download_content_length']) ?: 1) - 1, (array) $info, $resolve);
97104
};
98105

99106
$pauseDeferred = new Deferred();

‎Response/AsyncContext.php

Copy file name to clipboardExpand all lines: Response/AsyncContext.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ public function replaceRequest(string $method, string $url, array $options = [])
161161
$this->info['previous_info'][] = $info = $this->response->getInfo();
162162
if (null !== $onProgress = $options['on_progress'] ?? null) {
163163
$thisInfo = &$this->info;
164-
$options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use (&$thisInfo, $onProgress) {
165-
$onProgress($dlNow, $dlSize, $thisInfo + $info);
164+
$options['on_progress'] = static function (int $dlNow, int $dlSize, array $info, ?\Closure $resolve = null) use (&$thisInfo, $onProgress) {
165+
$onProgress($dlNow, $dlSize, $thisInfo + $info, $resolve);
166166
};
167167
}
168168
if (0 < ($info['max_duration'] ?? 0) && 0 < ($info['total_time'] ?? 0)) {

‎Response/AsyncResponse.php

Copy file name to clipboardExpand all lines: Response/AsyncResponse.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ public function __construct(HttpClientInterface $client, string $method, string
5252

5353
if (null !== $onProgress = $options['on_progress'] ?? null) {
5454
$thisInfo = &$this->info;
55-
$options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use (&$thisInfo, $onProgress) {
56-
$onProgress($dlNow, $dlSize, $thisInfo + $info);
55+
$options['on_progress'] = static function (int $dlNow, int $dlSize, array $info, ?\Closure $resolve = null) use (&$thisInfo, $onProgress) {
56+
$onProgress($dlNow, $dlSize, $thisInfo + $info, $resolve);
5757
};
5858
}
5959
$this->response = $client->request($method, $url, ['buffer' => false] + $options);

‎Response/CurlResponse.php

Copy file name to clipboardExpand all lines: Response/CurlResponse.php
+9-2Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,20 @@ public function __construct(
122122
curl_pause($ch, \CURLPAUSE_CONT);
123123

124124
if ($onProgress = $options['on_progress']) {
125+
$resolve = static function (string $host, ?string $ip = null) use ($multi): ?string {
126+
if (null !== $ip) {
127+
$multi->dnsCache->hostnames[$host] = $ip;
128+
}
129+
130+
return $multi->dnsCache->hostnames[$host] ?? null;
131+
};
125132
$url = isset($info['url']) ? ['url' => $info['url']] : [];
126133
curl_setopt($ch, \CURLOPT_NOPROGRESS, false);
127-
curl_setopt($ch, \CURLOPT_PROGRESSFUNCTION, static function ($ch, $dlSize, $dlNow) use ($onProgress, &$info, $url, $multi, $debugBuffer) {
134+
curl_setopt($ch, \CURLOPT_PROGRESSFUNCTION, static function ($ch, $dlSize, $dlNow) use ($onProgress, &$info, $url, $multi, $debugBuffer, $resolve) {
128135
try {
129136
rewind($debugBuffer);
130137
$debug = ['debug' => stream_get_contents($debugBuffer)];
131-
$onProgress($dlNow, $dlSize, $url + curl_getinfo($ch) + $info + $debug);
138+
$onProgress($dlNow, $dlSize, $url + curl_getinfo($ch) + $info + $debug, $resolve);
132139
} catch (\Throwable $e) {
133140
$multi->handlesActivity[(int) $ch][] = null;
134141
$multi->handlesActivity[(int) $ch][] = $e;

‎Tests/HttpClientTestCase.php

Copy file name to clipboardExpand all lines: Tests/HttpClientTestCase.php
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\HttpClient\Exception\InvalidArgumentException;
1616
use Symfony\Component\HttpClient\Exception\TransportException;
1717
use Symfony\Component\HttpClient\Internal\ClientState;
18+
use Symfony\Component\HttpClient\NoPrivateNetworkHttpClient;
1819
use Symfony\Component\HttpClient\Response\StreamWrapper;
1920
use Symfony\Component\Process\Exception\ProcessFailedException;
2021
use Symfony\Component\Process\Process;
@@ -467,6 +468,28 @@ public function testMisspelledScheme()
467468
$httpClient->request('GET', 'http:/localhost:8057/');
468469
}
469470

471+
public function testNoPrivateNetwork()
472+
{
473+
$client = $this->getHttpClient(__FUNCTION__);
474+
$client = new NoPrivateNetworkHttpClient($client);
475+
476+
$this->expectException(TransportException::class);
477+
$this->expectExceptionMessage('Host "localhost" is blocked');
478+
479+
$client->request('GET', 'http://localhost:8888');
480+
}
481+
482+
public function testNoPrivateNetworkWithResolve()
483+
{
484+
$client = $this->getHttpClient(__FUNCTION__);
485+
$client = new NoPrivateNetworkHttpClient($client);
486+
487+
$this->expectException(TransportException::class);
488+
$this->expectExceptionMessage('Host "symfony.com" is blocked');
489+
490+
$client->request('GET', 'http://symfony.com', ['resolve' => ['symfony.com' => '127.0.0.1']]);
491+
}
492+
470493
/**
471494
* @dataProvider getRedirectWithAuthTests
472495
*/

‎Tests/MockHttpClientTest.php

Copy file name to clipboardExpand all lines: Tests/MockHttpClientTest.php
+4-1Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,14 +331,17 @@ protected function getHttpClient(string $testCase): HttpClientInterface
331331

332332
switch ($testCase) {
333333
default:
334-
return new MockHttpClient(function (string $method, string $url, array $options) use ($client) {
334+
return new MockHttpClient(function (string $method, string $url, array $options) use ($client, $testCase) {
335335
try {
336336
// force the request to be completed so that we don't test side effects of the transport
337337
$response = $client->request($method, $url, ['buffer' => false] + $options);
338338
$content = $response->getContent(false);
339339

340340
return new MockResponse($content, $response->getInfo());
341341
} catch (\Throwable $e) {
342+
if (str_starts_with($testCase, 'testNoPrivateNetwork')) {
343+
throw $e;
344+
}
342345
$this->fail($e->getMessage());
343346
}
344347
});

‎TraceableHttpClient.php

Copy file name to clipboardExpand all lines: TraceableHttpClient.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ public function request(string $method, string $url, array $options = []): Respo
5555
$content = false;
5656
}
5757

58-
$options['on_progress'] = function (int $dlNow, int $dlSize, array $info) use (&$traceInfo, $onProgress) {
58+
$options['on_progress'] = function (int $dlNow, int $dlSize, array $info, ?\Closure $resolve = null) use (&$traceInfo, $onProgress) {
5959
$traceInfo = $info;
6060

6161
if (null !== $onProgress) {
62-
$onProgress($dlNow, $dlSize, $info);
62+
$onProgress($dlNow, $dlSize, $info, $resolve);
6363
}
6464
};
6565

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.