Resuming with (ftplib/httplib)?

Henning Schroeder hschroeder at gmx.net
Wed Aug 11 07:09:14 EDT 1999


Orlando Vazquez <ovazquez at sprint.ca> wrote:
> So my question is, how can I, using ftplib and httplib, resume a
> download? Is it possible? Has this been done before? Any code someone
> would be willing to share? I would appreciate it soo much. :-)
HTTP version 1.1 supports byte ranges. There is an interesting article in
ApacheWeek (http://www.apacheweek.org) about HTTP 1.1.
The ftp-protocoll has a REST command to resume transfers. See the hack 
below which works for me.

  Henning

------------------------------------------------------------
# Module xftplib.py
from ftplib import *

class XFTP(FTP):

    def size(self, filename):
	self.voidcmd("TYPE I") #seems necessary to get the *right* size	
	return FTP.size(self, filename)
		
    def rest(self, start):
	resp = self.sendcmd("REST %s" % start)
	if resp[:3] <> "350": raise error_reply, resp

    def ntransfercmd(self, cmd, resume):
	'''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.'''
	size = None
	if self.passiveserver:
	    host, port = parse227(self.sendcmd('PASV'))
	    conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	    conn.connect(host, port)
	    if resume: self.rest(resume)
	    resp = self.sendcmd(cmd)
	    if resp[0] <> '1':raise error_reply, resp
	else:
	    sock = self.makeport()
	    if resume: self.rest(resume)
	    resp = self.sendcmd(cmd)
	    if resp[0] <> '1':
		raise error_reply, resp
	    conn, sockaddr = sock.accept()
	    if resp[:3] == '150':
		# this is conditional in case we received a 125
		size = parse150(resp)
	    return conn, size

    def transfercmd(self, cmd, resume=0):
	'''Initiate a transfer over the data connection.  Returns
	the socket for the connection.  See also ntransfercmd().'''
	return self.ntransfercmd(cmd, resume)[0]

    def retrbinary(self, cmd, callback, resume=0, 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'''
	    self.voidcmd('TYPE I')
	    conn = self.transfercmd(cmd, resume)
	    while 1:
		    data = conn.recv(blocksize)
		    if not data:
			    break
		    callback(data)
	    conn.close()
	    return self.voidresp()




More information about the Python-list mailing list