Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b491e05

Browse files
Issue #21032. Fixed socket leak if HTTPConnection.getresponse() fails.
Original patch by Martin Panter.
1 parent 9cba989 commit b491e05

3 files changed

Lines changed: 41 additions & 11 deletions

File tree

Lib/http/client.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,18 +1169,22 @@ class the response_class variable.
11691169
else:
11701170
response = self.response_class(self.sock, method=self._method)
11711171

1172-
response.begin()
1173-
assert response.will_close != _UNKNOWN
1174-
self.__state = _CS_IDLE
1172+
try:
1173+
response.begin()
1174+
assert response.will_close != _UNKNOWN
1175+
self.__state = _CS_IDLE
11751176

1176-
if response.will_close:
1177-
# this effectively passes the connection to the response
1178-
self.close()
1179-
else:
1180-
# remember this, so we can tell when it is complete
1181-
self.__response = response
1177+
if response.will_close:
1178+
# this effectively passes the connection to the response
1179+
self.close()
1180+
else:
1181+
# remember this, so we can tell when it is complete
1182+
self.__response = response
11821183

1183-
return response
1184+
return response
1185+
except:
1186+
response.close()
1187+
raise
11841188

11851189
try:
11861190
import ssl

Lib/test/test_httplib.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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+
678701
class OfflineTest(TestCase):
679702
def test_responses(self):
680703
self.assertEqual(client.responses[client.NOT_FOUND], "Not Found")

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ Core and Builtins
3636
Library
3737
-------
3838

39+
- Issue #21032. Fixed socket leak if HTTPConnection.getresponse() fails.
40+
Original patch by Martin Panter.
41+
3942
- Issue #22960: Add a context argument to xmlrpclib.ServerProxy constructor.
4043

4144
- Issue #22915: SAX parser now supports files opened with file descriptor or

0 commit comments

Comments
 (0)