@@ -4828,12 +4828,16 @@ class TestPreHandshakeClose(unittest.TestCase):
48284828
48294829 class SingleConnectionTestServerThread (threading .Thread ):
48304830
4831- def __init__ (self , * , name , call_after_accept ):
4831+ def __init__ (self , * , name , call_after_accept , timeout = None ):
48324832 self .call_after_accept = call_after_accept
48334833 self .received_data = b'' # set by .run()
48344834 self .wrap_error = None # set by .run()
48354835 self .listener = None # set by .start()
48364836 self .port = None # set by .start()
4837+ if timeout is None :
4838+ self .timeout = support .SHORT_TIMEOUT
4839+ else :
4840+ self .timeout = timeout
48374841 super ().__init__ (name = name )
48384842
48394843 def __enter__ (self ):
@@ -4856,13 +4860,19 @@ def start(self):
48564860 self .ssl_ctx .load_cert_chain (certfile = ONLYCERT , keyfile = ONLYKEY )
48574861 self .listener = socket .socket ()
48584862 self .port = support .bind_port (self .listener )
4859- self .listener .settimeout (2.0 )
4863+ self .listener .settimeout (self . timeout )
48604864 self .listener .listen (1 )
48614865 super ().start ()
48624866
48634867 def run (self ):
4864- conn , address = self .listener .accept ()
4865- self .listener .close ()
4868+ try :
4869+ conn , address = self .listener .accept ()
4870+ except TimeoutError :
4871+ # on timeout, just close the listener
4872+ return
4873+ finally :
4874+ self .listener .close ()
4875+
48664876 with conn :
48674877 if self .call_after_accept (conn ):
48684878 return
@@ -4890,8 +4900,13 @@ def non_linux_skip_if_other_okay_error(self, err):
48904900 # we're specifically trying to test. The way this test is written
48914901 # is known to work on Linux. We'll skip it anywhere else that it
48924902 # does not present as doing so.
4893- self .skipTest (f"Could not recreate conditions on { sys .platform } :"
4894- f" { err = } " )
4903+ try :
4904+ self .skipTest (f"Could not recreate conditions on { sys .platform } :"
4905+ f" { err = } " )
4906+ finally :
4907+ # gh-108342: Explicitly break the reference cycle
4908+ err = None
4909+
48954910 # If maintaining this conditional winds up being a problem.
48964911 # just turn this into an unconditional skip anything but Linux.
48974912 # The important thing is that our CI has the logic covered.
@@ -4902,7 +4917,7 @@ def test_preauth_data_to_tls_server(self):
49024917
49034918 def call_after_accept (unused ):
49044919 server_accept_called .set ()
4905- if not ready_for_server_wrap_socket .wait (2.0 ):
4920+ if not ready_for_server_wrap_socket .wait (support . SHORT_TIMEOUT ):
49064921 raise RuntimeError ("wrap_socket event never set, test may fail." )
49074922 return False # Tell the server thread to continue.
49084923
@@ -4924,20 +4939,31 @@ def call_after_accept(unused):
49244939
49254940 ready_for_server_wrap_socket .set ()
49264941 server .join ()
4942+
49274943 wrap_error = server .wrap_error
4928- self .assertEqual (b"" , server .received_data )
4929- self .assertIsInstance (wrap_error , OSError ) # All platforms.
4930- self .non_linux_skip_if_other_okay_error (wrap_error )
4931- self .assertIsInstance (wrap_error , ssl .SSLError )
4932- self .assertIn ("before TLS handshake with data" , wrap_error .args [1 ])
4933- self .assertIn ("before TLS handshake with data" , wrap_error .reason )
4934- self .assertNotEqual (0 , wrap_error .args [0 ])
4935- self .assertIsNone (wrap_error .library , msg = "attr must exist" )
4944+ server .wrap_error = None
4945+ try :
4946+ self .assertEqual (b"" , server .received_data )
4947+ self .assertIsInstance (wrap_error , OSError ) # All platforms.
4948+ self .non_linux_skip_if_other_okay_error (wrap_error )
4949+ self .assertIsInstance (wrap_error , ssl .SSLError )
4950+ self .assertIn ("before TLS handshake with data" , wrap_error .args [1 ])
4951+ self .assertIn ("before TLS handshake with data" , wrap_error .reason )
4952+ self .assertNotEqual (0 , wrap_error .args [0 ])
4953+ self .assertIsNone (wrap_error .library , msg = "attr must exist" )
4954+ finally :
4955+ # gh-108342: Explicitly break the reference cycle
4956+ wrap_error = None
4957+ server = None
49364958
49374959 def test_preauth_data_to_tls_client (self ):
4960+ server_can_continue_with_wrap_socket = threading .Event ()
49384961 client_can_continue_with_wrap_socket = threading .Event ()
49394962
49404963 def call_after_accept (conn_to_client ):
4964+ if not server_can_continue_with_wrap_socket .wait (support .SHORT_TIMEOUT ):
4965+ print ("ERROR: test client took too long" )
4966+
49414967 # This forces an immediate connection close via RST on .close().
49424968 set_socket_so_linger_on_with_zero_timeout (conn_to_client )
49434969 conn_to_client .send (
@@ -4959,8 +4985,10 @@ def call_after_accept(conn_to_client):
49594985
49604986 with socket .socket () as client :
49614987 client .connect (server .listener .getsockname ())
4962- if not client_can_continue_with_wrap_socket .wait (2.0 ):
4963- self .fail ("test server took too long." )
4988+ server_can_continue_with_wrap_socket .set ()
4989+
4990+ if not client_can_continue_with_wrap_socket .wait (support .SHORT_TIMEOUT ):
4991+ self .fail ("test server took too long" )
49644992 ssl_ctx = ssl .create_default_context ()
49654993 try :
49664994 tls_client = ssl_ctx .wrap_socket (
@@ -4974,24 +5002,31 @@ def call_after_accept(conn_to_client):
49745002 tls_client .close ()
49755003
49765004 server .join ()
4977- self .assertEqual (b"" , received_data )
4978- self .assertIsInstance (wrap_error , OSError ) # All platforms.
4979- self .non_linux_skip_if_other_okay_error (wrap_error )
4980- self .assertIsInstance (wrap_error , ssl .SSLError )
4981- self .assertIn ("before TLS handshake with data" , wrap_error .args [1 ])
4982- self .assertIn ("before TLS handshake with data" , wrap_error .reason )
4983- self .assertNotEqual (0 , wrap_error .args [0 ])
4984- self .assertIsNone (wrap_error .library , msg = "attr must exist" )
5005+ try :
5006+ self .assertEqual (b"" , received_data )
5007+ self .assertIsInstance (wrap_error , OSError ) # All platforms.
5008+ self .non_linux_skip_if_other_okay_error (wrap_error )
5009+ self .assertIsInstance (wrap_error , ssl .SSLError )
5010+ self .assertIn ("before TLS handshake with data" , wrap_error .args [1 ])
5011+ self .assertIn ("before TLS handshake with data" , wrap_error .reason )
5012+ self .assertNotEqual (0 , wrap_error .args [0 ])
5013+ self .assertIsNone (wrap_error .library , msg = "attr must exist" )
5014+ finally :
5015+ # gh-108342: Explicitly break the reference cycle
5016+ wrap_error = None
5017+ server = None
49855018
49865019 def test_https_client_non_tls_response_ignored (self ):
4987-
49885020 server_responding = threading .Event ()
49895021
49905022 class SynchronizedHTTPSConnection (http .client .HTTPSConnection ):
49915023 def connect (self ):
5024+ # Call clear text HTTP connect(), not the encrypted HTTPS (TLS)
5025+ # connect(): wrap_socket() is called manually below.
49925026 http .client .HTTPConnection .connect (self )
5027+
49935028 # Wait for our fault injection server to have done its thing.
4994- if not server_responding .wait (1.0 ) and support .verbose :
5029+ if not server_responding .wait (support . SHORT_TIMEOUT ) and support .verbose :
49955030 sys .stdout .write ("server_responding event never set." )
49965031 self .sock = self ._context .wrap_socket (
49975032 self .sock , server_hostname = self .host )
@@ -5006,29 +5041,34 @@ def call_after_accept(conn_to_client):
50065041 server_responding .set ()
50075042 return True # Tell the server to stop.
50085043
5044+ timeout = 2.0
50095045 server = self .SingleConnectionTestServerThread (
50105046 call_after_accept = call_after_accept ,
5011- name = "non_tls_http_RST_responder" )
5047+ name = "non_tls_http_RST_responder" ,
5048+ timeout = timeout )
50125049 server .__enter__ () # starts it
50135050 self .addCleanup (server .__exit__ ) # ... & unittest.TestCase stops it.
50145051 # Redundant; call_after_accept sets SO_LINGER on the accepted conn.
50155052 set_socket_so_linger_on_with_zero_timeout (server .listener )
50165053
50175054 connection = SynchronizedHTTPSConnection (
5018- f"localhost" ,
5055+ server . listener . getsockname ()[ 0 ] ,
50195056 port = server .port ,
50205057 context = ssl .create_default_context (),
5021- timeout = 2.0 ,
5058+ timeout = timeout ,
50225059 )
5060+
50235061 # There are lots of reasons this raises as desired, long before this
50245062 # test was added. Sending the request requires a successful TLS wrapped
50255063 # socket; that fails if the connection is broken. It may seem pointless
50265064 # to test this. It serves as an illustration of something that we never
50275065 # want to happen... properly not happening.
5028- with self .assertRaises (OSError ) as err_ctx :
5066+ with self .assertRaises (OSError ):
50295067 connection .request ("HEAD" , "/test" , headers = {"Host" : "localhost" })
50305068 response = connection .getresponse ()
50315069
5070+ server .join ()
5071+
50325072
50335073def test_main (verbose = False ):
50345074 if support .verbose :
0 commit comments