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']);
|
$client->get('/', ['proxy' => 'tcp://localhost:8125']);
|
||||||
|
|
||||||
Pass an associative array to specify HTTP proxies for specific URI schemes
|
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
|
.. code-block:: php
|
||||||
|
|
||||||
$client->get('/', [
|
$client->get('/', [
|
||||||
'proxy' => [
|
'proxy' => [
|
||||||
'http' => 'tcp://localhost:8125', // Use this proxy with "http"
|
'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 (isset($options['proxy'])) {
|
||||||
if (!is_array($options['proxy'])) {
|
if (!is_array($options['proxy'])) {
|
||||||
$conf[CURLOPT_PROXY] = $options['proxy'];
|
$conf[CURLOPT_PROXY] = $options['proxy'];
|
||||||
} elseif ($scheme = $easy->request->getUri()->getScheme()) {
|
} else {
|
||||||
$host = $easy->request->getUri()->getHost();
|
$scheme = $easy->request->getUri()->getScheme();
|
||||||
if (!isset($options['proxy']['no'])
|
if (isset($options['proxy'][$scheme])) {
|
||||||
||!$this->isHostInProxyArea($host, $options['proxy']['no'])) {
|
$host = $easy->request->getUri()->getHost();
|
||||||
if (isset($options['proxy'][$scheme])) {
|
if (!isset($options['proxy']['no']) ||
|
||||||
|
!\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no'])
|
||||||
|
) {
|
||||||
$conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
|
$conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,27 +425,6 @@ class CurlFactory implements CurlFactoryInterface
|
|||||||
$conf[CURLOPT_VERBOSE] = true;
|
$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
|
* This function ensures that a response was set on a transaction. If one
|
||||||
|
@ -296,7 +296,14 @@ class StreamHandler
|
|||||||
} else {
|
} else {
|
||||||
$scheme = $request->getUri()->getScheme();
|
$scheme = $request->getUri()->getScheme();
|
||||||
if (isset($value[$scheme])) {
|
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;
|
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->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.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', ['*.test.com'], false);
|
$this->checkNoProxyForHost('http://test.test.com', ['*.test.com'], true);
|
||||||
$this->checkNoProxyForHost('http://test.test.com', ['*.test2.com'], true);
|
$this->checkNoProxyForHost('http://test.test.com', ['*'], false);
|
||||||
$this->checkNoProxyForHost('http://127.0.0.1', ['127.0.0.*'], false);
|
$this->checkNoProxyForHost('http://127.0.0.1', ['127.0.0.*'], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function checkNoProxyForHost($url, $noProxy, $assertUseProxy)
|
private function checkNoProxyForHost($url, $noProxy, $assertUseProxy)
|
||||||
{
|
{
|
||||||
$f = new Handler\CurlFactory(3);
|
$f = new Handler\CurlFactory(3);
|
||||||
$f->create(new Psr7\Request('GET', $url), [
|
$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']);
|
$this->assertArrayHasKey(CURLOPT_PROXY, $_SERVER['_curl']);
|
||||||
}else{
|
} else {
|
||||||
$this->assertArrayNotHasKey(CURLOPT_PROXY, $_SERVER['_curl']);
|
$this->assertArrayNotHasKey(CURLOPT_PROXY, $_SERVER['_curl']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \InvalidArgumentException
|
* @expectedException \InvalidArgumentException
|
||||||
|
@ -196,6 +196,17 @@ class StreamHandlerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals($url, $opts['http']['proxy']);
|
$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()
|
public function testAddsTimeout()
|
||||||
{
|
{
|
||||||
$res = $this->getSendResult(['stream' => true, 'timeout' => 200]);
|
$res = $this->getSendResult(['stream' => true, 'timeout' => 200]);
|
||||||
|
@ -70,6 +70,37 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase
|
|||||||
{
|
{
|
||||||
$this->assertFileExists(GuzzleHttp\default_ca_bundle());
|
$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
|
final class StrClass
|
||||||
|
Loading…
x
Reference in New Issue
Block a user