Skip to content

Commit

Permalink
Refactor proxy handling to require https_proxy (#11915)
Browse files Browse the repository at this point in the history
Composer has always allowed a single http_proxy (or CGI_HTTP_PROXY)
environment variable to be used for both HTTP and HTTPS requests. But
many other tools and libraries require scheme-specific values.

The landscape is already complicated by the use of and need for upper
and lower case values, so to bring matters inline with current practice
https_proxy is now required for HTTPS requests.

The new proxy handler incorporates a transition mechanism, which allows
http_proxy to be used for all requests when https_proxy is not set and
provides a `needsTransitionWarning` method for the main application.

Moving to scheme-specific environment variables means that a user may
set a single proxy for either HTTP or HTTPS requests. To accomodate this
situation during the transition period, an https_proxy value can be set
to an empty string which will prevent http_proxy being used for HTTPS
requests.
  • Loading branch information
johnstevenson committed Apr 17, 2024
1 parent 92f641a commit 3cc490d
Show file tree
Hide file tree
Showing 13 changed files with 687 additions and 704 deletions.
93 changes: 4 additions & 89 deletions phpstan/baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -4008,16 +4008,6 @@ parameters:
count: 1
path: ../src/Composer/Util/Http/CurlDownloader.php

-
message: "#^Constant CURLOPT_PROXY_CAINFO not found\\.$#"
count: 1
path: ../src/Composer/Util/Http/CurlDownloader.php

-
message: "#^Constant CURLOPT_PROXY_CAPATH not found\\.$#"
count: 1
path: ../src/Composer/Util/Http/CurlDownloader.php

-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 3
Expand Down Expand Up @@ -4199,72 +4189,17 @@ parameters:
path: ../src/Composer/Util/Http/CurlDownloader.php

-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: ../src/Composer/Util/Http/ProxyHelper.php

-
message: "#^Foreach overwrites \\$name with its value variable\\.$#"
count: 1
path: ../src/Composer/Util/Http/ProxyHelper.php

-
message: "#^Implicit array creation is not allowed \\- variable \\$options does not exist\\.$#"
count: 1
path: ../src/Composer/Util/Http/ProxyHelper.php

-
message: "#^Only booleans are allowed in a negated boolean, int\\<0, 65535\\>\\|false\\|null given\\.$#"
count: 1
path: ../src/Composer/Util/Http/ProxyHelper.php

-
message: "#^Only booleans are allowed in an if condition, string\\|null given\\.$#"
count: 3
path: ../src/Composer/Util/Http/ProxyHelper.php

-
message: "#^Parameter \\#1 \\$proxy of static method Composer\\\\Util\\\\Http\\\\ProxyHelper\\:\\:formatParsedUrl\\(\\) expects array\\{scheme\\?\\: string, host\\: string, port\\?\\: int, user\\?\\: string, pass\\?\\: string\\}, array\\{scheme\\?\\: string, host\\?\\: string, port\\?\\: int\\<0, 65535\\>, user\\?\\: string, pass\\?\\: string, path\\?\\: string, query\\?\\: string, fragment\\?\\: string\\}\\|false given\\.$#"
count: 1
path: ../src/Composer/Util/Http/ProxyHelper.php

-
message: "#^Only booleans are allowed in &&, Composer\\\\Util\\\\NoProxyPattern\\|null given on the left side\\.$#"
count: 1
path: ../src/Composer/Util/Http/ProxyManager.php

-
message: "#^Only booleans are allowed in &&, string\\|null given on the right side\\.$#"
message: "#^Method Composer\\\\Util\\\\Http\\\\RequestProxy::getCurlOptions\\(\\) should return array\\<int, int\\|string\\> but returns array\\<int\\|string, int\\|string\\>.$#"
count: 1
path: ../src/Composer/Util/Http/ProxyManager.php

-
message: "#^Only booleans are allowed in a negated boolean, Composer\\\\Util\\\\Http\\\\ProxyManager\\|null given\\.$#"
count: 1
path: ../src/Composer/Util/Http/ProxyManager.php

-
message: "#^Only booleans are allowed in an if condition, string\\|null given\\.$#"
count: 4
path: ../src/Composer/Util/Http/ProxyManager.php

-
message: "#^Parameter \\#3 \\$formattedUrl of class Composer\\\\Util\\\\Http\\\\RequestProxy constructor expects string, string\\|null given\\.$#"
count: 1
path: ../src/Composer/Util/Http/ProxyManager.php

-
message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#"
count: 1
path: ../src/Composer/Util/Http/ProxyManager.php
path: ../src/Composer/Util/Http/RequestProxy.php

-
message: "#^Only booleans are allowed in an if condition, string given\\.$#"
message: "#^Constant CURLOPT_PROXY_CAINFO not found\\.$#"
count: 1
path: ../src/Composer/Util/Http/RequestProxy.php

-
message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#"
message: "#^Constant CURLOPT_PROXY_CAPATH not found\\.$#"
count: 1
path: ../src/Composer/Util/Http/RequestProxy.php

Expand Down Expand Up @@ -5281,26 +5216,6 @@ parameters:
count: 1
path: ../tests/Composer/Test/Util/GitTest.php

-
message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with 'Composer\\\\\\\\Util\\\\\\\\Http…' and Composer\\\\Util\\\\Http\\\\ProxyManager will always evaluate to true\\.$#"
count: 1
path: ../tests/Composer/Test/Util/Http/ProxyManagerTest.php

-
message: "#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with 'Composer\\\\\\\\Util\\\\\\\\Http…' and Composer\\\\Util\\\\Http\\\\RequestProxy will always evaluate to true\\.$#"
count: 1
path: ../tests/Composer/Test/Util/Http/ProxyManagerTest.php

-
message: "#^Only booleans are allowed in an if condition, string given\\.$#"
count: 1
path: ../tests/Composer/Test/Util/Http/ProxyManagerTest.php

-
message: "#^Parameter \\#1 \\$haystack of function stripos expects string, string\\|null given\\.$#"
count: 1
path: ../tests/Composer/Test/Util/Http/ProxyManagerTest.php

-
message: "#^Only booleans are allowed in an if condition, string\\|false\\|null given\\.$#"
count: 1
Expand Down
8 changes: 8 additions & 0 deletions src/Composer/Console/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
use Composer\Exception\NoSslException;
use Composer\XdebugHandler\XdebugHandler;
use Symfony\Component\Process\Exception\ProcessTimedOutException;
use Composer\Util\Http\ProxyManager;

/**
* The console application that handles the commands
Expand Down Expand Up @@ -398,6 +399,13 @@ function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknow
$io->writeError('<info>Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MiB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MiB), time: '.round(microtime(true) - $startTime, 2).'s');
}

if (ProxyManager::getInstance()->needsTransitionWarning()) {
$io->writeError('');
$io->writeError('<warning>Composer now requires separate proxy environment variables for HTTP and HTTPS requests.</warning>');
$io->writeError('<warning>Please set `https_proxy` in addition to your existing proxy environment variables.</warning>');
$io->writeError('<warning>This fallback (and warning) will be removed in Composer 2.8.0.</warning>');
}

return $result;
} catch (ScriptExecutionException $e) {
if ($this->getDisablePluginsByDefault() && $this->isRunningAsRoot() && !$this->io->isInteractive()) {
Expand Down
33 changes: 3 additions & 30 deletions src/Composer/Util/Http/CurlDownloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,6 @@ class CurlDownloader
private $maxRedirects = 20;
/** @var int */
private $maxRetries = 3;
/** @var ProxyManager */
private $proxyManager;
/** @var bool */
private $supportsSecureProxy;
/** @var array<int, string[]> */
protected $multiErrors = [
CURLM_BAD_HANDLE => ['CURLM_BAD_HANDLE', 'The passed-in handle is not a valid CURLM handle.'],
Expand Down Expand Up @@ -117,11 +113,6 @@ public function __construct(IOInterface $io, Config $config, array $options = []
}

$this->authHelper = new AuthHelper($io, $config);
$this->proxyManager = ProxyManager::getInstance();

$version = curl_version();
$features = $version['features'];
$this->supportsSecureProxy = defined('CURL_VERSION_HTTPS_PROXY') && ($features & CURL_VERSION_HTTPS_PROXY);
}

/**
Expand Down Expand Up @@ -245,26 +236,8 @@ private function initDownload(callable $resolve, callable $reject, string $origi
}
}

// Always set CURLOPT_PROXY to enable/disable proxy handling
// Any proxy authorization is included in the proxy url
$proxy = $this->proxyManager->getProxyForRequest($url);
if ($proxy->getUrl() !== '') {
curl_setopt($curlHandle, CURLOPT_PROXY, $proxy->getUrl());
}

// Curl needs certificate locations for secure proxies.
// CURLOPT_PROXY_SSL_VERIFY_PEER/HOST are enabled by default
if ($proxy->isSecure()) {
if (!$this->supportsSecureProxy) {
throw new TransportException('Connecting to a secure proxy using curl is not supported on PHP versions below 7.3.0.');
}
if (!empty($options['ssl']['cafile'])) {
curl_setopt($curlHandle, CURLOPT_PROXY_CAINFO, $options['ssl']['cafile']);
}
if (!empty($options['ssl']['capath'])) {
curl_setopt($curlHandle, CURLOPT_PROXY_CAPATH, $options['ssl']['capath']);
}
}
$proxy = ProxyManager::getInstance()->getProxyForRequest($url);
curl_setopt_array($curlHandle, $proxy->getCurlOptions($options['ssl'] ?? []));

$progress = array_diff_key(curl_getinfo($curlHandle), self::$timeInfo);

Expand All @@ -283,7 +256,7 @@ private function initDownload(callable $resolve, callable $reject, string $origi
'primaryIp' => '',
];

$usingProxy = $proxy->getFormattedUrl(' using proxy (%s)');
$usingProxy = $proxy->getStatus(' using proxy (%s)');
$ifModified = false !== stripos(implode(',', $options['http']['header']), 'if-modified-since:') ? ' if modified' : '';
if ($attributes['redirects'] === 0 && $attributes['retries'] === 0) {
$this->io->writeError('Downloading ' . Url::sanitize($url) . $usingProxy . $ifModified, true, IOInterface::DEBUG);
Expand Down
183 changes: 0 additions & 183 deletions src/Composer/Util/Http/ProxyHelper.php

This file was deleted.

0 comments on commit 3cc490d

Please sign in to comment.