| OLD | NEW |
| 1 """An extensible library for opening URLs using a variety of protocols | 1 """An extensible library for opening URLs using a variety of protocols |
| 2 | 2 |
| 3 The simplest way to use this module is to call the urlopen function, | 3 The simplest way to use this module is to call the urlopen function, |
| 4 which accepts a string containing a URL or a Request object (described | 4 which accepts a string containing a URL or a Request object (described |
| 5 below). It opens the URL and returns the results as file-like | 5 below). It opens the URL and returns the results as file-like |
| 6 object; the returned object has some extra methods described below. | 6 object; the returned object has some extra methods described below. |
| 7 | 7 |
| 8 The OpenerDirector manages a collection of Handler objects that do | 8 The OpenerDirector manages a collection of Handler objects that do |
| 9 all the actual work. Each Handler implements a particular protocol or | 9 all the actual work. Each Handler implements a particular protocol or |
| 10 option. The OpenerDirector is a composite object that invokes the | 10 option. The OpenerDirector is a composite object that invokes the |
| (...skipping 1353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1364 headers += "Content-type: %s\n" % mtype | 1364 headers += "Content-type: %s\n" % mtype |
| 1365 if retrlen is not None and retrlen >= 0: | 1365 if retrlen is not None and retrlen >= 0: |
| 1366 headers += "Content-length: %d\n" % retrlen | 1366 headers += "Content-length: %d\n" % retrlen |
| 1367 headers = email.message_from_string(headers) | 1367 headers = email.message_from_string(headers) |
| 1368 return addinfourl(fp, headers, req.full_url) | 1368 return addinfourl(fp, headers, req.full_url) |
| 1369 except ftplib.all_errors as msg: | 1369 except ftplib.all_errors as msg: |
| 1370 exc = URLError('ftp error: %s' % msg) | 1370 exc = URLError('ftp error: %s' % msg) |
| 1371 raise exc.with_traceback(sys.exc_info()[2]) | 1371 raise exc.with_traceback(sys.exc_info()[2]) |
| 1372 | 1372 |
| 1373 def connect_ftp(self, user, passwd, host, port, dirs, timeout): | 1373 def connect_ftp(self, user, passwd, host, port, dirs, timeout): |
| 1374 fw = ftpwrapper(user, passwd, host, port, dirs, timeout) | 1374 return ftpwrapper(user, passwd, host, port, dirs, timeout, |
| 1375 return fw | 1375 persistent=False) |
| 1376 | 1376 |
| 1377 class CacheFTPHandler(FTPHandler): | 1377 class CacheFTPHandler(FTPHandler): |
| 1378 # XXX would be nice to have pluggable cache strategies | 1378 # XXX would be nice to have pluggable cache strategies |
| 1379 # XXX this stuff is definitely not thread safe | 1379 # XXX this stuff is definitely not thread safe |
| 1380 def __init__(self): | 1380 def __init__(self): |
| 1381 self.cache = {} | 1381 self.cache = {} |
| 1382 self.timeout = {} | 1382 self.timeout = {} |
| 1383 self.soonest = 0 | 1383 self.soonest = 0 |
| 1384 self.delay = 60 | 1384 self.delay = 60 |
| 1385 self.max_conns = 16 | 1385 self.max_conns = 16 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1413 self.soonest = min(list(self.timeout.values())) | 1413 self.soonest = min(list(self.timeout.values())) |
| 1414 | 1414 |
| 1415 # then check the size | 1415 # then check the size |
| 1416 if len(self.cache) == self.max_conns: | 1416 if len(self.cache) == self.max_conns: |
| 1417 for k, v in list(self.timeout.items()): | 1417 for k, v in list(self.timeout.items()): |
| 1418 if v == self.soonest: | 1418 if v == self.soonest: |
| 1419 del self.cache[k] | 1419 del self.cache[k] |
| 1420 del self.timeout[k] | 1420 del self.timeout[k] |
| 1421 break | 1421 break |
| 1422 self.soonest = min(list(self.timeout.values())) | 1422 self.soonest = min(list(self.timeout.values())) |
| 1423 |
| 1424 def clear_cache(self): |
| 1425 for conn in self.cache.values(): |
| 1426 conn.close() |
| 1427 self.cache.clear() |
| 1428 self.timeout.clear() |
| 1429 |
| 1423 | 1430 |
| 1424 # Code move from the old urllib module | 1431 # Code move from the old urllib module |
| 1425 | 1432 |
| 1426 MAXFTPCACHE = 10 # Trim the ftp cache beyond this size | 1433 MAXFTPCACHE = 10 # Trim the ftp cache beyond this size |
| 1427 | 1434 |
| 1428 # Helper for non-unix systems | 1435 # Helper for non-unix systems |
| 1429 if os.name == 'nt': | 1436 if os.name == 'nt': |
| 1430 from nturl2path import url2pathname, pathname2url | 1437 from nturl2path import url2pathname, pathname2url |
| 1431 else: | 1438 else: |
| 1432 def url2pathname(pathname): | 1439 def url2pathname(pathname): |
| (...skipping 704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2137 if _noheaders is None: | 2144 if _noheaders is None: |
| 2138 _noheaders = email.message_from_string("") | 2145 _noheaders = email.message_from_string("") |
| 2139 return _noheaders | 2146 return _noheaders |
| 2140 | 2147 |
| 2141 | 2148 |
| 2142 # Utility classes | 2149 # Utility classes |
| 2143 | 2150 |
| 2144 class ftpwrapper: | 2151 class ftpwrapper: |
| 2145 """Class used by open_ftp() for cache of open FTP connections.""" | 2152 """Class used by open_ftp() for cache of open FTP connections.""" |
| 2146 | 2153 |
| 2147 def __init__(self, user, passwd, host, port, dirs, timeout=None): | 2154 def __init__(self, user, passwd, host, port, dirs, timeout=None, |
| 2155 persistent=True): |
| 2148 self.user = user | 2156 self.user = user |
| 2149 self.passwd = passwd | 2157 self.passwd = passwd |
| 2150 self.host = host | 2158 self.host = host |
| 2151 self.port = port | 2159 self.port = port |
| 2152 self.dirs = dirs | 2160 self.dirs = dirs |
| 2153 self.timeout = timeout | 2161 self.timeout = timeout |
| 2162 self.refcount = 0 |
| 2163 self.keepalive = persistent |
| 2154 self.init() | 2164 self.init() |
| 2155 | 2165 |
| 2156 def init(self): | 2166 def init(self): |
| 2157 import ftplib | 2167 import ftplib |
| 2158 self.busy = 0 | 2168 self.busy = 0 |
| 2159 self.ftp = ftplib.FTP() | 2169 self.ftp = ftplib.FTP() |
| 2160 self.ftp.connect(self.host, self.port, self.timeout) | 2170 self.ftp.connect(self.host, self.port, self.timeout) |
| 2161 self.ftp.login(self.user, self.passwd) | 2171 self.ftp.login(self.user, self.passwd) |
| 2162 for dir in self.dirs: | 2172 for dir in self.dirs: |
| 2163 self.ftp.cwd(dir) | 2173 self.ftp.cwd(dir) |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2194 except ftplib.error_perm as reason: | 2204 except ftplib.error_perm as reason: |
| 2195 raise URLError('ftp error', reason) from reason | 2205 raise URLError('ftp error', reason) from reason |
| 2196 finally: | 2206 finally: |
| 2197 self.ftp.cwd(pwd) | 2207 self.ftp.cwd(pwd) |
| 2198 cmd = 'LIST ' + file | 2208 cmd = 'LIST ' + file |
| 2199 else: | 2209 else: |
| 2200 cmd = 'LIST' | 2210 cmd = 'LIST' |
| 2201 conn, retrlen = self.ftp.ntransfercmd(cmd) | 2211 conn, retrlen = self.ftp.ntransfercmd(cmd) |
| 2202 self.busy = 1 | 2212 self.busy = 1 |
| 2203 | 2213 |
| 2204 ftpobj = addclosehook(conn.makefile('rb'), self.endtransfer) | 2214 ftpobj = addclosehook(conn.makefile('rb'), self.file_close) |
| 2215 self.refcount += 1 |
| 2205 conn.close() | 2216 conn.close() |
| 2206 # Pass back both a suitably decorated object and a retrieval length | 2217 # Pass back both a suitably decorated object and a retrieval length |
| 2207 return (ftpobj, retrlen) | 2218 return (ftpobj, retrlen) |
| 2208 | 2219 |
| 2209 def endtransfer(self): | 2220 def endtransfer(self): |
| 2210 if not self.busy: | 2221 if not self.busy: |
| 2211 return | 2222 return |
| 2212 self.busy = 0 | 2223 self.busy = 0 |
| 2213 try: | 2224 try: |
| 2214 self.ftp.voidresp() | 2225 self.ftp.voidresp() |
| 2215 except ftperrors(): | 2226 except ftperrors(): |
| 2216 pass | 2227 pass |
| 2217 | 2228 |
| 2218 def close(self): | 2229 def close(self): |
| 2230 self.keepalive = False |
| 2231 if self.refcount <= 0: |
| 2232 self.real_close() |
| 2233 |
| 2234 def file_close(self): |
| 2235 self.endtransfer() |
| 2236 self.refcount -= 1 |
| 2237 if self.refcount <= 0 and not self.keepalive: |
| 2238 self.real_close() |
| 2239 |
| 2240 def real_close(self): |
| 2219 self.endtransfer() | 2241 self.endtransfer() |
| 2220 try: | 2242 try: |
| 2221 self.ftp.close() | 2243 self.ftp.close() |
| 2222 except ftperrors(): | 2244 except ftperrors(): |
| 2223 pass | 2245 pass |
| 2224 | 2246 |
| 2225 # Proxy handling | 2247 # Proxy handling |
| 2226 def getproxies_environment(): | 2248 def getproxies_environment(): |
| 2227 """Return a dictionary of scheme -> proxy server URL mappings. | 2249 """Return a dictionary of scheme -> proxy server URL mappings. |
| 2228 | 2250 |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2467 """ | 2489 """ |
| 2468 if getproxies_environment(): | 2490 if getproxies_environment(): |
| 2469 return proxy_bypass_environment(host) | 2491 return proxy_bypass_environment(host) |
| 2470 else: | 2492 else: |
| 2471 return proxy_bypass_registry(host) | 2493 return proxy_bypass_registry(host) |
| 2472 | 2494 |
| 2473 else: | 2495 else: |
| 2474 # By default use environment variables | 2496 # By default use environment variables |
| 2475 getproxies = getproxies_environment | 2497 getproxies = getproxies_environment |
| 2476 proxy_bypass = proxy_bypass_environment | 2498 proxy_bypass = proxy_bypass_environment |
| OLD | NEW |