2022-02-23 15:58:18 +00:00
|
|
|
<?php declare(strict_types=1);
|
2020-09-24 15:48:22 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This file is part of Composer.
|
|
|
|
*
|
|
|
|
* (c) Nils Adermann <naderman@naderman.de>
|
|
|
|
* Jordi Boggiano <j.boggiano@seld.be>
|
|
|
|
*
|
|
|
|
* For the full copyright and license information, please view the LICENSE
|
|
|
|
* file that was distributed with this source code.
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace Composer\Test\Util\Http;
|
|
|
|
|
|
|
|
use Composer\Util\Http\ProxyManager;
|
|
|
|
use Composer\Test\TestCase;
|
|
|
|
|
2024-04-17 12:34:26 +00:00
|
|
|
/**
|
|
|
|
* @phpstan-import-type contextOptions from \Composer\Util\Http\RequestProxy
|
|
|
|
*/
|
2020-09-24 15:48:22 +00:00
|
|
|
class ProxyManagerTest extends TestCase
|
|
|
|
{
|
2024-04-17 12:34:26 +00:00
|
|
|
// isTransitional can be removed after the transition period
|
|
|
|
|
|
|
|
/** @var bool */
|
|
|
|
private $isTransitional = true;
|
|
|
|
|
2021-12-08 16:03:05 +00:00
|
|
|
protected function setUp(): void
|
2020-09-24 15:48:22 +00:00
|
|
|
{
|
|
|
|
unset(
|
|
|
|
$_SERVER['HTTP_PROXY'],
|
|
|
|
$_SERVER['http_proxy'],
|
|
|
|
$_SERVER['HTTPS_PROXY'],
|
|
|
|
$_SERVER['https_proxy'],
|
|
|
|
$_SERVER['NO_PROXY'],
|
|
|
|
$_SERVER['no_proxy'],
|
2024-04-17 12:34:26 +00:00
|
|
|
$_SERVER['CGI_HTTP_PROXY'],
|
|
|
|
$_SERVER['cgi_http_proxy']
|
2020-09-24 15:48:22 +00:00
|
|
|
);
|
|
|
|
ProxyManager::reset();
|
|
|
|
}
|
|
|
|
|
2021-12-08 16:03:05 +00:00
|
|
|
protected function tearDown(): void
|
2020-09-24 15:48:22 +00:00
|
|
|
{
|
2021-12-09 16:09:07 +00:00
|
|
|
parent::tearDown();
|
2020-09-24 15:48:22 +00:00
|
|
|
unset(
|
|
|
|
$_SERVER['HTTP_PROXY'],
|
|
|
|
$_SERVER['http_proxy'],
|
|
|
|
$_SERVER['HTTPS_PROXY'],
|
|
|
|
$_SERVER['https_proxy'],
|
|
|
|
$_SERVER['NO_PROXY'],
|
|
|
|
$_SERVER['no_proxy'],
|
2024-04-17 12:34:26 +00:00
|
|
|
$_SERVER['CGI_HTTP_PROXY'],
|
|
|
|
$_SERVER['cgi_http_proxy']
|
2020-09-24 15:48:22 +00:00
|
|
|
);
|
|
|
|
ProxyManager::reset();
|
|
|
|
}
|
|
|
|
|
2022-02-18 09:38:54 +00:00
|
|
|
public function testInstantiation(): void
|
2020-09-24 15:48:22 +00:00
|
|
|
{
|
|
|
|
$originalInstance = ProxyManager::getInstance();
|
|
|
|
$sameInstance = ProxyManager::getInstance();
|
2024-04-17 12:34:26 +00:00
|
|
|
self::assertTrue($originalInstance === $sameInstance);
|
2020-09-24 15:48:22 +00:00
|
|
|
|
|
|
|
ProxyManager::reset();
|
|
|
|
$newInstance = ProxyManager::getInstance();
|
2024-04-17 12:34:26 +00:00
|
|
|
self::assertFalse($sameInstance === $newInstance);
|
2020-09-24 15:48:22 +00:00
|
|
|
}
|
|
|
|
|
2022-02-18 09:38:54 +00:00
|
|
|
public function testGetProxyForRequestThrowsOnBadProxyUrl(): void
|
2020-09-24 15:48:22 +00:00
|
|
|
{
|
|
|
|
$_SERVER['http_proxy'] = 'localhost';
|
|
|
|
$proxyManager = ProxyManager::getInstance();
|
2024-04-17 12:34:26 +00:00
|
|
|
|
2021-12-09 19:55:26 +00:00
|
|
|
self::expectException('Composer\Downloader\TransportException');
|
2020-09-24 15:48:22 +00:00
|
|
|
$proxyManager->getProxyForRequest('http://example.com');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2024-04-17 12:34:26 +00:00
|
|
|
* @dataProvider dataCaseOverrides
|
2021-10-27 14:18:46 +00:00
|
|
|
*
|
2024-04-17 12:34:26 +00:00
|
|
|
* @param array<string, string> $server
|
|
|
|
* @param non-empty-string $url
|
2020-09-24 15:48:22 +00:00
|
|
|
*/
|
2024-04-17 12:34:26 +00:00
|
|
|
public function testLowercaseOverridesUppercase(array $server, string $url, string $expectedUrl): void
|
2020-09-24 15:48:22 +00:00
|
|
|
{
|
|
|
|
$_SERVER = array_merge($_SERVER, $server);
|
|
|
|
$proxyManager = ProxyManager::getInstance();
|
|
|
|
|
|
|
|
$proxy = $proxyManager->getProxyForRequest($url);
|
2024-04-17 12:34:26 +00:00
|
|
|
self::assertSame($expectedUrl, $proxy->getStatus());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return list<array{0: array<string, string>, 1: string, 2: string}>
|
|
|
|
*/
|
|
|
|
public static function dataCaseOverrides(): array
|
|
|
|
{
|
|
|
|
// server, url, expectedUrl
|
|
|
|
return [
|
|
|
|
[['HTTP_PROXY' => 'http://upper.com', 'http_proxy' => 'http://lower.com'], 'http://repo.org', 'http://lower.com:80'],
|
|
|
|
[['CGI_HTTP_PROXY' => 'http://upper.com', 'cgi_http_proxy' => 'http://lower.com'], 'http://repo.org', 'http://lower.com:80'],
|
|
|
|
[['HTTPS_PROXY' => 'http://upper.com', 'https_proxy' => 'http://lower.com'], 'https://repo.org', 'http://lower.com:80'],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider dataCGIProxy
|
|
|
|
*
|
|
|
|
* @param array<string, string> $server
|
|
|
|
*/
|
|
|
|
public function testCGIProxyIsOnlyUsedWhenNoHttpProxy(array $server, string $expectedUrl): void
|
|
|
|
{
|
|
|
|
$_SERVER = array_merge($_SERVER, $server);
|
|
|
|
$proxyManager = ProxyManager::getInstance();
|
2020-09-24 15:48:22 +00:00
|
|
|
|
2024-04-17 12:34:26 +00:00
|
|
|
$proxy = $proxyManager->getProxyForRequest('http://repo.org');
|
|
|
|
self::assertSame($expectedUrl, $proxy->getStatus());
|
|
|
|
}
|
2020-09-24 15:48:22 +00:00
|
|
|
|
2024-04-17 12:34:26 +00:00
|
|
|
/**
|
|
|
|
* @return list<array{0: array<string, string>, 1: string}>
|
|
|
|
*/
|
|
|
|
public static function dataCGIProxy(): array
|
|
|
|
{
|
|
|
|
// server, expectedUrl
|
|
|
|
return [
|
|
|
|
[['CGI_HTTP_PROXY' => 'http://cgi.com:80'], 'http://cgi.com:80'],
|
|
|
|
[['http_proxy' => 'http://http.com:80', 'CGI_HTTP_PROXY' => 'http://cgi.com:80'], 'http://http.com:80'],
|
|
|
|
];
|
|
|
|
}
|
2020-09-24 15:48:22 +00:00
|
|
|
|
2024-04-17 12:34:26 +00:00
|
|
|
public function testNoHttpProxyDoesNotUseHttpsProxy(): void
|
|
|
|
{
|
|
|
|
$_SERVER['https_proxy'] = 'https://proxy.com:443';
|
|
|
|
$proxyManager = ProxyManager::getInstance();
|
|
|
|
|
|
|
|
$proxy = $proxyManager->getProxyForRequest('http://repo.org');
|
|
|
|
self::assertSame('', $proxy->getStatus());
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testNoHttpsProxyDoesNotUseHttpProxy(): void
|
|
|
|
{
|
|
|
|
$_SERVER['http_proxy'] = 'http://proxy.com:80';
|
|
|
|
|
|
|
|
// This can be removed after the transition period.
|
|
|
|
// An empty https_proxy value prevents using any http_proxy
|
|
|
|
if ($this->isTransitional) {
|
|
|
|
$_SERVER['https_proxy'] = '';
|
2020-09-24 15:48:22 +00:00
|
|
|
}
|
|
|
|
|
2024-04-17 12:34:26 +00:00
|
|
|
$proxyManager = ProxyManager::getInstance();
|
|
|
|
$proxy = $proxyManager->getProxyForRequest('https://repo.org');
|
|
|
|
self::assertSame('', $proxy->getStatus());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This test can be removed after the transition period
|
|
|
|
*/
|
|
|
|
public function testTransitional(): void
|
|
|
|
{
|
|
|
|
$_SERVER['http_proxy'] = 'http://proxy.com:80';
|
|
|
|
$proxyManager = ProxyManager::getInstance();
|
|
|
|
|
|
|
|
$proxy = $proxyManager->getProxyForRequest('https://repo.org');
|
|
|
|
self::assertSame('http://proxy.com:80', $proxy->getStatus());
|
|
|
|
self::assertTrue($proxyManager->needsTransitionWarning());
|
2020-09-24 15:48:22 +00:00
|
|
|
}
|
|
|
|
|
2024-04-17 12:34:26 +00:00
|
|
|
/**
|
|
|
|
* @dataProvider dataRequest
|
|
|
|
*
|
|
|
|
* @param array<string, string> $server
|
|
|
|
* @param non-empty-string $url
|
|
|
|
* @param ?contextOptions $options
|
|
|
|
*/
|
|
|
|
public function testGetProxyForRequest(array $server, string $url, ?array $options, string $status, bool $excluded): void
|
|
|
|
{
|
|
|
|
$_SERVER = array_merge($_SERVER, $server);
|
|
|
|
$proxyManager = ProxyManager::getInstance();
|
|
|
|
|
|
|
|
$proxy = $proxyManager->getProxyForRequest($url);
|
|
|
|
self::assertSame($options, $proxy->getContextOptions());
|
|
|
|
self::assertSame($status, $proxy->getStatus());
|
|
|
|
self::assertSame($excluded, $proxy->isExcludedByNoProxy());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tests context options. curl options are tested in RequestProxyTest.php
|
|
|
|
*
|
|
|
|
* @return list<array{0: array<string, string>, 1: string, 2: ?contextOptions, 3: string, 4: bool}>
|
|
|
|
*/
|
2022-11-24 13:39:08 +00:00
|
|
|
public static function dataRequest(): array
|
2020-09-24 15:48:22 +00:00
|
|
|
{
|
2022-08-17 12:20:07 +00:00
|
|
|
$server = [
|
2020-09-24 15:48:22 +00:00
|
|
|
'http_proxy' => 'http://user:p%40ss@proxy.com',
|
|
|
|
'https_proxy' => 'https://proxy.com:443',
|
|
|
|
'no_proxy' => 'other.repo.org',
|
2022-08-17 12:20:07 +00:00
|
|
|
];
|
2020-09-24 15:48:22 +00:00
|
|
|
|
2024-04-17 12:34:26 +00:00
|
|
|
// server, url, options, status, excluded
|
2022-08-17 12:20:07 +00:00
|
|
|
return [
|
2024-04-17 12:34:26 +00:00
|
|
|
[[], 'http://repo.org', null, '', false],
|
|
|
|
[$server, 'http://repo.org',
|
2022-08-17 12:20:07 +00:00
|
|
|
['http' => [
|
2020-09-24 15:48:22 +00:00
|
|
|
'proxy' => 'tcp://proxy.com:80',
|
|
|
|
'header' => 'Proxy-Authorization: Basic dXNlcjpwQHNz',
|
|
|
|
'request_fulluri' => true,
|
2022-08-17 12:20:07 +00:00
|
|
|
]],
|
2024-04-17 12:34:26 +00:00
|
|
|
'http://***:***@proxy.com:80',
|
2020-09-24 15:48:22 +00:00
|
|
|
false,
|
2022-08-17 12:20:07 +00:00
|
|
|
],
|
2024-04-17 12:34:26 +00:00
|
|
|
[$server, 'https://repo.org',
|
2022-08-17 12:20:07 +00:00
|
|
|
['http' => [
|
2020-09-24 15:48:22 +00:00
|
|
|
'proxy' => 'ssl://proxy.com:443',
|
2022-08-17 12:20:07 +00:00
|
|
|
]],
|
2020-09-24 15:48:22 +00:00
|
|
|
'https://proxy.com:443',
|
2024-04-17 12:34:26 +00:00
|
|
|
false,
|
2022-08-17 12:20:07 +00:00
|
|
|
],
|
2024-04-17 12:34:26 +00:00
|
|
|
[$server, 'https://other.repo.org', null, 'excluded by no_proxy', true],
|
2022-08-17 12:20:07 +00:00
|
|
|
];
|
2020-09-24 15:48:22 +00:00
|
|
|
}
|
|
|
|
}
|