mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 19:34:08 +00:00 
			
		
		
		
	Issue #21032. Fixed socket leak if HTTPConnection.getresponse() fails.
Original patch by Martin Panter.
This commit is contained in:
		
						commit
						2205da43a6
					
				
					 3 changed files with 38 additions and 11 deletions
				
			
		| 
						 | 
					@ -1233,18 +1233,22 @@ class HTTPConnection:
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            response = self.response_class(self.sock, method=self._method)
 | 
					            response = self.response_class(self.sock, method=self._method)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        response.begin()
 | 
					        try:
 | 
				
			||||||
        assert response.will_close != _UNKNOWN
 | 
					            response.begin()
 | 
				
			||||||
        self.__state = _CS_IDLE
 | 
					            assert response.will_close != _UNKNOWN
 | 
				
			||||||
 | 
					            self.__state = _CS_IDLE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if response.will_close:
 | 
					            if response.will_close:
 | 
				
			||||||
            # this effectively passes the connection to the response
 | 
					                # this effectively passes the connection to the response
 | 
				
			||||||
            self.close()
 | 
					                self.close()
 | 
				
			||||||
        else:
 | 
					            else:
 | 
				
			||||||
            # remember this, so we can tell when it is complete
 | 
					                # remember this, so we can tell when it is complete
 | 
				
			||||||
            self.__response = response
 | 
					                self.__response = response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return response
 | 
					            return response
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            response.close()
 | 
				
			||||||
 | 
					            raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
try:
 | 
					try:
 | 
				
			||||||
    import ssl
 | 
					    import ssl
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,6 +48,7 @@ class FakeSocket:
 | 
				
			||||||
        self.fileclass = fileclass
 | 
					        self.fileclass = fileclass
 | 
				
			||||||
        self.data = b''
 | 
					        self.data = b''
 | 
				
			||||||
        self.sendall_calls = 0
 | 
					        self.sendall_calls = 0
 | 
				
			||||||
 | 
					        self.file_closed = False
 | 
				
			||||||
        self.host = host
 | 
					        self.host = host
 | 
				
			||||||
        self.port = port
 | 
					        self.port = port
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,9 +61,12 @@ class FakeSocket:
 | 
				
			||||||
            raise client.UnimplementedFileMode()
 | 
					            raise client.UnimplementedFileMode()
 | 
				
			||||||
        # keep the file around so we can check how much was read from it
 | 
					        # keep the file around so we can check how much was read from it
 | 
				
			||||||
        self.file = self.fileclass(self.text)
 | 
					        self.file = self.fileclass(self.text)
 | 
				
			||||||
        self.file.close = lambda:None #nerf close ()
 | 
					        self.file.close = self.file_close #nerf close ()
 | 
				
			||||||
        return self.file
 | 
					        return self.file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def file_close(self):
 | 
				
			||||||
 | 
					        self.file_closed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def close(self):
 | 
					    def close(self):
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -676,6 +680,22 @@ class BasicTest(TestCase):
 | 
				
			||||||
        conn.request('POST', '/', body)
 | 
					        conn.request('POST', '/', body)
 | 
				
			||||||
        self.assertGreater(sock.sendall_calls, 1)
 | 
					        self.assertGreater(sock.sendall_calls, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_error_leak(self):
 | 
				
			||||||
 | 
					        # Test that the socket is not leaked if getresponse() fails
 | 
				
			||||||
 | 
					        conn = client.HTTPConnection('example.com')
 | 
				
			||||||
 | 
					        response = None
 | 
				
			||||||
 | 
					        class Response(client.HTTPResponse):
 | 
				
			||||||
 | 
					            def __init__(self, *pos, **kw):
 | 
				
			||||||
 | 
					                nonlocal response
 | 
				
			||||||
 | 
					                response = self  # Avoid garbage collector closing the socket
 | 
				
			||||||
 | 
					                client.HTTPResponse.__init__(self, *pos, **kw)
 | 
				
			||||||
 | 
					        conn.response_class = Response
 | 
				
			||||||
 | 
					        conn.sock = FakeSocket('')  # Emulate server dropping connection
 | 
				
			||||||
 | 
					        conn.request('GET', '/')
 | 
				
			||||||
 | 
					        self.assertRaises(client.BadStatusLine, conn.getresponse)
 | 
				
			||||||
 | 
					        self.assertTrue(response.closed)
 | 
				
			||||||
 | 
					        self.assertTrue(conn.sock.file_closed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_chunked_extension(self):
 | 
					    def test_chunked_extension(self):
 | 
				
			||||||
        extra = '3;foo=bar\r\n' + 'abc\r\n'
 | 
					        extra = '3;foo=bar\r\n' + 'abc\r\n'
 | 
				
			||||||
        expected = chunked_expected + b'abc'
 | 
					        expected = chunked_expected + b'abc'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -191,6 +191,9 @@ Core and Builtins
 | 
				
			||||||
Library
 | 
					Library
 | 
				
			||||||
-------
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Issue #21032. Fixed socket leak if HTTPConnection.getresponse() fails.
 | 
				
			||||||
 | 
					  Original patch by Martin Panter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Issue #22407: Deprecated the use of re.LOCALE flag with str patterns or
 | 
					- Issue #22407: Deprecated the use of re.LOCALE flag with str patterns or
 | 
				
			||||||
  re.ASCII. It was newer worked.
 | 
					  re.ASCII. It was newer worked.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue