@@ -4917,12 +4917,16 @@ class TestPreHandshakeClose(unittest.TestCase):
49174917
49184918 class SingleConnectionTestServerThread (threading .Thread ):
49194919
4920- def __init__ (self , * , name , call_after_accept ):
4920+ def __init__ (self , * , name , call_after_accept , timeout = None ):
49214921 self .call_after_accept = call_after_accept
49224922 self .received_data = b'' # set by .run()
49234923 self .wrap_error = None # set by .run()
49244924 self .listener = None # set by .start()
49254925 self .port = None # set by .start()
4926+ if timeout is None :
4927+ self .timeout = support .SHORT_TIMEOUT
4928+ else :
4929+ self .timeout = timeout
49264930 super ().__init__ (name = name )
49274931
49284932 def __enter__ (self ):
@@ -4945,13 +4949,19 @@ def start(self):
49454949 self .ssl_ctx .load_cert_chain (certfile = ONLYCERT , keyfile = ONLYKEY )
49464950 self .listener = socket .socket ()
49474951 self .port = socket_helper .bind_port (self .listener )
4948- self .listener .settimeout (2.0 )
4952+ self .listener .settimeout (self . timeout )
49494953 self .listener .listen (1 )
49504954 super ().start ()
49514955
49524956 def run (self ):
4953- conn , address = self .listener .accept ()
4954- self .listener .close ()
4957+ try :
4958+ conn , address = self .listener .accept ()
4959+ except TimeoutError :
4960+ # on timeout, just close the listener
4961+ return
4962+ finally :
4963+ self .listener .close ()
4964+
49554965 with conn :
49564966 if self .call_after_accept (conn ):
49574967 return
@@ -4979,8 +4989,13 @@ def non_linux_skip_if_other_okay_error(self, err):
49794989 # we're specifically trying to test. The way this test is written
49804990 # is known to work on Linux. We'll skip it anywhere else that it
49814991 # does not present as doing so.
4982- self .skipTest (f"Could not recreate conditions on { sys .platform } :"
4983- f" { err = } " )
4992+ try :
4993+ self .skipTest (f"Could not recreate conditions on { sys .platform } :"
4994+ f" { err = } " )
4995+ finally :
4996+ # gh-108342: Explicitly break the reference cycle
4997+ err = None
4998+
49844999 # If maintaining this conditional winds up being a problem.
49855000 # just turn this into an unconditional skip anything but Linux.
49865001 # The important thing is that our CI has the logic covered.
@@ -4991,7 +5006,7 @@ def test_preauth_data_to_tls_server(self):
49915006
49925007 def call_after_accept (unused ):
49935008 server_accept_called .set ()
4994- if not ready_for_server_wrap_socket .wait (2.0 ):
5009+ if not ready_for_server_wrap_socket .wait (support . SHORT_TIMEOUT ):
49955010 raise RuntimeError ("wrap_socket event never set, test may fail." )
49965011 return False # Tell the server thread to continue.
49975012
@@ -5013,20 +5028,31 @@ def call_after_accept(unused):
50135028
50145029 ready_for_server_wrap_socket .set ()
50155030 server .join ()
5031+
50165032 wrap_error = server .wrap_error
5017- self .assertEqual (b"" , server .received_data )
5018- self .assertIsInstance (wrap_error , OSError ) # All platforms.
5019- self .non_linux_skip_if_other_okay_error (wrap_error )
5020- self .assertIsInstance (wrap_error , ssl .SSLError )
5021- self .assertIn ("before TLS handshake with data" , wrap_error .args [1 ])
5022- self .assertIn ("before TLS handshake with data" , wrap_error .reason )
5023- self .assertNotEqual (0 , wrap_error .args [0 ])
5024- self .assertIsNone (wrap_error .library , msg = "attr must exist" )
5033+ server .wrap_error = None
5034+ try :
5035+ self .assertEqual (b"" , server .received_data )
5036+ self .assertIsInstance (wrap_error , OSError ) # All platforms.
5037+ self .non_linux_skip_if_other_okay_error (wrap_error )
5038+ self .assertIsInstance (wrap_error , ssl .SSLError )
5039+ self .assertIn ("before TLS handshake with data" , wrap_error .args [1 ])
5040+ self .assertIn ("before TLS handshake with data" , wrap_error .reason )
5041+ self .assertNotEqual (0 , wrap_error .args [0 ])
5042+ self .assertIsNone (wrap_error .library , msg = "attr must exist" )
5043+ finally :
5044+ # gh-108342: Explicitly break the reference cycle
5045+ wrap_error = None
5046+ server = None
50255047
50265048 def test_preauth_data_to_tls_client (self ):
5049+ server_can_continue_with_wrap_socket = threading .Event ()
50275050 client_can_continue_with_wrap_socket = threading .Event ()
50285051
50295052 def call_after_accept (conn_to_client ):
5053+ if not server_can_continue_with_wrap_socket .wait (support .SHORT_TIMEOUT ):
5054+ print ("ERROR: test client took too long" )
5055+
50305056 # This forces an immediate connection close via RST on .close().
50315057 set_socket_so_linger_on_with_zero_timeout (conn_to_client )
50325058 conn_to_client .send (
@@ -5048,8 +5074,10 @@ def call_after_accept(conn_to_client):
50485074
50495075 with socket .socket () as client :
50505076 client .connect (server .listener .getsockname ())
5051- if not client_can_continue_with_wrap_socket .wait (2.0 ):
5052- self .fail ("test server took too long." )
5077+ server_can_continue_with_wrap_socket .set ()
5078+
5079+ if not client_can_continue_with_wrap_socket .wait (support .SHORT_TIMEOUT ):
5080+ self .fail ("test server took too long" )
50535081 ssl_ctx = ssl .create_default_context ()
50545082 try :
50555083 tls_client = ssl_ctx .wrap_socket (
@@ -5063,24 +5091,31 @@ def call_after_accept(conn_to_client):
50635091 tls_client .close ()
50645092
50655093 server .join ()
5066- self .assertEqual (b"" , received_data )
5067- self .assertIsInstance (wrap_error , OSError ) # All platforms.
5068- self .non_linux_skip_if_other_okay_error (wrap_error )
5069- self .assertIsInstance (wrap_error , ssl .SSLError )
5070- self .assertIn ("before TLS handshake with data" , wrap_error .args [1 ])
5071- self .assertIn ("before TLS handshake with data" , wrap_error .reason )
5072- self .assertNotEqual (0 , wrap_error .args [0 ])
5073- self .assertIsNone (wrap_error .library , msg = "attr must exist" )
5094+ try :
5095+ self .assertEqual (b"" , received_data )
5096+ self .assertIsInstance (wrap_error , OSError ) # All platforms.
5097+ self .non_linux_skip_if_other_okay_error (wrap_error )
5098+ self .assertIsInstance (wrap_error , ssl .SSLError )
5099+ self .assertIn ("before TLS handshake with data" , wrap_error .args [1 ])
5100+ self .assertIn ("before TLS handshake with data" , wrap_error .reason )
5101+ self .assertNotEqual (0 , wrap_error .args [0 ])
5102+ self .assertIsNone (wrap_error .library , msg = "attr must exist" )
5103+ finally :
5104+ # gh-108342: Explicitly break the reference cycle
5105+ wrap_error = None
5106+ server = None
50745107
50755108 def test_https_client_non_tls_response_ignored (self ):
5076-
50775109 server_responding = threading .Event ()
50785110
50795111 class SynchronizedHTTPSConnection (http .client .HTTPSConnection ):
50805112 def connect (self ):
5113+ # Call clear text HTTP connect(), not the encrypted HTTPS (TLS)
5114+ # connect(): wrap_socket() is called manually below.
50815115 http .client .HTTPConnection .connect (self )
5116+
50825117 # Wait for our fault injection server to have done its thing.
5083- if not server_responding .wait (1.0 ) and support .verbose :
5118+ if not server_responding .wait (support . SHORT_TIMEOUT ) and support .verbose :
50845119 sys .stdout .write ("server_responding event never set." )
50855120 self .sock = self ._context .wrap_socket (
50865121 self .sock , server_hostname = self .host )
@@ -5095,29 +5130,35 @@ def call_after_accept(conn_to_client):
50955130 server_responding .set ()
50965131 return True # Tell the server to stop.
50975132
5133+ timeout = 2.0
50985134 server = self .SingleConnectionTestServerThread (
50995135 call_after_accept = call_after_accept ,
5100- name = "non_tls_http_RST_responder" )
5136+ name = "non_tls_http_RST_responder" ,
5137+ timeout = timeout )
51015138 server .__enter__ () # starts it
51025139 self .addCleanup (server .__exit__ ) # ... & unittest.TestCase stops it.
5140+
51035141 # Redundant; call_after_accept sets SO_LINGER on the accepted conn.
51045142 set_socket_so_linger_on_with_zero_timeout (server .listener )
51055143
51065144 connection = SynchronizedHTTPSConnection (
5107- f"localhost" ,
5145+ server . listener . getsockname ()[ 0 ] ,
51085146 port = server .port ,
51095147 context = ssl .create_default_context (),
5110- timeout = 2.0 ,
5148+ timeout = timeout ,
51115149 )
5150+
51125151 # There are lots of reasons this raises as desired, long before this
51135152 # test was added. Sending the request requires a successful TLS wrapped
51145153 # socket; that fails if the connection is broken. It may seem pointless
51155154 # to test this. It serves as an illustration of something that we never
51165155 # want to happen... properly not happening.
5117- with self .assertRaises (OSError ) as err_ctx :
5156+ with self .assertRaises (OSError ):
51185157 connection .request ("HEAD" , "/test" , headers = {"Host" : "localhost" })
51195158 response = connection .getresponse ()
51205159
5160+ server .join ()
5161+
51215162
51225163def setUpModule ():
51235164 if support .verbose :
0 commit comments