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