Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/py/test/unit/selenium/webdriver/remote/remote_connection_tests.py
1990 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
import base64
19
import os
20
from unittest.mock import patch
21
from urllib import parse
22
23
import pytest
24
from urllib3 import PoolManager, ProxyManager, make_headers
25
from urllib3.contrib.socks import SOCKSProxyManager
26
from urllib3.util import Retry, Timeout
27
28
from selenium import __version__
29
from selenium.webdriver import Proxy
30
from selenium.webdriver.common.proxy import ProxyType
31
from selenium.webdriver.remote.client_config import AuthType
32
from selenium.webdriver.remote.remote_connection import ClientConfig, RemoteConnection
33
34
35
@pytest.fixture
36
def remote_connection():
37
"""Fixture to create a RemoteConnection instance."""
38
return RemoteConnection("http://localhost:4444")
39
40
41
def test_add_command(remote_connection):
42
"""Test adding a custom command to the connection."""
43
remote_connection.add_command("CUSTOM_COMMAND", "PUT", "/session/$sessionId/custom")
44
assert remote_connection.get_command("CUSTOM_COMMAND") == ("PUT", "/session/$sessionId/custom")
45
46
47
@patch("selenium.webdriver.remote.remote_connection.RemoteConnection._request")
48
def test_execute_custom_command(mock_request, remote_connection):
49
"""Test executing a custom command through the connection."""
50
remote_connection.add_command("CUSTOM_COMMAND", "PUT", "/session/$sessionId/custom")
51
mock_request.return_value = {"status": 200, "value": "OK"}
52
53
params = {"sessionId": "12345"}
54
response = remote_connection.execute("CUSTOM_COMMAND", params)
55
56
mock_request.assert_called_once_with("PUT", "http://localhost:4444/session/12345/custom", body="{}")
57
assert response == {"status": 200, "value": "OK"}
58
59
60
def test_get_remote_connection_headers_defaults():
61
url = "http://remote"
62
headers = RemoteConnection.get_remote_connection_headers(parse.urlparse(url))
63
assert "Authorization" not in headers
64
assert "Connection" not in headers
65
assert headers.get("Accept") == "application/json"
66
assert headers.get("Content-Type") == "application/json;charset=UTF-8"
67
assert headers.get("User-Agent").startswith(f"selenium/{__version__} (python ")
68
assert headers.get("User-Agent").split(" ")[-1].rstrip(")") in ("win32", "windows", "mac", "linux")
69
70
71
def test_get_remote_connection_headers_adds_auth_header_if_pass(recwarn):
72
url = "http://user:pass@remote"
73
headers = RemoteConnection.get_remote_connection_headers(parse.urlparse(url))
74
assert headers.get("Authorization") == "Basic dXNlcjpwYXNz"
75
assert (
76
recwarn[0].message.args[0]
77
== "Embedding username and password in URL could be insecure, use ClientConfig instead"
78
)
79
80
81
def test_get_remote_connection_headers_adds_keep_alive_if_requested():
82
url = "http://remote"
83
headers = RemoteConnection.get_remote_connection_headers(parse.urlparse(url), keep_alive=True)
84
assert headers.get("Connection") == "keep-alive"
85
86
87
def test_get_proxy_url_http(mock_proxy_settings):
88
proxy = "http://http_proxy.com:8080"
89
remote_connection = RemoteConnection("http://remote", keep_alive=False)
90
proxy_url = remote_connection.client_config.get_proxy_url()
91
assert proxy_url == proxy
92
93
94
def test_get_auth_header_if_client_config_pass_basic_auth():
95
custom_config = ClientConfig(
96
remote_server_addr="http://localhost:4444",
97
keep_alive=True,
98
username="user",
99
password="pass",
100
auth_type=AuthType.BASIC,
101
)
102
remote_connection = RemoteConnection(custom_config.remote_server_addr, client_config=custom_config)
103
headers = remote_connection.client_config.get_auth_header()
104
assert headers.get("Authorization") == "Basic dXNlcjpwYXNz"
105
106
107
def test_get_auth_header_if_client_config_pass_bearer_token():
108
custom_config = ClientConfig(
109
remote_server_addr="http://localhost:4444", keep_alive=True, auth_type=AuthType.BEARER, token="dXNlcjpwYXNz"
110
)
111
remote_connection = RemoteConnection(custom_config.remote_server_addr, client_config=custom_config)
112
headers = remote_connection.client_config.get_auth_header()
113
assert headers.get("Authorization") == "Bearer dXNlcjpwYXNz"
114
115
116
def test_get_auth_header_if_client_config_pass_x_api_key():
117
custom_config = ClientConfig(
118
remote_server_addr="http://localhost:4444",
119
keep_alive=True,
120
auth_type=AuthType.X_API_KEY,
121
token="abcdefgh123456789",
122
)
123
remote_connection = RemoteConnection(custom_config.remote_server_addr, client_config=custom_config)
124
headers = remote_connection.client_config.get_auth_header()
125
assert headers.get("X-API-Key") == "abcdefgh123456789"
126
127
128
def test_get_proxy_url_https(mock_proxy_settings):
129
proxy = "http://https_proxy.com:8080"
130
remote_connection = RemoteConnection("https://remote", keep_alive=False)
131
proxy_url = remote_connection.client_config.get_proxy_url()
132
assert proxy_url == proxy
133
134
135
def test_get_proxy_url_https_via_client_config():
136
client_config = ClientConfig(
137
remote_server_addr="https://localhost:4444",
138
proxy=Proxy({"proxyType": ProxyType.MANUAL, "sslProxy": "https://admin:admin@http_proxy.com:8080"}),
139
)
140
remote_connection = RemoteConnection(client_config=client_config)
141
conn = remote_connection._get_connection_manager()
142
assert isinstance(conn, ProxyManager)
143
conn.proxy_url = "https://http_proxy.com:8080"
144
conn.connection_pool_kw["proxy_headers"] = make_headers(proxy_basic_auth="admin:admin")
145
146
147
def test_get_proxy_url_http_via_client_config():
148
client_config = ClientConfig(
149
remote_server_addr="http://localhost:4444",
150
proxy=Proxy(
151
{
152
"proxyType": ProxyType.MANUAL,
153
"httpProxy": "http://admin:admin@http_proxy.com:8080",
154
"sslProxy": "https://admin:admin@http_proxy.com:8080",
155
}
156
),
157
)
158
remote_connection = RemoteConnection(client_config=client_config)
159
conn = remote_connection._get_connection_manager()
160
assert isinstance(conn, ProxyManager)
161
conn.proxy_url = "http://http_proxy.com:8080"
162
conn.connection_pool_kw["proxy_headers"] = make_headers(proxy_basic_auth="admin:admin")
163
164
165
def test_get_proxy_direct_via_client_config():
166
client_config = ClientConfig(
167
remote_server_addr="http://localhost:4444", proxy=Proxy({"proxyType": ProxyType.DIRECT})
168
)
169
remote_connection = RemoteConnection(client_config=client_config)
170
conn = remote_connection._get_connection_manager()
171
assert isinstance(conn, PoolManager)
172
proxy_url = remote_connection.client_config.get_proxy_url()
173
assert proxy_url is None
174
175
176
def test_get_proxy_system_matches_no_proxy_via_client_config():
177
with patch.dict(
178
"os.environ", {"HTTP_PROXY": "http://admin:admin@system_proxy.com:8080", "NO_PROXY": "localhost,127.0.0.1"}
179
):
180
client_config = ClientConfig(
181
remote_server_addr="http://localhost:4444", proxy=Proxy({"proxyType": ProxyType.SYSTEM})
182
)
183
remote_connection = RemoteConnection(client_config=client_config)
184
conn = remote_connection._get_connection_manager()
185
assert isinstance(conn, PoolManager)
186
proxy_url = remote_connection.client_config.get_proxy_url()
187
assert proxy_url is None
188
189
190
def test_get_proxy_url_none(mock_proxy_settings_missing):
191
remote_connection = RemoteConnection("https://remote", keep_alive=False)
192
proxy_url = remote_connection.client_config.get_proxy_url()
193
assert proxy_url is None
194
195
196
def test_get_proxy_url_http_auth(mock_proxy_auth_settings):
197
remote_connection = RemoteConnection("http://remote", keep_alive=False)
198
proxy_url = remote_connection.client_config.get_proxy_url()
199
raw_proxy_url, basic_auth_string = remote_connection._separate_http_proxy_auth()
200
assert proxy_url == "http://user:password@http_proxy.com:8080"
201
assert raw_proxy_url == "http://http_proxy.com:8080"
202
assert basic_auth_string == "user:password"
203
204
205
def test_get_proxy_url_https_auth(mock_proxy_auth_settings):
206
remote_connection = RemoteConnection("https://remote", keep_alive=False)
207
proxy_url = remote_connection.client_config.get_proxy_url()
208
raw_proxy_url, basic_auth_string = remote_connection._separate_http_proxy_auth()
209
assert proxy_url == "https://user:password@https_proxy.com:8080"
210
assert raw_proxy_url == "https://https_proxy.com:8080"
211
assert basic_auth_string == "user:password"
212
213
214
def test_get_connection_manager_without_proxy(mock_proxy_settings_missing):
215
remote_connection = RemoteConnection("http://remote", keep_alive=False)
216
conn = remote_connection._get_connection_manager()
217
assert isinstance(conn, PoolManager)
218
219
220
def test_get_connection_manager_for_certs_and_timeout():
221
remote_connection = RemoteConnection("http://remote", keep_alive=False)
222
remote_connection.set_timeout(10)
223
assert remote_connection.get_timeout() == 10
224
conn = remote_connection._get_connection_manager()
225
assert conn.connection_pool_kw["timeout"] == 10
226
assert conn.connection_pool_kw["cert_reqs"] == "CERT_REQUIRED"
227
assert f"certifi{os.path.sep}cacert.pem" in conn.connection_pool_kw["ca_certs"]
228
229
230
def test_default_socket_timeout_is_correct():
231
remote_connection = RemoteConnection("http://remote", keep_alive=True)
232
conn = remote_connection._get_connection_manager()
233
assert conn.connection_pool_kw["timeout"] is None
234
235
236
def test_get_connection_manager_with_http_proxy(mock_proxy_settings):
237
remote_connection = RemoteConnection("http://remote", keep_alive=False)
238
conn = remote_connection._get_connection_manager()
239
assert isinstance(conn, ProxyManager)
240
assert conn.proxy.scheme == "http"
241
assert conn.proxy.host == "http_proxy.com"
242
assert conn.proxy.port == 8080
243
244
245
def test_get_connection_manager_with_https_proxy(mock_proxy_settings):
246
remote_connection_https = RemoteConnection("https://remote", keep_alive=False)
247
conn = remote_connection_https._get_connection_manager()
248
assert isinstance(conn, ProxyManager)
249
assert conn.proxy.scheme == "http"
250
assert conn.proxy.host == "https_proxy.com"
251
assert conn.proxy.port == 8080
252
253
254
def test_get_connection_manager_with_auth_http_proxy(mock_proxy_auth_settings):
255
proxy_auth_header = make_headers(proxy_basic_auth="user:password")
256
remote_connection = RemoteConnection("http://remote", keep_alive=False)
257
conn = remote_connection._get_connection_manager()
258
assert isinstance(conn, ProxyManager)
259
assert conn.proxy.scheme == "http"
260
assert conn.proxy.host == "http_proxy.com"
261
assert conn.proxy.port == 8080
262
assert conn.proxy_headers == proxy_auth_header
263
264
265
def test_get_connection_manager_with_auth_https_proxy(mock_proxy_auth_settings):
266
proxy_auth_header = make_headers(proxy_basic_auth="user:password")
267
remote_connection_https = RemoteConnection("https://remote", keep_alive=False)
268
conn = remote_connection_https._get_connection_manager()
269
assert isinstance(conn, ProxyManager)
270
assert conn.proxy.scheme == "https"
271
assert conn.proxy.host == "https_proxy.com"
272
assert conn.proxy.port == 8080
273
assert conn.proxy_headers == proxy_auth_header
274
275
276
@pytest.mark.parametrize(
277
"url",
278
[
279
"*",
280
".localhost",
281
"localhost:80",
282
"localhost",
283
"LOCALHOST",
284
"LOCALHOST:80",
285
"http://localhost",
286
"https://localhost",
287
"test.localhost",
288
" localhost",
289
"127.0.0.1",
290
"127.0.0.2",
291
"::1",
292
],
293
)
294
def test_get_connection_manager_when_no_proxy_set(mock_no_proxy_settings, url):
295
remote_connection = RemoteConnection(url)
296
conn = remote_connection._get_connection_manager()
297
assert isinstance(conn, PoolManager)
298
299
300
def test_ignore_proxy_env_vars(mock_proxy_settings):
301
remote_connection = RemoteConnection("http://remote", ignore_proxy=True)
302
conn = remote_connection._get_connection_manager()
303
assert isinstance(conn, PoolManager)
304
305
306
def test_get_socks_proxy_when_set(mock_socks_proxy_settings):
307
remote_connection = RemoteConnection("http://remote")
308
conn = remote_connection._get_connection_manager()
309
310
assert isinstance(conn, SOCKSProxyManager)
311
312
313
class MockResponse:
314
code = 200
315
headers = []
316
317
def read(self):
318
return b"{}"
319
320
def close(self):
321
pass
322
323
def getheader(self, *args, **kwargs):
324
pass
325
326
327
@pytest.fixture(scope="function")
328
def mock_proxy_settings_missing(monkeypatch):
329
monkeypatch.delenv("HTTPS_PROXY", raising=False)
330
monkeypatch.delenv("HTTP_PROXY", raising=False)
331
monkeypatch.delenv("https_proxy", raising=False)
332
monkeypatch.delenv("http_proxy", raising=False)
333
334
335
@pytest.fixture(scope="function")
336
def mock_socks_proxy_settings(monkeypatch):
337
http_proxy = "SOCKS5://http_proxy.com:8080"
338
https_proxy = "SOCKS5://https_proxy.com:8080"
339
monkeypatch.setenv("HTTPS_PROXY", https_proxy)
340
monkeypatch.setenv("HTTP_PROXY", http_proxy)
341
monkeypatch.setenv("https_proxy", https_proxy)
342
monkeypatch.setenv("http_proxy", http_proxy)
343
344
345
@pytest.fixture(scope="function")
346
def mock_proxy_settings(monkeypatch):
347
http_proxy = "http://http_proxy.com:8080"
348
https_proxy = "http://https_proxy.com:8080"
349
monkeypatch.setenv("HTTPS_PROXY", https_proxy)
350
monkeypatch.setenv("HTTP_PROXY", http_proxy)
351
monkeypatch.setenv("https_proxy", https_proxy)
352
monkeypatch.setenv("http_proxy", http_proxy)
353
354
355
@pytest.fixture(scope="function")
356
def mock_proxy_auth_settings(monkeypatch):
357
http_proxy = "http://user:password@http_proxy.com:8080"
358
https_proxy = "https://user:password@https_proxy.com:8080"
359
monkeypatch.setenv("HTTPS_PROXY", https_proxy)
360
monkeypatch.setenv("HTTP_PROXY", http_proxy)
361
monkeypatch.setenv("https_proxy", https_proxy)
362
monkeypatch.setenv("http_proxy", http_proxy)
363
364
365
@pytest.fixture(scope="function")
366
def mock_no_proxy_settings(monkeypatch):
367
http_proxy = "http://http_proxy.com:8080"
368
https_proxy = "http://https_proxy.com:8080"
369
monkeypatch.setenv("HTTPS_PROXY", https_proxy)
370
monkeypatch.setenv("HTTP_PROXY", http_proxy)
371
monkeypatch.setenv("https_proxy", https_proxy)
372
monkeypatch.setenv("http_proxy", http_proxy)
373
monkeypatch.setenv("no_proxy", "65.253.214.253,localhost,127.0.0.1,*zyz.xx,::1")
374
monkeypatch.setenv("NO_PROXY", "65.253.214.253,localhost,127.0.0.1,*zyz.xx,::1,127.0.0.0/8")
375
376
377
@patch("selenium.webdriver.remote.remote_connection.RemoteConnection.get_remote_connection_headers")
378
def test_override_user_agent_in_headers(mock_get_remote_connection_headers, remote_connection):
379
RemoteConnection.user_agent = "custom-agent/1.0 (python 3.13)"
380
381
mock_get_remote_connection_headers.return_value = {
382
"Accept": "application/json",
383
"Content-Type": "application/json;charset=UTF-8",
384
"User-Agent": "custom-agent/1.0 (python 3.13)",
385
}
386
387
headers = RemoteConnection.get_remote_connection_headers(parse.urlparse("http://remote"))
388
389
assert headers.get("User-Agent") == "custom-agent/1.0 (python 3.13)"
390
assert headers.get("Accept") == "application/json"
391
assert headers.get("Content-Type") == "application/json;charset=UTF-8"
392
393
394
@patch("selenium.webdriver.remote.remote_connection.RemoteConnection.get_remote_connection_headers")
395
def test_override_user_agent_via_client_config(mock_get_remote_connection_headers):
396
client_config = ClientConfig(
397
remote_server_addr="http://localhost:4444",
398
user_agent="custom-agent/1.0 (python 3.13)",
399
extra_headers={"Content-Type": "application/xml;charset=UTF-8"},
400
)
401
remote_connection = RemoteConnection(client_config=client_config)
402
403
mock_get_remote_connection_headers.return_value = {
404
"Accept": "application/json",
405
"Content-Type": "application/xml;charset=UTF-8",
406
"User-Agent": "custom-agent/1.0 (python 3.13)",
407
}
408
409
headers = remote_connection.get_remote_connection_headers(parse.urlparse("http://localhost:4444"))
410
411
assert headers.get("User-Agent") == "custom-agent/1.0 (python 3.13)"
412
assert headers.get("Accept") == "application/json"
413
assert headers.get("Content-Type") == "application/xml;charset=UTF-8"
414
415
416
@patch("selenium.webdriver.remote.remote_connection.RemoteConnection._request")
417
def test_register_extra_headers(mock_request, remote_connection):
418
RemoteConnection.extra_headers = {"Foo": "bar"}
419
420
mock_request.return_value = {"status": 200, "value": "OK"}
421
remote_connection.execute("newSession", {})
422
423
mock_request.assert_called_once_with("POST", "http://localhost:4444/session", body="{}")
424
headers = RemoteConnection.get_remote_connection_headers(parse.urlparse("http://localhost:4444"), False)
425
assert headers["Foo"] == "bar"
426
427
428
@patch("selenium.webdriver.remote.remote_connection.RemoteConnection._request")
429
def test_register_extra_headers_via_client_config(mock_request):
430
client_config = ClientConfig(
431
remote_server_addr="http://localhost:4444",
432
extra_headers={
433
"Authorization": "AWS4-HMAC-SHA256",
434
"Credential": "abc/20200618/us-east-1/execute-api/aws4_request",
435
},
436
)
437
remote_connection = RemoteConnection(client_config=client_config)
438
439
mock_request.return_value = {"status": 200, "value": "OK"}
440
remote_connection.execute("newSession", {})
441
442
mock_request.assert_called_once_with("POST", "http://localhost:4444/session", body="{}")
443
headers = remote_connection.get_remote_connection_headers(parse.urlparse("http://localhost:4444"), False)
444
assert headers["Authorization"] == "AWS4-HMAC-SHA256"
445
assert headers["Credential"] == "abc/20200618/us-east-1/execute-api/aws4_request"
446
447
448
def test_backwards_compatibility_with_appium_connection():
449
# Keep backward compatibility for AppiumConnection - https://github.com/SeleniumHQ/selenium/issues/14694
450
client_config = ClientConfig(
451
remote_server_addr="http://localhost:4444", ca_certs="/path/to/cacert.pem", timeout=300
452
)
453
remote_connection = RemoteConnection(client_config=client_config)
454
assert remote_connection._ca_certs == "/path/to/cacert.pem"
455
assert remote_connection._timeout == 300
456
assert remote_connection._client_config == client_config
457
remote_connection.set_timeout(120)
458
assert remote_connection.get_timeout() == 120
459
remote_connection.set_certificate_bundle_path("/path/to/cacert2.pem")
460
assert remote_connection.get_certificate_bundle_path() == "/path/to/cacert2.pem"
461
462
463
def test_get_connection_manager_with_timeout_from_client_config():
464
remote_connection = RemoteConnection(remote_server_addr="http://localhost:4444", keep_alive=False)
465
remote_connection.set_timeout(10)
466
conn = remote_connection._get_connection_manager()
467
assert remote_connection.get_timeout() == 10
468
assert conn.connection_pool_kw["timeout"] == 10
469
assert isinstance(conn, PoolManager)
470
471
472
def test_connection_manager_with_timeout_via_client_config():
473
client_config = ClientConfig("http://remote", timeout=300)
474
remote_connection = RemoteConnection(client_config=client_config)
475
conn = remote_connection._get_connection_manager()
476
assert conn.connection_pool_kw["timeout"] == 300
477
assert isinstance(conn, PoolManager)
478
479
480
def test_get_connection_manager_with_ca_certs():
481
remote_connection = RemoteConnection(remote_server_addr="http://localhost:4444")
482
remote_connection.set_certificate_bundle_path("/path/to/cacert.pem")
483
conn = remote_connection._get_connection_manager()
484
assert conn.connection_pool_kw["timeout"] is None
485
assert conn.connection_pool_kw["cert_reqs"] == "CERT_REQUIRED"
486
assert conn.connection_pool_kw["ca_certs"] == "/path/to/cacert.pem"
487
assert isinstance(conn, PoolManager)
488
489
490
def test_connection_manager_with_ca_certs_via_client_config():
491
client_config = ClientConfig(remote_server_addr="http://localhost:4444", ca_certs="/path/to/cacert.pem")
492
remote_connection = RemoteConnection(client_config=client_config)
493
conn = remote_connection._get_connection_manager()
494
assert conn.connection_pool_kw["timeout"] is None
495
assert conn.connection_pool_kw["cert_reqs"] == "CERT_REQUIRED"
496
assert conn.connection_pool_kw["ca_certs"] == "/path/to/cacert.pem"
497
assert isinstance(conn, PoolManager)
498
499
500
def test_get_connection_manager_ignores_certificates():
501
remote_connection = RemoteConnection(
502
remote_server_addr="http://localhost:4444", keep_alive=False, ignore_certificates=True
503
)
504
remote_connection.set_timeout(10)
505
conn = remote_connection._get_connection_manager()
506
assert conn.connection_pool_kw["timeout"] == 10
507
assert conn.connection_pool_kw["cert_reqs"] == "CERT_NONE"
508
assert isinstance(conn, PoolManager)
509
remote_connection.reset_timeout()
510
assert remote_connection.get_timeout() is None
511
512
513
def test_connection_manager_ignores_certificates_via_client_config():
514
client_config = ClientConfig(remote_server_addr="http://localhost:4444", ignore_certificates=True, timeout=10)
515
remote_connection = RemoteConnection(client_config=client_config)
516
conn = remote_connection._get_connection_manager()
517
assert isinstance(conn, PoolManager)
518
assert conn.connection_pool_kw["timeout"] == 10
519
assert conn.connection_pool_kw["cert_reqs"] == "CERT_NONE"
520
521
522
def test_get_connection_manager_with_custom_args():
523
custom_args = {"init_args_for_pool_manager": {"retries": 3, "block": True}}
524
525
remote_connection = RemoteConnection(
526
remote_server_addr="http://localhost:4444", keep_alive=False, init_args_for_pool_manager=custom_args
527
)
528
conn = remote_connection._get_connection_manager()
529
assert isinstance(conn, PoolManager)
530
assert isinstance(conn.connection_pool_kw["retries"], Retry)
531
assert conn.connection_pool_kw["retries"].total == 3
532
assert conn.connection_pool_kw["block"] is True
533
assert conn.connection_pool_kw["timeout"] is None
534
535
536
def test_connection_manager_with_custom_args_via_client_config():
537
retries = Retry(connect=2, read=2, redirect=2)
538
timeout = Timeout(connect=300, read=3600)
539
client_config = ClientConfig(
540
remote_server_addr="http://localhost:4444",
541
init_args_for_pool_manager={"init_args_for_pool_manager": {"retries": retries, "timeout": timeout}},
542
)
543
remote_connection = RemoteConnection(client_config=client_config)
544
conn = remote_connection._get_connection_manager()
545
assert isinstance(conn, PoolManager)
546
assert conn.connection_pool_kw["retries"] == retries
547
assert conn.connection_pool_kw["timeout"] == timeout
548
549
550
def test_proxy_auth_with_special_characters_url_encoded():
551
proxy_url = "http://user:passw%[email protected]:8080"
552
client_config = ClientConfig(
553
remote_server_addr="http://localhost:4444",
554
keep_alive=False,
555
proxy=Proxy({"proxyType": ProxyType.MANUAL, "httpProxy": proxy_url}),
556
)
557
remote_connection = RemoteConnection(client_config=client_config)
558
559
proxy_without_auth, basic_auth = remote_connection._separate_http_proxy_auth()
560
561
assert proxy_without_auth == "http://proxy.example.com:8080"
562
assert basic_auth == "user:passw%23rd" # Still URL-encoded
563
564
conn = remote_connection._get_connection_manager()
565
assert isinstance(conn, ProxyManager)
566
567
expected_auth = base64.b64encode("user:passw#rd".encode()).decode() # Decoded password
568
expected_headers = make_headers(proxy_basic_auth="user:passw#rd") # Unquoted password
569
570
assert conn.proxy_headers == expected_headers
571
assert conn.proxy_headers["proxy-authorization"] == f"Basic {expected_auth}"
572
573
574
def test_proxy_auth_with_multiple_special_characters():
575
test_cases = [
576
("passw%23rd", "passw#rd"), # # character
577
("passw%40rd", "passw@rd"), # @ character
578
("passw%26rd", "passw&rd"), # & character
579
("passw%3Drd", "passw=rd"), # = character
580
("passw%2Brd", "passw+rd"), # + character
581
("passw%20rd", "passw rd"), # space character
582
("passw%21%40%23%24", "passw!@#$"), # Multiple special chars
583
]
584
585
for encoded_password, decoded_password in test_cases:
586
proxy_url = f"http://testuser:{encoded_password}@proxy.example.com:8080"
587
client_config = ClientConfig(
588
remote_server_addr="http://localhost:4444",
589
keep_alive=False,
590
proxy=Proxy({"proxyType": ProxyType.MANUAL, "httpProxy": proxy_url}),
591
)
592
remote_connection = RemoteConnection(client_config=client_config)
593
594
proxy_without_auth, basic_auth = remote_connection._separate_http_proxy_auth()
595
assert basic_auth == f"testuser:{encoded_password}"
596
597
conn = remote_connection._get_connection_manager()
598
expected_auth = base64.b64encode(f"testuser:{decoded_password}".encode()).decode()
599
expected_headers = make_headers(proxy_basic_auth=f"testuser:{decoded_password}")
600
601
assert conn.proxy_headers == expected_headers
602
assert conn.proxy_headers["proxy-authorization"] == f"Basic {expected_auth}"
603
604