Skip to content

Commit 5384a47

Browse files
authored
Merge pull request #5073 from dvermd/ftplib_311
Update ftplib to CPython 3.11.5
2 parents a12233e + 0a76a9b commit 5384a47

File tree

2 files changed

+149
-70
lines changed

2 files changed

+149
-70
lines changed

Lib/ftplib.py

+32-23
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,17 @@ class error_proto(Error): pass # response does not begin with [1-5]
7272

7373
# The class itself
7474
class FTP:
75-
7675
'''An FTP client class.
7776
7877
To create a connection, call the class using these arguments:
79-
host, user, passwd, acct, timeout
78+
host, user, passwd, acct, timeout, source_address, encoding
8079
8180
The first four arguments are all strings, and have default value ''.
82-
timeout must be numeric and defaults to None if not passed,
83-
meaning that no timeout will be set on any ftp socket(s)
81+
The parameter ´timeout´ must be numeric and defaults to None if not
82+
passed, meaning that no timeout will be set on any ftp socket(s).
8483
If a timeout is passed, then this is now the default timeout for all ftp
8584
socket operations for this instance.
85+
The last parameter is the encoding of filenames, which defaults to utf-8.
8686
8787
Then use self.connect() with optional host and port argument.
8888
@@ -102,15 +102,19 @@ class FTP:
102102
sock = None
103103
file = None
104104
welcome = None
105-
passiveserver = 1
106-
encoding = "latin-1"
105+
passiveserver = True
106+
# Disables https://bugs.python.org/issue43285 security if set to True.
107+
trust_server_pasv_ipv4_address = False
107108

108-
# Initialization method (called by class instantiation).
109-
# Initialize host to localhost, port to standard ftp port
110-
# Optional arguments are host (for connect()),
111-
# and user, passwd, acct (for login())
112109
def __init__(self, host='', user='', passwd='', acct='',
113-
timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None):
110+
timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None, *,
111+
encoding='utf-8'):
112+
"""Initialization method (called by class instantiation).
113+
Initialize host to localhost, port to standard ftp port.
114+
Optional arguments are host (for connect()),
115+
and user, passwd, acct (for login()).
116+
"""
117+
self.encoding = encoding
114118
self.source_address = source_address
115119
self.timeout = timeout
116120
if host:
@@ -146,6 +150,8 @@ def connect(self, host='', port=0, timeout=-999, source_address=None):
146150
self.port = port
147151
if timeout != -999:
148152
self.timeout = timeout
153+
if self.timeout is not None and not self.timeout:
154+
raise ValueError('Non-blocking socket (timeout=0) is not supported')
149155
if source_address is not None:
150156
self.source_address = source_address
151157
sys.audit("ftplib.connect", self, self.host, self.port)
@@ -316,8 +322,13 @@ def makeport(self):
316322
return sock
317323

318324
def makepasv(self):
325+
"""Internal: Does the PASV or EPSV handshake -> (address, port)"""
319326
if self.af == socket.AF_INET:
320-
host, port = parse227(self.sendcmd('PASV'))
327+
untrusted_host, port = parse227(self.sendcmd('PASV'))
328+
if self.trust_server_pasv_ipv4_address:
329+
host = untrusted_host
330+
else:
331+
host = self.sock.getpeername()[0]
321332
else:
322333
host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername())
323334
return host, port
@@ -704,9 +715,10 @@ class FTP_TLS(FTP):
704715
'''
705716
ssl_version = ssl.PROTOCOL_TLS_CLIENT
706717

707-
def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
708-
certfile=None, context=None,
709-
timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None):
718+
def __init__(self, host='', user='', passwd='', acct='',
719+
keyfile=None, certfile=None, context=None,
720+
timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None, *,
721+
encoding='utf-8'):
710722
if context is not None and keyfile is not None:
711723
raise ValueError("context and keyfile arguments are mutually "
712724
"exclusive")
@@ -725,12 +737,13 @@ def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
725737
keyfile=keyfile)
726738
self.context = context
727739
self._prot_p = False
728-
FTP.__init__(self, host, user, passwd, acct, timeout, source_address)
740+
super().__init__(host, user, passwd, acct,
741+
timeout, source_address, encoding=encoding)
729742

730743
def login(self, user='', passwd='', acct='', secure=True):
731744
if secure and not isinstance(self.sock, ssl.SSLSocket):
732745
self.auth()
733-
return FTP.login(self, user, passwd, acct)
746+
return super().login(user, passwd, acct)
734747

735748
def auth(self):
736749
'''Set up secure control connection by using TLS/SSL.'''
@@ -740,8 +753,7 @@ def auth(self):
740753
resp = self.voidcmd('AUTH TLS')
741754
else:
742755
resp = self.voidcmd('AUTH SSL')
743-
self.sock = self.context.wrap_socket(self.sock,
744-
server_hostname=self.host)
756+
self.sock = self.context.wrap_socket(self.sock, server_hostname=self.host)
745757
self.file = self.sock.makefile(mode='r', encoding=self.encoding)
746758
return resp
747759

@@ -778,7 +790,7 @@ def prot_c(self):
778790
# --- Overridden FTP methods
779791

780792
def ntransfercmd(self, cmd, rest=None):
781-
conn, size = FTP.ntransfercmd(self, cmd, rest)
793+
conn, size = super().ntransfercmd(cmd, rest)
782794
if self._prot_p:
783795
conn = self.context.wrap_socket(conn,
784796
server_hostname=self.host)
@@ -823,7 +835,6 @@ def parse227(resp):
823835
'''Parse the '227' response for a PASV request.
824836
Raises error_proto if it does not contain '(h1,h2,h3,h4,p1,p2)'
825837
Return ('host.addr.as.numbers', port#) tuple.'''
826-
827838
if resp[:3] != '227':
828839
raise error_reply(resp)
829840
global _227_re
@@ -843,7 +854,6 @@ def parse229(resp, peer):
843854
'''Parse the '229' response for an EPSV request.
844855
Raises error_proto if it does not contain '(|||port|)'
845856
Return ('host.addr.as.numbers', port#) tuple.'''
846-
847857
if resp[:3] != '229':
848858
raise error_reply(resp)
849859
left = resp.find('(')
@@ -865,7 +875,6 @@ def parse257(resp):
865875
'''Parse the '257' response for a MKD or PWD request.
866876
This is a response to a MKD or PWD request: a directory name.
867877
Returns the directoryname in the 257 reply.'''
868-
869878
if resp[:3] != '257':
870879
raise error_reply(resp)
871880
if resp[3:5] != ' "':

0 commit comments

Comments
 (0)