[Python-checkins] cpython (merge 3.4 -> default): Issue #21032. Fixed socket leak if HTTPConnection.getresponse() fails.

serhiy.storchaka python-checkins at python.org
Mon Dec 1 12:16:37 CET 2014


https://hg.python.org/cpython/rev/62a058c76869
changeset:   93680:62a058c76869
parent:      93677:abc7fe393016
parent:      93679:ba72da4883eb
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Mon Dec 01 13:10:12 2014 +0200
summary:
  Issue #21032. Fixed socket leak if HTTPConnection.getresponse() fails.
Original patch by Martin Panter.

files:
  Lib/http/client.py       |  24 ++++++++++++++----------
  Lib/test/test_httplib.py |  22 +++++++++++++++++++++-
  Misc/NEWS                |   3 +++
  3 files changed, 38 insertions(+), 11 deletions(-)


diff --git a/Lib/http/client.py b/Lib/http/client.py
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -1233,18 +1233,22 @@
         else:
             response = self.response_class(self.sock, method=self._method)
 
-        response.begin()
-        assert response.will_close != _UNKNOWN
-        self.__state = _CS_IDLE
+        try:
+            response.begin()
+            assert response.will_close != _UNKNOWN
+            self.__state = _CS_IDLE
 
-        if response.will_close:
-            # this effectively passes the connection to the response
-            self.close()
-        else:
-            # remember this, so we can tell when it is complete
-            self.__response = response
+            if response.will_close:
+                # this effectively passes the connection to the response
+                self.close()
+            else:
+                # remember this, so we can tell when it is complete
+                self.__response = response
 
-        return response
+            return response
+        except:
+            response.close()
+            raise
 
 try:
     import ssl
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -48,6 +48,7 @@
         self.fileclass = fileclass
         self.data = b''
         self.sendall_calls = 0
+        self.file_closed = False
         self.host = host
         self.port = port
 
@@ -60,9 +61,12 @@
             raise client.UnimplementedFileMode()
         # keep the file around so we can check how much was read from it
         self.file = self.fileclass(self.text)
-        self.file.close = lambda:None #nerf close ()
+        self.file.close = self.file_close #nerf close ()
         return self.file
 
+    def file_close(self):
+        self.file_closed = True
+
     def close(self):
         pass
 
@@ -676,6 +680,22 @@
         conn.request('POST', '/', body)
         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):
         extra = '3;foo=bar\r\n' + 'abc\r\n'
         expected = chunked_expected + b'abc'
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -191,6 +191,9 @@
 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
   re.ASCII. It was newer worked.
 

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list