patch_openuri.rb 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. require 'uri'
  2. require 'stringio'
  3. require 'time'
  4. module URI
  5. class FTP
  6. def buffer_open(buf, proxy, options) # :nodoc:
  7. if proxy
  8. OpenURI.open_http(buf, self, proxy, options)
  9. return
  10. end
  11. require 'net/ftp'
  12. directories = self.path.split(%r{/}, -1)
  13. directories.shift if directories[0] == '' # strip a field before leading slash
  14. directories.each {|d|
  15. d.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/) { [$1].pack("H2") }
  16. }
  17. unless filename = directories.pop
  18. raise ArgumentError, "no filename: #{self.inspect}"
  19. end
  20. directories.each {|d|
  21. if /[\r\n]/ =~ d
  22. raise ArgumentError, "invalid directory: #{d.inspect}"
  23. end
  24. }
  25. if /[\r\n]/ =~ filename
  26. raise ArgumentError, "invalid filename: #{filename.inspect}"
  27. end
  28. typecode = self.typecode
  29. if typecode && /\A[aid]\z/ !~ typecode
  30. raise ArgumentError, "invalid typecode: #{typecode.inspect}"
  31. end
  32. # The access sequence is defined by RFC 1738
  33. ftp = Net::FTP.open(self.host)
  34. ftp.passive = true if !options[:ftp_active_mode]
  35. # todo: extract user/passwd from .netrc.
  36. user = 'anonymous'
  37. passwd = nil
  38. user, passwd = self.userinfo.split(/:/) if self.userinfo
  39. ftp.login(user, passwd)
  40. directories.each {|cwd|
  41. ftp.voidcmd("CWD #{cwd}")
  42. }
  43. if typecode
  44. # xxx: typecode D is not handled.
  45. ftp.voidcmd("TYPE #{typecode.upcase}")
  46. end
  47. if options[:content_length_proc]
  48. options[:content_length_proc].call(ftp.size(filename))
  49. end
  50. ftp.retrbinary("RETR #{filename}", 4096) { |str|
  51. buf << str
  52. options[:progress_proc].call(buf.size) if options[:progress_proc]
  53. }
  54. ftp.close
  55. buf.io.rewind
  56. end
  57. include OpenURI::OpenRead
  58. end
  59. end