System proxy detection
proxylib.os
Platform-agnostic system proxy detection.
Dispatches to a per-OS backend (:mod:.nt on Windows, :mod:.darwin on
macOS, :mod:.posix elsewhere) and, via :func:auto_proxy, falls back to
WPAD discovery (:mod:proxylib.pac.wpad) when the OS/env has no explicit
proxy configured.
Both :func:system_proxy and :func:auto_proxy take a provider:
"python"(default): proxylib's own detection + PAC-via-dukpypath -- works everywhere, including sandboxes/testing."system": outsources resolution to the OS's native proxy engine (WinHttpProxyMapon Windows,CFNetworkProxyMapon macOS,LibProxyMapon POSIX if its shared library is loadable -- falls back to"python"there if not). These already do their own WPAD/PAC, so :func:auto_proxydoesn't run its own WPAD fallback on top of them.
__all__ = ('system_proxy', 'auto_proxy')
module-attribute
auto_proxy(provider='python', **urlopen_kwargs)
Resolve the effective ProxyMap for this machine.
Order: OS-native settings / env vars (:func:system_proxy) → if that
yields a PAC URL, load it → if it yields no usable config at all (the
"python" provider's own signal for "OS has nothing configured"),
try WPAD discovery → otherwise DIRECT.
Source code in src/proxylib/os/__init__.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | |
system_proxy(provider='python')
Read this machine's proxy configuration. See the module docstring
for what provider means.
Source code in src/proxylib/os/__init__.py
56 57 58 59 60 61 62 63 | |
proxylib.os.nt
Windows system proxy detection via the WinHTTP "IE proxy config" API.
Uses WinHttpGetIEProxyConfigForCurrentUser (stdlib ctypes, no extra
dependency) rather than hand-parsing the registry's undocumented
Connections\DefaultConnectionSettings/SavedLegacySettings binary
blob. That blob is the underlying data source (its flags DWORD at offset 8
has bit 0x08 set when "Automatically detect settings" is on — verified
empirically), but its trailing layout has known version differences across
Windows releases; the WinHTTP API is Microsoft's supported way to read the
same data without guessing byte offsets. This mirrors what Chromium does.
__all__ = ('system_proxy', 'WinHttpProxyMap')
module-attribute
WinHttpProxyMap()
Bases: ProxyMap
A ProxyMap backed by WinHTTP's own autoproxy engine (WinHttpGetProxyForUrl).
Unlike :func:system_proxy's Python-side WPAD/PAC path, this outsources
WPAD/DHCP-252 discovery, NTLM/Kerberos SSO for fetching the PAC script,
and PAC JS execution itself to WinHTTP -- no dukpy needed on
Windows. Falls back to the static manual proxy (from
WinHttpGetIEProxyConfigForCurrentUser) when autoproxy isn't
configured, or when WinHttpGetProxyForUrl fails; DIRECT if nothing
at all is configured.
Reuses one WinHttpOpen session handle for its lifetime (release it
with :meth:close, or let garbage collection do it) -- opening a
session per lookup would be wasteful, and WinHTTP's own autoproxy
result caching is scoped to the session.
Source code in src/proxylib/os/nt.py
245 246 247 248 | |
__slots__ = ('_hsession',)
class-attribute
instance-attribute
__del__()
Source code in src/proxylib/os/nt.py
255 256 | |
__getitem__(url)
Source code in src/proxylib/os/nt.py
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | |
close()
Source code in src/proxylib/os/nt.py
250 251 252 253 | |
system_proxy()
Read proxy settings the way Windows/IE/Edge do.
Mirrors Windows' own precedence: if "Automatically detect settings" is on, WPAD is tried first; then the configured PAC script (if any); then a manual proxy (if any); otherwise DIRECT.
Source code in src/proxylib/os/nt.py
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | |
proxylib.os.darwin
macOS system proxy detection via scutil --proxy (no extra dependency),
plus :class:CFNetworkProxyMap, a ctypes binding to the native CFNetwork
proxy-resolution API.
__all__ = ('system_proxy', 'CFNetworkProxyMap')
module-attribute
CFNetworkProxyMap(deadline=5.0)
Bases: ProxyMap
Resolves each request URL via macOS's native CFNetwork proxy engine.
Unlike :func:system_proxy (which reads static settings once via
scutil --proxy and relies on EnvProxyConfig for NO_PROXY-style
matching), CFNetworkCopyProxiesForURL applies the system's real
per-URL bypass-exception matching itself. When the system is configured
with a PAC URL, it's executed natively (CFNetworkExecuteProxyAutoConfigurationURL)
-- no dukpy needed -- pumped against a run loop in small slices up to
deadline seconds (default 5.0) so a dead PAC server or hung DNS
lookup can't block forever; on timeout, raises KeyError (a
resolution failure per the ProxyMap contract -- same as
LibProxyMap -- so a fallback/chain can proceed) rather than hanging
or silently returning DIRECT.
Validated by a real (unmocked) smoke test on macOS CI, but only for the
common "direct/manual proxy" path -- the PAC-execution/run-loop-deadline
branch is not yet exercised by that CI job, so treat it more cautiously.
See root AGENTS.md for details.
Source code in src/proxylib/os/darwin.py
414 415 | |
__slots__ = ('deadline',)
class-attribute
instance-attribute
deadline = deadline
instance-attribute
__getitem__(url)
Source code in src/proxylib/os/darwin.py
417 418 419 420 421 | |
system_proxy()
Read proxy settings from macOS's System Configuration via scutil --proxy.
Mirrors macOS's own Network preferences precedence: if "Auto Proxy Discovery" (WPAD) is on, it's tried first; then Automatic Proxy Configuration (a PAC URL) if enabled; then a manual HTTP/HTTPS proxy; otherwise DIRECT.
Source code in src/proxylib/os/darwin.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | |
proxylib.os.posix
Linux/other POSIX system proxy detection.
There is no single authoritative proxy config store on Linux; the portable
convention is environment variables. As a best-effort improvement,
:func:system_proxy also tries (in order): libproxy (:mod:.libproxy, if
its proxy CLI is installed -- generally the most authoritative single
source since it's itself a full cross-desktop resolution engine), GNOME
(:mod:.gnome), MATE (:mod:.mate), KDE (:mod:.kde), and NetworkManager
(:mod:.networkmanager) -- each only if its respective binary/file is
present, each degrading to "not configured" (not an error) otherwise. If
more than one of these has stale/leftover config on the same machine (e.g.
switched desktop environments), the first match in that order wins -- there
is no desktop-session detection (XDG_CURRENT_DESKTOP) to disambiguate.
Other desktop environments (Xfce, Cinnamon, ...) aren't covered directly
(though libproxy, if installed, may cover them) — set HTTP_PROXY/
HTTPS_PROXY/NO_PROXY or PROXY_PAC explicitly on those.
__all__ = ('system_proxy',)
module-attribute
system_proxy()
PROXY_PAC/HTTP_PROXY-family env vars, with best-effort desktop checks.
Source code in src/proxylib/os/posix/__init__.py
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | |
proxylib.os.posix.gnome
GNOME desktop proxy detection via gsettings (org.gnome.system.proxy).
__all__ = ('detect',)
module-attribute
detect()
Source code in src/proxylib/os/posix/gnome.py
11 12 | |
proxylib.os.posix.mate
MATE desktop proxy detection via gsettings (org.mate.system.proxy).
MATE's schema is a near-verbatim fork of GNOME's (same key names), inherited from their shared GNOME 2 ancestry.
__all__ = ('detect',)
module-attribute
detect()
Source code in src/proxylib/os/posix/mate.py
15 16 | |
proxylib.os.posix.kde
KDE desktop proxy detection via kioslaverc.
__all__ = ('detect',)
module-attribute
detect()
Source code in src/proxylib/os/posix/kde.py
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
proxylib.os.posix.networkmanager
NetworkManager proxy detection.
NetworkManager's own per-connection proxy setting (see the
settings-proxy docs <https://networkmanager.dev/docs/api/latest/settings-proxy.html>_,
exposed over D-Bus on org.freedesktop.NetworkManager.Settings.Connection)
only supports method = "none" or "auto" -- there's no manual
host:port option at this layer, unlike the desktop-level backends.
Read via nmcli (NetworkManager's own CLI) when it's on PATH; if it
isn't (a minimal install with just the daemon + D-Bus, no CLI tools),
fall back to talking to the same D-Bus interface directly via dbus-send.
Neither needs a non-stdlib dependency (e.g. dbus-python/pydbus).
__all__ = ('detect',)
module-attribute
detect()
Source code in src/proxylib/os/posix/networkmanager.py
176 177 178 | |
proxylib.os.posix.libproxy
libproxy integration, via ctypes bindings to its C API directly
(no subprocess, no non-stdlib dependency).
libproxy <https://libproxy.github.io/libproxy/>_ is itself a cross-desktop
proxy-resolution engine -- it already knows how to read GNOME/KDE/env vars/
PAC/WPAD/etc, generally with more fidelity than proxylib's own best-effort
per-desktop probes (:mod:.gnome, :mod:.kde, ...). When its shared library
is loadable, :mod:..posix prefers it over those probes.
Unlike the other backends, this isn't a "read the config once at startup"
detector -- resolution is per-URL, so :class:LibProxyMap is its own
:class:~proxylib.proxy.ProxyMap implementation that calls into libproxy
fresh for every lookup: a new pxProxyFactory per call (matching
libproxy's own API contract -- see px_proxy_factory_free -- and
sidestepping any question of whether a shared factory is safe to reuse
across threads).
__all__ = ('LibProxyMap', 'detect')
module-attribute
LibProxyMap(lib=None)
Bases: ProxyMap
Resolves each request URL via libproxy's C API.
Construct with no arguments to use the auto-detected shared library;
__getitem__ raises KeyError (like any other resolution failure)
if libproxy isn't available, rather than erroring at construction time.
Source code in src/proxylib/os/posix/libproxy.py
74 75 | |
__slots__ = ('_lib',)
class-attribute
instance-attribute
__getitem__(uri)
Source code in src/proxylib/os/posix/libproxy.py
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | |
detect()
Source code in src/proxylib/os/posix/libproxy.py
105 106 107 | |