rubysl-net-ftp 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +25 -0
  6. data/README.md +29 -0
  7. data/Rakefile +1 -0
  8. data/lib/net/ftp.rb +1 -0
  9. data/lib/net/ftptls.rb +1 -0
  10. data/lib/rubysl/net/ftp.rb +2 -0
  11. data/lib/rubysl/net/ftp/ftp.rb +926 -0
  12. data/lib/rubysl/net/ftp/version.rb +7 -0
  13. data/rubysl-net-ftp.gemspec +23 -0
  14. data/spec/FTPError_spec.rb +7 -0
  15. data/spec/FTPPermError_spec.rb +11 -0
  16. data/spec/FTPProtoError_spec.rb +11 -0
  17. data/spec/FTPReplyError_spec.rb +11 -0
  18. data/spec/FTPTempError_spec.rb +11 -0
  19. data/spec/abort_spec.rb +61 -0
  20. data/spec/acct_spec.rb +57 -0
  21. data/spec/binary_spec.rb +23 -0
  22. data/spec/chdir_spec.rb +100 -0
  23. data/spec/close_spec.rb +29 -0
  24. data/spec/closed_spec.rb +20 -0
  25. data/spec/connect_spec.rb +48 -0
  26. data/spec/debug_mode_spec.rb +22 -0
  27. data/spec/delete_spec.rb +58 -0
  28. data/spec/dir_spec.rb +7 -0
  29. data/spec/fixtures/putbinaryfile +3 -0
  30. data/spec/fixtures/puttextfile +3 -0
  31. data/spec/fixtures/server.rb +265 -0
  32. data/spec/get_spec.rb +20 -0
  33. data/spec/getbinaryfile_spec.rb +7 -0
  34. data/spec/getdir_spec.rb +6 -0
  35. data/spec/gettextfile_spec.rb +7 -0
  36. data/spec/help_spec.rb +65 -0
  37. data/spec/initialize_spec.rb +86 -0
  38. data/spec/last_response_code_spec.rb +7 -0
  39. data/spec/last_response_spec.rb +24 -0
  40. data/spec/lastresp_spec.rb +7 -0
  41. data/spec/list_spec.rb +7 -0
  42. data/spec/login_spec.rb +215 -0
  43. data/spec/ls_spec.rb +7 -0
  44. data/spec/mdtm_spec.rb +37 -0
  45. data/spec/mkdir_spec.rb +60 -0
  46. data/spec/mtime_spec.rb +49 -0
  47. data/spec/nlst_spec.rb +120 -0
  48. data/spec/noop_spec.rb +37 -0
  49. data/spec/open_spec.rb +54 -0
  50. data/spec/passive_spec.rb +23 -0
  51. data/spec/put_spec.rb +20 -0
  52. data/spec/putbinaryfile_spec.rb +7 -0
  53. data/spec/puttextfile_spec.rb +7 -0
  54. data/spec/pwd_spec.rb +52 -0
  55. data/spec/quit_spec.rb +32 -0
  56. data/spec/rename_spec.rb +93 -0
  57. data/spec/resume_spec.rb +22 -0
  58. data/spec/retrbinary_spec.rb +29 -0
  59. data/spec/retrlines_spec.rb +33 -0
  60. data/spec/return_code_spec.rb +23 -0
  61. data/spec/rmdir_spec.rb +57 -0
  62. data/spec/sendcmd_spec.rb +53 -0
  63. data/spec/set_socket_spec.rb +7 -0
  64. data/spec/shared/getbinaryfile.rb +179 -0
  65. data/spec/shared/gettextfile.rb +129 -0
  66. data/spec/shared/last_response_code.rb +25 -0
  67. data/spec/shared/list.rb +133 -0
  68. data/spec/shared/putbinaryfile.rb +232 -0
  69. data/spec/shared/puttextfile.rb +149 -0
  70. data/spec/shared/pwd.rb +3 -0
  71. data/spec/site_spec.rb +52 -0
  72. data/spec/size_spec.rb +47 -0
  73. data/spec/status_spec.rb +62 -0
  74. data/spec/storbinary_spec.rb +47 -0
  75. data/spec/storlines_spec.rb +42 -0
  76. data/spec/system_spec.rb +47 -0
  77. data/spec/voidcmd_spec.rb +53 -0
  78. data/spec/welcome_spec.rb +24 -0
  79. metadata +243 -0
@@ -0,0 +1,58 @@
1
+ require 'net/ftp'
2
+ require File.expand_path('../fixtures/server', __FILE__)
3
+
4
+ describe "Net::FTP#delete" do
5
+ before(:each) do
6
+ @server = NetFTPSpecs::DummyFTP.new
7
+ @server.serve_once
8
+
9
+ @ftp = Net::FTP.new
10
+ @ftp.connect("localhost", 9921)
11
+ end
12
+
13
+ after(:each) do
14
+ @ftp.quit rescue nil
15
+ @ftp.close
16
+ @server.stop
17
+ end
18
+
19
+ it "sends the DELE command with the passed filename to the server" do
20
+ @ftp.delete("test.file")
21
+ @ftp.last_response.should == "250 Requested file action okay, completed. (DELE test.file)\n"
22
+ end
23
+
24
+ it "raises a Net::FTPTempError when the response code is 450" do
25
+ @server.should_receive(:dele).and_respond("450 Requested file action not taken.")
26
+ lambda { @ftp.delete("test.file") }.should raise_error(Net::FTPTempError)
27
+ end
28
+
29
+ it "raises a Net::FTPPermError when the response code is 550" do
30
+ @server.should_receive(:dele).and_respond("550 Requested action not taken.")
31
+ lambda { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
32
+ end
33
+
34
+ it "raises a Net::FTPPermError when the response code is 500" do
35
+ @server.should_receive(:dele).and_respond("500 Syntax error, command unrecognized.")
36
+ lambda { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
37
+ end
38
+
39
+ it "raises a Net::FTPPermError when the response code is 501" do
40
+ @server.should_receive(:dele).and_respond("501 Syntax error in parameters or arguments.")
41
+ lambda { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
42
+ end
43
+
44
+ it "raises a Net::FTPPermError when the response code is 502" do
45
+ @server.should_receive(:dele).and_respond("502 Command not implemented.")
46
+ lambda { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
47
+ end
48
+
49
+ it "raises a Net::FTPTempError when the response code is 421" do
50
+ @server.should_receive(:dele).and_respond("421 Service not available, closing control connection.")
51
+ lambda { @ftp.delete("test.file") }.should raise_error(Net::FTPTempError)
52
+ end
53
+
54
+ it "raises a Net::FTPPermError when the response code is 530" do
55
+ @server.should_receive(:dele).and_respond("530 Not logged in.")
56
+ lambda { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
57
+ end
58
+ end
data/spec/dir_spec.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'net/ftp'
2
+ require File.expand_path('../fixtures/server', __FILE__)
3
+ require File.expand_path('../shared/list', __FILE__)
4
+
5
+ describe "Net::FTP#dir" do
6
+ it_behaves_like :net_ftp_list, :dir
7
+ end
@@ -0,0 +1,3 @@
1
+ This is an example file
2
+ which is going to be transmitted
3
+ using #putbinaryfile.
@@ -0,0 +1,3 @@
1
+ This is an example file
2
+ which is going to be transmitted
3
+ using #puttextfile.
@@ -0,0 +1,265 @@
1
+ module NetFTPSpecs
2
+ class DummyFTP
3
+ attr_accessor :connect_message
4
+ attr_reader :login_user, :login_pass, :login_acct
5
+
6
+ def initialize(port = 9921)
7
+ @server = TCPServer.new("localhost", port)
8
+
9
+ @handlers = {}
10
+ @commands = []
11
+ @connect_message = nil
12
+ end
13
+
14
+ def serve_once
15
+ @thread = Thread.new do
16
+ @socket = @server.accept
17
+ handle_request
18
+ @socket.close
19
+ end
20
+ end
21
+
22
+ def handle_request
23
+ # Send out the welcome message.
24
+ response @connect_message || "220 Dummy FTP Server ready!"
25
+
26
+ begin
27
+ loop do
28
+ command = @socket.recv(1024)
29
+ break if command.nil?
30
+
31
+ command, argument = command.chomp.split(" ", 2)
32
+
33
+ if command == "QUIT"
34
+ self.response("221 OK, bye")
35
+ break
36
+ elsif proc_handler = @handlers[command.downcase.to_sym]
37
+ if argument.nil?
38
+ proc_handler.call(self)
39
+ else
40
+ proc_handler.call(self, argument)
41
+ end
42
+ else
43
+ if argument.nil?
44
+ self.send(command.downcase.to_sym)
45
+ else
46
+ self.send(command.downcase.to_sym, argument)
47
+ end
48
+ end
49
+ end
50
+ rescue => e
51
+ self.error_response("Exception: #{e} #{e.backtrace.inspect}")
52
+ end
53
+ end
54
+
55
+ def error_response(text)
56
+ self.response("451 #{text}")
57
+ end
58
+
59
+ def response(text)
60
+ @socket.puts(text) unless @socket.closed?
61
+ end
62
+
63
+ def stop
64
+ @datasocket.close unless @datasocket.nil? || @datasocket.closed?
65
+ @server.close
66
+ @thread.join
67
+ end
68
+
69
+
70
+ ##
71
+ def handle(sym, &block)
72
+ @handlers[sym] = block
73
+ end
74
+
75
+ def should_receive(method)
76
+ @handler_for = method
77
+ self
78
+ end
79
+
80
+ def and_respond(text)
81
+ @handlers[@handler_for] = lambda { |s, *args| s.response(text) }
82
+ end
83
+
84
+ ##
85
+ # FTP methods
86
+ ##
87
+
88
+ def abor
89
+ self.response("226 Closing data connection. (ABOR)")
90
+ end
91
+
92
+ def acct(account)
93
+ @login_acct = account
94
+ self.response("230 User '#{account}' logged in, proceed. (ACCT)")
95
+ end
96
+
97
+ def cdup
98
+ self.response("200 Command okay. (CDUP)")
99
+ end
100
+
101
+ def cwd(dir)
102
+ self.response("200 Command okay. (CWD #{dir})")
103
+ end
104
+
105
+ def dele(file)
106
+ self.response("250 Requested file action okay, completed. (DELE #{file})")
107
+ end
108
+
109
+ def eprt(arg)
110
+ _, _, host, port = arg.split("|")
111
+
112
+ @datasocket = TCPSocket.new(host, port)
113
+ self.response("200 port opened")
114
+ end
115
+
116
+ def help(param = :default)
117
+ if param == :default
118
+ self.response("211 System status, or system help reply. (HELP)")
119
+ else
120
+ self.response("211 System status, or system help reply. (HELP #{param})")
121
+ end
122
+ end
123
+
124
+ def list(folder)
125
+ self.response("150 opening ASCII connection for file list")
126
+ @datasocket.puts("-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb")
127
+ @datasocket.puts("-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb")
128
+ @datasocket.puts("-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb")
129
+ @datasocket.close()
130
+ self.response("226 transfer complete (LIST #{folder})")
131
+ end
132
+
133
+ def mdtm(filename)
134
+ self.response("213 19980705132316")
135
+ end
136
+
137
+ def mkd(foldername)
138
+ self.response(%Q{257 "#{foldername.gsub('"', '""')}" created.})
139
+ end
140
+
141
+ def nlst(folder = nil)
142
+ self.response("150 opening ASCII connection for file list")
143
+ @datasocket.puts("last_response_code.rb")
144
+ @datasocket.puts("list.rb")
145
+ @datasocket.puts("pwd.rb")
146
+ @datasocket.close()
147
+ self.response("226 transfer complete (NLST#{folder ? " #{folder}" : ""})")
148
+ end
149
+
150
+ def noop
151
+ self.response("200 Command okay. (NOOP)")
152
+ end
153
+
154
+ def pass(password)
155
+ @login_pass = password
156
+ self.response("230 User logged in, proceed. (PASS #{password})")
157
+ end
158
+
159
+ def port(arg)
160
+ nums = arg.split(",")
161
+
162
+ if nums[0] == "::1"
163
+ # IPv6
164
+ port = nums[1].to_i * 256 + nums[2].to_i
165
+ host = nums[0]
166
+ else
167
+ # IPv4
168
+ port = nums[4].to_i * 256 + nums[5].to_i
169
+ host = nums[0..3].join(".")
170
+ end
171
+
172
+ @datasocket = TCPSocket.new(host, port)
173
+ self.response("200 port opened")
174
+ end
175
+
176
+ def pwd
177
+ self.response('257 "/some/dir/" - current directory')
178
+ end
179
+
180
+ def retr(file)
181
+ self.response("125 Data transfer starting")
182
+ if @restart_at && @restart_at == 20
183
+ @datasocket.puts("of the file named '#{file}'.")
184
+ @restart_at = nil
185
+ else
186
+ @datasocket.puts("This is the content")
187
+ @datasocket.puts("of the file named '#{file}'.")
188
+ end
189
+ @datasocket.close()
190
+ self.response("226 Closing data connection. (RETR #{file})")
191
+ end
192
+
193
+ def rest(at_bytes)
194
+ @restart_at = at_bytes.to_i
195
+ self.response("350 Requested file action pending further information. (REST)")
196
+ end
197
+
198
+ def rmd(folder)
199
+ self.response("250 Requested file action okay, completed. (RMD #{folder})")
200
+ end
201
+
202
+ def rnfr(from)
203
+ @rename_from = from
204
+ self.response("350 Requested file action pending further information.")
205
+ end
206
+
207
+ def rnto(to)
208
+ self.response("250 Requested file action okay, completed. (Renamed #{@rename_from} to #{to})")
209
+ @rename_from = nil
210
+ end
211
+
212
+ def site(param)
213
+ self.response("200 Command okay. (SITE #{param})")
214
+ end
215
+
216
+ def size(filename)
217
+ if filename == "binary"
218
+ self.response("213 24")
219
+ else
220
+ self.response("213 1024")
221
+ end
222
+ end
223
+
224
+ def stat
225
+ self.response("211 System status, or system help reply. (STAT)")
226
+ end
227
+
228
+ def stor(file)
229
+ tmp_file = tmp("#{file}file", false)
230
+
231
+ self.response("125 Data transfer starting.")
232
+
233
+ mode = @restart_at ? "a" : "w"
234
+
235
+ File.open(tmp_file, mode + "b") do |f|
236
+ loop do
237
+ data = @datasocket.recv(1024)
238
+ break if !data || data.empty?
239
+ f << data
240
+ end
241
+ end
242
+
243
+ #@datasocket.close()
244
+ self.response("200 OK, Data received. (STOR #{file})")
245
+ end
246
+
247
+ def appe(file)
248
+ @restart_at = true
249
+ stor(file)
250
+ end
251
+
252
+ def syst
253
+ self.response("215 FTP Dummy Server (SYST)")
254
+ end
255
+
256
+ def type(type)
257
+ self.response("200 TYPE switched to #{type}")
258
+ end
259
+
260
+ def user(name)
261
+ @login_user = name
262
+ self.response("230 User logged in, proceed. (USER #{name})")
263
+ end
264
+ end
265
+ end
data/spec/get_spec.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'net/ftp'
2
+ require File.expand_path('../fixtures/server', __FILE__)
3
+ require File.expand_path('../shared/gettextfile', __FILE__)
4
+ require File.expand_path('../shared/getbinaryfile', __FILE__)
5
+
6
+ describe "Net::FTP#get (binary mode)" do
7
+ before(:each) do
8
+ @binary_mode = true
9
+ end
10
+
11
+ it_behaves_like :net_ftp_getbinaryfile, :get
12
+ end
13
+
14
+ describe "Net::FTP#get (text mode)" do
15
+ before(:each) do
16
+ @binary_mode = false
17
+ end
18
+
19
+ it_behaves_like :net_ftp_gettextfile, :get
20
+ end
@@ -0,0 +1,7 @@
1
+ require 'net/ftp'
2
+ require File.expand_path('../fixtures/server', __FILE__)
3
+ require File.expand_path('../shared/getbinaryfile', __FILE__)
4
+
5
+ describe "Net::FTP#getbinaryfile" do
6
+ it_behaves_like :net_ftp_getbinaryfile, :getbinaryfile
7
+ end
@@ -0,0 +1,6 @@
1
+ require 'net/ftp'
2
+ require File.expand_path('../shared/pwd', __FILE__)
3
+
4
+ describe "Net::FTP#getdir" do
5
+ it_behaves_like :net_ftp_pwd, :getdir
6
+ end
@@ -0,0 +1,7 @@
1
+ require 'net/ftp'
2
+ require File.expand_path('../fixtures/server', __FILE__)
3
+ require File.expand_path('../shared/gettextfile', __FILE__)
4
+
5
+ describe "Net::FTP#gettextfile" do
6
+ it_behaves_like :net_ftp_gettextfile, :gettextfile
7
+ end
data/spec/help_spec.rb ADDED
@@ -0,0 +1,65 @@
1
+ require 'net/ftp'
2
+ require File.expand_path('../fixtures/server', __FILE__)
3
+
4
+ describe "Net::FTP#help" do
5
+ def with_connection
6
+ yield
7
+ end
8
+
9
+ before(:each) do
10
+ @server = NetFTPSpecs::DummyFTP.new
11
+ @server.serve_once
12
+
13
+ @ftp = Net::FTP.new
14
+ @ftp.connect("localhost", 9921)
15
+ end
16
+
17
+ after(:each) do
18
+ @ftp.quit rescue nil
19
+ @ftp.close
20
+ @server.stop
21
+ end
22
+
23
+ it "writes the HELP command to the server" do
24
+ @ftp.help
25
+ @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
26
+ end
27
+
28
+ it "returns the server's response" do
29
+ @ftp.help.should == "211 System status, or system help reply. (HELP)\n"
30
+ end
31
+
32
+ it "writes the HELP command with an optional parameter to the socket" do
33
+ @ftp.help("some parameter").should == "211 System status, or system help reply. (HELP some parameter)\n"
34
+ end
35
+
36
+ it "does not raise any error when the response code is 211" do
37
+ @server.should_receive(:help).and_respond("211 System status, or system help reply.")
38
+ lambda { @ftp.help }.should_not raise_error
39
+ end
40
+
41
+ it "does not raise any error when the response code is 214" do
42
+ @server.should_receive(:help).and_respond("214 Help message.")
43
+ lambda { @ftp.help }.should_not raise_error
44
+ end
45
+
46
+ it "raises a Net::FTPPermError when the response code is 500" do
47
+ @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
48
+ lambda { @ftp.help }.should raise_error(Net::FTPPermError)
49
+ end
50
+
51
+ it "raises a Net::FTPPermError when the response code is 501" do
52
+ @server.should_receive(:help).and_respond("501 Syntax error in parameters or arguments.")
53
+ lambda { @ftp.help }.should raise_error(Net::FTPPermError)
54
+ end
55
+
56
+ it "raises a Net::FTPPermError when the response code is 502" do
57
+ @server.should_receive(:help).and_respond("502 Command not implemented.")
58
+ lambda { @ftp.help }.should raise_error(Net::FTPPermError)
59
+ end
60
+
61
+ it "raises a Net::FTPTempError when the response code is 421" do
62
+ @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
63
+ lambda { @ftp.help }.should raise_error(Net::FTPTempError)
64
+ end
65
+ end