Added support for RFC 959's REST command (restart), closing SF patch

#101187, which some modifications.  Specifically,

ntransfercmd(), transfercmd(), and retrbinary() all grow an optional
`rest' argument, which if not None, is used as the argument to an FTP
REST comman dbefore the socket is returned.  Differences from the SF
patch:

- always compare against None with `is' or `is not' instead of == or !=

- no parens around conditional

- RFC 959 defines the argument to REST is a string containing any
  ASCII characters in the range [33..126].  Therefore, we use the %s
  format character instead of %f or %d as suggested in the patch's
  comments.  Note that we do /not/ sanity checkthe contents of the
  rest argument (but we'll document this in the library reference
  manual).
This commit is contained in:
Barry Warsaw 2000-09-01 06:09:23 +00:00
parent e0d9a83bea
commit 100d81e8e3
1 changed files with 38 additions and 23 deletions

View File

@ -1,7 +1,6 @@
"""An FTP client class and some helper functions.
Based on RFC 959: File Transfer Protocol
(FTP), by J. Postel and J. Reynolds
Based on RFC 959: File Transfer Protocol (FTP), by J. Postel and J. Reynolds
Example:
@ -235,7 +234,9 @@ class FTP:
return self.voidresp()
def sendport(self, host, port):
'''Send a PORT command with the current host and the given port number.'''
'''Send a PORT command with the current host and the given
port number.
'''
hbytes = string.splitfields(host, '.')
pbytes = [`port/256`, `port%256`]
bytes = hbytes + pbytes
@ -253,25 +254,35 @@ class FTP:
resp = self.sendport(host, port)
return sock
def ntransfercmd(self, cmd):
'''Initiate a transfer over the data connection.
If the transfer is active, send a port command and
the transfer command, and accept the connection.
If the server is passive, send a pasv command, connect
to it, and start the transfer command.
Either way, return the socket for the connection and
the expected size of the transfer. The expected size
may be None if it could not be determined.'''
def ntransfercmd(self, cmd, rest=None):
"""Initiate a transfer over the data connection.
If the transfer is active, send a port command and the
transfer command, and accept the connection. If the server is
passive, send a pasv command, connect to it, and start the
transfer command. Either way, return the socket for the
connection and the expected size of the transfer. The
expected size may be None if it could not be determined.
Optional `rest' argument can be a string that is sent as the
argument to a RESTART command. This is essentially a server
marker used to tell the server to skip over any data up to the
given marker.
"""
size = None
if self.passiveserver:
host, port = parse227(self.sendcmd('PASV'))
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.connect((host, port))
if rest is not None:
self.sendcmd("REST %s" % rest)
resp = self.sendcmd(cmd)
if resp[0] <> '1':
raise error_reply, resp
else:
sock = self.makeport()
if rest is not None:
self.sendcmd("REST %s" % rest)
resp = self.sendcmd(cmd)
if resp[0] <> '1':
raise error_reply, resp
@ -281,10 +292,9 @@ class FTP:
size = parse150(resp)
return conn, size
def transfercmd(self, cmd):
'''Initiate a transfer over the data connection. Returns
the socket for the connection. See also ntransfercmd().'''
return self.ntransfercmd(cmd)[0]
def transfercmd(self, cmd, rest=None):
"""Like nstransfercmd() but returns only the socket."""
return self.ntransfercmd(cmd, rest)[0]
def login(self, user = '', passwd = '', acct = ''):
'''Login, default anonymous.'''
@ -312,13 +322,18 @@ class FTP:
raise error_reply, resp
return resp
def retrbinary(self, cmd, callback, blocksize=8192):
'''Retrieve data in binary mode.
The argument is a RETR command.
The callback function is called for each block.
This creates a new port for you'''
def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
"""Retrieve data in binary mode.
`cmd' is a RETR command. `callback' is a callback function is
called for each block. No more than `blocksize' number of
bytes will be read from the socket. Optional `rest' is passed
to transfercmd().
A new port is created for you. Return the response code.
"""
self.voidcmd('TYPE I')
conn = self.transfercmd(cmd)
conn = self.transfercmd(cmd, rest)
while 1:
data = conn.recv(blocksize)
if not data: