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.
- data/Gemfile +3 -1
- data/Gemfile.lock +14 -14
- data/README.md +71 -23
- data/Rakefile +9 -3
- data/VERSION +1 -1
- data/examples/example.rb +132 -53
- data/examples/hello_world.rb +32 -0
- data/features/example/example.feature +18 -0
- data/features/example/step_definitions/example_server.rb +3 -0
- data/features/{command_errors.feature → ftp_server/command_errors.feature} +3 -0
- data/features/ftp_server/concurrent_sessions.feature +14 -0
- data/features/ftp_server/debug.feature +15 -0
- data/features/{delete.feature → ftp_server/delete.feature} +23 -2
- data/features/{directory_navigation.feature → ftp_server/directory_navigation.feature} +17 -4
- data/features/ftp_server/file_structure.feature +43 -0
- data/features/{get.feature → ftp_server/get.feature} +21 -10
- data/features/ftp_server/get_tls.feature +18 -0
- data/features/{list.feature → ftp_server/list.feature} +24 -30
- data/features/ftp_server/list_tls.feature +21 -0
- data/features/{login.feature → ftp_server/login.feature} +4 -2
- data/features/ftp_server/mode.feature +43 -0
- data/features/{name_list.feature → ftp_server/name_list.feature} +25 -31
- data/features/ftp_server/name_list_tls.feature +22 -0
- data/features/{noop.feature → ftp_server/noop.feature} +3 -0
- data/features/{port.feature → ftp_server/port.feature} +3 -0
- data/features/{put.feature → ftp_server/put.feature} +19 -11
- data/features/ftp_server/put_tls.feature +18 -0
- data/features/{quit.feature → ftp_server/quit.feature} +3 -0
- data/features/ftp_server/step_definitions/debug.rb +8 -0
- data/features/ftp_server/step_definitions/test_server.rb +12 -0
- data/features/{syntax_errors.feature → ftp_server/syntax_errors.feature} +3 -0
- data/features/ftp_server/type.feature +56 -0
- data/features/step_definitions/error.rb +10 -3
- data/features/step_definitions/list.rb +21 -4
- data/features/step_definitions/login.rb +0 -2
- data/features/step_definitions/server_files.rb +4 -0
- data/features/step_definitions/stop_server.rb +3 -0
- data/features/support/example_server.rb +58 -0
- data/features/support/test_client.rb +1 -1
- data/features/support/test_server.rb +106 -24
- data/features/support/test_server_files.rb +30 -0
- data/ftpd.gemspec +56 -25
- data/lib/ftpd.rb +22 -4
- data/lib/ftpd/disk_file_system.rb +137 -0
- data/lib/ftpd/error.rb +9 -0
- data/lib/ftpd/exception_translator.rb +29 -0
- data/lib/ftpd/exceptions.rb +13 -0
- data/lib/ftpd/file_system_error_translator.rb +21 -0
- data/lib/ftpd/ftp_server.rb +8 -645
- data/lib/ftpd/insecure_certificate.rb +10 -0
- data/lib/ftpd/server.rb +15 -12
- data/lib/ftpd/session.rb +569 -0
- data/lib/ftpd/temp_dir.rb +10 -11
- data/lib/ftpd/tls_server.rb +27 -15
- data/lib/ftpd/translate_exceptions.rb +44 -0
- data/rake_tasks/cucumber.rake +4 -2
- data/rake_tasks/default.rake +1 -0
- data/rake_tasks/spec.rake +3 -0
- data/rake_tasks/test.rake +2 -0
- data/sandbox/em-server.rb +37 -0
- data/spec/disk_file_system_spec.rb +239 -0
- data/spec/exception_translator_spec.rb +35 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/translate_exceptions_spec.rb +40 -0
- metadata +143 -115
- data/features/concurrent_sessions.feature +0 -11
- data/features/file_structure.feature +0 -40
- data/features/mode.feature +0 -40
- data/features/step_definitions/server.rb +0 -7
- 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
|
-
|
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
|
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:
|
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
|
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:
|
28
|
+
Scenario: Parent of root
|
26
29
|
Given a successful login
|
27
|
-
And the server has file "
|
28
|
-
|
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:
|
37
|
+
Scenario: Subdir
|
33
38
|
Given a successful login
|
34
|
-
And the server has file "foo"
|
35
|
-
|
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:
|
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
|
-
|
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:
|
55
|
-
Given a successful login
|
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
|
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:
|
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
|
72
|
-
Then the
|
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
|
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"
|
@@ -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:
|
35
|
-
|
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
|
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:
|
46
|
+
Scenario: Access denied
|
45
47
|
Given a successful login
|
46
|
-
And the client has file "
|
47
|
-
When the client puts text "
|
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
|
@@ -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
|
@@ -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 "
|
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(
|
31
|
+
When /^the client lists the directory( "(?:.*?)")?$/ do |directory|
|
24
32
|
capture_error do
|
25
|
-
|
33
|
+
step "the client successfully lists the directory#{directory}"
|
26
34
|
end
|
27
35
|
end
|
28
36
|
|
29
|
-
When /^the client name
|
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
|
-
|
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
|
@@ -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
|