15
15
from ..http11 import USER_AGENT , Response
16
16
from ..protocol import CONNECTING , Event
17
17
from ..typing import LoggerLike , Origin , Subprotocol
18
- from ..uri import Proxy , get_proxy , parse_proxy , parse_uri
18
+ from ..uri import Proxy , WebSocketURI , get_proxy , parse_proxy , parse_uri
19
19
from .connection import Connection
20
20
from .utils import Deadline
21
21
@@ -258,15 +258,12 @@ def connect(
258
258
elif compression is not None :
259
259
raise ValueError (f"unsupported compression: { compression } " )
260
260
261
- proxy_uri : Proxy | None = None
262
261
if unix :
263
262
proxy = None
264
263
if sock is not None :
265
264
proxy = None
266
265
if proxy is True :
267
266
proxy = get_proxy (ws_uri )
268
- if proxy is not None :
269
- proxy_uri = parse_proxy (proxy )
270
267
271
268
# Calculate timeouts on the TCP, TLS, and WebSocket handshakes.
272
269
# The TCP and TLS timeouts must be set on the socket, then removed
@@ -285,54 +282,19 @@ def connect(
285
282
sock .settimeout (deadline .timeout ())
286
283
assert path is not None # mypy cannot figure this out
287
284
sock .connect (path )
285
+ elif proxy is not None :
286
+ sock = connect_proxy (
287
+ parse_proxy (proxy ),
288
+ ws_uri ,
289
+ deadline ,
290
+ ** kwargs ,
291
+ )
288
292
else :
289
- if proxy_uri is not None :
290
- if proxy_uri .scheme [:5 ] == "socks" :
291
- try :
292
- from python_socks import ProxyType
293
- from python_socks .sync import Proxy
294
- except ImportError :
295
- raise ImportError (
296
- "python-socks is required to use a SOCKS proxy"
297
- )
298
- if proxy_uri .scheme == "socks5h" :
299
- proxy_type = ProxyType .SOCKS5
300
- rdns = True
301
- elif proxy_uri .scheme == "socks5" :
302
- proxy_type = ProxyType .SOCKS5
303
- rdns = False
304
- # We use mitmproxy for testing and it doesn't support SOCKS4.
305
- elif proxy_uri .scheme == "socks4a" : # pragma: no cover
306
- proxy_type = ProxyType .SOCKS4
307
- rdns = True
308
- elif proxy_uri .scheme == "socks4" : # pragma: no cover
309
- proxy_type = ProxyType .SOCKS4
310
- rdns = False
311
- # Proxy types are enforced in parse_proxy().
312
- else :
313
- raise AssertionError ("unsupported SOCKS proxy" )
314
- socks_proxy = Proxy (
315
- proxy_type ,
316
- proxy_uri .host ,
317
- proxy_uri .port ,
318
- proxy_uri .username ,
319
- proxy_uri .password ,
320
- rdns ,
321
- )
322
- sock = socks_proxy .connect (
323
- ws_uri .host ,
324
- ws_uri .port ,
325
- timeout = deadline .timeout (),
326
- local_addr = kwargs .pop ("local_addr" , None ),
327
- )
328
- # Proxy types are enforced in parse_proxy().
329
- else :
330
- raise AssertionError ("unsupported proxy" )
331
- else :
332
- kwargs .setdefault ("timeout" , deadline .timeout ())
333
- sock = socket .create_connection (
334
- (ws_uri .host , ws_uri .port ), ** kwargs
335
- )
293
+ kwargs .setdefault ("timeout" , deadline .timeout ())
294
+ sock = socket .create_connection (
295
+ (ws_uri .host , ws_uri .port ),
296
+ ** kwargs ,
297
+ )
336
298
sock .settimeout (None )
337
299
338
300
# Disable Nagle algorithm
@@ -420,3 +382,64 @@ def unix_connect(
420
382
else :
421
383
uri = "wss://localhost/"
422
384
return connect (uri = uri , unix = True , path = path , ** kwargs )
385
+
386
+
387
+ try :
388
+ from python_socks import ProxyType
389
+ from python_socks .sync import Proxy as SocksProxy
390
+
391
+ SOCKS_PROXY_TYPES = {
392
+ "socks5h" : ProxyType .SOCKS5 ,
393
+ "socks5" : ProxyType .SOCKS5 ,
394
+ "socks4a" : ProxyType .SOCKS4 ,
395
+ "socks4" : ProxyType .SOCKS4 ,
396
+ }
397
+
398
+ SOCKS_PROXY_RDNS = {
399
+ "socks5h" : True ,
400
+ "socks5" : False ,
401
+ "socks4a" : True ,
402
+ "socks4" : False ,
403
+ }
404
+
405
+ def connect_socks_proxy (
406
+ proxy : Proxy ,
407
+ ws_uri : WebSocketURI ,
408
+ deadline : Deadline ,
409
+ ** kwargs : Any ,
410
+ ) -> socket .socket :
411
+ """Connect via a SOCKS proxy and return the socket."""
412
+ socks_proxy = SocksProxy (
413
+ SOCKS_PROXY_TYPES [proxy .scheme ],
414
+ proxy .host ,
415
+ proxy .port ,
416
+ proxy .username ,
417
+ proxy .password ,
418
+ SOCKS_PROXY_RDNS [proxy .scheme ],
419
+ )
420
+ kwargs .setdefault ("timeout" , deadline .timeout ())
421
+ return socks_proxy .connect (ws_uri .host , ws_uri .port , ** kwargs )
422
+
423
+ except ImportError :
424
+
425
+ def connect_socks_proxy (
426
+ proxy : Proxy ,
427
+ ws_uri : WebSocketURI ,
428
+ deadline : Deadline ,
429
+ ** kwargs : Any ,
430
+ ) -> socket .socket :
431
+ raise ImportError ("python-socks is required to use a SOCKS proxy" )
432
+
433
+
434
+ def connect_proxy (
435
+ proxy : Proxy ,
436
+ ws_uri : WebSocketURI ,
437
+ deadline : Deadline ,
438
+ ** kwargs : Any ,
439
+ ) -> socket .socket :
440
+ """Connect via a proxy and return the socket."""
441
+ # parse_proxy() validates proxy.scheme.
442
+ if proxy .scheme [:5 ] == "socks" :
443
+ return connect_socks_proxy (proxy , ws_uri , deadline , ** kwargs )
444
+ else :
445
+ raise AssertionError ("unsupported proxy" )
0 commit comments