diff options
author | Nadeem Vawda <nadeem.vawda@gmail.com> | 2011-07-23 13:51:16 (GMT) |
---|---|---|
committer | Nadeem Vawda <nadeem.vawda@gmail.com> | 2011-07-23 13:51:16 (GMT) |
commit | b42c53e442b211d0ded1d4c9abd18c74d29ed663 (patch) | |
tree | 0ad39ae840da96efaa2ff6bdb49f2c44a226c0aa /Lib/urllib.py | |
parent | 578617ad453c399ea52c0aef937fdf0904b2213c (diff) | |
download | cpython-b42c53e442b211d0ded1d4c9abd18c74d29ed663.zip cpython-b42c53e442b211d0ded1d4c9abd18c74d29ed663.tar.gz cpython-b42c53e442b211d0ded1d4c9abd18c74d29ed663.tar.bz2 |
Issue #10883: Fix socket leaks in urllib.request.
* ftpwrapper now uses reference counting to ensure that the underlying socket
is closed when the ftpwrapper object is no longer in use
* ftplib.FTP.ntransfercmd() now closes the socket if an error occurs
Initial patch by Victor Stinner.
Diffstat (limited to 'Lib/urllib.py')
-rw-r--r-- | Lib/urllib.py | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/Lib/urllib.py b/Lib/urllib.py index 62c08c9..ce90e91 100644 --- a/Lib/urllib.py +++ b/Lib/urllib.py @@ -850,13 +850,16 @@ class ftpwrapper: """Class used by open_ftp() for cache of open FTP connections.""" def __init__(self, user, passwd, host, port, dirs, - timeout=socket._GLOBAL_DEFAULT_TIMEOUT): + timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + persistent=False): self.user = user self.passwd = passwd self.host = host self.port = port self.dirs = dirs self.timeout = timeout + self.refcount = 0 + self.keepalive = persistent self.init() def init(self): @@ -883,7 +886,7 @@ class ftpwrapper: # Try to retrieve as a file try: cmd = 'RETR ' + file - conn = self.ftp.ntransfercmd(cmd) + conn, retrlen = self.ftp.ntransfercmd(cmd) except ftplib.error_perm, reason: if str(reason)[:3] != '550': raise IOError, ('ftp error', reason), sys.exc_info()[2] @@ -903,11 +906,14 @@ class ftpwrapper: cmd = 'LIST ' + file else: cmd = 'LIST' - conn = self.ftp.ntransfercmd(cmd) + conn, retrlen = self.ftp.ntransfercmd(cmd) self.busy = 1 + ftpobj = addclosehook(conn.makefile('rb'), self.file_close) + self.refcount += 1 + conn.close() # Pass back both a suitably decorated object and a retrieval length - return (addclosehook(conn[0].makefile('rb'), - self.endtransfer), conn[1]) + return (ftpobj, retrlen) + def endtransfer(self): if not self.busy: return @@ -918,6 +924,17 @@ class ftpwrapper: pass def close(self): + self.keepalive = False + if self.refcount <= 0: + self.real_close() + + def file_close(self): + self.endtransfer() + self.refcount -= 1 + if self.refcount <= 0 and not self.keepalive: + self.real_close() + + def real_close(self): self.endtransfer() try: self.ftp.close() |