/tools/Ruby/lib/ruby/1.8/uri/ftp.rb

http://github.com/agross/netopenspace · Ruby · 198 lines · 97 code · 22 blank · 79 comment · 15 complexity · 0a20367f152582a7420da61e441472f3 MD5 · raw file

  1. #
  2. # = uri/ftp.rb
  3. #
  4. # Author:: Akira Yamada <akira@ruby-lang.org>
  5. # License:: You can redistribute it and/or modify it under the same term as Ruby.
  6. # Revision:: $Id: ftp.rb 16085 2008-04-19 11:56:22Z knu $
  7. #
  8. require 'uri/generic'
  9. module URI
  10. #
  11. # FTP URI syntax is defined by RFC1738 section 3.2.
  12. #
  13. class FTP < Generic
  14. DEFAULT_PORT = 21
  15. COMPONENT = [
  16. :scheme,
  17. :userinfo, :host, :port,
  18. :path, :typecode
  19. ].freeze
  20. #
  21. # Typecode is "a", "i" or "d".
  22. #
  23. # * "a" indicates a text file (the FTP command was ASCII)
  24. # * "i" indicates a binary file (FTP command IMAGE)
  25. # * "d" indicates the contents of a directory should be displayed
  26. #
  27. TYPECODE = ['a', 'i', 'd'].freeze
  28. TYPECODE_PREFIX = ';type='.freeze
  29. def self.new2(user, password, host, port, path,
  30. typecode = nil, arg_check = true)
  31. typecode = nil if typecode.size == 0
  32. if typecode && !TYPECODE.include?(typecode)
  33. raise ArgumentError,
  34. "bad typecode is specified: #{typecode}"
  35. end
  36. # do escape
  37. self.new('ftp',
  38. [user, password],
  39. host, port, nil,
  40. typecode ? path + TYPECODE_PREFIX + typecode : path,
  41. nil, nil, nil, arg_check)
  42. end
  43. #
  44. # == Description
  45. #
  46. # Creates a new URI::FTP object from components, with syntax checking.
  47. #
  48. # The components accepted are +userinfo+, +host+, +port+, +path+ and
  49. # +typecode+.
  50. #
  51. # The components should be provided either as an Array, or as a Hash
  52. # with keys formed by preceding the component names with a colon.
  53. #
  54. # If an Array is used, the components must be passed in the order
  55. # [userinfo, host, port, path, typecode]
  56. #
  57. # If the path supplied is absolute, it will be escaped in order to
  58. # make it absolute in the URI. Examples:
  59. #
  60. # require 'uri'
  61. #
  62. # uri = URI::FTP.build(['user:password', 'ftp.example.com', nil,
  63. # '/path/file.> zip', 'i'])
  64. # puts uri.to_s -> ftp://user:password@ftp.example.com/%2Fpath/file.zip;type=a
  65. #
  66. # uri2 = URI::FTP.build({:host => 'ftp.example.com',
  67. # :path => 'ruby/src'})
  68. # puts uri2.to_s -> ftp://ftp.example.com/ruby/src
  69. #
  70. def self.build(args)
  71. # Fix the incoming path to be generic URL syntax
  72. # FTP path -> URL path
  73. # foo/bar /foo/bar
  74. # /foo/bar /%2Ffoo/bar
  75. #
  76. if args.kind_of?(Array)
  77. args[3] = '/' + args[3].sub(/^\//, '%2F')
  78. else
  79. args[:path] = '/' + args[:path].sub(/^\//, '%2F')
  80. end
  81. tmp = Util::make_components_hash(self, args)
  82. if tmp[:typecode]
  83. if tmp[:typecode].size == 1
  84. tmp[:typecode] = TYPECODE_PREFIX + tmp[:typecode]
  85. end
  86. tmp[:path] << tmp[:typecode]
  87. end
  88. return super(tmp)
  89. end
  90. #
  91. # == Description
  92. #
  93. # Creates a new URI::FTP object from generic URL components with no
  94. # syntax checking.
  95. #
  96. # Unlike build(), this method does not escape the path component as
  97. # required by RFC1738; instead it is treated as per RFC2396.
  98. #
  99. # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+,
  100. # +opaque+, +query+ and +fragment+, in that order.
  101. #
  102. def initialize(*arg)
  103. super(*arg)
  104. @typecode = nil
  105. tmp = @path.index(TYPECODE_PREFIX)
  106. if tmp
  107. typecode = @path[tmp + TYPECODE_PREFIX.size..-1]
  108. self.set_path(@path[0..tmp - 1])
  109. if arg[-1]
  110. self.typecode = typecode
  111. else
  112. self.set_typecode(typecode)
  113. end
  114. end
  115. end
  116. attr_reader :typecode
  117. def check_typecode(v)
  118. if TYPECODE.include?(v)
  119. return true
  120. else
  121. raise InvalidComponentError,
  122. "bad typecode(expected #{TYPECODE.join(', ')}): #{v}"
  123. end
  124. end
  125. private :check_typecode
  126. def set_typecode(v)
  127. @typecode = v
  128. end
  129. protected :set_typecode
  130. def typecode=(typecode)
  131. check_typecode(typecode)
  132. set_typecode(typecode)
  133. typecode
  134. end
  135. def merge(oth) # :nodoc:
  136. tmp = super(oth)
  137. if self != tmp
  138. tmp.set_typecode(oth.typecode)
  139. end
  140. return tmp
  141. end
  142. # Returns the path from an FTP URI.
  143. #
  144. # RFC 1738 specifically states that the path for an FTP URI does not
  145. # include the / which separates the URI path from the URI host. Example:
  146. #
  147. # ftp://ftp.example.com/pub/ruby
  148. #
  149. # The above URI indicates that the client should connect to
  150. # ftp.example.com then cd pub/ruby from the initial login directory.
  151. #
  152. # If you want to cd to an absolute directory, you must include an
  153. # escaped / (%2F) in the path. Example:
  154. #
  155. # ftp://ftp.example.com/%2Fpub/ruby
  156. #
  157. # This method will then return "/pub/ruby"
  158. #
  159. def path
  160. return @path.sub(/^\//,'').sub(/^%2F/i,'/')
  161. end
  162. def to_s
  163. save_path = nil
  164. if @typecode
  165. save_path = @path
  166. @path = @path + TYPECODE_PREFIX + @typecode
  167. end
  168. str = super
  169. if @typecode
  170. @path = save_path
  171. end
  172. return str
  173. end
  174. end
  175. @@schemes['FTP'] = FTP
  176. end