This is an automated email from the ASF dual-hosted git repository.
tison pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/libcloud.git
The following commit(s) were added to refs/heads/trunk by this push:
new 3fb37a2d2 Consistent handling of HTTP/S proxy environment variables
(#2079)
3fb37a2d2 is described below
commit 3fb37a2d22f06f7a57ff796911499cfa2929a0c8
Author: David Wegsman <[email protected]>
AuthorDate: Fri Mar 13 05:09:14 2026 -0400
Consistent handling of HTTP/S proxy environment variables (#2079)
* Remove explicit handling of proxy env variables in favor of downstream
handling through Requests library
* Add unit test to verify underlying library respects proxy env vars
* fix formatting errors
---
libcloud/http.py | 14 ++--------
libcloud/test/test_connection.py | 59 ++++++++++++++++++++++++++++++++--------
2 files changed, 50 insertions(+), 23 deletions(-)
diff --git a/libcloud/http.py b/libcloud/http.py
index e09cc68b5..4c1c1b01e 100644
--- a/libcloud/http.py
+++ b/libcloud/http.py
@@ -18,7 +18,6 @@ Subclass for httplib.HTTPSConnection with optional
certificate name
verification, depending on libcloud.security settings.
"""
-import os
import warnings
import requests
@@ -42,9 +41,6 @@ ALLOW_REDIRECTS = 1
# Default timeout for HTTP requests in seconds
DEFAULT_REQUEST_TIMEOUT = 60
-HTTP_PROXY_ENV_VARIABLE_NAME = "http_proxy"
-HTTPS_PROXY_ENV_VARIABLE_NAME = "https_proxy"
-
class SignedHTTPSAdapter(HTTPAdapter):
def __init__(self, cert_file, key_file):
@@ -88,6 +84,7 @@ class LibcloudBaseConnection:
def set_http_proxy(self, proxy_url):
"""
Set a HTTP proxy which will be used with this connection.
+ This will override any proxy environment variables.
:param proxy_url: Proxy URL (e.g. http://<hostname>:<port> without
authentication and
@@ -197,13 +194,8 @@ class LibcloudConnection(LibcloudBaseConnection):
":{}".format(port) if port not in (80, 443) else "",
)
- # Support for HTTP(s) proxy
- # NOTE: We always only use a single proxy (either HTTP or HTTPS)
- https_proxy_url_env = os.environ.get(HTTPS_PROXY_ENV_VARIABLE_NAME,
None)
- http_proxy_url_env = os.environ.get(HTTP_PROXY_ENV_VARIABLE_NAME,
https_proxy_url_env)
-
- # Connection argument has precedence over environment variables
- proxy_url = kwargs.pop("proxy_url", http_proxy_url_env)
+ # Connection argument has precedence over environment variables, which
are handled downstream
+ proxy_url = kwargs.pop("proxy_url", None)
self._setup_verify()
self._setup_ca_cert()
diff --git a/libcloud/test/test_connection.py b/libcloud/test/test_connection.py
index c2e008e03..a7bf1d7c8 100644
--- a/libcloud/test/test_connection.py
+++ b/libcloud/test/test_connection.py
@@ -21,6 +21,7 @@ from unittest import mock
from unittest.mock import Mock, patch
import requests_mock
+from requests.adapters import HTTPAdapter
from requests.exceptions import ConnectTimeout
import libcloud.common.base
@@ -36,6 +37,7 @@ class BaseConnectionClassTestCase(unittest.TestCase):
def setUp(self):
self.orig_http_proxy = os.environ.pop("http_proxy", None)
self.orig_https_proxy = os.environ.pop("https_proxy", None)
+ self.orig_no_proxy = os.environ.pop("no_proxy", None)
def tearDown(self):
if self.orig_http_proxy:
@@ -48,6 +50,11 @@ class BaseConnectionClassTestCase(unittest.TestCase):
elif "https_proxy" in os.environ:
del os.environ["https_proxy"]
+ if self.orig_no_proxy:
+ os.environ["no_proxy"] = self.orig_no_proxy
+ elif "no_proxy" in os.environ:
+ del os.environ["no_proxy"]
+
libcloud.common.base.ALLOW_PATH_DOUBLE_SLASHES = False
def test_parse_proxy_url(self):
@@ -104,22 +111,12 @@ class BaseConnectionClassTestCase(unittest.TestCase):
)
def test_constructor(self):
- proxy_url = "http://127.0.0.2:3128"
- os.environ["http_proxy"] = proxy_url
- conn = LibcloudConnection(host="localhost", port=80)
- self.assertEqual(conn.proxy_scheme, "http")
- self.assertEqual(conn.proxy_host, "127.0.0.2")
- self.assertEqual(conn.proxy_port, 3128)
- self.assertEqual(
- conn.session.proxies,
- {"http": "http://127.0.0.2:3128", "https":
"http://127.0.0.2:3128"},
- )
-
_ = os.environ.pop("http_proxy", None)
conn = LibcloudConnection(host="localhost", port=80)
self.assertIsNone(conn.proxy_scheme)
self.assertIsNone(conn.proxy_host)
self.assertIsNone(conn.proxy_port)
+ self.assertTrue(conn.session.proxies is None or not
conn.session.proxies)
proxy_url = "http://127.0.0.3:3128"
conn.set_http_proxy(proxy_url=proxy_url)
@@ -143,7 +140,8 @@ class BaseConnectionClassTestCase(unittest.TestCase):
os.environ["http_proxy"] = proxy_url
proxy_url = "http://127.0.0.5:3128"
- conn = LibcloudConnection(host="localhost", port=80,
proxy_url=proxy_url)
+ conn = LibcloudConnection(host="localhost", port=80)
+ conn.set_http_proxy(proxy_url=proxy_url)
self.assertEqual(conn.proxy_scheme, "http")
self.assertEqual(conn.proxy_host, "127.0.0.5")
self.assertEqual(conn.proxy_port, 3128)
@@ -163,6 +161,43 @@ class BaseConnectionClassTestCase(unittest.TestCase):
{"http": "https://127.0.0.6:3129", "https":
"https://127.0.0.6:3129"},
)
+ def test_proxy_environment_variables_respected(self):
+ """
+ Test that proxy environment variables are respected by the underlying
Requests library
+ """
+
+ def mock_send(self, request, **kwargs):
+ captured_proxies.update(kwargs.get("proxies", {}))
+ nonlocal captured_url
+ captured_url = request.url
+ mock_response = Mock()
+ mock_response.status_code = 200
+ mock_response.headers = {"content-type": "application/json",
"location": ""}
+ mock_response.text = "OK"
+ mock_response.history = [] # No redirects
+ return mock_response
+
+ with patch.object(HTTPAdapter, "send", mock_send):
+ os.environ["http_proxy"] = "http://proxy.example.com:8080"
+ os.environ["https_proxy"] = "https://secure-proxy.example.com:8443"
+ os.environ["no_proxy"] = "localhost,127.0.0.1"
+ captured_proxies = {}
+ captured_url = None
+
+ conn = LibcloudConnection(host="localhost", port=80)
+ conn.request("GET", "/get")
+
+ self.assertEqual(captured_proxies, {})
+ self.assertIn("localhost", captured_url)
+
+ conn = LibcloudConnection(host="test.com", port=80)
+ conn.request("GET", "/get")
+
+ self.assertEqual(captured_proxies.get("http", None),
"http://proxy.example.com:8080")
+ self.assertEqual(
+ captured_proxies.get("https", None),
"https://secure-proxy.example.com:8443"
+ )
+
def test_connection_to_unusual_port(self):
conn = LibcloudConnection(host="localhost", port=8080)
self.assertIsNone(conn.proxy_scheme)