@@ -4917,12 +4917,16 @@ class TestPreHandshakeClose(unittest.TestCase):
4917
4917
4918
4918
class SingleConnectionTestServerThread (threading .Thread ):
4919
4919
4920
- def __init__ (self , * , name , call_after_accept ):
4920
+ def __init__ (self , * , name , call_after_accept , timeout = None ):
4921
4921
self .call_after_accept = call_after_accept
4922
4922
self .received_data = b'' # set by .run()
4923
4923
self .wrap_error = None # set by .run()
4924
4924
self .listener = None # set by .start()
4925
4925
self .port = None # set by .start()
4926
+ if timeout is None :
4927
+ self .timeout = support .SHORT_TIMEOUT
4928
+ else :
4929
+ self .timeout = timeout
4926
4930
super ().__init__ (name = name )
4927
4931
4928
4932
def __enter__ (self ):
@@ -4945,13 +4949,19 @@ def start(self):
4945
4949
self .ssl_ctx .load_cert_chain (certfile = ONLYCERT , keyfile = ONLYKEY )
4946
4950
self .listener = socket .socket ()
4947
4951
self .port = socket_helper .bind_port (self .listener )
4948
- self .listener .settimeout (2.0 )
4952
+ self .listener .settimeout (self . timeout )
4949
4953
self .listener .listen (1 )
4950
4954
super ().start ()
4951
4955
4952
4956
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
+
4955
4965
with conn :
4956
4966
if self .call_after_accept (conn ):
4957
4967
return
@@ -4979,8 +4989,13 @@ def non_linux_skip_if_other_okay_error(self, err):
4979
4989
# we're specifically trying to test. The way this test is written
4980
4990
# is known to work on Linux. We'll skip it anywhere else that it
4981
4991
# 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
+
4984
4999
# If maintaining this conditional winds up being a problem.
4985
5000
# just turn this into an unconditional skip anything but Linux.
4986
5001
# The important thing is that our CI has the logic covered.
@@ -4991,7 +5006,7 @@ def test_preauth_data_to_tls_server(self):
4991
5006
4992
5007
def call_after_accept (unused ):
4993
5008
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 ):
4995
5010
raise RuntimeError ("wrap_socket event never set, test may fail." )
4996
5011
return False # Tell the server thread to continue.
4997
5012
@@ -5013,20 +5028,31 @@ def call_after_accept(unused):
5013
5028
5014
5029
ready_for_server_wrap_socket .set ()
5015
5030
server .join ()
5031
+
5016
5032
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
5025
5047
5026
5048
def test_preauth_data_to_tls_client (self ):
5049
+ server_can_continue_with_wrap_socket = threading .Event ()
5027
5050
client_can_continue_with_wrap_socket = threading .Event ()
5028
5051
5029
5052
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
+
5030
5056
# This forces an immediate connection close via RST on .close().
5031
5057
set_socket_so_linger_on_with_zero_timeout (conn_to_client )
5032
5058
conn_to_client .send (
@@ -5048,8 +5074,10 @@ def call_after_accept(conn_to_client):
5048
5074
5049
5075
with socket .socket () as client :
5050
5076
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" )
5053
5081
ssl_ctx = ssl .create_default_context ()
5054
5082
try :
5055
5083
tls_client = ssl_ctx .wrap_socket (
@@ -5063,24 +5091,31 @@ def call_after_accept(conn_to_client):
5063
5091
tls_client .close ()
5064
5092
5065
5093
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
5074
5107
5075
5108
def test_https_client_non_tls_response_ignored (self ):
5076
-
5077
5109
server_responding = threading .Event ()
5078
5110
5079
5111
class SynchronizedHTTPSConnection (http .client .HTTPSConnection ):
5080
5112
def connect (self ):
5113
+ # Call clear text HTTP connect(), not the encrypted HTTPS (TLS)
5114
+ # connect(): wrap_socket() is called manually below.
5081
5115
http .client .HTTPConnection .connect (self )
5116
+
5082
5117
# 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 :
5084
5119
sys .stdout .write ("server_responding event never set." )
5085
5120
self .sock = self ._context .wrap_socket (
5086
5121
self .sock , server_hostname = self .host )
@@ -5095,29 +5130,35 @@ def call_after_accept(conn_to_client):
5095
5130
server_responding .set ()
5096
5131
return True # Tell the server to stop.
5097
5132
5133
+ timeout = 2.0
5098
5134
server = self .SingleConnectionTestServerThread (
5099
5135
call_after_accept = call_after_accept ,
5100
- name = "non_tls_http_RST_responder" )
5136
+ name = "non_tls_http_RST_responder" ,
5137
+ timeout = timeout )
5101
5138
server .__enter__ () # starts it
5102
5139
self .addCleanup (server .__exit__ ) # ... & unittest.TestCase stops it.
5140
+
5103
5141
# Redundant; call_after_accept sets SO_LINGER on the accepted conn.
5104
5142
set_socket_so_linger_on_with_zero_timeout (server .listener )
5105
5143
5106
5144
connection = SynchronizedHTTPSConnection (
5107
- f"localhost" ,
5145
+ server . listener . getsockname ()[ 0 ] ,
5108
5146
port = server .port ,
5109
5147
context = ssl .create_default_context (),
5110
- timeout = 2.0 ,
5148
+ timeout = timeout ,
5111
5149
)
5150
+
5112
5151
# There are lots of reasons this raises as desired, long before this
5113
5152
# test was added. Sending the request requires a successful TLS wrapped
5114
5153
# socket; that fails if the connection is broken. It may seem pointless
5115
5154
# to test this. It serves as an illustration of something that we never
5116
5155
# want to happen... properly not happening.
5117
- with self .assertRaises (OSError ) as err_ctx :
5156
+ with self .assertRaises (OSError ):
5118
5157
connection .request ("HEAD" , "/test" , headers = {"Host" : "localhost" })
5119
5158
response = connection .getresponse ()
5120
5159
5160
+ server .join ()
5161
+
5121
5162
5122
5163
def setUpModule ():
5123
5164
if support .verbose :
0 commit comments