@@ -4855,12 +4855,16 @@ class TestPreHandshakeClose(unittest.TestCase):
48554855
48564856 class SingleConnectionTestServerThread (threading .Thread ):
48574857
4858- def __init__ (self , * , name , call_after_accept ):
4858+ def __init__ (self , * , name , call_after_accept , timeout = None ):
48594859 self .call_after_accept = call_after_accept
48604860 self .received_data = b'' # set by .run()
48614861 self .wrap_error = None # set by .run()
48624862 self .listener = None # set by .start()
48634863 self .port = None # set by .start()
4864+ if timeout is None :
4865+ self .timeout = support .SHORT_TIMEOUT
4866+ else :
4867+ self .timeout = timeout
48644868 super ().__init__ (name = name )
48654869
48664870 def __enter__ (self ):
@@ -4883,13 +4887,19 @@ def start(self):
48834887 self .ssl_ctx .load_cert_chain (certfile = ONLYCERT , keyfile = ONLYKEY )
48844888 self .listener = socket .socket ()
48854889 self .port = socket_helper .bind_port (self .listener )
4886- self .listener .settimeout (2.0 )
4890+ self .listener .settimeout (self . timeout )
48874891 self .listener .listen (1 )
48884892 super ().start ()
48894893
48904894 def run (self ):
4891- conn , address = self .listener .accept ()
4892- self .listener .close ()
4895+ try :
4896+ conn , address = self .listener .accept ()
4897+ except TimeoutError :
4898+ # on timeout, just close the listener
4899+ return
4900+ finally :
4901+ self .listener .close ()
4902+
48934903 with conn :
48944904 if self .call_after_accept (conn ):
48954905 return
@@ -4917,8 +4927,13 @@ def non_linux_skip_if_other_okay_error(self, err):
49174927 # we're specifically trying to test. The way this test is written
49184928 # is known to work on Linux. We'll skip it anywhere else that it
49194929 # does not present as doing so.
4920- self .skipTest (f"Could not recreate conditions on { sys .platform } :"
4921- f" { err = } " )
4930+ try :
4931+ self .skipTest (f"Could not recreate conditions on { sys .platform } :"
4932+ f" { err = } " )
4933+ finally :
4934+ # gh-108342: Explicitly break the reference cycle
4935+ err = None
4936+
49224937 # If maintaining this conditional winds up being a problem.
49234938 # just turn this into an unconditional skip anything but Linux.
49244939 # The important thing is that our CI has the logic covered.
@@ -4929,7 +4944,7 @@ def test_preauth_data_to_tls_server(self):
49294944
49304945 def call_after_accept (unused ):
49314946 server_accept_called .set ()
4932- if not ready_for_server_wrap_socket .wait (2.0 ):
4947+ if not ready_for_server_wrap_socket .wait (support . SHORT_TIMEOUT ):
49334948 raise RuntimeError ("wrap_socket event never set, test may fail." )
49344949 return False # Tell the server thread to continue.
49354950
@@ -4951,20 +4966,31 @@ def call_after_accept(unused):
49514966
49524967 ready_for_server_wrap_socket .set ()
49534968 server .join ()
4969+
49544970 wrap_error = server .wrap_error
4955- self .assertEqual (b"" , server .received_data )
4956- self .assertIsInstance (wrap_error , OSError ) # All platforms.
4957- self .non_linux_skip_if_other_okay_error (wrap_error )
4958- self .assertIsInstance (wrap_error , ssl .SSLError )
4959- self .assertIn ("before TLS handshake with data" , wrap_error .args [1 ])
4960- self .assertIn ("before TLS handshake with data" , wrap_error .reason )
4961- self .assertNotEqual (0 , wrap_error .args [0 ])
4962- self .assertIsNone (wrap_error .library , msg = "attr must exist" )
4971+ server .wrap_error = None
4972+ try :
4973+ self .assertEqual (b"" , server .received_data )
4974+ self .assertIsInstance (wrap_error , OSError ) # All platforms.
4975+ self .non_linux_skip_if_other_okay_error (wrap_error )
4976+ self .assertIsInstance (wrap_error , ssl .SSLError )
4977+ self .assertIn ("before TLS handshake with data" , wrap_error .args [1 ])
4978+ self .assertIn ("before TLS handshake with data" , wrap_error .reason )
4979+ self .assertNotEqual (0 , wrap_error .args [0 ])
4980+ self .assertIsNone (wrap_error .library , msg = "attr must exist" )
4981+ finally :
4982+ # gh-108342: Explicitly break the reference cycle
4983+ wrap_error = None
4984+ server = None
49634985
49644986 def test_preauth_data_to_tls_client (self ):
4987+ server_can_continue_with_wrap_socket = threading .Event ()
49654988 client_can_continue_with_wrap_socket = threading .Event ()
49664989
49674990 def call_after_accept (conn_to_client ):
4991+ if not server_can_continue_with_wrap_socket .wait (support .SHORT_TIMEOUT ):
4992+ print ("ERROR: test client took too long" )
4993+
49684994 # This forces an immediate connection close via RST on .close().
49694995 set_socket_so_linger_on_with_zero_timeout (conn_to_client )
49704996 conn_to_client .send (
@@ -4986,8 +5012,10 @@ def call_after_accept(conn_to_client):
49865012
49875013 with socket .socket () as client :
49885014 client .connect (server .listener .getsockname ())
4989- if not client_can_continue_with_wrap_socket .wait (2.0 ):
4990- self .fail ("test server took too long." )
5015+ server_can_continue_with_wrap_socket .set ()
5016+
5017+ if not client_can_continue_with_wrap_socket .wait (support .SHORT_TIMEOUT ):
5018+ self .fail ("test server took too long" )
49915019 ssl_ctx = ssl .create_default_context ()
49925020 try :
49935021 tls_client = ssl_ctx .wrap_socket (
@@ -5001,24 +5029,31 @@ def call_after_accept(conn_to_client):
50015029 tls_client .close ()
50025030
50035031 server .join ()
5004- self .assertEqual (b"" , received_data )
5005- self .assertIsInstance (wrap_error , OSError ) # All platforms.
5006- self .non_linux_skip_if_other_okay_error (wrap_error )
5007- self .assertIsInstance (wrap_error , ssl .SSLError )
5008- self .assertIn ("before TLS handshake with data" , wrap_error .args [1 ])
5009- self .assertIn ("before TLS handshake with data" , wrap_error .reason )
5010- self .assertNotEqual (0 , wrap_error .args [0 ])
5011- self .assertIsNone (wrap_error .library , msg = "attr must exist" )
5032+ try :
5033+ self .assertEqual (b"" , received_data )
5034+ self .assertIsInstance (wrap_error , OSError ) # All platforms.
5035+ self .non_linux_skip_if_other_okay_error (wrap_error )
5036+ self .assertIsInstance (wrap_error , ssl .SSLError )
5037+ self .assertIn ("before TLS handshake with data" , wrap_error .args [1 ])
5038+ self .assertIn ("before TLS handshake with data" , wrap_error .reason )
5039+ self .assertNotEqual (0 , wrap_error .args [0 ])
5040+ self .assertIsNone (wrap_error .library , msg = "attr must exist" )
5041+ finally :
5042+ # gh-108342: Explicitly break the reference cycle
5043+ wrap_error = None
5044+ server = None
50125045
50135046 def test_https_client_non_tls_response_ignored (self ):
5014-
50155047 server_responding = threading .Event ()
50165048
50175049 class SynchronizedHTTPSConnection (http .client .HTTPSConnection ):
50185050 def connect (self ):
5051+ # Call clear text HTTP connect(), not the encrypted HTTPS (TLS)
5052+ # connect(): wrap_socket() is called manually below.
50195053 http .client .HTTPConnection .connect (self )
5054+
50205055 # Wait for our fault injection server to have done its thing.
5021- if not server_responding .wait (1.0 ) and support .verbose :
5056+ if not server_responding .wait (support . SHORT_TIMEOUT ) and support .verbose :
50225057 sys .stdout .write ("server_responding event never set." )
50235058 self .sock = self ._context .wrap_socket (
50245059 self .sock , server_hostname = self .host )
@@ -5033,29 +5068,34 @@ def call_after_accept(conn_to_client):
50335068 server_responding .set ()
50345069 return True # Tell the server to stop.
50355070
5071+ timeout = 2.0
50365072 server = self .SingleConnectionTestServerThread (
50375073 call_after_accept = call_after_accept ,
5038- name = "non_tls_http_RST_responder" )
5074+ name = "non_tls_http_RST_responder" ,
5075+ timeout = timeout )
50395076 server .__enter__ () # starts it
50405077 self .addCleanup (server .__exit__ ) # ... & unittest.TestCase stops it.
50415078 # Redundant; call_after_accept sets SO_LINGER on the accepted conn.
50425079 set_socket_so_linger_on_with_zero_timeout (server .listener )
50435080
50445081 connection = SynchronizedHTTPSConnection (
5045- f"localhost" ,
5082+ server . listener . getsockname ()[ 0 ] ,
50465083 port = server .port ,
50475084 context = ssl .create_default_context (),
5048- timeout = 2.0 ,
5085+ timeout = timeout ,
50495086 )
5087+
50505088 # There are lots of reasons this raises as desired, long before this
50515089 # test was added. Sending the request requires a successful TLS wrapped
50525090 # socket; that fails if the connection is broken. It may seem pointless
50535091 # to test this. It serves as an illustration of something that we never
50545092 # want to happen... properly not happening.
5055- with self .assertRaises (OSError ) as err_ctx :
5093+ with self .assertRaises (OSError ):
50565094 connection .request ("HEAD" , "/test" , headers = {"Host" : "localhost" })
50575095 response = connection .getresponse ()
50585096
5097+ server .join ()
5098+
50595099
50605100def setUpModule ():
50615101 if support .verbose :
0 commit comments