mirror of
https://github.com/guzzle/guzzle.git
synced 2025-03-14 19:29:49 +01:00
Cleaning up no_proxy support
This commit is contained in:
parent
cae1fec097
commit
d687700d60
@ -638,14 +638,24 @@ Pass a string to specify a proxy for all protocols.
|
||||
$client->get('/', ['proxy' => 'tcp://localhost:8125']);
|
||||
|
||||
Pass an associative array to specify HTTP proxies for specific URI schemes
|
||||
(i.e., "http", "https").
|
||||
(i.e., "http", "https"). Provide a ``no`` key value pair to provide a list of
|
||||
host names that should not be proxied to.
|
||||
|
||||
.. note::
|
||||
|
||||
Guzzle will automatically populate this value with your environment's
|
||||
``NO_PROXY`` environment variable. However, when providing a ``proxy``
|
||||
request option, it is up to your to provide the ``no`` value parsed from
|
||||
the ``NO_PROXY`` environment variable
|
||||
(e.g., ``explode(',', getenv('NO_PROXY'))``).
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$client->get('/', [
|
||||
'proxy' => [
|
||||
'http' => 'tcp://localhost:8125', // Use this proxy with "http"
|
||||
'https' => 'tcp://localhost:9124' // Use this proxy with "https"
|
||||
'https' => 'tcp://localhost:9124', // Use this proxy with "https",
|
||||
'no' => ['.mit.edu', 'foo.com'] // Don't use a proxy with these
|
||||
]
|
||||
]);
|
||||
|
||||
|
@ -361,14 +361,16 @@ class CurlFactory implements CurlFactoryInterface
|
||||
if (isset($options['proxy'])) {
|
||||
if (!is_array($options['proxy'])) {
|
||||
$conf[CURLOPT_PROXY] = $options['proxy'];
|
||||
} elseif ($scheme = $easy->request->getUri()->getScheme()) {
|
||||
$host = $easy->request->getUri()->getHost();
|
||||
if (!isset($options['proxy']['no'])
|
||||
||!$this->isHostInProxyArea($host, $options['proxy']['no'])) {
|
||||
if (isset($options['proxy'][$scheme])) {
|
||||
} else {
|
||||
$scheme = $easy->request->getUri()->getScheme();
|
||||
if (isset($options['proxy'][$scheme])) {
|
||||
$host = $easy->request->getUri()->getHost();
|
||||
if (!isset($options['proxy']['no']) ||
|
||||
!\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no'])
|
||||
) {
|
||||
$conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -423,27 +425,6 @@ class CurlFactory implements CurlFactoryInterface
|
||||
$conf[CURLOPT_VERBOSE] = true;
|
||||
}
|
||||
}
|
||||
|
||||
private function isHostInProxyArea($host, array $areas)
|
||||
{
|
||||
$matches = false;
|
||||
foreach ($areas as $area) {
|
||||
$areaToMatch = $area;
|
||||
// if include all subdomains
|
||||
if (!empty($area) && substr($area, 0, 1) === '.'){
|
||||
$areaToMatch = "*$area";
|
||||
}
|
||||
// Use wilcards
|
||||
$delimiter = '#';
|
||||
$areaToMatch = preg_quote($areaToMatch, $delimiter);
|
||||
$areaToMatch = str_replace('\*', '.*', $areaToMatch);
|
||||
if (preg_match("$delimiter^$areaToMatch$$delimiter", $host)) {
|
||||
$matches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function ensures that a response was set on a transaction. If one
|
||||
|
@ -296,7 +296,14 @@ class StreamHandler
|
||||
} else {
|
||||
$scheme = $request->getUri()->getScheme();
|
||||
if (isset($value[$scheme])) {
|
||||
$options['http']['proxy'] = $value[$scheme];
|
||||
if (!isset($value['no'])
|
||||
|| !\GuzzleHttp\is_host_in_noproxy(
|
||||
$request->getUri()->getHost(),
|
||||
$value['no']
|
||||
)
|
||||
) {
|
||||
$options['http']['proxy'] = $value[$scheme];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,3 +225,56 @@ function normalize_header_keys(array $headers)
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provided host matches any of the no proxy areas.
|
||||
*
|
||||
* This method will strip a port from the host if it is present. Each pattern
|
||||
* can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
|
||||
* partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
|
||||
* "baz.foo.com", but ".foo.com" != "foo.com").
|
||||
*
|
||||
* Areas are matched in the following cases:
|
||||
* 1. "*" (without quotes) always matches any hosts.
|
||||
* 2. An exact match.
|
||||
* 3. The area starts with "." and the area is the last part of the host. e.g.
|
||||
* '.mit.edu' will match any host that ends with '.mit.edu'.
|
||||
*
|
||||
* @param string $host Host to check against the patterns.
|
||||
* @param array $noProxyArray An array of host patterns.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_host_in_noproxy($host, array $noProxyArray)
|
||||
{
|
||||
if (strlen($host) === 0) {
|
||||
throw new \InvalidArgumentException('Empty host provided');
|
||||
}
|
||||
|
||||
// Strip port if present.
|
||||
if (strpos($host, ':')) {
|
||||
$host = explode($host, ':', 2)[0];
|
||||
}
|
||||
|
||||
foreach ($noProxyArray as $area) {
|
||||
// Always match on wildcards.
|
||||
if ($area === '*') {
|
||||
return true;
|
||||
} elseif (empty($area)) {
|
||||
// Don't match on empty values.
|
||||
continue;
|
||||
} elseif ($area === $host) {
|
||||
// Exact matches.
|
||||
return true;
|
||||
} else {
|
||||
// Special match if the area when prefixed with ".". Remove any
|
||||
// existing leading "." and add a new leading ".".
|
||||
$area = '.' . ltrim($area, '.');
|
||||
if (substr($host, -(strlen($area))) === $area) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -145,25 +145,28 @@ class CurlFactoryTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('http://bar.com', $_SERVER['_curl'][CURLOPT_PROXY]);
|
||||
$this->checkNoProxyForHost('http://test.test.com', ['test.test.com'], false);
|
||||
$this->checkNoProxyForHost('http://test.test.com', ['.test.com'], false);
|
||||
$this->checkNoProxyForHost('http://test.test.com', ['*.test.com'], false);
|
||||
$this->checkNoProxyForHost('http://test.test.com', ['*.test2.com'], true);
|
||||
$this->checkNoProxyForHost('http://127.0.0.1', ['127.0.0.*'], false);
|
||||
$this->checkNoProxyForHost('http://test.test.com', ['*.test.com'], true);
|
||||
$this->checkNoProxyForHost('http://test.test.com', ['*'], false);
|
||||
$this->checkNoProxyForHost('http://127.0.0.1', ['127.0.0.*'], true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function checkNoProxyForHost($url, $noProxy, $assertUseProxy)
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', $url), [
|
||||
'proxy' => ['http' => 'http://bar.com', 'https' => 'https://t', 'no' => $noProxy],
|
||||
'proxy' => [
|
||||
'http' => 'http://bar.com',
|
||||
'https' => 'https://t',
|
||||
'no' => $noProxy
|
||||
],
|
||||
]);
|
||||
if($assertUseProxy) {
|
||||
if ($assertUseProxy) {
|
||||
$this->assertArrayHasKey(CURLOPT_PROXY, $_SERVER['_curl']);
|
||||
}else{
|
||||
} else {
|
||||
$this->assertArrayNotHasKey(CURLOPT_PROXY, $_SERVER['_curl']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
|
@ -196,6 +196,17 @@ class StreamHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals($url, $opts['http']['proxy']);
|
||||
}
|
||||
|
||||
public function testAddsProxyButHonorsNoProxy()
|
||||
{
|
||||
$url = str_replace('http', 'tcp', Server::$url);
|
||||
$res = $this->getSendResult(['proxy' => [
|
||||
'http' => $url,
|
||||
'no' => ['*']
|
||||
]]);
|
||||
$opts = stream_context_get_options($res->getBody()->detach());
|
||||
$this->assertTrue(empty($opts['http']['proxy']));
|
||||
}
|
||||
|
||||
public function testAddsTimeout()
|
||||
{
|
||||
$res = $this->getSendResult(['stream' => true, 'timeout' => 200]);
|
||||
|
@ -70,6 +70,37 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$this->assertFileExists(GuzzleHttp\default_ca_bundle());
|
||||
}
|
||||
|
||||
public function noProxyProvider()
|
||||
{
|
||||
return [
|
||||
['mit.edu', ['.mit.edu'], false],
|
||||
['foo.mit.edu', ['.mit.edu'], true],
|
||||
['mit.edu', ['mit.edu'], true],
|
||||
['mit.edu', ['baz', 'mit.edu'], true],
|
||||
['mit.edu', ['', '', 'mit.edu'], true],
|
||||
['mit.edu', ['baz', '*'], true],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider noproxyProvider
|
||||
*/
|
||||
public function testChecksNoProxyList($host, $list, $result)
|
||||
{
|
||||
$this->assertSame(
|
||||
$result,
|
||||
\GuzzleHttp\is_host_in_noproxy($host, $list)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testEnsuresNoProxyCheckHostIsSet()
|
||||
{
|
||||
\GuzzleHttp\is_host_in_noproxy('', []);
|
||||
}
|
||||
}
|
||||
|
||||
final class StrClass
|
||||
|
Loading…
x
Reference in New Issue
Block a user