Path: blob/trunk/py/selenium/webdriver/common/proxy.py
3998 views
# Licensed to the Software Freedom Conservancy (SFC) under one1# or more contributor license agreements. See the NOTICE file2# distributed with this work for additional information3# regarding copyright ownership. The SFC licenses this file4# to you under the Apache License, Version 2.0 (the5# "License"); you may not use this file except in compliance6# with the License. You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing,11# software distributed under the License is distributed on an12# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13# KIND, either express or implied. See the License for the14# specific language governing permissions and limitations15# under the License.1617"""The Proxy implementation."""181920class ProxyTypeFactory:21"""Factory for proxy types."""2223@staticmethod24def make(ff_value, string):25return {"ff_value": ff_value, "string": string}262728class ProxyType:29"""Set of possible types of proxy.3031Each proxy type has 2 properties: 'ff_value' is value of Firefox32profile preference, 'string' is id of proxy type.33"""3435DIRECT = ProxyTypeFactory.make(0, "DIRECT") # Direct connection, no proxy (default on Windows).36MANUAL = ProxyTypeFactory.make(1, "MANUAL") # Manual proxy settings (e.g., for httpProxy).37PAC = ProxyTypeFactory.make(2, "PAC") # Proxy autoconfiguration from URL.38RESERVED_1 = ProxyTypeFactory.make(3, "RESERVED1") # Never used.39AUTODETECT = ProxyTypeFactory.make(4, "AUTODETECT") # Proxy autodetection (presumably with WPAD).40SYSTEM = ProxyTypeFactory.make(5, "SYSTEM") # Use system settings (default on Linux).41UNSPECIFIED = ProxyTypeFactory.make(6, "UNSPECIFIED") # Not initialized (for internal use).4243@classmethod44def load(cls, value):45if isinstance(value, dict) and "string" in value:46value = value["string"]47value = str(value).upper()48for attr in dir(cls):49attr_value = getattr(cls, attr)50if isinstance(attr_value, dict) and "string" in attr_value and attr_value["string"] == value:51return attr_value52raise Exception(f"No proxy type is found for {value}")535455class _ProxyTypeDescriptor:56def __init__(self, name, p_type):57self.name = name58self.p_type = p_type5960def __get__(self, obj, cls):61return getattr(obj, self.name)6263def __set__(self, obj, value):64if self.name == "autodetect" and not isinstance(value, bool):65raise ValueError("Autodetect proxy value needs to be a boolean")66getattr(obj, "_verify_proxy_type_compatibility")(self.p_type)67setattr(obj, "proxyType", self.p_type)68setattr(obj, self.name, value)697071class Proxy:72"""Proxy configuration containing proxy type and necessary proxy settings."""7374proxyType = ProxyType.UNSPECIFIED75autodetect = False76httpProxy = ""77noProxy = ""78proxyAutoconfigUrl = ""79sslProxy = ""80socksProxy = ""81socksUsername = ""82socksPassword = ""83socksVersion = None8485# create descriptor type objects86auto_detect = _ProxyTypeDescriptor("autodetect", ProxyType.AUTODETECT)87"""Proxy autodetection setting (boolean)."""8889http_proxy = _ProxyTypeDescriptor("httpProxy", ProxyType.MANUAL)90"""HTTP proxy address."""9192no_proxy = _ProxyTypeDescriptor("noProxy", ProxyType.MANUAL)93"""Addresses to bypass proxy."""9495proxy_autoconfig_url = _ProxyTypeDescriptor("proxyAutoconfigUrl", ProxyType.PAC)96"""Proxy autoconfiguration URL."""9798ssl_proxy = _ProxyTypeDescriptor("sslProxy", ProxyType.MANUAL)99"""SSL proxy address."""100101socks_proxy = _ProxyTypeDescriptor("socksProxy", ProxyType.MANUAL)102"""SOCKS proxy address."""103104socks_username = _ProxyTypeDescriptor("socksUsername", ProxyType.MANUAL)105"""SOCKS proxy username."""106107socks_password = _ProxyTypeDescriptor("socksPassword", ProxyType.MANUAL)108"""SOCKS proxy password."""109110socks_version = _ProxyTypeDescriptor("socksVersion", ProxyType.MANUAL)111"""SOCKS proxy version."""112113def __init__(self, raw: dict | None = None):114"""Creates a new Proxy.115116Args:117raw: Raw proxy data. If None, default class values are used.118"""119if raw is None:120return121if not isinstance(raw, dict):122raise TypeError(f"`raw` must be a dict, got {type(raw)}")123if raw.get("proxyType"):124self.proxy_type = ProxyType.load(raw["proxyType"])125if raw.get("httpProxy"):126self.http_proxy = raw["httpProxy"]127if raw.get("noProxy"):128self.no_proxy = raw["noProxy"]129if raw.get("proxyAutoconfigUrl"):130self.proxy_autoconfig_url = raw["proxyAutoconfigUrl"]131if raw.get("sslProxy"):132self.sslProxy = raw["sslProxy"]133if raw.get("autodetect"):134self.auto_detect = raw["autodetect"]135if raw.get("socksProxy"):136self.socks_proxy = raw["socksProxy"]137if raw.get("socksUsername"):138self.socks_username = raw["socksUsername"]139if raw.get("socksPassword"):140self.socks_password = raw["socksPassword"]141if raw.get("socksVersion"):142self.socks_version = raw["socksVersion"]143144@property145def proxy_type(self):146"""Returns proxy type as `ProxyType`."""147return self.proxyType148149@proxy_type.setter150def proxy_type(self, value) -> None:151"""Sets proxy type.152153Args:154value: The proxy type.155"""156self._verify_proxy_type_compatibility(value)157self.proxyType = value158159def _verify_proxy_type_compatibility(self, compatible_proxy):160if self.proxyType not in (ProxyType.UNSPECIFIED, compatible_proxy):161raise ValueError(162f"Specified proxy type ({compatible_proxy}) not compatible with current setting ({self.proxyType})"163)164165def to_capabilities(self):166proxy_caps = {"proxyType": self.proxyType["string"].lower()}167proxies = [168"autodetect",169"httpProxy",170"proxyAutoconfigUrl",171"sslProxy",172"noProxy",173"socksProxy",174"socksUsername",175"socksPassword",176"socksVersion",177]178for proxy in proxies:179attr_value = getattr(self, proxy)180if attr_value:181proxy_caps[proxy] = attr_value182return proxy_caps183184def to_bidi_dict(self) -> dict:185"""Convert proxy settings to BiDi format.186187Returns:188Proxy configuration in BiDi format.189"""190proxy_type = self.proxyType["string"].lower()191result = {"proxyType": proxy_type}192193if proxy_type == "manual":194if self.httpProxy:195result["httpProxy"] = self.httpProxy196if self.sslProxy:197result["sslProxy"] = self.sslProxy198if self.socksProxy:199result["socksProxy"] = self.socksProxy200if self.socksVersion is not None:201result["socksVersion"] = self.socksVersion202if self.noProxy:203# Convert comma-separated string to list204if isinstance(self.noProxy, str):205result["noProxy"] = [host.strip() for host in self.noProxy.split(",") if host.strip()]206elif isinstance(self.noProxy, list):207if not all(isinstance(h, str) for h in self.noProxy):208raise TypeError("no_proxy list must contain only strings")209result["noProxy"] = self.noProxy210else:211raise TypeError("no_proxy must be a comma-separated string or a list of strings")212213elif proxy_type == "pac":214if self.proxyAutoconfigUrl:215result["proxyAutoconfigUrl"] = self.proxyAutoconfigUrl216217return result218219220