PageRenderTime 50ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

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

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