Refactor proxy handling for Composer2
parent
8564dd8dac
commit
d47261eb93
@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Util\Http;
|
||||
|
||||
/**
|
||||
* Proxy discovery and helper class
|
||||
*
|
||||
* @internal
|
||||
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
|
||||
*/
|
||||
class ProxyHelper
|
||||
{
|
||||
/**
|
||||
* Returns proxy environment values
|
||||
*
|
||||
* @throws \RuntimeException on malformed url
|
||||
* @return array httpProxy, httpsProxy, noProxy values
|
||||
*/
|
||||
public static function getProxyData()
|
||||
{
|
||||
$httpProxy = null;
|
||||
$httpsProxy = null;
|
||||
|
||||
// Handle http_proxy/HTTP_PROXY on CLI only for security reasons
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
if ($env = self::getProxyEnv(array('http_proxy', 'HTTP_PROXY'), $name)) {
|
||||
$httpProxy = self::checkProxy($env, $name);
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer CGI_HTTP_PROXY if available
|
||||
if ($env = self::getProxyEnv(array('CGI_HTTP_PROXY'), $name)) {
|
||||
$httpProxy = self::checkProxy($env, $name);
|
||||
}
|
||||
|
||||
// Handle https_proxy/HTTPS_PROXY
|
||||
if ($env = self::getProxyEnv(array('https_proxy', 'HTTPS_PROXY'), $name)) {
|
||||
$httpsProxy = self::checkProxy($env, $name);
|
||||
} else {
|
||||
$httpsProxy = $httpProxy;
|
||||
}
|
||||
|
||||
// Handle no_proxy
|
||||
$noProxy = self::getProxyEnv(array('no_proxy', 'NO_PROXY'), $name);
|
||||
|
||||
return array($httpProxy, $httpsProxy, $noProxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns http context options for the proxy url
|
||||
*
|
||||
* @param string $proxyUrl
|
||||
* @return array
|
||||
*/
|
||||
public static function getContextOptions($proxyUrl)
|
||||
{
|
||||
$proxy = parse_url($proxyUrl);
|
||||
|
||||
// Remove any authorization
|
||||
$proxyUrl = self::formatParsedUrl($proxy, false);
|
||||
$proxyUrl = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyUrl);
|
||||
|
||||
$options['http']['proxy'] = $proxyUrl;
|
||||
|
||||
// Handle any authorization
|
||||
if (isset($proxy['user'])) {
|
||||
$auth = rawurldecode($proxy['user']);
|
||||
|
||||
if (isset($proxy['pass'])) {
|
||||
$auth .= ':' . rawurldecode($proxy['pass']);
|
||||
}
|
||||
$auth = base64_encode($auth);
|
||||
// Set header as a string
|
||||
$options['http']['header'] = "Proxy-Authorization: Basic {$auth}";
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets/unsets request_fulluri value in http context options array
|
||||
*
|
||||
* @param string $requestUrl
|
||||
* @param array $options Set by method
|
||||
*/
|
||||
public static function setRequestFullUri($requestUrl, array &$options)
|
||||
{
|
||||
if ('http' === parse_url($requestUrl, PHP_URL_SCHEME)) {
|
||||
$options['http']['request_fulluri'] = true;
|
||||
} else {
|
||||
unset($options['http']['request_fulluri']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches $_SERVER for case-sensitive values
|
||||
*
|
||||
* @param array $names Names to search for
|
||||
* @param mixed $name Name of any found value
|
||||
* @return string|null The found value
|
||||
*/
|
||||
private static function getProxyEnv(array $names, &$name)
|
||||
{
|
||||
foreach ($names as $name) {
|
||||
if (!empty($_SERVER[$name])) {
|
||||
return $_SERVER[$name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks and formats a proxy url from the environment
|
||||
*
|
||||
* @param string $proxyUrl
|
||||
* @param string $envName
|
||||
* @throws \RuntimeException on malformed url
|
||||
* @return string The formatted proxy url
|
||||
*/
|
||||
private static function checkProxy($proxyUrl, $envName)
|
||||
{
|
||||
$error = sprintf('malformed %s url', $envName);
|
||||
$proxy = parse_url($proxyUrl);
|
||||
|
||||
if (!isset($proxy['host'])) {
|
||||
throw new \RuntimeException($error);
|
||||
}
|
||||
|
||||
$proxyUrl = self::formatParsedUrl($proxy, true);
|
||||
|
||||
if (!parse_url($proxyUrl, PHP_URL_PORT)) {
|
||||
throw new \RuntimeException($error);
|
||||
}
|
||||
|
||||
return $proxyUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a url from its component parts
|
||||
*
|
||||
* @param array $proxy Values from parse_url
|
||||
* @param bool $includeAuth Whether to include authorization values
|
||||
* @return string The formatted value
|
||||
*/
|
||||
private static function formatParsedUrl(array $proxy, $includeAuth)
|
||||
{
|
||||
$proxyUrl = isset($proxy['scheme']) ? strtolower($proxy['scheme']) . '://' : '';
|
||||
|
||||
if ($includeAuth && isset($proxy['user'])) {
|
||||
$proxyUrl .= $proxy['user'];
|
||||
|
||||
if (isset($proxy['pass'])) {
|
||||
$proxyUrl .= ':' . $proxy['pass'];
|
||||
}
|
||||
$proxyUrl .= '@';
|
||||
}
|
||||
|
||||
$proxyUrl .= $proxy['host'];
|
||||
|
||||
if (isset($proxy['port'])) {
|
||||
$proxyUrl .= ':' . $proxy['port'];
|
||||
} elseif (strpos($proxyUrl, 'http://') === 0) {
|
||||
$proxyUrl .= ':80';
|
||||
} elseif (strpos($proxyUrl, 'https://') === 0) {
|
||||
$proxyUrl .= ':443';
|
||||
}
|
||||
|
||||
return $proxyUrl;
|
||||
}
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Util\Http;
|
||||
|
||||
use Composer\Downloader\TransportException;
|
||||
use Composer\Util\NoProxyPattern;
|
||||
use Composer\Util\Url;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
|
||||
*/
|
||||
class ProxyManager
|
||||
{
|
||||
private $error;
|
||||
private $fullProxy;
|
||||
private $safeProxy;
|
||||
private $streams;
|
||||
private $hasProxy;
|
||||
private $info;
|
||||
private $lastProxy;
|
||||
/** @var NoProxyPattern */
|
||||
private $noProxyHandler;
|
||||
|
||||
/** @var ProxyManager */
|
||||
private static $instance;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->fullProxy = $this->safeProxy = array(
|
||||
'http' => null,
|
||||
'https' => null,
|
||||
);
|
||||
|
||||
$this->streams['http'] = $this->streams['https'] = array(
|
||||
'options' => null,
|
||||
);
|
||||
|
||||
$this->hasProxy = false;
|
||||
$this->initProxyData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ProxyManager *
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if (!self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the persistent instance
|
||||
*/
|
||||
public static function reset()
|
||||
{
|
||||
self::$instance = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a RequestProxy instance for the request url
|
||||
*
|
||||
* @param string $requestUrl
|
||||
* @return RequestProxy
|
||||
*/
|
||||
public function getProxyForRequest($requestUrl)
|
||||
{
|
||||
if ($this->error) {
|
||||
throw new TransportException('Unable to use a proxy: '.$this->error);
|
||||
}
|
||||
|
||||
$scheme = parse_url($requestUrl, PHP_URL_SCHEME) ?: 'http';
|
||||
$proxyUrl = '';
|
||||
$options = array();
|
||||
$lastProxy = '';
|
||||
|
||||
if ($this->hasProxy && $this->fullProxy[$scheme]) {
|
||||
if ($this->noProxy($requestUrl)) {
|
||||
$lastProxy = 'excluded by no_proxy';
|
||||
} else {
|
||||
$proxyUrl = $this->fullProxy[$scheme];
|
||||
$options = $this->streams[$scheme]['options'];
|
||||
ProxyHelper::setRequestFullUri($requestUrl, $options);
|
||||
$lastProxy = $this->safeProxy[$scheme];
|
||||
}
|
||||
}
|
||||
|
||||
return new RequestProxy($proxyUrl, $options, $lastProxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a proxy is being used
|
||||
*
|
||||
* @param string|null $message Set to safe proxy values
|
||||
* @return bool If false any error will be in $message
|
||||
*/
|
||||
public function getStatus(&$message)
|
||||
{
|
||||
$message = $this->hasProxy ? $this->info : $this->error;
|
||||
return $this->hasProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes proxy values from the environment
|
||||
*/
|
||||
private function initProxyData()
|
||||
{
|
||||
try {
|
||||
list($httpProxy, $httpsProxy, $noProxy) = ProxyHelper::getProxyData();
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->error = $e->getMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
$info = array();
|
||||
|
||||
if ($httpProxy) {
|
||||
$info[] = $this->setData($httpProxy, 'http');
|
||||
}
|
||||
if ($httpsProxy) {
|
||||
$info[] = $this->setData($httpsProxy, 'https');
|
||||
}
|
||||
if ($this->hasProxy) {
|
||||
$this->info = implode(', ', $info);
|
||||
if ($noProxy) {
|
||||
$this->noProxyHandler = array(new NoProxyPattern($noProxy), 'test');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets initial data
|
||||
*
|
||||
* @param string $proxyUrl Proxy url
|
||||
* @param string $scheme Environment variable scheme
|
||||
*/
|
||||
private function setData($url, $scheme)
|
||||
{
|
||||
$safeProxy = Url::sanitize($url);
|
||||
$this->fullProxy[$scheme] = $url;
|
||||
$this->safeProxy[$scheme] = $safeProxy;
|
||||
$this->streams[$scheme]['options'] = ProxyHelper::getContextOptions($url);
|
||||
$this->hasProxy = true;
|
||||
|
||||
return sprintf('%s=%s', $scheme, $safeProxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a url matches no_proxy value
|
||||
*
|
||||
* @param string $requestUrl
|
||||
* @return bool
|
||||
*/
|
||||
private function noProxy($requestUrl)
|
||||
{
|
||||
if ($this->noProxyHandler) {
|
||||
if (call_user_func($this->noProxyHandler, $requestUrl)) {
|
||||
$this->lastProxy = 'excluded by no_proxy';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Util\Http;
|
||||
|
||||
use Composer\Util\Url;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
|
||||
*/
|
||||
class RequestProxy
|
||||
{
|
||||
private $contextOptions;
|
||||
private $isSecure;
|
||||
private $lastProxy;
|
||||
private $safeUrl;
|
||||
private $url;
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param array $contextOptions
|
||||
* @param string $lastProxy
|
||||
*/
|
||||
public function __construct($url, array $contextOptions, $lastProxy)
|
||||
{
|
||||
$this->url = $url;
|
||||
$this->contextOptions = $contextOptions;
|
||||
$this->lastProxy = $lastProxy;
|
||||
$this->safeUrl = Url::sanitize($url);
|
||||
$this->isSecure = 0 === strpos($url, 'https://');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of context options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getContextOptions()
|
||||
{
|
||||
return $this->contextOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the safe proxy url from the last request
|
||||
*
|
||||
* @param string|null $format Output format specifier
|
||||
* @return string Safe proxy, no proxy or empty
|
||||
*/
|
||||
public function getLastProxy($format = '')
|
||||
{
|
||||
$result = '';
|
||||
if ($this->lastProxy) {
|
||||
$format = $format ?: '%s';
|
||||
$result = sprintf($format, $this->lastProxy);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the proxy url
|
||||
*
|
||||
* @return string Proxy url or empty
|
||||
*/
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a secure-proxy
|
||||
*
|
||||
* @return bool False if not secure or there is no proxy
|
||||
*/
|
||||
public function isSecure()
|
||||
{
|
||||
return $this->isSecure;
|
||||
}
|
||||
}
|
@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\ProxyHelper;
|
||||
use Composer\Test\TestCase;
|
||||
|
||||
class ProxyHelperTest extends TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
unset(
|
||||
$_SERVER['HTTP_PROXY'],
|
||||
$_SERVER['http_proxy'],
|
||||
$_SERVER['HTTPS_PROXY'],
|
||||
$_SERVER['https_proxy'],
|
||||
$_SERVER['NO_PROXY'],
|
||||
$_SERVER['no_proxy'],
|
||||
$_SERVER['CGI_HTTP_PROXY']
|
||||
);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
unset(
|
||||
$_SERVER['HTTP_PROXY'],
|
||||
$_SERVER['http_proxy'],
|
||||
$_SERVER['HTTPS_PROXY'],
|
||||
$_SERVER['https_proxy'],
|
||||
$_SERVER['NO_PROXY'],
|
||||
$_SERVER['no_proxy'],
|
||||
$_SERVER['CGI_HTTP_PROXY']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataMalformed
|
||||
*/
|
||||
public function testThrowsOnMalformedUrl($url)
|
||||
{
|
||||
$_SERVER['http_proxy'] = $url;
|
||||
|
||||
$this->setExpectedException('RuntimeException');
|
||||
ProxyHelper::getProxyData();
|
||||
}
|
||||
|
||||
public function dataMalformed()
|
||||
{
|
||||
return array(
|
||||
'no-host' => array('localhost'),
|
||||
'no-port' => array('scheme://localhost'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataFormatting
|
||||
*/
|
||||
public function testUrlFormatting($url, $expected)
|
||||
{
|
||||
$_SERVER['http_proxy'] = $url;
|
||||
|
||||
list($httpProxy, $httpsProxy, $noProxy) = ProxyHelper::getProxyData();
|
||||
$this->assertSame($expected, $httpProxy);
|
||||
}
|
||||
|
||||
public function dataFormatting()
|
||||
{
|
||||
// url, expected
|
||||
return array(
|
||||
'lowercases-scheme' => array('HTTP://proxy.com:8888', 'http://proxy.com:8888'),
|
||||
'adds-http-port' => array('http://proxy.com', 'http://proxy.com:80'),
|
||||
'adds-https-port' => array('https://proxy.com', 'https://proxy.com:443'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataCaseOverrides
|
||||
*/
|
||||
public function testLowercaseOverridesUppercase(array $server, $expected, $index)
|
||||
{
|
||||
$_SERVER = array_merge($_SERVER, $server);
|
||||
|
||||
$list = ProxyHelper::getProxyData();
|
||||
$this->assertSame($expected, $list[$index]);
|
||||
}
|
||||
|
||||
public function dataCaseOverrides()
|
||||
{
|
||||
// server, expected, list index
|
||||
return array(
|
||||
array(array('HTTP_PROXY' => 'http://upper.com', 'http_proxy' => 'http://lower.com'), 'http://lower.com:80', 0),
|
||||
array(array('HTTPS_PROXY' => 'http://upper.com', 'https_proxy' => 'http://lower.com'), 'http://lower.com:80', 1),
|
||||
array(array('NO_PROXY' => 'upper.com', 'no_proxy' => 'lower.com'), 'lower.com', 2),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataCGIOverrides
|
||||
*/
|
||||
public function testCGIUpperCaseOverridesHttp(array $server, $expected, $index)
|
||||
{
|
||||
$_SERVER = array_merge($_SERVER, $server);
|
||||
|
||||
$list = ProxyHelper::getProxyData();
|
||||
$this->assertSame($expected, $list[$index]);
|
||||
}
|
||||
|
||||
public function dataCGIOverrides()
|
||||
{
|
||||
// server, expected, list index
|
||||
return array(
|
||||
array(array('http_proxy' => 'http://http.com', 'CGI_HTTP_PROXY' => 'http://cgi.com'), 'http://cgi.com:80', 0),
|
||||
array(array('http_proxy' => 'http://http.com', 'cgi_http_proxy' => 'http://cgi.com'), 'http://http.com:80', 0),
|
||||
);
|
||||
}
|
||||
|
||||
public function testNoHttpsProxyUsesHttpProxy()
|
||||
{
|
||||
$_SERVER['http_proxy'] = 'http://http.com';
|
||||
|
||||
list($httpProxy, $httpsProxy, $noProxy) = ProxyHelper::getProxyData();
|
||||
$this->assertSame('http://http.com:80', $httpsProxy);
|
||||
}
|
||||
|
||||
public function testNoHttpProxyDoesNotUseHttpsProxy()
|
||||
{
|
||||
$_SERVER['https_proxy'] = 'http://https.com';
|
||||
|
||||
list($httpProxy, $httpsProxy, $noProxy) = ProxyHelper::getProxyData();
|
||||
$this->assertSame(null, $httpProxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataContextOptions
|
||||
*/
|
||||
public function testGetContextOptions($url, $expected)
|
||||
{
|
||||
$this->assertEquals($expected, ProxyHelper::getContextOptions($url));
|
||||
}
|
||||
|
||||
public function dataContextOptions()
|
||||
{
|
||||
// url, expected
|
||||
return array(
|
||||
array('http://proxy.com', array('http' => array(
|
||||
'proxy' => 'tcp://proxy.com:80',
|
||||
))),
|
||||
array('https://proxy.com', array('http' => array(
|
||||
'proxy' => 'ssl://proxy.com:443',
|
||||
))),
|
||||
array('http://user:p%40ss@proxy.com', array('http' => array(
|
||||
'proxy' => 'tcp://proxy.com:80',
|
||||
'header' => 'Proxy-Authorization: Basic dXNlcjpwQHNz',
|
||||
))),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataRequestFullUri
|
||||
*/
|
||||
public function testSetRequestFullUri($requestUrl, $expected)
|
||||
{
|
||||
$options = array();
|
||||
ProxyHelper::setRequestFullUri($requestUrl, $options);
|
||||
|
||||
$this->assertEquals($expected, $options);
|
||||
}
|
||||
|
||||
public function dataRequestFullUri()
|
||||
{
|
||||
$options = array('http' => array('request_fulluri' => true));
|
||||
|
||||
// $requestUrl, expected
|
||||
return array(
|
||||
'http' => array('http://repo.org', $options),
|
||||
'https' => array('https://repo.org', array()),
|
||||
'no-scheme' => array('repo.org', array()),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\ProxyHelper;
|
||||
use Composer\Util\Http\ProxyManager;
|
||||
use Composer\Test\TestCase;
|
||||
|
||||
class ProxyManagerTest extends TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
unset(
|
||||
$_SERVER['HTTP_PROXY'],
|
||||
$_SERVER['http_proxy'],
|
||||
$_SERVER['HTTPS_PROXY'],
|
||||
$_SERVER['https_proxy'],
|
||||
$_SERVER['NO_PROXY'],
|
||||
$_SERVER['no_proxy'],
|
||||
$_SERVER['CGI_HTTP_PROXY']
|
||||
);
|
||||
ProxyManager::reset();
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
unset(
|
||||
$_SERVER['HTTP_PROXY'],
|
||||
$_SERVER['http_proxy'],
|
||||
$_SERVER['HTTPS_PROXY'],
|
||||
$_SERVER['https_proxy'],
|
||||
$_SERVER['NO_PROXY'],
|
||||
$_SERVER['no_proxy'],
|
||||
$_SERVER['CGI_HTTP_PROXY']
|
||||
);
|
||||
ProxyManager::reset();
|
||||
}
|
||||
|
||||
public function testInstantiation()
|
||||
{
|
||||
$originalInstance = ProxyManager::getInstance();
|
||||
$this->assertInstanceOf('Composer\Util\Http\ProxyManager', $originalInstance);
|
||||
|
||||
$sameInstance = ProxyManager::getInstance();
|
||||
$this->assertTrue($originalInstance === $sameInstance);
|
||||
|
||||
ProxyManager::reset();
|
||||
$newInstance = ProxyManager::getInstance();
|
||||
$this->assertFalse($sameInstance === $newInstance);
|
||||
}
|
||||
|
||||
public function testGetProxyForRequestThrowsOnBadProxyUrl()
|
||||
{
|
||||
$_SERVER['http_proxy'] = 'localhost';
|
||||
$proxyManager = ProxyManager::getInstance();
|
||||
$this->setExpectedException('Composer\Downloader\TransportException');
|
||||
$proxyManager->getProxyForRequest('http://example.com');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataRequest
|
||||
*/
|
||||
public function testGetProxyForRequest($server, $url, $expectedUrl, $expectedOptions, $expectedSecure, $expectedMessage)
|
||||
{
|
||||
$_SERVER = array_merge($_SERVER, $server);
|
||||
$proxyManager = ProxyManager::getInstance();
|
||||
|
||||
$proxy = $proxyManager->getProxyForRequest($url);
|
||||
$this->assertInstanceOf('Composer\Util\Http\RequestProxy', $proxy);
|
||||
|
||||
$this->assertSame($expectedUrl, $proxy->getUrl());
|
||||
$this->assertSame($expectedOptions, $proxy->getContextOptions());
|
||||
$this->assertSame($expectedSecure, $proxy->isSecure());
|
||||
|
||||
$message = $proxy->getLastProxy();
|
||||
|
||||
if ($expectedMessage) {
|
||||
$condition = stripos($message, $expectedMessage) !== false;
|
||||
} else {
|
||||
$condition = $expectedMessage === $message;
|
||||
}
|
||||
|
||||
$this->assertTrue($condition, 'lastProxy check');
|
||||
}
|
||||
|
||||
public function dataRequest()
|
||||
{
|
||||
$server = array(
|
||||
'http_proxy' => 'http://user:p%40ss@proxy.com',
|
||||
'https_proxy' => 'https://proxy.com:443',
|
||||
'no_proxy' => 'other.repo.org',
|
||||
);
|
||||
|
||||
// server, url, expectedUrl, expectedOptions, expectedSecure, expectedMessage
|
||||
return array(
|
||||
array(array(), 'http://repo.org', '', array(), false, ''),
|
||||
array($server, 'http://repo.org', 'http://user:p%40ss@proxy.com:80',
|
||||
array('http' => array(
|
||||
'proxy' => 'tcp://proxy.com:80',
|
||||
'header' => 'Proxy-Authorization: Basic dXNlcjpwQHNz',
|
||||
'request_fulluri' => true,
|
||||
)
|
||||
),
|
||||
false,
|
||||
'http://user:***@proxy.com:80',
|
||||
),
|
||||
array(
|
||||
$server, 'https://repo.org', 'https://proxy.com:443',
|
||||
array('http' => array(
|
||||
'proxy' => 'ssl://proxy.com:443',
|
||||
)
|
||||
),
|
||||
true,
|
||||
'https://proxy.com:443',
|
||||
),
|
||||
array($server, 'https://other.repo.org', '', array(), false, 'no_proxy'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataStatus
|
||||
*/
|
||||
public function testGetStatus($server, $expectedStatus, $expectedMessage)
|
||||
{
|
||||
$_SERVER = array_merge($_SERVER, $server);
|
||||
$proxyManager = ProxyManager::getInstance();
|
||||
$status = $proxyManager->getStatus($message);
|
||||
|
||||
$this->assertSame($expectedStatus, $status);
|
||||
|
||||
if ($expectedMessage) {
|
||||
$condition = stripos($message, $expectedMessage) !== false;
|
||||
} else {
|
||||
$condition = $expectedMessage === $message;
|
||||
}
|
||||
$this->assertTrue($condition, 'message check');
|
||||
}
|
||||
|
||||
public function dataStatus()
|
||||
{
|
||||
// server, expectedStatus, expectedMessage
|
||||
return array(
|
||||
array(array(), false, null),
|
||||
array(array('http_proxy' => 'localhost'), false, 'malformed'),
|
||||
array(
|
||||
array('http_proxy' => 'http://user:p%40ss@proxy.com:80'),
|
||||
true,
|
||||
'http=http://user:***@proxy.com:80'
|
||||
),
|
||||
array(
|
||||
array('http_proxy' => 'proxy.com:80', 'https_proxy' => 'proxy.com:80'),
|
||||
true,
|
||||
'http=proxy.com:80, https=proxy.com:80'
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\RequestProxy;
|
||||
use Composer\Test\TestCase;
|
||||
|
||||
class RequestProxyTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider dataSecure
|
||||
*/
|
||||
public function testIsSecure($url, $expectedSecure)
|
||||
{
|
||||
$proxy = new RequestProxy($url, array(), '');
|
||||
|
||||
$this->assertSame($expectedSecure, $proxy->isSecure());
|
||||
}
|
||||
|
||||
public function dataSecure()
|
||||
{
|
||||
// url, secure
|
||||
return array(
|
||||
'basic' => array('http://proxy.com:80', false),
|
||||
'secure' => array('https://proxy.com:443', true),
|
||||
'none' => array('', false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataLastProxy
|
||||
*/
|
||||
public function testGetLastProxyFormat($url, $format, $expected)
|
||||
{
|
||||
$proxy = new RequestProxy($url, array(), $url);
|
||||
|
||||
$message = $proxy->getLastProxy($format);
|
||||
$this->assertSame($expected, $message);
|
||||
}
|
||||
|
||||
public function dataLastProxy()
|
||||
{
|
||||
$format = 'proxy (%s)';
|
||||
|
||||
// url, format, expected
|
||||
return array(
|
||||
array('', $format, ''),
|
||||
array('http://proxy.com:80', $format, 'proxy (http://proxy.com:80)'),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue