@@ -28,6 +28,7 @@ def __init__(self, text, fileclass=io.BytesIO, host=None, port=None):
2828 self .fileclass = fileclass
2929 self .data = b''
3030 self .sendall_calls = 0
31+ self .file_closed = False
3132 self .host = host
3233 self .port = port
3334
@@ -38,7 +39,13 @@ def sendall(self, data):
3839 def makefile (self , mode , bufsize = None ):
3940 if mode != 'r' and mode != 'rb' :
4041 raise client .UnimplementedFileMode ()
41- return self .fileclass (self .text )
42+ # keep the file around so we can check how much was read from it
43+ self .file = self .fileclass (self .text )
44+ self .file .close = self .file_close #nerf close ()
45+ return self .file
46+
47+ def file_close (self ):
48+ self .file_closed = True
4249
4350 def close (self ):
4451 pass
@@ -675,6 +682,22 @@ def test_delayed_ack_opt(self):
675682 conn .request ('POST' , '/' , body )
676683 self .assertGreater (sock .sendall_calls , 1 )
677684
685+ def test_error_leak (self ):
686+ # Test that the socket is not leaked if getresponse() fails
687+ conn = client .HTTPConnection ('example.com' )
688+ response = None
689+ class Response (client .HTTPResponse ):
690+ def __init__ (self , * pos , ** kw ):
691+ nonlocal response
692+ response = self # Avoid garbage collector closing the socket
693+ client .HTTPResponse .__init__ (self , * pos , ** kw )
694+ conn .response_class = Response
695+ conn .sock = FakeSocket ('' ) # Emulate server dropping connection
696+ conn .request ('GET' , '/' )
697+ self .assertRaises (client .BadStatusLine , conn .getresponse )
698+ self .assertTrue (response .closed )
699+ self .assertTrue (conn .sock .file_closed )
700+
678701class OfflineTest (TestCase ):
679702 def test_responses (self ):
680703 self .assertEqual (client .responses [client .NOT_FOUND ], "Not Found" )
0 commit comments