1717 InvalidProxy ,
1818 InvalidStatus ,
1919 InvalidURI ,
20+ ProxyError ,
2021 SecurityError ,
2122)
2223from websockets .extensions .permessage_deflate import PerMessageDeflate
@@ -379,24 +380,16 @@ def remove_accept_header(self, request, response):
379380
380381 async def test_timeout_during_handshake (self ):
381382 """Client times out before receiving handshake response from server."""
382- gate = asyncio .get_running_loop ().create_future ()
383-
384- async def stall_connection (self , request ):
385- await gate
386-
387- # The connection will be open for the server but failed for the client.
388- # Use a connection handler that exits immediately to avoid an exception.
389- async with serve (* args , process_request = stall_connection ) as server :
390- try :
391- with self .assertRaises (TimeoutError ) as raised :
392- async with connect (get_uri (server ) + "/no-op" , open_timeout = 2 * MS ):
393- self .fail ("did not raise" )
394- self .assertEqual (
395- str (raised .exception ),
396- "timed out during handshake" ,
397- )
398- finally :
399- gate .set_result (None )
383+ # Replace the WebSocket server with a TCP server that does't respond.
384+ with socket .create_server (("localhost" , 0 )) as sock :
385+ host , port = sock .getsockname ()
386+ with self .assertRaises (TimeoutError ) as raised :
387+ async with connect (f"ws://{ host } :{ port } " , open_timeout = MS ):
388+ self .fail ("did not raise" )
389+ self .assertEqual (
390+ str (raised .exception ),
391+ "timed out during handshake" ,
392+ )
400393
401394 async def test_connection_closed_during_handshake (self ):
402395 """Client reads EOF before receiving handshake response from server."""
@@ -570,11 +563,13 @@ class ProxyClientTests(unittest.IsolatedAsyncioTestCase):
570563 async def socks_proxy (self , auth = None ):
571564 if auth :
572565 proxyauth = "hello:iloveyou"
573- proxy_uri = "http://hello:iloveyou@localhost:1080 "
566+ proxy_uri = "http://hello:iloveyou@localhost:51080 "
574567 else :
575568 proxyauth = None
576- proxy_uri = "http://localhost:1080"
577- async with async_proxy (mode = ["socks5" ], proxyauth = proxyauth ) as record_flows :
569+ proxy_uri = "http://localhost:51080"
570+ async with async_proxy (
571+ mode = ["socks5@51080" ], proxyauth = proxyauth
572+ ) as record_flows :
578573 with patch_environ ({"socks_proxy" : proxy_uri }):
579574 yield record_flows
580575
@@ -602,14 +597,62 @@ async def test_authenticated_socks_proxy(self):
602597 self .assertEqual (client .protocol .state .name , "OPEN" )
603598 self .assertEqual (len (proxy .get_flows ()), 1 )
604599
600+ async def test_socks_proxy_connection_error (self ):
601+ """Client receives an error when connecting to the SOCKS5 proxy."""
602+ from python_socks import ProxyError as SocksProxyError
603+
604+ async with self .socks_proxy (auth = True ) as proxy :
605+ with self .assertRaises (ProxyError ) as raised :
606+ async with connect (
607+ "ws://example.com/" ,
608+ proxy = "socks5h://localhost:51080" , # remove credentials
609+ ):
610+ self .fail ("did not raise" )
611+ self .assertEqual (
612+ str (raised .exception ),
613+ "failed to connect to SOCKS proxy" ,
614+ )
615+ self .assertIsInstance (raised .exception .__cause__ , SocksProxyError )
616+ self .assertEqual (len (proxy .get_flows ()), 0 )
617+
618+ async def test_socks_proxy_connection_fails (self ):
619+ """Client fails to connect to the SOCKS5 proxy."""
620+ from python_socks import ProxyConnectionError as SocksProxyConnectionError
621+
622+ with self .assertRaises (OSError ) as raised :
623+ async with connect (
624+ "ws://example.com/" ,
625+ proxy = "socks5h://localhost:51080" , # nothing at this address
626+ ):
627+ self .fail ("did not raise" )
628+ # Don't test str(raised.exception) because we don't control it.
629+ self .assertIsInstance (raised .exception , SocksProxyConnectionError )
630+
631+ async def test_socks_proxy_connection_timeout (self ):
632+ """Client times out while connecting to the SOCKS5 proxy."""
633+ # Replace the proxy with a TCP server that does't respond.
634+ with socket .create_server (("localhost" , 0 )) as sock :
635+ host , port = sock .getsockname ()
636+ with self .assertRaises (TimeoutError ) as raised :
637+ async with connect (
638+ "ws://example.com/" ,
639+ proxy = f"socks5h://{ host } :{ port } /" ,
640+ open_timeout = MS ,
641+ ):
642+ self .fail ("did not raise" )
643+ self .assertEqual (
644+ str (raised .exception ),
645+ "timed out during handshake" ,
646+ )
647+
605648 async def test_explicit_proxy (self ):
606649 """Client connects to server through a proxy set explicitly."""
607- async with async_proxy (mode = ["socks5" ]) as proxy :
650+ async with async_proxy (mode = ["socks5@51080 " ]) as proxy :
608651 async with serve (* args ) as server :
609652 async with connect (
610653 get_uri (server ),
611654 # Take this opportunity to test socks5 instead of socks5h.
612- proxy = "socks5://localhost:1080 " ,
655+ proxy = "socks5://localhost:51080 " ,
613656 ) as client :
614657 self .assertEqual (client .protocol .state .name , "OPEN" )
615658 self .assertEqual (len (proxy .get_flows ()), 1 )
@@ -626,13 +669,13 @@ async def test_ignore_proxy_with_existing_socket(self):
626669
627670 async def test_unsupported_proxy (self ):
628671 """Client connects to server through an unsupported proxy."""
629- with patch_environ ({"ws_proxy" : "other://localhost:1080 " }):
672+ with patch_environ ({"ws_proxy" : "other://localhost:51080 " }):
630673 with self .assertRaises (InvalidProxy ) as raised :
631674 async with connect ("ws://example.com/" ):
632675 self .fail ("did not raise" )
633676 self .assertEqual (
634677 str (raised .exception ),
635- "other://localhost:1080 isn't a valid proxy: scheme other isn't supported" ,
678+ "other://localhost:51080 isn't a valid proxy: scheme other isn't supported" ,
636679 )
637680
638681
0 commit comments