ftpd 0.1.1 → 0.2.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/Changelog.md +41 -0
- data/README.md +70 -3
- data/VERSION +1 -1
- data/examples/example.rb +2 -1
- data/features/ftp_server/allo.feature +33 -0
- data/features/ftp_server/command_errors.feature +0 -2
- data/features/ftp_server/delete.feature +7 -0
- data/features/ftp_server/get.feature +7 -0
- data/features/ftp_server/list.feature +6 -0
- data/features/ftp_server/name_list.feature +6 -0
- data/features/ftp_server/put.feature +7 -0
- data/features/ftp_server/step_definitions/test_server.rb +14 -4
- data/features/ftp_server/syst.feature +18 -0
- data/features/step_definitions/{error.rb → error_replies.rb} +0 -0
- data/features/step_definitions/generic_send.rb +9 -0
- data/features/step_definitions/success_replies.rb +7 -0
- data/features/step_definitions/system.rb +7 -0
- data/features/support/test_client.rb +2 -1
- data/features/support/test_server.rb +144 -41
- data/ftpd.gemspec +11 -4
- data/lib/ftpd/disk_file_system.rb +266 -101
- data/lib/ftpd/session.rb +66 -35
- data/spec/disk_file_system_spec.rb +4 -4
- data/spec/file_system_error_translator_spec.rb +43 -0
- metadata +12 -5
data/lib/ftpd/session.rb
CHANGED
@@ -24,7 +24,7 @@ module Ftpd
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def run
|
27
|
-
reply "220
|
27
|
+
reply "220 ftpd"
|
28
28
|
@state = :user
|
29
29
|
catch :done do
|
30
30
|
loop do
|
@@ -37,7 +37,7 @@ module Ftpd
|
|
37
37
|
end
|
38
38
|
method = 'cmd_' + command
|
39
39
|
unless self.class.private_method_defined?(method)
|
40
|
-
|
40
|
+
unimplemented
|
41
41
|
end
|
42
42
|
send(method, argument)
|
43
43
|
rescue CommandError => e
|
@@ -89,6 +89,17 @@ module Ftpd
|
|
89
89
|
"user",
|
90
90
|
]
|
91
91
|
|
92
|
+
def cmd_allo(argument)
|
93
|
+
ensure_logged_in
|
94
|
+
syntax_error unless argument =~ /^\d+( R \d+)?$/
|
95
|
+
command_not_needed
|
96
|
+
end
|
97
|
+
|
98
|
+
def cmd_syst(argument)
|
99
|
+
syntax_error if argument
|
100
|
+
reply "215 UNIX Type: L8"
|
101
|
+
end
|
102
|
+
|
92
103
|
def cmd_user(argument)
|
93
104
|
syntax_error unless argument
|
94
105
|
bad_sequence unless @state == :user
|
@@ -101,6 +112,10 @@ module Ftpd
|
|
101
112
|
error "503 Bad sequence of commands"
|
102
113
|
end
|
103
114
|
|
115
|
+
def unimplemented
|
116
|
+
error "502 Command not implemented"
|
117
|
+
end
|
118
|
+
|
104
119
|
def cmd_pass(argument)
|
105
120
|
syntax_error unless argument
|
106
121
|
bad_sequence unless @state == :password
|
@@ -143,6 +158,7 @@ module Ftpd
|
|
143
158
|
def cmd_stor(argument)
|
144
159
|
close_data_server_socket_when_done do
|
145
160
|
ensure_logged_in
|
161
|
+
ensure_write_supported
|
146
162
|
path = argument
|
147
163
|
syntax_error unless path
|
148
164
|
path = File.expand_path(path, @name_prefix)
|
@@ -157,6 +173,7 @@ module Ftpd
|
|
157
173
|
def cmd_retr(argument)
|
158
174
|
close_data_server_socket_when_done do
|
159
175
|
ensure_logged_in
|
176
|
+
ensure_read_supported
|
160
177
|
path = argument
|
161
178
|
syntax_error unless path
|
162
179
|
path = File.expand_path(path, @name_prefix)
|
@@ -169,6 +186,7 @@ module Ftpd
|
|
169
186
|
|
170
187
|
def cmd_dele(argument)
|
171
188
|
ensure_logged_in
|
189
|
+
ensure_delete_supported
|
172
190
|
path = argument
|
173
191
|
error "501 Path required" unless path
|
174
192
|
path = File.expand_path(path, @name_prefix)
|
@@ -179,38 +197,29 @@ module Ftpd
|
|
179
197
|
end
|
180
198
|
|
181
199
|
def cmd_list(argument)
|
182
|
-
ls(argument, :list_long)
|
183
|
-
end
|
184
|
-
|
185
|
-
def cmd_nlst(argument)
|
186
|
-
ls(argument, :list_short)
|
187
|
-
end
|
188
|
-
|
189
|
-
def ls(path, file_system_method)
|
190
200
|
close_data_server_socket_when_done do
|
191
201
|
ensure_logged_in
|
202
|
+
ensure_list_supported
|
203
|
+
path = argument
|
192
204
|
path ||= '.'
|
193
205
|
path = File.expand_path(path, @name_prefix)
|
194
|
-
list = @file_system.
|
206
|
+
list = @file_system.list(path)
|
195
207
|
transmit_file(list, 'A')
|
196
208
|
end
|
197
209
|
end
|
198
210
|
|
199
|
-
def
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
211
|
+
def cmd_nlst(argument)
|
212
|
+
close_data_server_socket_when_done do
|
213
|
+
ensure_logged_in
|
214
|
+
ensure_name_list_supported
|
215
|
+
path = argument
|
216
|
+
path ||= '.'
|
217
|
+
path = File.expand_path(path, @name_prefix)
|
218
|
+
list = @file_system.name_list(path)
|
219
|
+
transmit_file(list, 'A')
|
207
220
|
end
|
208
221
|
end
|
209
222
|
|
210
|
-
def is_glob?(filename)
|
211
|
-
filename =~ /[.*]/
|
212
|
-
end
|
213
|
-
|
214
223
|
def cmd_type(argument)
|
215
224
|
ensure_logged_in
|
216
225
|
syntax_error unless argument =~ /^(\S)(?: (\S+))?$/
|
@@ -317,6 +326,36 @@ module Ftpd
|
|
317
326
|
end
|
318
327
|
end
|
319
328
|
|
329
|
+
def ensure_write_supported
|
330
|
+
unless @file_system.respond_to?(:write)
|
331
|
+
unimplemented
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def ensure_read_supported
|
336
|
+
unless @file_system.respond_to?(:read)
|
337
|
+
unimplemented
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def ensure_delete_supported
|
342
|
+
unless @file_system.respond_to?(:delete)
|
343
|
+
unimplemented
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def ensure_list_supported
|
348
|
+
unless @file_system.respond_to?(:list)
|
349
|
+
unimplemented
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def ensure_name_list_supported
|
354
|
+
unless @file_system.respond_to?(:name_list)
|
355
|
+
unimplemented
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
320
359
|
def tls_enabled?
|
321
360
|
@tls != :off
|
322
361
|
end
|
@@ -413,18 +452,6 @@ module Ftpd
|
|
413
452
|
@file_system = FileSystemErrorTranslator.new(file_system)
|
414
453
|
end
|
415
454
|
|
416
|
-
def child_path_of?(parent, child)
|
417
|
-
child.cleanpath.to_s.index(parent.cleanpath.to_s) == 0
|
418
|
-
end
|
419
|
-
|
420
|
-
def handle_system_error
|
421
|
-
begin
|
422
|
-
yield
|
423
|
-
rescue SystemCallError => e
|
424
|
-
error "550 #{e}"
|
425
|
-
end
|
426
|
-
end
|
427
|
-
|
428
455
|
def transmit_file(contents, data_type = @data_type)
|
429
456
|
open_data_connection do |data_socket|
|
430
457
|
contents = unix_to_nvt_ascii(contents) if data_type == 'A'
|
@@ -477,6 +504,10 @@ module Ftpd
|
|
477
504
|
].compact.join(' ')
|
478
505
|
end
|
479
506
|
|
507
|
+
def command_not_needed
|
508
|
+
reply '202 Command not needed at this site'
|
509
|
+
end
|
510
|
+
|
480
511
|
def encrypt_data?
|
481
512
|
@data_channel_protection_level != :clear
|
482
513
|
end
|
@@ -155,10 +155,10 @@ module Ftpd
|
|
155
155
|
|
156
156
|
end
|
157
157
|
|
158
|
-
describe '#
|
158
|
+
describe '#name_list' do
|
159
159
|
|
160
160
|
subject do
|
161
|
-
disk_file_system.
|
161
|
+
disk_file_system.name_list(path)
|
162
162
|
end
|
163
163
|
|
164
164
|
shared_examples 'returns short list of root' do
|
@@ -195,10 +195,10 @@ module Ftpd
|
|
195
195
|
|
196
196
|
end
|
197
197
|
|
198
|
-
describe '#
|
198
|
+
describe '#list' do
|
199
199
|
|
200
200
|
subject do
|
201
|
-
disk_file_system.
|
201
|
+
disk_file_system.list(path)
|
202
202
|
end
|
203
203
|
|
204
204
|
shared_examples 'returns long list of root' do
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module Ftpd
|
4
|
+
describe FileSystemErrorTranslator do
|
5
|
+
|
6
|
+
class MockFileSystem
|
7
|
+
|
8
|
+
def with_error
|
9
|
+
raise FileSystemError, 'An error occurred'
|
10
|
+
end
|
11
|
+
|
12
|
+
def without_error
|
13
|
+
123
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
subject(:translator) do
|
19
|
+
FileSystemErrorTranslator.new(MockFileSystem.new)
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'missing method' do
|
23
|
+
specify do
|
24
|
+
expect {
|
25
|
+
translator.no_such_method
|
26
|
+
}.to raise_error NoMethodError, /no_such_method/
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'no exception' do
|
31
|
+
its(:without_error) {should == 123}
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'exception' do
|
35
|
+
specify do
|
36
|
+
expect {
|
37
|
+
translator.with_error
|
38
|
+
}.to raise_error CommandError, '450 An error occurred'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ftpd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: memoizer
|
@@ -124,7 +124,7 @@ dependencies:
|
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '0'
|
126
126
|
description: ftpd is a pure Ruby FTP server library. It supports implicit and explicit
|
127
|
-
TLS, and
|
127
|
+
TLS, and can be used as part of a test fixture or to embed in another program.
|
128
128
|
email: wconrad@yagni.com
|
129
129
|
executables: []
|
130
130
|
extensions: []
|
@@ -132,6 +132,7 @@ extra_rdoc_files:
|
|
132
132
|
- LICENSE.md
|
133
133
|
- README.md
|
134
134
|
files:
|
135
|
+
- Changelog.md
|
135
136
|
- Gemfile
|
136
137
|
- Gemfile.lock
|
137
138
|
- LICENSE.md
|
@@ -142,6 +143,7 @@ files:
|
|
142
143
|
- examples/hello_world.rb
|
143
144
|
- features/example/example.feature
|
144
145
|
- features/example/step_definitions/example_server.rb
|
146
|
+
- features/ftp_server/allo.feature
|
145
147
|
- features/ftp_server/command_errors.feature
|
146
148
|
- features/ftp_server/concurrent_sessions.feature
|
147
149
|
- features/ftp_server/debug.feature
|
@@ -164,6 +166,7 @@ files:
|
|
164
166
|
- features/ftp_server/step_definitions/debug.rb
|
165
167
|
- features/ftp_server/step_definitions/test_server.rb
|
166
168
|
- features/ftp_server/syntax_errors.feature
|
169
|
+
- features/ftp_server/syst.feature
|
167
170
|
- features/ftp_server/type.feature
|
168
171
|
- features/step_definitions/client.rb
|
169
172
|
- features/step_definitions/client_and_server_files.rb
|
@@ -172,8 +175,9 @@ files:
|
|
172
175
|
- features/step_definitions/connect.rb
|
173
176
|
- features/step_definitions/delete.rb
|
174
177
|
- features/step_definitions/directories.rb
|
175
|
-
- features/step_definitions/
|
178
|
+
- features/step_definitions/error_replies.rb
|
176
179
|
- features/step_definitions/file_structure.rb
|
180
|
+
- features/step_definitions/generic_send.rb
|
177
181
|
- features/step_definitions/get.rb
|
178
182
|
- features/step_definitions/invalid_commands.rb
|
179
183
|
- features/step_definitions/line_endings.rb
|
@@ -187,6 +191,8 @@ files:
|
|
187
191
|
- features/step_definitions/quit.rb
|
188
192
|
- features/step_definitions/server_files.rb
|
189
193
|
- features/step_definitions/stop_server.rb
|
194
|
+
- features/step_definitions/success_replies.rb
|
195
|
+
- features/step_definitions/system.rb
|
190
196
|
- features/step_definitions/type.rb
|
191
197
|
- features/support/env.rb
|
192
198
|
- features/support/example_server.rb
|
@@ -221,6 +227,7 @@ files:
|
|
221
227
|
- sandbox/em-server.rb
|
222
228
|
- spec/disk_file_system_spec.rb
|
223
229
|
- spec/exception_translator_spec.rb
|
230
|
+
- spec/file_system_error_translator_spec.rb
|
224
231
|
- spec/spec_helper.rb
|
225
232
|
- spec/translate_exceptions_spec.rb
|
226
233
|
homepage: http://github.com/wconrad/ftpd
|
@@ -238,7 +245,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
238
245
|
version: '0'
|
239
246
|
segments:
|
240
247
|
- 0
|
241
|
-
hash:
|
248
|
+
hash: 198418525
|
242
249
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
243
250
|
none: false
|
244
251
|
requirements:
|