diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 4ed34b83b3a40..70fb803a99ddb 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -95,10 +95,7 @@ public function request(string $method, string $url, array $options = []): Respo $scheme = $url['scheme']; $authority = $url['authority']; $host = parse_url($authority, \PHP_URL_HOST); - $proxy = $options['proxy'] - ?? ('https:' === $url['scheme'] ? $_SERVER['https_proxy'] ?? $_SERVER['HTTPS_PROXY'] ?? null : null) - // Ignore HTTP_PROXY except on the CLI to work around httpoxy set of vulnerabilities - ?? $_SERVER['http_proxy'] ?? (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? $_SERVER['HTTP_PROXY'] ?? null : null) ?? $_SERVER['all_proxy'] ?? $_SERVER['ALL_PROXY'] ?? null; + $proxy = self::getProxyUrl($options['proxy'], $url); $url = implode('', $url); if (!isset($options['normalized_headers']['user-agent'])) { @@ -411,7 +408,7 @@ private static function createRedirectResolver(array $options, string $host): \C } } - return static function ($ch, string $location, bool $noContent) use (&$redirectHeaders) { + return static function ($ch, string $location, bool $noContent) use (&$redirectHeaders, $options) { try { $location = self::parseUrl($location); } catch (InvalidArgumentException $e) { @@ -436,11 +433,7 @@ private static function createRedirectResolver(array $options, string $host): \C $url = self::parseUrl(curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL)); $url = self::resolveUrl($location, $url); - curl_setopt($ch, \CURLOPT_PROXY, $options['proxy'] - ?? ('https:' === $url['scheme'] ? $_SERVER['https_proxy'] ?? $_SERVER['HTTPS_PROXY'] ?? null : null) - // Ignore HTTP_PROXY except on the CLI to work around httpoxy set of vulnerabilities - ?? $_SERVER['http_proxy'] ?? (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? $_SERVER['HTTP_PROXY'] ?? null : null) ?? $_SERVER['all_proxy'] ?? $_SERVER['ALL_PROXY'] ?? null - ); + curl_setopt($ch, \CURLOPT_PROXY, self::getProxyUrl($options['proxy'], $url)); return implode('', $url); }; diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php index 47454923051d1..411fcf65f7017 100644 --- a/src/Symfony/Component/HttpClient/HttpClientTrait.php +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -655,16 +655,7 @@ private static function mergeQueryString(?string $queryString, array $queryArray */ private static function getProxy(?string $proxy, array $url, ?string $noProxy): ?array { - if (null === $proxy) { - // Ignore HTTP_PROXY except on the CLI to work around httpoxy set of vulnerabilities - $proxy = $_SERVER['http_proxy'] ?? (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? $_SERVER['HTTP_PROXY'] ?? null : null) ?? $_SERVER['all_proxy'] ?? $_SERVER['ALL_PROXY'] ?? null; - - if ('https:' === $url['scheme']) { - $proxy = $_SERVER['https_proxy'] ?? $_SERVER['HTTPS_PROXY'] ?? $proxy; - } - } - - if (null === $proxy) { + if (null === $proxy = self::getProxyUrl($proxy, $url)) { return null; } @@ -692,6 +683,22 @@ private static function getProxy(?string $proxy, array $url, ?string $noProxy): ]; } + private static function getProxyUrl(?string $proxy, array $url): ?string + { + if (null !== $proxy) { + return $proxy; + } + + // Ignore HTTP_PROXY except on the CLI to work around httpoxy set of vulnerabilities + $proxy = $_SERVER['http_proxy'] ?? (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? $_SERVER['HTTP_PROXY'] ?? null : null) ?? $_SERVER['all_proxy'] ?? $_SERVER['ALL_PROXY'] ?? null; + + if ('https:' === $url['scheme']) { + $proxy = $_SERVER['https_proxy'] ?? $_SERVER['HTTPS_PROXY'] ?? $proxy; + } + + return $proxy; + } + private static function shouldBuffer(array $headers): bool { if (null === $contentType = $headers['content-type'][0] ?? null) { diff --git a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php index 30a7049758d0d..cf947cb25a545 100644 --- a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php +++ b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php @@ -86,6 +86,12 @@ header('Location: //?foo=bar', true, 301); break; + case '/301/proxy': + case 'http://localhost:8057/301/proxy': + case 'http://127.0.0.1:8057/301/proxy': + header('Location: http://localhost:8057/', true, 301); + break; + case '/302': if (!isset($vars['HTTP_AUTHORIZATION'])) { header('Location: http://localhost:8057/', true, 302); diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 7acd6b79c1a41..78b02786a8857 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -969,6 +969,14 @@ public function testProxy() } finally { unset($_SERVER['http_proxy']); } + + $response = $client->request('GET', 'http://localhost:8057/301/proxy', [ + 'proxy' => 'http://localhost:8057', + ]); + + $body = $response->toArray(); + $this->assertSame('localhost:8057', $body['HTTP_HOST']); + $this->assertMatchesRegularExpression('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']); } public function testNoProxy()