mirror of
https://github.com/composer/composer
synced 2025-05-10 17:12:51 +00:00
Refactor proxy handling to require https_proxy (#11915)
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.
This commit is contained in:
parent
92f641ac3d
commit
3cc490d4c4
13 changed files with 717 additions and 734 deletions
|
@ -17,45 +17,174 @@ use Composer\Test\TestCase;
|
|||
|
||||
class RequestProxyTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider dataSecure
|
||||
*/
|
||||
public function testIsSecure(string $url, bool $expectedSecure): void
|
||||
public function testFactoryNone(): void
|
||||
{
|
||||
$proxy = new RequestProxy($url, [], '');
|
||||
$proxy = RequestProxy::none();
|
||||
|
||||
$this->assertSame($expectedSecure, $proxy->isSecure());
|
||||
$options = extension_loaded('curl') ? [CURLOPT_PROXY => ''] : [];
|
||||
self::assertSame($options, $proxy->getCurlOptions([]));
|
||||
self::assertNull($proxy->getContextOptions());
|
||||
self::assertSame('', $proxy->getStatus());
|
||||
}
|
||||
|
||||
public function testFactoryNoProxy(): void
|
||||
{
|
||||
$proxy = RequestProxy::noProxy();
|
||||
|
||||
$options = extension_loaded('curl') ? [CURLOPT_PROXY => ''] : [];
|
||||
self::assertSame($options, $proxy->getCurlOptions([]));
|
||||
self::assertNull($proxy->getContextOptions());
|
||||
self::assertSame('excluded by no_proxy', $proxy->getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataSecure
|
||||
*
|
||||
* @param ?non-empty-string $url
|
||||
*/
|
||||
public function testIsSecure(?string $url, bool $expected): void
|
||||
{
|
||||
$proxy = new RequestProxy($url, null, null, null);
|
||||
self::assertSame($expected, $proxy->isSecure());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array{0: ?non-empty-string, 1: bool}>
|
||||
*/
|
||||
public static function dataSecure(): array
|
||||
{
|
||||
// url, secure
|
||||
// url, expected
|
||||
return [
|
||||
'basic' => ['http://proxy.com:80', false],
|
||||
'secure' => ['https://proxy.com:443', true],
|
||||
'none' => ['', false],
|
||||
'none' => [null, false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProxyUrl
|
||||
*/
|
||||
public function testGetFormattedUrlFormat(string $url, string $format, string $expected): void
|
||||
public function testGetStatusThrowsOnBadFormatSpecifier(): void
|
||||
{
|
||||
$proxy = new RequestProxy($url, [], $url);
|
||||
|
||||
$message = $proxy->getFormattedUrl($format);
|
||||
$this->assertSame($expected, $message);
|
||||
$proxy = new RequestProxy('http://proxy.com:80', null, null, 'http://proxy.com:80');
|
||||
self::expectException('InvalidArgumentException');
|
||||
$proxy->getStatus('using proxy');
|
||||
}
|
||||
|
||||
public static function dataProxyUrl(): array
|
||||
/**
|
||||
* @dataProvider dataStatus
|
||||
*
|
||||
* @param ?non-empty-string $url
|
||||
*/
|
||||
public function testGetStatus(?string $url, ?string $format, string $expected): void
|
||||
{
|
||||
$proxy = new RequestProxy($url, null, null, $url);
|
||||
|
||||
if ($format === null) {
|
||||
// try with and without optional param
|
||||
self::assertSame($expected, $proxy->getStatus());
|
||||
self::assertSame($expected, $proxy->getStatus($format));
|
||||
} else {
|
||||
self::assertSame($expected, $proxy->getStatus($format));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array{0: ?non-empty-string, 1: ?string, 2: string}>
|
||||
*/
|
||||
public static function dataStatus(): array
|
||||
{
|
||||
$format = 'proxy (%s)';
|
||||
|
||||
// url, format, expected
|
||||
return [
|
||||
['', $format, ''],
|
||||
['http://proxy.com:80', $format, 'proxy (http://proxy.com:80)'],
|
||||
'no-proxy' => [null, $format, ''],
|
||||
'null-format' => ['http://proxy.com:80', null, 'http://proxy.com:80'],
|
||||
'with-format' => ['http://proxy.com:80', $format, 'proxy (http://proxy.com:80)'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* This test avoids HTTPS proxies so that it can be run on PHP < 7.3
|
||||
*
|
||||
* @requires extension curl
|
||||
* @dataProvider dataCurlOptions
|
||||
*
|
||||
* @param ?non-empty-string $url
|
||||
* @param ?non-empty-string $auth
|
||||
* @param array<int, string|int> $expected
|
||||
*/
|
||||
public function testGetCurlOptions(?string $url, ?string $auth, array $expected): void
|
||||
{
|
||||
$proxy = new RequestProxy($url, $auth, null, null);
|
||||
self::assertSame($expected, $proxy->getCurlOptions([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{0: ?string, 1: ?string, 2: array<int, string|int>}>
|
||||
*/
|
||||
public static function dataCurlOptions(): array
|
||||
{
|
||||
// url, auth, expected
|
||||
return [
|
||||
[null, null, [CURLOPT_PROXY => '']],
|
||||
['http://proxy.com:80', null,
|
||||
[
|
||||
CURLOPT_PROXY => 'http://proxy.com:80',
|
||||
CURLOPT_NOPROXY => '',
|
||||
],
|
||||
],
|
||||
['http://proxy.com:80', 'user:p%40ss',
|
||||
[
|
||||
CURLOPT_PROXY => 'http://proxy.com:80',
|
||||
CURLOPT_NOPROXY => '',
|
||||
CURLOPT_PROXYAUTH => CURLAUTH_BASIC,
|
||||
CURLOPT_PROXYUSERPWD => 'user:p%40ss',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP >= 7.3.0
|
||||
* @requires extension curl >= 7.52.0
|
||||
* @dataProvider dataCurlSSLOptions
|
||||
*
|
||||
* @param non-empty-string $url
|
||||
* @param ?non-empty-string $auth
|
||||
* @param array<string, string> $sslOptions
|
||||
* @param array<int, string|int> $expected
|
||||
*/
|
||||
public function testGetCurlOptionsWithSSL(string $url, ?string $auth, array $sslOptions, array $expected): void
|
||||
{
|
||||
$proxy = new RequestProxy($url, $auth, null, null);
|
||||
self::assertSame($expected, $proxy->getCurlOptions($sslOptions));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{0: string, 1: ?string, 2: array<string, string>, 3: array<int, string|int>}>
|
||||
*/
|
||||
public static function dataCurlSSLOptions(): array
|
||||
{
|
||||
// for PHPStan on PHP < 7.3
|
||||
$caInfo = 10246; // CURLOPT_PROXY_CAINFO
|
||||
$caPath = 10247; // CURLOPT_PROXY_CAPATH
|
||||
|
||||
// url, auth, sslOptions, expected
|
||||
return [
|
||||
['https://proxy.com:443', null, ['cafile' => '/certs/bundle.pem'],
|
||||
[
|
||||
CURLOPT_PROXY => 'https://proxy.com:443',
|
||||
CURLOPT_NOPROXY => '',
|
||||
$caInfo => '/certs/bundle.pem',
|
||||
],
|
||||
],
|
||||
['https://proxy.com:443', 'user:p%40ss', ['capath' => '/certs'],
|
||||
[
|
||||
CURLOPT_PROXY => 'https://proxy.com:443',
|
||||
CURLOPT_NOPROXY => '',
|
||||
CURLOPT_PROXYAUTH => CURLAUTH_BASIC,
|
||||
CURLOPT_PROXYUSERPWD => 'user:p%40ss',
|
||||
$caPath => '/certs',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue