ftpd 0.0.1.pre → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ftpd might be problematic. Click here for more details.

Files changed (70) hide show
  1. data/Gemfile +3 -1
  2. data/Gemfile.lock +14 -14
  3. data/README.md +71 -23
  4. data/Rakefile +9 -3
  5. data/VERSION +1 -1
  6. data/examples/example.rb +132 -53
  7. data/examples/hello_world.rb +32 -0
  8. data/features/example/example.feature +18 -0
  9. data/features/example/step_definitions/example_server.rb +3 -0
  10. data/features/{command_errors.feature → ftp_server/command_errors.feature} +3 -0
  11. data/features/ftp_server/concurrent_sessions.feature +14 -0
  12. data/features/ftp_server/debug.feature +15 -0
  13. data/features/{delete.feature → ftp_server/delete.feature} +23 -2
  14. data/features/{directory_navigation.feature → ftp_server/directory_navigation.feature} +17 -4
  15. data/features/ftp_server/file_structure.feature +43 -0
  16. data/features/{get.feature → ftp_server/get.feature} +21 -10
  17. data/features/ftp_server/get_tls.feature +18 -0
  18. data/features/{list.feature → ftp_server/list.feature} +24 -30
  19. data/features/ftp_server/list_tls.feature +21 -0
  20. data/features/{login.feature → ftp_server/login.feature} +4 -2
  21. data/features/ftp_server/mode.feature +43 -0
  22. data/features/{name_list.feature → ftp_server/name_list.feature} +25 -31
  23. data/features/ftp_server/name_list_tls.feature +22 -0
  24. data/features/{noop.feature → ftp_server/noop.feature} +3 -0
  25. data/features/{port.feature → ftp_server/port.feature} +3 -0
  26. data/features/{put.feature → ftp_server/put.feature} +19 -11
  27. data/features/ftp_server/put_tls.feature +18 -0
  28. data/features/{quit.feature → ftp_server/quit.feature} +3 -0
  29. data/features/ftp_server/step_definitions/debug.rb +8 -0
  30. data/features/ftp_server/step_definitions/test_server.rb +12 -0
  31. data/features/{syntax_errors.feature → ftp_server/syntax_errors.feature} +3 -0
  32. data/features/ftp_server/type.feature +56 -0
  33. data/features/step_definitions/error.rb +10 -3
  34. data/features/step_definitions/list.rb +21 -4
  35. data/features/step_definitions/login.rb +0 -2
  36. data/features/step_definitions/server_files.rb +4 -0
  37. data/features/step_definitions/stop_server.rb +3 -0
  38. data/features/support/example_server.rb +58 -0
  39. data/features/support/test_client.rb +1 -1
  40. data/features/support/test_server.rb +106 -24
  41. data/features/support/test_server_files.rb +30 -0
  42. data/ftpd.gemspec +56 -25
  43. data/lib/ftpd.rb +22 -4
  44. data/lib/ftpd/disk_file_system.rb +137 -0
  45. data/lib/ftpd/error.rb +9 -0
  46. data/lib/ftpd/exception_translator.rb +29 -0
  47. data/lib/ftpd/exceptions.rb +13 -0
  48. data/lib/ftpd/file_system_error_translator.rb +21 -0
  49. data/lib/ftpd/ftp_server.rb +8 -645
  50. data/lib/ftpd/insecure_certificate.rb +10 -0
  51. data/lib/ftpd/server.rb +15 -12
  52. data/lib/ftpd/session.rb +569 -0
  53. data/lib/ftpd/temp_dir.rb +10 -11
  54. data/lib/ftpd/tls_server.rb +27 -15
  55. data/lib/ftpd/translate_exceptions.rb +44 -0
  56. data/rake_tasks/cucumber.rake +4 -2
  57. data/rake_tasks/default.rake +1 -0
  58. data/rake_tasks/spec.rake +3 -0
  59. data/rake_tasks/test.rake +2 -0
  60. data/sandbox/em-server.rb +37 -0
  61. data/spec/disk_file_system_spec.rb +239 -0
  62. data/spec/exception_translator_spec.rb +35 -0
  63. data/spec/spec_helper.rb +5 -0
  64. data/spec/translate_exceptions_spec.rb +40 -0
  65. metadata +143 -115
  66. data/features/concurrent_sessions.feature +0 -11
  67. data/features/file_structure.feature +0 -40
  68. data/features/mode.feature +0 -40
  69. data/features/step_definitions/server.rb +0 -7
  70. data/features/type.feature +0 -53
@@ -4,74 +4,68 @@ Feature: Name List
4
4
  I want to list file names
5
5
  So that I can see what file to transfer
6
6
 
7
- Scenario: List implicit
7
+ Background:
8
+ Given the test server is started
9
+
10
+ Scenario: Implicit
8
11
  Given a successful login
9
12
  And the server has file "foo"
10
13
  And the server has file "bar"
11
- When the client name lists the directory
14
+ When the client successfully name-lists the directory
12
15
  Then the file list should be in short form
13
16
  And the file list should contain "foo"
14
17
  And the file list should contain "bar"
15
18
 
16
- Scenario: List root
19
+ Scenario: Root
17
20
  Given a successful login
18
21
  And the server has file "foo"
19
22
  And the server has file "bar"
20
- When the client name lists the directory "/"
23
+ When the client successfully name-lists the directory "/"
21
24
  Then the file list should be in short form
22
25
  And the file list should contain "foo"
23
26
  And the file list should contain "bar"
24
27
 
25
- Scenario: List subdir
28
+ Scenario: Parent of root
26
29
  Given a successful login
27
- And the server has file "subdir/foo"
28
- When the client name lists the directory "subdir"
30
+ And the server has file "foo"
31
+ And the server has file "bar"
32
+ When the client successfully name-lists the directory "/.."
29
33
  Then the file list should be in short form
30
34
  And the file list should contain "foo"
35
+ And the file list should contain "bar"
31
36
 
32
- Scenario: List glob
37
+ Scenario: Subdir
33
38
  Given a successful login
34
- And the server has file "foo"
35
- And the server has file "bar"
36
- When the client name lists the directory "f*"
39
+ And the server has file "subdir/foo"
40
+ When the client successfully name-lists the directory "subdir"
37
41
  Then the file list should be in short form
38
42
  And the file list should contain "foo"
39
- And the file list should not contain "bar"
40
43
 
41
- Scenario: Passive
44
+ Scenario: Glob
42
45
  Given a successful login
43
46
  And the server has file "foo"
44
47
  And the server has file "bar"
45
- And the client is in passive mode
46
- When the client name lists the directory
48
+ When the client successfully name-lists the directory "f*"
47
49
  Then the file list should be in short form
48
50
  And the file list should contain "foo"
49
- And the file list should contain "bar"
50
-
51
- Scenario: TLS
52
- pending "TLS not supported in active mode (see README)"
51
+ And the file list should not contain "bar"
53
52
 
54
- Scenario: TLS, Passive
55
- Given a successful login with TLS
53
+ Scenario: Passive
54
+ Given a successful login
56
55
  And the server has file "foo"
57
56
  And the server has file "bar"
58
57
  And the client is in passive mode
59
- When the client name lists the directory
58
+ When the client successfully name-lists the directory
60
59
  Then the file list should be in short form
61
60
  And the file list should contain "foo"
62
61
  And the file list should contain "bar"
63
62
 
64
- Scenario: Path outside tree
65
- Given a successful login
66
- When the client name lists the directory ".."
67
- Then the server returns an access denied error
68
-
69
- Scenario: Missing file
63
+ Scenario: Missing directory
70
64
  Given a successful login
71
- When the client name lists the directory "missing/file"
72
- Then the server returns a no such file error
65
+ When the client successfully name-lists the directory "missing/file"
66
+ Then the file list should be empty
73
67
 
74
68
  Scenario: Not logged in
75
69
  Given a successful connection
76
- When the client name lists the directory
70
+ When the client name-lists the directory
77
71
  Then the server returns a not logged in error
@@ -0,0 +1,22 @@
1
+ Feature: Name List TLS
2
+
3
+ As a client
4
+ I want to securely list file names
5
+ So that I can see what file to transfer
6
+ And nobody else can
7
+
8
+ Background:
9
+ Given the test server is started with TLS
10
+
11
+ Scenario: TLS
12
+ pending "TLS not supported in active mode (see README)"
13
+
14
+ Scenario: TLS, Passive
15
+ Given a successful login with TLS
16
+ And the server has file "foo"
17
+ And the server has file "bar"
18
+ And the client is in passive mode
19
+ When the client successfully name-lists the directory
20
+ Then the file list should be in short form
21
+ And the file list should contain "foo"
22
+ And the file list should contain "bar"
@@ -4,6 +4,9 @@ Feature: No Operation
4
4
  I want to keep the connection alive
5
5
  So that I don't have to log in so often
6
6
 
7
+ Background:
8
+ Given the test server is started
9
+
7
10
  Scenario: NOP
8
11
  Given a successful connection
9
12
  Then the client successfully does nothing
@@ -4,6 +4,9 @@ Feature: Port
4
4
  I want good error messages
5
5
  So that I can correct problems
6
6
 
7
+ Background:
8
+ Given the test server is started
9
+
7
10
  Scenario: Not logged in
8
11
  Given a successful connection
9
12
  When the client sends PORT "1,2,3,4,5,6"
@@ -1,8 +1,12 @@
1
1
  Feature: Put
2
2
 
3
3
  As a client
4
- I want to put a file
4
+ I want to securely put a file
5
5
  So that someone else can have it
6
+ But nobody else can
7
+
8
+ Background:
9
+ Given the test server is started
6
10
 
7
11
  Scenario: ASCII file with *nix line endings
8
12
  Given a successful login
@@ -31,20 +35,18 @@ Feature: Put
31
35
  When the client successfully puts text "ascii_unix"
32
36
  Then the remote file "ascii_unix" should match the local file
33
37
 
34
- Scenario: TLS
35
- pending "TLS not supported in active mode (see README)"
36
-
37
- Scenario: TLS, Passive
38
- Given a successful login with TLS
38
+ Scenario: Non-root working directory
39
+ Given a successful login
39
40
  And the client has file "ascii_unix"
40
- And the client is in passive mode
41
+ And the server has directory "foo"
42
+ And the client successfully cd's to "foo"
41
43
  When the client successfully puts text "ascii_unix"
42
- Then the remote file "ascii_unix" should match the local file
44
+ Then the remote file "foo/ascii_unix" should match the local file
43
45
 
44
- Scenario: Path outside tree
46
+ Scenario: Access denied
45
47
  Given a successful login
46
- And the client has file "foo"
47
- When the client puts text "../foo"
48
+ And the client has file "forbidden"
49
+ When the client puts text "forbidden"
48
50
  Then the server returns an access denied error
49
51
 
50
52
  Scenario: Missing directory
@@ -63,3 +65,9 @@ Feature: Put
63
65
  Given a successful login
64
66
  When the client puts with no path
65
67
  Then the server returns a syntax error
68
+
69
+ Scenario: File system error
70
+ Given a successful login
71
+ And the client has file "unable"
72
+ When the client puts text "unable"
73
+ Then the server returns an action not taken error
@@ -0,0 +1,18 @@
1
+ Feature: Put TLS
2
+
3
+ As a client
4
+ I want to put a file
5
+ So that someone else can have it
6
+
7
+ Background:
8
+ Given the test server is started with TLS
9
+
10
+ Scenario: TLS
11
+ pending "TLS not supported in active mode (see README)"
12
+
13
+ Scenario: TLS, Passive
14
+ Given a successful login with TLS
15
+ And the client has file "ascii_unix"
16
+ And the client is in passive mode
17
+ When the client successfully puts text "ascii_unix"
18
+ Then the remote file "ascii_unix" should match the local file
@@ -4,6 +4,9 @@ Feature: Quit
4
4
  In order to free up resources
5
5
  I want to close the connection
6
6
 
7
+ Background:
8
+ Given the test server is started
9
+
7
10
  Scenario: Logged in
8
11
  Given a successful login
9
12
  When the client successfully quits
@@ -0,0 +1,8 @@
1
+ Then /^the server should have written( no)? debug output$/ do |neg|
2
+ matcher = if neg
3
+ be_false
4
+ else
5
+ be_true
6
+ end
7
+ @server.wrote_debug_output?.should matcher
8
+ end
@@ -0,0 +1,12 @@
1
+ Given /^the test server is started$/ do
2
+ @server = TestServer.new(:tls => :off)
3
+ end
4
+
5
+ Given /^the test server is started with TLS$/ do
6
+ @server = TestServer.new(:tls => :explicit)
7
+ end
8
+
9
+ Given /^the test server is started with debug$/ do
10
+ @server = TestServer.new(:tls => :off,
11
+ :debug => true)
12
+ end
@@ -4,6 +4,9 @@ Feature: Syntax Errors
4
4
  I want good error messages
5
5
  So that I can figure out what went wrong
6
6
 
7
+ Background:
8
+ Given the test server is started
9
+
7
10
  Scenario: Empty command
8
11
  Given a successful connection
9
12
  When the client sends an empty command
@@ -0,0 +1,56 @@
1
+ Feature: Representation Type
2
+
3
+ As a client
4
+ I want to set the representation type
5
+ So that I can interoperate with foreign operating systems
6
+
7
+ Background:
8
+ Given the test server is started
9
+
10
+ Scenario: Type ASCII
11
+ Given a successful login
12
+ Then the client successfully sets type "A"
13
+
14
+ Scenario: Type IMAGE
15
+ Given a successful login
16
+ Then the client successfully sets type "I"
17
+
18
+ Scenario: Type EBCDIC
19
+ Given a successful login
20
+ When the client sets type "E"
21
+ Then the server returns a type not implemented error
22
+
23
+ Scenario: Type Local
24
+ Given a successful login
25
+ When the client sets type "L 7"
26
+ Then the server returns a type not implemented error
27
+
28
+ Scenario: Invalid Type
29
+ Given a successful login
30
+ When the client sets type "*"
31
+ Then the server returns an invalid type error
32
+
33
+ Scenario: Format Telnet
34
+ Given a successful login
35
+ When the client sets type "A T"
36
+ Then the server returns a format not implemented error
37
+
38
+ Scenario: Format Carriage Control
39
+ Given a successful login
40
+ When the client sets type "A C"
41
+ Then the server returns a format not implemented error
42
+
43
+ Scenario: Invalid Format
44
+ Given a successful login
45
+ When the client sets type "A *"
46
+ Then the server returns an invalid format error
47
+
48
+ Scenario: Not logged in
49
+ Given a successful connection
50
+ When the client sets type "S"
51
+ Then the server returns a not logged in error
52
+
53
+ Scenario: Missing parameter
54
+ Given a successful login
55
+ When the client sets type with no parameter
56
+ Then the server returns a syntax error
@@ -10,16 +10,19 @@ Then /^the server returns no error$/ do
10
10
  end
11
11
 
12
12
  Then /^the server returns a "(.*?)" error$/ do |error_message|
13
- @error.should include error_message
13
+ (@error || '').should include error_message
14
14
  end
15
15
 
16
16
  Then /^the server returns a no such file error$/ do
17
17
  step 'the server returns a "550 No such file or directory" error'
18
18
  end
19
19
 
20
+ Then /^the server returns a not a directory error$/ do
21
+ step 'the server returns a "550 Not a directory" error'
22
+ end
23
+
20
24
  Then /^the server returns a login incorrect error$/ do
21
25
  step 'the server returns a "530 Login incorrect" error'
22
-
23
26
  end
24
27
 
25
28
  Then /^the server returns a not logged in error$/ do
@@ -35,7 +38,7 @@ Then /^the server returns a path required error$/ do
35
38
  end
36
39
 
37
40
  Then /^the server returns a not found error$/ do
38
- step 'the server returns a "450 No such file or directory" error'
41
+ step 'the server returns a "550 No such file or directory" error'
39
42
  end
40
43
 
41
44
  Then /^the server returns a syntax error$/ do
@@ -85,3 +88,7 @@ end
85
88
  Then /^the server returns an unimplemented command error$/ do
86
89
  step 'the server returns a "502 Command not implemented" error'
87
90
  end
91
+
92
+ Then /^the server returns an action not taken error$/ do
93
+ step 'the server returns a "450 Unable to do it" error'
94
+ end
@@ -18,17 +18,30 @@ class FileList
18
18
  !long_form?
19
19
  end
20
20
 
21
+ def empty?
22
+ @lines.empty?
23
+ end
24
+
25
+ end
26
+
27
+ When /^the client successfully lists the directory(?: "(.*?)")?$/ do |directory|
28
+ @list = FileList.new(@client.ls(*[directory].compact))
21
29
  end
22
30
 
23
- When /^the client lists the directory(?: "(.*?)")?$/ do |directory|
31
+ When /^the client lists the directory( "(?:.*?)")?$/ do |directory|
24
32
  capture_error do
25
- @list = FileList.new(@client.ls(*[directory].compact))
33
+ step "the client successfully lists the directory#{directory}"
26
34
  end
27
35
  end
28
36
 
29
- When /^the client name lists the directory(?: "(.*?)")?$/ do |directory|
37
+ When /^the client successfully name-lists the directory(?: "(.*?)")?$/ do
38
+ |directory|
39
+ @list = FileList.new(@client.nlst(*[directory].compact))
40
+ end
41
+
42
+ When /^the client name-lists the directory( "(?:.*?)")?$/ do |directory|
30
43
  capture_error do
31
- @list = FileList.new(@client.nlst(*[directory].compact))
44
+ step "the client successfully name-lists the directory#{directory}"
32
45
  end
33
46
  end
34
47
 
@@ -44,3 +57,7 @@ end
44
57
  Then /^the file list should be in (long|short) form$/ do |form|
45
58
  @list.should send("be_#{form}_form")
46
59
  end
60
+
61
+ Then /^the file list should be empty$/ do
62
+ @list.should be_empty
63
+ end
@@ -10,7 +10,6 @@ def login(user, password, client_name = nil)
10
10
  end
11
11
 
12
12
  Given /^a successful connection( with TLS)?$/ do |with_tls|
13
- step 'the server is started'
14
13
  step "the client connects#{with_tls}"
15
14
  end
16
15
 
@@ -25,7 +24,6 @@ Given /^the( \w+)? client connects and logs in$/ do |client_name|
25
24
  end
26
25
 
27
26
  Given /^a failed login$/ do
28
- step 'the server is started'
29
27
  step 'the client connects'
30
28
  step 'the client logs in with a bad password'
31
29
  end
@@ -1,3 +1,7 @@
1
+ Given /^the server has directory "(.*?)"$/ do |remote_path|
2
+ @server.add_directory remote_path
3
+ end
4
+
1
5
  Given /^the server has file "(.*?)"$/ do |remote_path|
2
6
  @server.add_file remote_path
3
7
  end
@@ -0,0 +1,3 @@
1
+ After do
2
+ @server.stop if @server
3
+ end
@@ -0,0 +1,58 @@
1
+ require 'fileutils'
2
+ require 'forwardable'
3
+ require File.expand_path('test_server_files',
4
+ File.dirname(__FILE__))
5
+
6
+ class ExampleServer
7
+
8
+ extend Forwardable
9
+ include FileUtils
10
+ include TestServerFiles
11
+
12
+ def initialize
13
+ command = [
14
+ File.expand_path('../../examples/example.rb',
15
+ File.dirname(__FILE__))
16
+ ].join(' ')
17
+ @io = IO.popen(command, 'r+')
18
+ @output = read_output
19
+ end
20
+
21
+ def stop
22
+ @io.close
23
+ end
24
+
25
+ def host
26
+ @output[/Host: (.*)$/, 1]
27
+ end
28
+
29
+ def port
30
+ @output[/Port: (.*)$/, 1].to_i
31
+ end
32
+
33
+ def user
34
+ @output[/User: (.*)$/, 1]
35
+ end
36
+
37
+ def password
38
+ @output[/Pass: (.*)$/, 1]
39
+ end
40
+
41
+ private
42
+
43
+ def read_output
44
+ output = ''
45
+ loop do
46
+ line = @io.gets
47
+ break if line.nil?
48
+ output << line
49
+ break if line =~ /FTP server started/
50
+ end
51
+ output
52
+ end
53
+
54
+ def temp_dir
55
+ @output[/Directory: (.*)$/, 1]
56
+ end
57
+
58
+ end