PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/spec/ruby/library/net/ftp/fixtures/server.rb

http://github.com/jruby/jruby
Ruby | 276 lines | 215 code | 51 blank | 10 comment | 20 complexity | c59a3337644c976a4d7acc0972d22e95 MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause, GPL-2.0, JSON, LGPL-2.1
  1. module NetFTPSpecs
  2. class DummyFTP
  3. attr_accessor :connect_message
  4. attr_reader :login_user, :login_pass, :login_acct
  5. # hostname or IP address
  6. attr_reader :hostname
  7. # port number
  8. attr_reader :server_port
  9. def initialize(hostname = "localhost", server_port = 0)
  10. @hostname = hostname
  11. @server = TCPServer.new(@hostname, server_port)
  12. @server_port = @server.addr[1]
  13. @handlers = {}
  14. @commands = []
  15. @connect_message = nil
  16. end
  17. def serve_once
  18. @thread = Thread.new do
  19. @socket = @server.accept
  20. @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, 1)
  21. begin
  22. handle_request
  23. ensure
  24. @socket.close
  25. end
  26. end
  27. end
  28. def handle_request
  29. # Send out the welcome message.
  30. response @connect_message || "220 Dummy FTP Server ready!"
  31. begin
  32. loop do
  33. command = @socket.recv(1024)
  34. break if command.nil?
  35. command, argument = command.chomp.split(" ", 2)
  36. if command == "QUIT"
  37. self.response("221 OK, bye")
  38. break
  39. elsif proc_handler = @handlers[command.downcase.to_sym]
  40. if argument.nil?
  41. proc_handler.call(self)
  42. else
  43. proc_handler.call(self, argument)
  44. end
  45. else
  46. if argument.nil?
  47. self.send(command.downcase.to_sym)
  48. else
  49. self.send(command.downcase.to_sym, argument)
  50. end
  51. end
  52. end
  53. rescue => e
  54. self.error_response("Exception: #{e} #{e.backtrace.inspect}")
  55. end
  56. end
  57. def error_response(text)
  58. self.response("451 #{text}")
  59. end
  60. def response(text)
  61. @socket.puts(text) unless @socket.closed?
  62. end
  63. def stop
  64. @datasocket.close unless @datasocket.nil? || @datasocket.closed?
  65. @server.close
  66. @thread.join
  67. end
  68. ##
  69. def handle(sym, &block)
  70. @handlers[sym] = block
  71. end
  72. def should_receive(method)
  73. @handler_for = method
  74. self
  75. end
  76. def and_respond(text)
  77. @handlers[@handler_for] = lambda { |s, *args| s.response(text) }
  78. end
  79. ##
  80. # FTP methods
  81. ##
  82. def abor
  83. self.response("226 Closing data connection. (ABOR)")
  84. end
  85. def acct(account)
  86. @login_acct = account
  87. self.response("230 User '#{account}' logged in, proceed. (ACCT)")
  88. end
  89. def cdup
  90. self.response("200 Command okay. (CDUP)")
  91. end
  92. def cwd(dir)
  93. self.response("200 Command okay. (CWD #{dir})")
  94. end
  95. def dele(file)
  96. self.response("250 Requested file action okay, completed. (DELE #{file})")
  97. end
  98. def eprt(arg)
  99. _, _, host, port = arg.split("|")
  100. @datasocket = TCPSocket.new(host, port)
  101. self.response("200 port opened")
  102. end
  103. def help(param = :default)
  104. if param == :default
  105. self.response("211 System status, or system help reply. (HELP)")
  106. else
  107. self.response("211 System status, or system help reply. (HELP #{param})")
  108. end
  109. end
  110. def list(folder)
  111. self.response("150 opening ASCII connection for file list")
  112. @datasocket.puts("-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb")
  113. @datasocket.puts("-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb")
  114. @datasocket.puts("-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb")
  115. @datasocket.close()
  116. self.response("226 transfer complete (LIST #{folder})")
  117. end
  118. def mdtm(filename)
  119. self.response("213 19980705132316")
  120. end
  121. def mkd(foldername)
  122. self.response(%Q{257 "#{foldername.gsub('"', '""')}" created.})
  123. end
  124. def nlst(folder = nil)
  125. self.response("150 opening ASCII connection for file list")
  126. @datasocket.puts("last_response_code.rb")
  127. @datasocket.puts("list.rb")
  128. @datasocket.puts("pwd.rb")
  129. @datasocket.close()
  130. self.response("226 transfer complete (NLST#{folder ? " #{folder}" : ""})")
  131. end
  132. def noop
  133. self.response("200 Command okay. (NOOP)")
  134. end
  135. def pass(password)
  136. @login_pass = password
  137. self.response("230 User logged in, proceed. (PASS #{password})")
  138. end
  139. def port(arg)
  140. nums = arg.split(",")
  141. if nums[0] == "::1"
  142. # IPv6
  143. port = nums[1].to_i * 256 + nums[2].to_i
  144. host = nums[0]
  145. else
  146. # IPv4
  147. port = nums[4].to_i * 256 + nums[5].to_i
  148. host = nums[0..3].join(".")
  149. end
  150. @datasocket = TCPSocket.new(host, port)
  151. self.response("200 port opened")
  152. end
  153. def pwd
  154. self.response('257 "/some/dir/" - current directory')
  155. end
  156. def retr(file)
  157. self.response("125 Data transfer starting")
  158. if @restart_at && @restart_at == 20
  159. @datasocket.puts("of the file named '#{file}'.")
  160. @restart_at = nil
  161. else
  162. @datasocket.puts("This is the content")
  163. @datasocket.puts("of the file named '#{file}'.")
  164. end
  165. @datasocket.close()
  166. self.response("226 Closing data connection. (RETR #{file})")
  167. end
  168. def rest(at_bytes)
  169. @restart_at = at_bytes.to_i
  170. self.response("350 Requested file action pending further information. (REST)")
  171. end
  172. def rmd(folder)
  173. self.response("250 Requested file action okay, completed. (RMD #{folder})")
  174. end
  175. def rnfr(from)
  176. @rename_from = from
  177. self.response("350 Requested file action pending further information.")
  178. end
  179. def rnto(to)
  180. self.response("250 Requested file action okay, completed. (Renamed #{@rename_from} to #{to})")
  181. @rename_from = nil
  182. end
  183. def site(param)
  184. self.response("200 Command okay. (SITE #{param})")
  185. end
  186. def size(filename)
  187. if filename == "binary"
  188. self.response("213 24")
  189. else
  190. self.response("213 1024")
  191. end
  192. end
  193. def stat
  194. self.response("211 System status, or system help reply. (STAT)")
  195. end
  196. def stor(file)
  197. tmp_file = tmp("#{file}file", false)
  198. self.response("125 Data transfer starting.")
  199. mode = @restart_at ? "a" : "w"
  200. File.open(tmp_file, mode + "b") do |f|
  201. loop do
  202. data = @datasocket.recv(1024)
  203. break if !data || data.empty?
  204. f << data
  205. end
  206. end
  207. #@datasocket.close()
  208. self.response("200 OK, Data received. (STOR #{file})")
  209. end
  210. def appe(file)
  211. @restart_at = true
  212. stor(file)
  213. end
  214. def syst
  215. self.response("215 FTP Dummy Server (SYST)")
  216. end
  217. def type(type)
  218. self.response("200 TYPE switched to #{type}")
  219. end
  220. def user(name)
  221. @login_user = name
  222. self.response("230 User logged in, proceed. (USER #{name})")
  223. end
  224. end
  225. end