Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The no proxy request option does not avoid falling back to proxies set in ENV vars #3163

Open
oostapov opened this issue Aug 18, 2023 · 3 comments

Comments

@oostapov
Copy link

Guzzle version(s) affected: 7.7
PHP version: 8.1.22 (hint: php --version)
cURL version: 8.2.1 (hint: php -i | grep cURL)

Description
When using the proxy => no request option guzzle fails to ignore the proxy if ENV vars are present on the server i.e. http_proxy or https_proxy.

The issue was introduced in #3093 . Original solution in the first commit e0de379 (setting CURLOPT_PROXY to an empty string) solved the problem but due to a failing test a proposed final fix to unset it with unset($conf[\CURLOPT_PROXY]); does not actually do anything as the $conf[\CURLOPT_PROXY] option is never defined before being unset.

How to reproduce
Create http_proxy & https_proxy ENV var pointing to a proxy.
Create no_proxy ENV var and make sure it does not include the host that we are about to send a test request to.
Set the proxy => no request option to the host of a request.
Send a request and the proxy sittings of the ENV will be used.

Possible Solution
The following lines of code in the CurlFactory.php:448 could be changed to set the CURLOPT_NOPROXY to a requesting host string when a proxy is not required.

From:

                    if (isset($options['proxy']['no']) && Utils::isHostInNoProxy($host, $options['proxy']['no'])) {
                        unset($conf[\CURLOPT_PROXY]);
                    } else {
                        $conf[\CURLOPT_PROXY] = $options['proxy'][$scheme];
                    }

To:

                    if (isset($options['proxy']['no']) && Utils::isHostInNoProxy($host, $options['proxy']['no'])) {
                        $conf[\CURLOPT_NOPROXY] = $host;
                    } else {
                        $conf[\CURLOPT_PROXY] = $options['proxy'][$scheme];
                    }

Additional context
Another solution is to force the $conf[\CURLOPT_PROXY] option to en empty string as it was originally proposed in e0de379 but then the test CurlFactoryTest.php:194 should be updated from:

        if ($assertUseProxy) {
            self::assertArrayHasKey(\CURLOPT_PROXY, $_SERVER['_curl']);
        } else {
            self::assertArrayNotHasKey(\CURLOPT_PROXY, $_SERVER['_curl']);
        }

to:

        self::assertArrayHasKey(\CURLOPT_PROXY, $_SERVER['_curl']);
        if (!$assertUseProxy) {
            self::assertEquals('', $_SERVER['_curl'][\CURLOPT_PROXY]);
        }
@gergokee
Copy link
Contributor

gergokee commented Aug 18, 2023

yep, the reason i set CURLOPT_PROXY to empty cause older php versions had a bug where the CURLOPT_NOPROXY was not taken into account. But my first fix was wrong, unset() is doing nothing. So we need another fix then.

I like the first solution if that is stable in latest php versions.

UPDATE: let's do both, that will cover all PHP versions.

@gergokee
Copy link
Contributor

gergokee commented Dec 19, 2023

Is there any hope for adding this to the next release? :)

@TravisWhitehead
Copy link

TravisWhitehead commented Apr 19, 2024

I've hit this bug in a similar case.

My intention was to configure guzzle's proxy behavior to override/ignore the environment (variables) NO_PROXY / no_proxy so that all traffic is proxied.

I tried this approach:

'proxy' => [
    'http' => 'http://example:8080',
    'https' => 'http://example:8080',
    # Send everything through the proxy
    'no' => []
]

And I found that the environment variable's NO_PROXY was still taking effect.

My workaround was:

diff --git a/src/Handler/CurlFactory.php b/src/Handler/CurlFactory.php
index 16a94223..59b79da2 100644
--- a/src/Handler/CurlFactory.php
+++ b/src/Handler/CurlFactory.php
@@ -448,6 +448,9 @@ class CurlFactory implements CurlFactoryInterface
                     if (isset($options['proxy']['no']) && Utils::isHostInNoProxy($host, $options['proxy']['no'])) {
                         unset($conf[\CURLOPT_PROXY]);
                     } else {
+                        $conf[\CURLOPT_NOPROXY] = "";
                         $conf[\CURLOPT_PROXY] = $options['proxy'][$scheme];
                     }
                 }

So there are at least two cases to consider here:

  • When the request's host/address matches an entry in guzzle's no proxy options (but the environment NO_PROXY does not include this host/address)
  • When the request's host/address does not match an entry in guzzle's no proxy options (but the environment NO_PROXY does include this host/address)

Either of these will result in unexpected behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants