63 rader
1,8 KiB
Ruby
63 rader
1,8 KiB
Ruby
require 'uri'
|
|
require 'stringio'
|
|
require 'time'
|
|
|
|
module URI
|
|
class FTP
|
|
def buffer_open(buf, proxy, options) # :nodoc:
|
|
if proxy
|
|
OpenURI.open_http(buf, self, proxy, options)
|
|
return
|
|
end
|
|
require 'net/ftp'
|
|
|
|
directories = self.path.split(%r{/}, -1)
|
|
directories.shift if directories[0] == '' # strip a field before leading slash
|
|
directories.each {|d|
|
|
d.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/) { [$1].pack("H2") }
|
|
}
|
|
unless filename = directories.pop
|
|
raise ArgumentError, "no filename: #{self.inspect}"
|
|
end
|
|
directories.each {|d|
|
|
if /[\r\n]/ =~ d
|
|
raise ArgumentError, "invalid directory: #{d.inspect}"
|
|
end
|
|
}
|
|
if /[\r\n]/ =~ filename
|
|
raise ArgumentError, "invalid filename: #{filename.inspect}"
|
|
end
|
|
typecode = self.typecode
|
|
if typecode && /\A[aid]\z/ !~ typecode
|
|
raise ArgumentError, "invalid typecode: #{typecode.inspect}"
|
|
end
|
|
|
|
# The access sequence is defined by RFC 1738
|
|
ftp = Net::FTP.open(self.host)
|
|
ftp.passive = true if !options[:ftp_active_mode]
|
|
# todo: extract user/passwd from .netrc.
|
|
user = 'anonymous'
|
|
passwd = nil
|
|
user, passwd = self.userinfo.split(/:/) if self.userinfo
|
|
ftp.login(user, passwd)
|
|
directories.each {|cwd|
|
|
ftp.voidcmd("CWD #{cwd}")
|
|
}
|
|
if typecode
|
|
# xxx: typecode D is not handled.
|
|
ftp.voidcmd("TYPE #{typecode.upcase}")
|
|
end
|
|
if options[:content_length_proc]
|
|
options[:content_length_proc].call(ftp.size(filename))
|
|
end
|
|
ftp.retrbinary("RETR #{filename}", 4096) { |str|
|
|
buf << str
|
|
options[:progress_proc].call(buf.size) if options[:progress_proc]
|
|
}
|
|
ftp.close
|
|
buf.io.rewind
|
|
end
|
|
|
|
include OpenURI::OpenRead
|
|
end
|
|
end
|