Makes NO_PROXY, HTTP_PROXY and HTTPS_PROXY values configurable in settings by zooba · Pull Request #430 · python/pymanager · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/manage/commands.py
7 changes: 3 additions & 4 deletions src/manage/install_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from .tagutils import install_matches_any, tag_or_range
from .urlutils import (
sanitise_url,
urlopen as _urlopen,
urlretrieve as _urlretrieve,
IndexDownloader,
)
Expand Down Expand Up @@ -48,7 +47,7 @@ def _expand_versions_by_tag(versions):
yield {**v, "tag": t}


def select_package(index_downloader, tag, platform=None, *, urlopen=_urlopen, by_id=False, allow_pre=True):
def select_package(index_downloader, tag, platform=None, *, by_id=False, allow_pre=True):
"""Finds suitable package from index.json that looks like:
{"versions": [
{"id": ..., "company": ..., "tag": ..., "url": ..., "hash": {"sha256": hexdigest}},
Expand Down Expand Up @@ -96,7 +95,7 @@ def select_package(index_downloader, tag, platform=None, *, urlopen=_urlopen, by
raise RuntimeError("End of select_package reached")


def download_package(cmd, install, dest, cache, *, on_progress=None, urlopen=_urlopen, urlretrieve=_urlretrieve):
def download_package(cmd, install, dest, cache, *, on_progress=None, urlretrieve=_urlretrieve):
LOGGER.debug("Starting download package %s to %s", sanitise_url(install["url"]), dest)

if not cmd.force and dest.is_file():
Expand Down Expand Up @@ -130,7 +129,7 @@ def _find_creds(url):
if auth:
LOGGER.debug("Found credentials in URL or configured source.")
return auth
auth = os.getenv("PYMANAGER_USERNAME", ""), os.getenv("PYMANAGER_PASSWORD", "")
auth = cmd.username, (cmd.password or "")
if auth[0]:
LOGGER.debug("Found credentials in environment.")
return auth
Expand Down
54 changes: 38 additions & 16 deletions src/manage/urlutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,21 +102,34 @@ def _parse_proxy(value):
return proxy, credentials


def _proxy_settings_from_env():
if os.getenv("NO_PROXY"):
return _ProxySettings(mode=PROXY_MODE_DIRECT)
def _proxy_settings(info):
if not info:
return _ProxySettings()

http_value = os.getenv("HTTP_PROXY")
https_value = os.getenv("HTTPS_PROXY")
if not http_value and not https_value:
if info.no_proxy:
if info.no_proxy.lower() in ("1", "*", "y", "yes", "t", "true"):
return _ProxySettings(mode=PROXY_MODE_DIRECT)
if info.no_proxy.lower() not in ("0", "n", "no", "f", "false"):
# TODO: Parse and filter based on info.no_proxy IF we can be sure it's
# secure, preferably by delegating responsibility for parsing to the OS.
# Claiming to support proper whitelisting of domains is very likely to
# attract reports of bypasses, none of which we would treat as a
# vulnerability (due to non-default configuration settings), but they
# historically create more noise than they're worth. Let's just avoid
# breaking into jail until we're sure we can do it right.
LOGGER.warn("Values for NO_PROXY other than 1, *, y[es], t[rue], "
"or the equivalent false values are not supported. "
"Other proxy settings will be used.")

if not info.http_proxy and not info.https_proxy:
return _ProxySettings()

http_proxy = http_credentials = None
https_proxy = https_credentials = None
if http_value:
http_proxy, http_credentials = _parse_proxy(http_value)
if https_value:
https_proxy, https_credentials = _parse_proxy(https_value)
if info.http_proxy:
http_proxy, http_credentials = _parse_proxy(info.http_proxy)
if info.https_proxy:
https_proxy, https_credentials = _parse_proxy(info.https_proxy)

proxy_list = " ".join(
value for value in (
Expand All @@ -134,20 +147,27 @@ def _proxy_settings_from_env():
)


class _EnvProxyInfo:
"""Default value for proxy_info arguments from environment variables."""
no_proxy = os.getenv("NO_PROXY")
http_proxy = os.getenv("HTTP_PROXY")
https_proxy = os.getenv("HTTPS_PROXY")


class NoInternetError(Exception):
pass


class _Request:
def __init__(self, url, method="GET", headers={}, outfile=None):
def __init__(self, url, method="GET", headers={}, outfile=None, proxy_info=None):
self.url = url
self.method = method.upper()
self.headers = dict(headers)
self.chunksize = 64 * 1024
self.username = None
self.password = None
self.outfile = Path(outfile) if outfile else None
self.proxy_settings = _proxy_settings_from_env()
self.proxy_settings = _proxy_settings(proxy_info)
self._on_progress = None
self._on_auth_request = None
self._on_cancel = None
Expand Down Expand Up @@ -488,7 +508,8 @@ def _powershell_urlretrieve(request):
raise


def urlopen(url, method="GET", headers={}, on_progress=None, on_auth_request=None):
def urlopen(url, method="GET", headers={}, on_progress=None,
on_auth_request=None, proxy_info=_EnvProxyInfo):
scheme, sep, path = url.partition("://")
if not sep:
scheme = "file"
Expand All @@ -500,7 +521,7 @@ def urlopen(url, method="GET", headers={}, on_progress=None, on_auth_request=Non
with open(file_url_to_path(url), "rb") as f:
return f.read()

request = _Request(url, method=method, headers=headers)
request = _Request(url, method=method, headers=headers, proxy_info=proxy_info)
request._on_progress = on_progress
request._on_auth_request = on_auth_request

Expand Down Expand Up @@ -561,7 +582,8 @@ def urlopen(url, method="GET", headers={}, on_progress=None, on_auth_request=Non


def urlretrieve(url, outfile, method="GET", headers={}, chunksize=64 * 1024,
on_progress=None, on_auth_request=None, on_cancel=None):
on_progress=None, on_auth_request=None, on_cancel=None,
proxy_info=_EnvProxyInfo):
scheme, sep, path = url.partition("://")
if not sep:
scheme = "file"
Expand All @@ -588,7 +610,7 @@ def on_progress(_): pass
on_progress(100)
return

request = _Request(url, method=method, headers=headers)
request = _Request(url, method=method, headers=headers, proxy_info=proxy_info)
request.outfile = Path(outfile)
request.chunksize = chunksize
request._on_progress = on_progress
Expand Down
8 changes: 8 additions & 0 deletions src/pymanager.json
Loading