raval 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ # coding: utf-8
2
+
3
+ module Raval
4
+ # converts a list of objects that describe the contents of a directory and
5
+ # formats them to be valid responses to the LIST or NLST FTP commands.
6
+ class ListFormatter
7
+ def initialize(files)
8
+ @files = check_duck_type(files)
9
+ end
10
+
11
+ # response to the NLST command
12
+ #
13
+ def short
14
+ @files.map(&:name)
15
+ end
16
+
17
+ # response to the LIST command
18
+ #
19
+ def detailed
20
+ now = Time.now
21
+ @files.map { |item|
22
+ directory = item.directory ? 'd' : '-'
23
+ permissions = item.permissions || 'rwxrwxrwx'
24
+ owner = item.owner || 'owner'
25
+ group = item.group || 'group'
26
+ size = (item.size || 0).to_s.rjust(12)
27
+ time = (item.time || now).strftime("%b %d %H:%M")
28
+ name = item.name || "UNKNOWN"
29
+
30
+ "#{directory}#{permissions} 1 #{owner} #{group} #{size} #{time} #{name}"
31
+ }
32
+ end
33
+
34
+ private
35
+
36
+ def check_duck_type(files)
37
+ files.each do |file|
38
+ file.respond_to?(:directory) || raise(ArgumentError, "file must respond to #directory")
39
+ file.respond_to?(:size) || raise(ArgumentError, "file must respond to #size")
40
+ file.respond_to?(:permissions) || raise(ArgumentError, "file must respond to #permissions")
41
+ file.respond_to?(:owner) || raise(ArgumentError, "file must respond to #owner")
42
+ file.respond_to?(:group) || raise(ArgumentError, "file must respond to #group")
43
+ file.respond_to?(:time) || raise(ArgumentError, "file must respond to #time")
44
+ file.respond_to?(:name) || raise(ArgumentError, "file must respond to #name")
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,86 @@
1
+ # coding: utf-8
2
+
3
+ require 'celluloid/io'
4
+
5
+ module Raval
6
+ # In passive FTP mode, the server opens a listening data socket and the client
7
+ # will connect to it.
8
+ #
9
+ # A different class is used when operating in active FTP mode. They both
10
+ # have a #read and #write method, so the quack like each other in the ways
11
+ # that matter.
12
+ class PassiveSocket
13
+ include Celluloid::IO
14
+
15
+ attr_reader :port
16
+
17
+ def initialize(host)
18
+ @host = host
19
+ @socket = nil
20
+ puts "*** Starting passive socket on #{host}"
21
+
22
+ # TODO ::TcpServer#addr exists, but Celluloid::IO::TcpServer#addr does
23
+ # not. Once that's fixed, make this port random by replacing 30000
24
+ # with 0
25
+ #@server = TCPServer.new(@host, 0)
26
+ #@port = @server.addr[1]
27
+ @port = choose_port(@host)
28
+ @server = TCPServer.new(@host, @port)
29
+ #@port = @server.addr[1]
30
+ run!
31
+ end
32
+
33
+ def run
34
+ handle_connection @server.accept
35
+ end
36
+
37
+ def read
38
+ raise "socket not connected" unless @socket
39
+ @socket.readpartial(4096)
40
+ rescue EOFError, Errno::ECONNRESET
41
+ close
42
+ nil
43
+ end
44
+
45
+ def write(data)
46
+ raise "socket not connected" unless @socket
47
+ @socket.write(data)
48
+ end
49
+
50
+ def connected?
51
+ @socket != nil
52
+ end
53
+
54
+ def close
55
+ @socket.close if @socket
56
+ @socket = nil
57
+ @server.close if @server
58
+ @server = nil
59
+ end
60
+
61
+ private
62
+
63
+ def handle_connection(socket)
64
+ @socket = socket
65
+ @server.close
66
+ @server = nil
67
+ rescue EOFError, IOError
68
+ puts "*** passive socket disconnected"
69
+ end
70
+
71
+ def choose_port(host)
72
+ candidate = 30000
73
+ while candidate < 40000
74
+ begin
75
+ server = TCPServer.new(host, candidate)
76
+ server.close
77
+ return candidate
78
+ rescue
79
+ candidate += 1
80
+ end
81
+ end
82
+ nil
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,45 @@
1
+ # coding: utf-8
2
+
3
+ require 'celluloid/io'
4
+ require 'raval/handler'
5
+ require 'raval/connection'
6
+
7
+ module Raval
8
+ # The beginning of things. Listens on a TCP socket for incoming connections
9
+ # and spins off a new agent to handle each connection.
10
+ class Server
11
+ include Celluloid::IO
12
+
13
+ def initialize(host, port, driver, driver_opts)
14
+ @driver, @driver_opts = driver, driver_opts
15
+ # Since we included Celluloid::IO, we're actually making a
16
+ # Celluloid::IO::TCPServer here
17
+ @server = TCPServer.new(host, port)
18
+ run!
19
+ rescue Errno::EACCES
20
+ $stderr.puts "Unable to listen on port #{port}"
21
+ exit
22
+ end
23
+
24
+ def finalize
25
+ @server.close if @server
26
+ end
27
+
28
+ def run
29
+ loop { handle_connection! @server.accept }
30
+ end
31
+
32
+ def handle_connection(socket)
33
+ if @driver_opts
34
+ driver = @driver.new(@driver_opts)
35
+ else
36
+ driver = @driver.new
37
+ end
38
+ handler = Handler.new(driver)
39
+ connection = Connection.new(handler, socket)
40
+ connection.read_commands
41
+ rescue EOFError, IOError
42
+ puts "*** #{connection.host}:#{connection.port} disconnected"
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,832 @@
1
+ # coding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ def handler_with_unauthenticated_user
6
+ connection = double(:connection)
7
+
8
+ handler = Raval::Handler.new(TestDriver.new)
9
+ connection.should_receive(:send_response).with(220, anything)
10
+ handler.new_connection(connection)
11
+ handler
12
+ end
13
+
14
+ def handler_with_authenticated_user
15
+ connection = double(:connection)
16
+
17
+ handler = Raval::Handler.new(TestDriver.new)
18
+ connection.should_receive(:send_response).with(220, anything)
19
+ handler.new_connection(connection)
20
+ connection.should_receive(:send_response).with(331, anything).and_return(331)
21
+ connection.should_receive(:send_response).with(230, anything).and_return(230)
22
+ handler.receive_line("USER test")
23
+ handler.receive_line("PASS 1234")
24
+ handler
25
+ end
26
+
27
+ describe Raval::Handler, "#new_connection" do
28
+
29
+ let(:connection) { double(:connection) }
30
+
31
+ subject {
32
+ Raval::Handler.new(TestDriver.new)
33
+ }
34
+
35
+ it "should default to a root name_prefix" do
36
+ connection.should_receive(:send_response).with(220, anything)
37
+ subject.new_connection(connection)
38
+ subject.name_prefix.should eql("/")
39
+ end
40
+
41
+ it "should respond with 220 when connection is opened" do
42
+ connection.should_receive(:send_response).with(220, anything)
43
+ subject.new_connection(connection)
44
+ end
45
+ end
46
+
47
+ describe Raval::Handler, "ALLO" do
48
+ context "with an unauthenticated user" do
49
+ subject { handler_with_unauthenticated_user }
50
+
51
+ it "should always respond with 202 when called" do
52
+ subject.connection.should_receive(:send_response).with(202, anything)
53
+ subject.receive_line("ALLO")
54
+ end
55
+ end
56
+ end
57
+
58
+ describe Raval::Handler, "USER" do
59
+ context "with an unauthenticated user" do
60
+
61
+ subject { handler_with_unauthenticated_user }
62
+
63
+ it "should respond with 331 when called by non-logged in user" do
64
+ subject.connection.should_receive(:send_response).with(331, anything)
65
+ subject.receive_line("USER jh")
66
+ end
67
+
68
+ it "should respond with 500 when called by a logged in user" do
69
+ subject.connection.should_receive(:send_response).with(331, anything).and_return(331)
70
+ subject.connection.should_receive(:send_response).with(230, anything).and_return(230)
71
+ subject.connection.should_receive(:send_response).with(500, anything).and_return(500)
72
+ subject.receive_line("USER test")
73
+ subject.receive_line("PASS 1234")
74
+ subject.receive_line("USER test")
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ describe Raval::Handler, "PASS" do
81
+ context "with an unauthenticated user" do
82
+ subject { handler_with_unauthenticated_user }
83
+
84
+ it "should respond with 202 when called by logged in user" do
85
+ subject.connection.should_receive(:send_response).with(331, anything).and_return(331)
86
+ subject.connection.should_receive(:send_response).with(230, anything).and_return(230)
87
+ subject.connection.should_receive(:send_response).with(202, anything).and_return(202)
88
+ subject.receive_line("USER test")
89
+ subject.receive_line("PASS 1234")
90
+ subject.receive_line("PASS 1234")
91
+ end
92
+
93
+ it "should respond with 553 when called with no param" do
94
+ subject.connection.should_receive(:send_response).with(331, anything).and_return(331)
95
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
96
+ subject.receive_line("USER test")
97
+ subject.receive_line("PASS")
98
+ end
99
+
100
+ it "should respond with 530 when called without first providing a username" do
101
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
102
+ subject.receive_line("PASS 1234")
103
+ end
104
+
105
+ it "should respond with 230 when user is authenticated" do
106
+ subject.connection.should_receive(:send_response).with(331, anything).and_return(331)
107
+ subject.connection.should_receive(:send_response).with(230, anything).and_return(230)
108
+ subject.receive_line("USER test")
109
+ subject.receive_line("PASS 1234")
110
+ end
111
+
112
+ it "should respond with 530 when password is incorrect" do
113
+ subject.connection.should_receive(:send_response).with(331, anything).and_return(331)
114
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
115
+ subject.receive_line("USER test")
116
+ subject.receive_line("PASS 1235")
117
+ end
118
+ end
119
+ end
120
+
121
+ %w(CDUP XCUP).each do |command|
122
+
123
+ describe Raval::Handler, command do
124
+ context "with an unauthenticated user" do
125
+ subject { handler_with_unauthenticated_user }
126
+
127
+ it "should respond with 530 if user is not logged in" do
128
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
129
+ subject.receive_line(command)
130
+ subject.name_prefix.should eql("/")
131
+ end
132
+ end
133
+ context "with an authenticated user" do
134
+ subject { handler_with_authenticated_user }
135
+
136
+ it "should respond with 250 if called from root dir" do
137
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
138
+ subject.receive_line(command)
139
+ subject.name_prefix.should eql("/")
140
+ end
141
+
142
+ it "should respond with 250 if called from inside a dir" do
143
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
144
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
145
+ subject.receive_line("CWD files")
146
+ subject.receive_line(command)
147
+ subject.name_prefix.should eql("/")
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+ describe Raval::Handler, "CWD" do
154
+ context "with an unauthenticated user" do
155
+ subject { handler_with_unauthenticated_user }
156
+
157
+ it "should respond with 530 if user is not logged in" do
158
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
159
+ subject.receive_line("CWD")
160
+ end
161
+ end
162
+
163
+ context "with an authenticated user" do
164
+ subject { handler_with_authenticated_user }
165
+
166
+ it "should respond with 250 if called with '..' from users home" do
167
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
168
+ subject.receive_line("CWD ..")
169
+ subject.name_prefix.should eql("/")
170
+ end
171
+
172
+ it "should respond with 250 if called with '.' from users home" do
173
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
174
+ subject.receive_line("CWD .")
175
+ subject.name_prefix.should eql("/")
176
+ end
177
+
178
+ it "should respond with 250 if called with '/' from users home" do
179
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
180
+ subject.receive_line("CWD /")
181
+ subject.name_prefix.should eql("/")
182
+ end
183
+
184
+ it "should respond with 250 if called with 'files' from users home" do
185
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
186
+ subject.receive_line("CWD files")
187
+ subject.name_prefix.should eql("/files")
188
+ end
189
+
190
+ it "should respond with 250 if called with 'files/' from users home" do
191
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
192
+ subject.receive_line("CWD files/")
193
+ subject.name_prefix.should eql("/files")
194
+ end
195
+
196
+ it "should respond with 250 if called with '/files/' from users home" do
197
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
198
+ subject.receive_line("CWD /files/")
199
+ subject.name_prefix.should eql("/files")
200
+ end
201
+
202
+ it "should respond with 250 if called with '..' from the files dir" do
203
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
204
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
205
+ subject.receive_line("CWD files")
206
+ subject.name_prefix.should eql("/files")
207
+ subject.receive_line("CWD ..")
208
+ subject.name_prefix.should eql("/")
209
+ end
210
+
211
+ it "should respond with 250 if called with '/files' from the files dir" do
212
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
213
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
214
+ subject.receive_line("CWD files")
215
+ subject.name_prefix.should eql("/files")
216
+ subject.receive_line("CWD /files")
217
+ subject.name_prefix.should eql("/files")
218
+ end
219
+
220
+ it "should respond with 550 if called with unrecognised dir" do
221
+ subject.connection.should_receive(:send_response).with(550, anything).and_return(550)
222
+ subject.receive_line("CWD test")
223
+ subject.name_prefix.should eql("/")
224
+ end
225
+ end
226
+ end
227
+
228
+ describe Raval::Handler, "DELE" do
229
+ context "with an unauthenticated user" do
230
+ subject { handler_with_unauthenticated_user }
231
+
232
+ it "should respond with 530" do
233
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
234
+ subject.receive_line("DELE x")
235
+ end
236
+ end
237
+
238
+ context "with an authenticated user" do
239
+ subject { handler_with_authenticated_user }
240
+
241
+ it "should respond with 553 when the paramater is omitted" do
242
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
243
+ subject.receive_line("DELE")
244
+ end
245
+
246
+ it "should respond with 250 when the file is deleted" do
247
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
248
+ subject.receive_line("DELE four.txt")
249
+ end
250
+
251
+ it "should respond with 550 when the file is not deleted" do
252
+ subject.connection.should_receive(:send_response).with(550, anything).and_return(550)
253
+ subject.receive_line("DELE one.txt")
254
+ end
255
+ end
256
+ end
257
+
258
+ describe Raval::Handler, "HELP" do
259
+ context "with an unauthenticated user" do
260
+ subject { handler_with_unauthenticated_user }
261
+ it "should always respond with 214 when called" do
262
+ subject.connection.should_receive(:send_response).with("214-", anything).and_return("214-")
263
+ subject.connection.should_receive(:send_response)
264
+ subject.connection.should_receive(:send_response).with(214, anything).and_return(214)
265
+ subject.receive_line("HELP")
266
+ end
267
+ end
268
+ end
269
+
270
+ describe Raval::Handler, "NLST" do
271
+ context "with an unauthenticated user" do
272
+ subject { handler_with_unauthenticated_user }
273
+ it "should respond with 530" do
274
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
275
+ subject.receive_line("NLST")
276
+ end
277
+ end
278
+
279
+ context "with an authenticated user" do
280
+ subject { handler_with_authenticated_user }
281
+
282
+ it "should respond with 150 ...425 when called with no data socket"
283
+
284
+ it "should respond with 150 ... 226 when called in the root dir with no param"
285
+
286
+ it "should respond with 150 ... 226 when called in the files dir with no param"
287
+
288
+ it "should respond with 150 ... 226 when called in the files dir with wildcard (LIST *.txt)"
289
+
290
+ it "should respond with 150 ... 226 when called in the subdir with .. param"
291
+
292
+ it "should respond with 150 ... 226 when called in the subdir with / param"
293
+
294
+ it "should respond with 150 ... 226 when called in the root with files param"
295
+
296
+ it "should respond with 150 ... 226 when called in the root with files/ param"
297
+
298
+ it "should properly list subdirs etc."
299
+ end
300
+ end
301
+
302
+ describe Raval::Handler, "LIST" do
303
+ context "with an unauthenticated user" do
304
+ subject { handler_with_unauthenticated_user }
305
+ it "should respond with 530" do
306
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
307
+ subject.receive_line("LIST")
308
+ end
309
+ end
310
+
311
+ context "with an authenticated user" do
312
+ subject { handler_with_authenticated_user }
313
+
314
+ it "should respond with 150 ...425 when called with no data socket"
315
+
316
+ it "should respond with 150 ... 226 when called in the root dir with no param"
317
+
318
+ it "should respond with 150 ... 226 when called in the files dir with no param"
319
+
320
+ it "should respond with 150 ... 226 when called in the files dir with wildcard (LIST *.txt)"
321
+
322
+ it "should respond with 150 ... 226 when called in the subdir with .. param"
323
+
324
+ it "should respond with 150 ... 226 when called in the subdir with / param"
325
+
326
+ it "should respond with 150 ... 226 when called in the root with files param"
327
+
328
+ it "should respond with 150 ... 226 when called in the root with files/ param"
329
+
330
+ it "should properly list subdirs etc."
331
+ end
332
+ end
333
+
334
+ describe Raval::Handler, "MKD" do
335
+ context "with an unauthenticated user" do
336
+ subject { handler_with_unauthenticated_user }
337
+
338
+ it "should respond with 530 if user is not logged in" do
339
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
340
+ subject.receive_line("MKD x")
341
+ end
342
+ end
343
+
344
+ context "with an authenticated user" do
345
+ subject { handler_with_authenticated_user }
346
+ it "should respond with 553 when the paramater is omitted" do
347
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
348
+ subject.receive_line("MKD")
349
+ end
350
+
351
+ it "should respond with 257 when the directory is created" do
352
+ subject.connection.should_receive(:send_response).with(257, anything).and_return(257)
353
+ subject.receive_line("MKD four")
354
+ end
355
+
356
+ it "should respond with 550 when the directory is not created" do
357
+ subject.connection.should_receive(:send_response).with(550, anything).and_return(550)
358
+ subject.receive_line("MKD five")
359
+ end
360
+ end
361
+ end
362
+
363
+ describe Raval::Handler, "MODE" do
364
+ context "with an unauthenticated user" do
365
+ subject { handler_with_unauthenticated_user }
366
+
367
+ it "should always respond with 530 when called by user not logged in" do
368
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
369
+ subject.receive_line("MODE S")
370
+ end
371
+ end
372
+ context "with an authenticated user" do
373
+ subject { handler_with_authenticated_user }
374
+ it "should respond with 553 when called with no param" do
375
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
376
+ subject.receive_line("MODE")
377
+ end
378
+
379
+ it "should always respond with 200 when called with S param" do
380
+ subject.connection.should_receive(:send_response).with(200, anything).and_return(200)
381
+ subject.receive_line("MODE S")
382
+ end
383
+
384
+ it "should always respond with 504 when called with non-S param" do
385
+ subject.connection.should_receive(:send_response).with(504, anything).and_return(504)
386
+ subject.receive_line("MODE F")
387
+ end
388
+ end
389
+ end
390
+
391
+ describe Raval::Handler, "NOOP" do
392
+ context "with an unauthenticated user" do
393
+ subject { handler_with_unauthenticated_user }
394
+
395
+ it "should always respond with 200" do
396
+ subject.connection.should_receive(:send_response).with(200, anything).and_return(200)
397
+ subject.receive_line("NOOP")
398
+ end
399
+ end
400
+ end
401
+
402
+ describe Raval::Handler, "PASV" do
403
+ context "with an unauthenticated user" do
404
+ subject { handler_with_unauthenticated_user }
405
+
406
+ it "should always respond with 530 when called by user not logged in" do
407
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
408
+ subject.receive_line("PASV")
409
+ end
410
+ end
411
+ context "with an authenticated user" do
412
+ subject { handler_with_authenticated_user }
413
+
414
+ it "should always respond with 227 after opening the new socket"
415
+ end
416
+ end
417
+
418
+ describe Raval::Handler, "EPSV" do
419
+ context "with an unauthenticated user" do
420
+ subject { handler_with_unauthenticated_user }
421
+
422
+ it "should always respond with 530 when called by user not logged in" do
423
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
424
+ subject.receive_line("EPSV")
425
+ end
426
+ end
427
+ context "with an authenticated user" do
428
+ subject { handler_with_authenticated_user }
429
+
430
+ it "should always respond with 229 after opening the new socket"
431
+ end
432
+ end
433
+
434
+ describe Raval::Handler, "PORT" do
435
+ context "with an unauthenticated user" do
436
+ subject { handler_with_unauthenticated_user }
437
+
438
+ it "should always respond with 530 when called by user not logged in" do
439
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
440
+ subject.receive_line("PORT 127,0,0,1,128,12")
441
+ end
442
+ end
443
+ context "with an authenticated user" do
444
+ subject { handler_with_authenticated_user }
445
+
446
+ it "should always respond with 200 after opening the new socket"
447
+ end
448
+ end
449
+
450
+ describe Raval::Handler, "EPRT" do
451
+ context "with an unauthenticated user" do
452
+ subject { handler_with_unauthenticated_user }
453
+
454
+ it "should always respond with 530 when called by user not logged in" do
455
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
456
+ subject.receive_line("EPRT -1-127.0.0.1-32000")
457
+ end
458
+ end
459
+ context "with an authenticated user" do
460
+ subject { handler_with_authenticated_user }
461
+
462
+ it "should always respond with 200 after opening the new socket"
463
+ end
464
+ end
465
+
466
+ %w(PWD XPWD).each do |command|
467
+ describe Raval::Handler, command do
468
+ context "with an unauthenticated user" do
469
+ subject { handler_with_unauthenticated_user }
470
+
471
+ it "should always respond with 550 (permission denied)" do
472
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
473
+ subject.receive_line(command)
474
+ end
475
+ end
476
+
477
+ context "with an authenticated user" do
478
+ subject { handler_with_authenticated_user }
479
+ it 'should always respond with 257 "/" when called from root dir' do
480
+ subject.connection.should_receive(:send_response).with(257, '"/" is the current directory')
481
+ subject.receive_line(command)
482
+ end
483
+
484
+ it 'should always respond with 257 "/files" when called from files dir' do
485
+ connection = subject.connection
486
+ connection.should_receive(:send_response).with(250, anything).and_return(250)
487
+ connection.should_receive(:send_response).with(257, '"/files" is the current directory')
488
+ subject.receive_line("CWD files")
489
+ subject.receive_line(command)
490
+ end
491
+ end
492
+ end
493
+ end
494
+
495
+ describe Raval::Handler, "RETR" do
496
+ context "with an unauthenticated user" do
497
+ subject { handler_with_unauthenticated_user }
498
+
499
+ it "should always respond with 530 when called by user not logged in" do
500
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
501
+ subject.receive_line("RETR blah.txt")
502
+ end
503
+ end
504
+ context "with an authenticated user" do
505
+ subject { handler_with_authenticated_user }
506
+
507
+ it "should respond with 553 when called with no param" do
508
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
509
+ subject.receive_line("RETR")
510
+ end
511
+
512
+ it "should always respond with 551 when called with an invalid file" do
513
+ pending
514
+ subject.receive_line("PASV")
515
+ subject.reset_sent!
516
+ subject.receive_line("RETR blah.txt")
517
+ subject.sent_data.should match(/551.+/)
518
+ end
519
+
520
+ it "should always respond with 150..226 when called with valid file" do
521
+ pending
522
+ subject.receive_line("PASV")
523
+ subject.reset_sent!
524
+ subject.receive_line("RETR one.txt")
525
+ subject.sent_data.should match(/150.+226.+/m)
526
+ end
527
+
528
+ it "should always respond with 150..226 when called outside files dir with appropriate param" do
529
+ pending
530
+ subject.receive_line("PASV")
531
+ subject.receive_line("RETR files/two.txt")
532
+ subject.sent_data.should match(/150.+226.+/m)
533
+ end
534
+ end
535
+ end
536
+
537
+ describe Raval::Handler, "REST" do
538
+ context "with an authenticated user" do
539
+ subject { handler_with_authenticated_user }
540
+
541
+ it "should always respond with 500" do
542
+ subject.connection.should_receive(:send_response).with(500, anything).and_return(500)
543
+ subject.receive_line("REST")
544
+ end
545
+ end
546
+ end
547
+
548
+ %w(RMD XRMD).each do |command|
549
+ describe Raval::Handler, command do
550
+ context "with an unauthenticated user" do
551
+ subject { handler_with_unauthenticated_user }
552
+
553
+ it "should respond with 530 if user is not logged in" do
554
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
555
+ subject.receive_line("#{command} x")
556
+ end
557
+ end
558
+ context "with an authenticated user" do
559
+ subject { handler_with_authenticated_user }
560
+
561
+ it "should respond with 553 when the paramater is omitted" do
562
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
563
+ subject.receive_line("#{command}")
564
+ end
565
+
566
+ it "should respond with 250 when the directory is deleted" do
567
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
568
+ subject.receive_line("#{command} four")
569
+ end
570
+
571
+ it "should respond with 550 when the directory is not deleted" do
572
+ subject.connection.should_receive(:send_response).with(550, anything).and_return(550)
573
+ subject.receive_line("#{command} x")
574
+ end
575
+ end
576
+ end
577
+ end
578
+
579
+ describe Raval::Handler, "RNFR" do
580
+ context "with an unauthenticated user" do
581
+ subject { handler_with_unauthenticated_user }
582
+
583
+ it "should respond with 530" do
584
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
585
+ subject.receive_line("RNFR x")
586
+ end
587
+ end
588
+ context "with an authenticated user" do
589
+ subject { handler_with_authenticated_user }
590
+
591
+ it "should respond with 553 when the paramater is omitted" do
592
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
593
+ subject.receive_line("RNFR")
594
+ end
595
+
596
+ it "should always respond with 350 when called" do
597
+ subject.connection.should_receive(:send_response).with(350, anything).and_return(350)
598
+ subject.receive_line("RNFR x")
599
+ end
600
+ end
601
+ end
602
+
603
+ describe Raval::Handler, "RNTO" do
604
+ context "with an unauthenticated user" do
605
+ subject { handler_with_unauthenticated_user }
606
+
607
+ it "should respond with 530" do
608
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
609
+ subject.receive_line("RNTO x")
610
+ end
611
+ end
612
+ context "with an authenticated user" do
613
+ subject { handler_with_authenticated_user }
614
+ it "should respond with 553 when the paramater is omitted" do
615
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
616
+ subject.receive_line("RNTO")
617
+ end
618
+
619
+ it "should respond with XXX when the RNFR command is omitted"
620
+
621
+ it "should respond with 250 when the file is renamed" do
622
+ subject.connection.should_receive(:send_response).with(350, anything).and_return(350)
623
+ subject.connection.should_receive(:send_response).with(250, anything).and_return(250)
624
+ subject.receive_line("RNFR one.txt")
625
+ subject.receive_line("RNTO two.txt")
626
+ end
627
+
628
+ it "should respond with 550 when the file is not renamed" do
629
+ subject.connection.should_receive(:send_response).with(350, anything).and_return(350)
630
+ subject.connection.should_receive(:send_response).with(550, anything).and_return(550)
631
+ subject.receive_line("RNFR two.txt")
632
+ subject.receive_line("RNTO one.txt")
633
+ end
634
+ end
635
+ end
636
+
637
+ describe Raval::Handler, "QUIT" do
638
+ context "with an unauthenticated user" do
639
+ subject { handler_with_unauthenticated_user }
640
+
641
+ it "should always respond with 221 when called" do
642
+ subject.connection.should_receive(:close)
643
+ subject.connection.should_receive(:send_response).with(221, anything).and_return(221)
644
+ subject.receive_line("QUIT")
645
+ end
646
+ end
647
+ end
648
+
649
+ describe Raval::Handler, "SIZE" do
650
+
651
+ context "with an unauthenticated user" do
652
+ subject { handler_with_unauthenticated_user }
653
+
654
+ it "should always respond with 530" do
655
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
656
+ subject.receive_line("SIZE one.txt")
657
+ end
658
+ end
659
+
660
+ context "with an authenticated user" do
661
+ subject { handler_with_authenticated_user }
662
+ it "should always respond with 553 when called with no param" do
663
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
664
+ subject.receive_line("SIZE")
665
+ end
666
+
667
+ it "should always respond with 450 when called with a directory param" do
668
+ subject.connection.should_receive(:send_response).with(450, anything).and_return(450)
669
+ subject.receive_line("SIZE files")
670
+ end
671
+
672
+ it "should always respond with 450 when called with a non-file param" do
673
+ subject.connection.should_receive(:send_response).with(450, anything).and_return(450)
674
+ subject.receive_line("SIZE blah")
675
+ end
676
+
677
+ it "should always respond with 213 when called with a valid file param" do
678
+ subject.connection.should_receive(:send_response).with(213, 56).and_return(213)
679
+ subject.receive_line("SIZE one.txt")
680
+ end
681
+
682
+ it "should always respond with 213 when called with a valid file param" do
683
+ subject.connection.should_receive(:send_response).with(213, 40).and_return(213)
684
+ subject.receive_line("SIZE files/two.txt")
685
+ end
686
+ end
687
+ end
688
+
689
+ describe Raval::Handler, "MDTM" do
690
+
691
+ context "with an unauthenticated user" do
692
+ subject { handler_with_unauthenticated_user }
693
+
694
+ it "should always respond with 530" do
695
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
696
+ subject.receive_line("MDTM one.txt")
697
+ end
698
+ end
699
+
700
+ context "with an authenticated user" do
701
+ subject { handler_with_authenticated_user }
702
+ it "should always respond with 553 when called with no param" do
703
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
704
+ subject.receive_line("MDTM")
705
+ end
706
+
707
+ it "should always respond with 450 when called with a directory param" do
708
+ subject.connection.should_receive(:send_response).with(450, anything).and_return(450)
709
+ subject.receive_line("MDTM files")
710
+ end
711
+
712
+ it "should always respond with 450 when called with a non-file param" do
713
+ subject.connection.should_receive(:send_response).with(450, anything).and_return(450)
714
+ subject.receive_line("MDTM blah")
715
+ end
716
+
717
+ it "should always respond with 213 when called with a valid file param" do
718
+ subject.connection.should_receive(:send_response).with(213, "20121010101000").and_return(213)
719
+ subject.receive_line("MDTM one.txt")
720
+ end
721
+
722
+ it "should always respond with 213 when called with a valid file param" do
723
+ subject.connection.should_receive(:send_response).with(213, "20121111111100").and_return(213)
724
+ subject.receive_line("MDTM files/two.txt")
725
+ end
726
+ end
727
+ end
728
+
729
+ describe Raval::Handler, "STOR" do
730
+ context "with an unauthenticated user" do
731
+ subject { handler_with_unauthenticated_user }
732
+
733
+ it "should always respond with 530 when called by user not logged in" do
734
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
735
+ subject.receive_line("STOR blah.txt")
736
+ end
737
+ end
738
+ context "with an authenticated user" do
739
+ subject { handler_with_authenticated_user }
740
+
741
+ it "should respond with 553 when called with no param" do
742
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
743
+ subject.receive_line("STOR")
744
+ end
745
+
746
+ it "should respond with 150...206 after a successful transfer"
747
+ end
748
+ end
749
+
750
+ describe Raval::Handler, "STRU" do
751
+ context "with an unauthenticated user" do
752
+ subject { handler_with_unauthenticated_user }
753
+
754
+ it "should always respond with 530" do
755
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
756
+ subject.receive_line("STRU F")
757
+ end
758
+ end
759
+
760
+ context "with an authenticated user" do
761
+ subject { handler_with_authenticated_user }
762
+ it "should respond with 553 when called with no param" do
763
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
764
+ subject.receive_line("STRU")
765
+ end
766
+
767
+ it "should always respond with 200 when called with F param" do
768
+ subject.connection.should_receive(:send_response).with(200, anything).and_return(200)
769
+ subject.receive_line("STRU F")
770
+ end
771
+
772
+ it "should always respond with 504 when called with non-F param" do
773
+ subject.connection.should_receive(:send_response).with(504, anything).and_return(504)
774
+ subject.receive_line("STRU S")
775
+ end
776
+ end
777
+ end
778
+
779
+ describe Raval::Handler, "SYST" do
780
+ context "with an unauthenticated user" do
781
+ subject { handler_with_unauthenticated_user }
782
+
783
+ it "should always respond with 530" do
784
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
785
+ subject.receive_line("SYST")
786
+ end
787
+ end
788
+
789
+ context "with an authenticated user" do
790
+ subject { handler_with_authenticated_user }
791
+
792
+ it "should respond with 215 when called by a logged in user" do
793
+ subject.connection.should_receive(:send_response).with(215, "UNIX Type: L8").and_return(215)
794
+ subject.receive_line("SYST")
795
+ end
796
+ end
797
+ end
798
+
799
+ describe Raval::Handler, "TYPE" do
800
+ context "with an unauthenticated user" do
801
+ subject { handler_with_unauthenticated_user }
802
+
803
+ it "should always respond with 530" do
804
+ subject.connection.should_receive(:send_response).with(530, anything).and_return(530)
805
+ subject.receive_line("TYPE A")
806
+ end
807
+ end
808
+
809
+ context "with an authenticated user" do
810
+ subject { handler_with_authenticated_user }
811
+
812
+ it "should respond with 553 when called with no param" do
813
+ subject.connection.should_receive(:send_response).with(553, anything).and_return(553)
814
+ subject.receive_line("TYPE")
815
+ end
816
+
817
+ it "should respond with 200 when called with 'A' by a logged in user" do
818
+ subject.connection.should_receive(:send_response).with(200, /ASCII/).and_return(200)
819
+ subject.receive_line("TYPE A")
820
+ end
821
+
822
+ it "should respond with 200 when called with 'I' by a logged in user" do
823
+ subject.connection.should_receive(:send_response).with(200, /binary/).and_return(200)
824
+ subject.receive_line("TYPE I")
825
+ end
826
+
827
+ it "should respond with 500 when called by a logged in user with un unrecognised param" do
828
+ subject.connection.should_receive(:send_response).with(500, anything).and_return(500)
829
+ subject.receive_line("TYPE T")
830
+ end
831
+ end
832
+ end