Commit 91453026 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #19524: Fixed resource leak in the HTTP connection when an invalid

response is received.  Patch by Martin Panter.
parents d8a1447c f54c3501
...@@ -48,8 +48,7 @@ def urlopen(url, data=None, proxies=None): ...@@ -48,8 +48,7 @@ def urlopen(url, data=None, proxies=None):
return opener.open(url, data) return opener.open(url, data)
class FakeHTTPMixin(object): def fakehttp(fakedata):
def fakehttp(self, fakedata):
class FakeSocket(io.BytesIO): class FakeSocket(io.BytesIO):
io_refs = 1 io_refs = 1
...@@ -79,12 +78,18 @@ class FakeHTTPMixin(object): ...@@ -79,12 +78,18 @@ class FakeHTTPMixin(object):
# buffer to store data for verification in urlopen tests. # buffer to store data for verification in urlopen tests.
buf = None buf = None
fakesock = FakeSocket(fakedata)
def connect(self): def connect(self):
self.sock = FakeSocket(fakedata) self.sock = self.fakesock
return FakeHTTPConnection
class FakeHTTPMixin(object):
def fakehttp(self, fakedata):
self._connection_class = http.client.HTTPConnection self._connection_class = http.client.HTTPConnection
http.client.HTTPConnection = FakeHTTPConnection http.client.HTTPConnection = fakehttp(fakedata)
def unfakehttp(self): def unfakehttp(self):
http.client.HTTPConnection = self._connection_class http.client.HTTPConnection = self._connection_class
......
import unittest import unittest
from test import support from test import support
from test import test_urllib
import os import os
import io import io
...@@ -13,6 +14,7 @@ import urllib.request ...@@ -13,6 +14,7 @@ import urllib.request
from urllib.request import Request, OpenerDirector, _parse_proxy, _proxy_bypass_macosx_sysconf from urllib.request import Request, OpenerDirector, _parse_proxy, _proxy_bypass_macosx_sysconf
from urllib.parse import urlparse from urllib.parse import urlparse
import urllib.error import urllib.error
import http.client
# XXX # XXX
# Request # Request
...@@ -1393,6 +1395,33 @@ class HandlerTests(unittest.TestCase): ...@@ -1393,6 +1395,33 @@ class HandlerTests(unittest.TestCase):
self.assertEqual(len(http_handler.requests), 1) self.assertEqual(len(http_handler.requests), 1)
self.assertFalse(http_handler.requests[0].has_header(auth_header)) self.assertFalse(http_handler.requests[0].has_header(auth_header))
def test_http_closed(self):
"""Test the connection is cleaned up when the response is closed"""
for (transfer, data) in (
("Connection: close", b"data"),
("Transfer-Encoding: chunked", b"4\r\ndata\r\n0\r\n\r\n"),
("Content-Length: 4", b"data"),
):
header = "HTTP/1.1 200 OK\r\n{}\r\n\r\n".format(transfer)
conn = test_urllib.fakehttp(header.encode() + data)
handler = urllib.request.AbstractHTTPHandler()
req = Request("http://dummy/")
req.timeout = None
with handler.do_open(conn, req) as resp:
resp.read()
self.assertTrue(conn.fakesock.closed,
"Connection not closed with {!r}".format(transfer))
def test_invalid_closed(self):
"""Test the connection is cleaned up after an invalid response"""
conn = test_urllib.fakehttp(b"")
handler = urllib.request.AbstractHTTPHandler()
req = Request("http://dummy/")
req.timeout = None
with self.assertRaises(http.client.BadStatusLine):
handler.do_open(conn, req)
self.assertTrue(conn.fakesock.closed, "Connection not closed")
class MiscTests(unittest.TestCase): class MiscTests(unittest.TestCase):
......
...@@ -1169,13 +1169,16 @@ class AbstractHTTPHandler(BaseHandler): ...@@ -1169,13 +1169,16 @@ class AbstractHTTPHandler(BaseHandler):
del headers[proxy_auth_hdr] del headers[proxy_auth_hdr]
h.set_tunnel(req._tunnel_host, headers=tunnel_headers) h.set_tunnel(req._tunnel_host, headers=tunnel_headers)
try:
try: try:
h.request(req.get_method(), req.selector, req.data, headers) h.request(req.get_method(), req.selector, req.data, headers)
except OSError as err: # timeout error except OSError as err: # timeout error
h.close()
raise URLError(err) raise URLError(err)
else:
r = h.getresponse() r = h.getresponse()
except:
h.close()
raise
# If the server does not send us a 'Connection: close' header, # If the server does not send us a 'Connection: close' header,
# HTTPConnection assumes the socket should be left open. Manually # HTTPConnection assumes the socket should be left open. Manually
# mark the socket to be closed when this response object goes away. # mark the socket to be closed when this response object goes away.
......
...@@ -1012,6 +1012,7 @@ Mike Pall ...@@ -1012,6 +1012,7 @@ Mike Pall
Todd R. Palmer Todd R. Palmer
Juan David Ibáñez Palomar Juan David Ibáñez Palomar
Jan Palus Jan Palus
Martin Panter
Mathias Panzenböck Mathias Panzenböck
M. Papillon M. Papillon
Peter Parente Peter Parente
......
...@@ -132,6 +132,9 @@ Core and Builtins ...@@ -132,6 +132,9 @@ Core and Builtins
Library Library
------- -------
- Issue #19524: Fixed resource leak in the HTTP connection when an invalid
response is received. Patch by Martin Panter.
- Issue #20421: Add a .version() method to SSL sockets exposing the actual - Issue #20421: Add a .version() method to SSL sockets exposing the actual
protocol version in use. protocol version in use.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment