Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/py/selenium/webdriver/common/proxy.py
3998 views
1
# Licensed to the Software Freedom Conservancy (SFC) under one
2
# or more contributor license agreements. See the NOTICE file
3
# distributed with this work for additional information
4
# regarding copyright ownership. The SFC licenses this file
5
# to you under the Apache License, Version 2.0 (the
6
# "License"); you may not use this file except in compliance
7
# with the License. You may obtain a copy of the License at
8
#
9
# http://www.apache.org/licenses/LICENSE-2.0
10
#
11
# Unless required by applicable law or agreed to in writing,
12
# software distributed under the License is distributed on an
13
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
# KIND, either express or implied. See the License for the
15
# specific language governing permissions and limitations
16
# under the License.
17
18
"""The Proxy implementation."""
19
20
21
class ProxyTypeFactory:
22
"""Factory for proxy types."""
23
24
@staticmethod
25
def make(ff_value, string):
26
return {"ff_value": ff_value, "string": string}
27
28
29
class ProxyType:
30
"""Set of possible types of proxy.
31
32
Each proxy type has 2 properties: 'ff_value' is value of Firefox
33
profile preference, 'string' is id of proxy type.
34
"""
35
36
DIRECT = ProxyTypeFactory.make(0, "DIRECT") # Direct connection, no proxy (default on Windows).
37
MANUAL = ProxyTypeFactory.make(1, "MANUAL") # Manual proxy settings (e.g., for httpProxy).
38
PAC = ProxyTypeFactory.make(2, "PAC") # Proxy autoconfiguration from URL.
39
RESERVED_1 = ProxyTypeFactory.make(3, "RESERVED1") # Never used.
40
AUTODETECT = ProxyTypeFactory.make(4, "AUTODETECT") # Proxy autodetection (presumably with WPAD).
41
SYSTEM = ProxyTypeFactory.make(5, "SYSTEM") # Use system settings (default on Linux).
42
UNSPECIFIED = ProxyTypeFactory.make(6, "UNSPECIFIED") # Not initialized (for internal use).
43
44
@classmethod
45
def load(cls, value):
46
if isinstance(value, dict) and "string" in value:
47
value = value["string"]
48
value = str(value).upper()
49
for attr in dir(cls):
50
attr_value = getattr(cls, attr)
51
if isinstance(attr_value, dict) and "string" in attr_value and attr_value["string"] == value:
52
return attr_value
53
raise Exception(f"No proxy type is found for {value}")
54
55
56
class _ProxyTypeDescriptor:
57
def __init__(self, name, p_type):
58
self.name = name
59
self.p_type = p_type
60
61
def __get__(self, obj, cls):
62
return getattr(obj, self.name)
63
64
def __set__(self, obj, value):
65
if self.name == "autodetect" and not isinstance(value, bool):
66
raise ValueError("Autodetect proxy value needs to be a boolean")
67
getattr(obj, "_verify_proxy_type_compatibility")(self.p_type)
68
setattr(obj, "proxyType", self.p_type)
69
setattr(obj, self.name, value)
70
71
72
class Proxy:
73
"""Proxy configuration containing proxy type and necessary proxy settings."""
74
75
proxyType = ProxyType.UNSPECIFIED
76
autodetect = False
77
httpProxy = ""
78
noProxy = ""
79
proxyAutoconfigUrl = ""
80
sslProxy = ""
81
socksProxy = ""
82
socksUsername = ""
83
socksPassword = ""
84
socksVersion = None
85
86
# create descriptor type objects
87
auto_detect = _ProxyTypeDescriptor("autodetect", ProxyType.AUTODETECT)
88
"""Proxy autodetection setting (boolean)."""
89
90
http_proxy = _ProxyTypeDescriptor("httpProxy", ProxyType.MANUAL)
91
"""HTTP proxy address."""
92
93
no_proxy = _ProxyTypeDescriptor("noProxy", ProxyType.MANUAL)
94
"""Addresses to bypass proxy."""
95
96
proxy_autoconfig_url = _ProxyTypeDescriptor("proxyAutoconfigUrl", ProxyType.PAC)
97
"""Proxy autoconfiguration URL."""
98
99
ssl_proxy = _ProxyTypeDescriptor("sslProxy", ProxyType.MANUAL)
100
"""SSL proxy address."""
101
102
socks_proxy = _ProxyTypeDescriptor("socksProxy", ProxyType.MANUAL)
103
"""SOCKS proxy address."""
104
105
socks_username = _ProxyTypeDescriptor("socksUsername", ProxyType.MANUAL)
106
"""SOCKS proxy username."""
107
108
socks_password = _ProxyTypeDescriptor("socksPassword", ProxyType.MANUAL)
109
"""SOCKS proxy password."""
110
111
socks_version = _ProxyTypeDescriptor("socksVersion", ProxyType.MANUAL)
112
"""SOCKS proxy version."""
113
114
def __init__(self, raw: dict | None = None):
115
"""Creates a new Proxy.
116
117
Args:
118
raw: Raw proxy data. If None, default class values are used.
119
"""
120
if raw is None:
121
return
122
if not isinstance(raw, dict):
123
raise TypeError(f"`raw` must be a dict, got {type(raw)}")
124
if raw.get("proxyType"):
125
self.proxy_type = ProxyType.load(raw["proxyType"])
126
if raw.get("httpProxy"):
127
self.http_proxy = raw["httpProxy"]
128
if raw.get("noProxy"):
129
self.no_proxy = raw["noProxy"]
130
if raw.get("proxyAutoconfigUrl"):
131
self.proxy_autoconfig_url = raw["proxyAutoconfigUrl"]
132
if raw.get("sslProxy"):
133
self.sslProxy = raw["sslProxy"]
134
if raw.get("autodetect"):
135
self.auto_detect = raw["autodetect"]
136
if raw.get("socksProxy"):
137
self.socks_proxy = raw["socksProxy"]
138
if raw.get("socksUsername"):
139
self.socks_username = raw["socksUsername"]
140
if raw.get("socksPassword"):
141
self.socks_password = raw["socksPassword"]
142
if raw.get("socksVersion"):
143
self.socks_version = raw["socksVersion"]
144
145
@property
146
def proxy_type(self):
147
"""Returns proxy type as `ProxyType`."""
148
return self.proxyType
149
150
@proxy_type.setter
151
def proxy_type(self, value) -> None:
152
"""Sets proxy type.
153
154
Args:
155
value: The proxy type.
156
"""
157
self._verify_proxy_type_compatibility(value)
158
self.proxyType = value
159
160
def _verify_proxy_type_compatibility(self, compatible_proxy):
161
if self.proxyType not in (ProxyType.UNSPECIFIED, compatible_proxy):
162
raise ValueError(
163
f"Specified proxy type ({compatible_proxy}) not compatible with current setting ({self.proxyType})"
164
)
165
166
def to_capabilities(self):
167
proxy_caps = {"proxyType": self.proxyType["string"].lower()}
168
proxies = [
169
"autodetect",
170
"httpProxy",
171
"proxyAutoconfigUrl",
172
"sslProxy",
173
"noProxy",
174
"socksProxy",
175
"socksUsername",
176
"socksPassword",
177
"socksVersion",
178
]
179
for proxy in proxies:
180
attr_value = getattr(self, proxy)
181
if attr_value:
182
proxy_caps[proxy] = attr_value
183
return proxy_caps
184
185
def to_bidi_dict(self) -> dict:
186
"""Convert proxy settings to BiDi format.
187
188
Returns:
189
Proxy configuration in BiDi format.
190
"""
191
proxy_type = self.proxyType["string"].lower()
192
result = {"proxyType": proxy_type}
193
194
if proxy_type == "manual":
195
if self.httpProxy:
196
result["httpProxy"] = self.httpProxy
197
if self.sslProxy:
198
result["sslProxy"] = self.sslProxy
199
if self.socksProxy:
200
result["socksProxy"] = self.socksProxy
201
if self.socksVersion is not None:
202
result["socksVersion"] = self.socksVersion
203
if self.noProxy:
204
# Convert comma-separated string to list
205
if isinstance(self.noProxy, str):
206
result["noProxy"] = [host.strip() for host in self.noProxy.split(",") if host.strip()]
207
elif isinstance(self.noProxy, list):
208
if not all(isinstance(h, str) for h in self.noProxy):
209
raise TypeError("no_proxy list must contain only strings")
210
result["noProxy"] = self.noProxy
211
else:
212
raise TypeError("no_proxy must be a comma-separated string or a list of strings")
213
214
elif proxy_type == "pac":
215
if self.proxyAutoconfigUrl:
216
result["proxyAutoconfigUrl"] = self.proxyAutoconfigUrl
217
218
return result
219
220