ftpd 0.0.0.pre1 → 0.0.0.pre2
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/README.md +17 -1
- data/VERSION +1 -1
- data/examples/example.rb +77 -0
- data/features/step_definitions/connect.rb +4 -0
- data/features/support/test_client.rb +7 -2
- data/features/support/test_server.rb +4 -4
- data/ftpd.gemspec +7 -8
- data/lib/ftpd.rb +4 -6
- data/lib/ftpd/ftp_server.rb +665 -0
- data/lib/ftpd/server.rb +59 -0
- data/lib/ftpd/temp_dir.rb +56 -0
- data/lib/ftpd/tls_server.rb +57 -0
- metadata +17 -18
- data/lib/ftpd/FakeFtpServer.rb +0 -736
- data/lib/ftpd/FakeServer.rb +0 -57
- data/lib/ftpd/FakeTlsServer.rb +0 -52
- data/lib/ftpd/ObjectUtil.rb +0 -66
- data/lib/ftpd/TempDir.rb +0 -54
- data/lib/ftpd/q.rb +0 -92
data/lib/ftpd/FakeServer.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
|
3
|
-
class FakeServer
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
@server_socket = make_server_socket
|
7
|
-
@server_thread = make_server_thread
|
8
|
-
end
|
9
|
-
|
10
|
-
def port
|
11
|
-
@server_socket.addr[1]
|
12
|
-
end
|
13
|
-
|
14
|
-
def close
|
15
|
-
# An apparent race condition causes this to sometimes not stop the
|
16
|
-
# thread. When this happens, the thread remains blocked in the
|
17
|
-
# accept method; I hypothesize that this happens whenever the
|
18
|
-
# close happens first. Once this bug is fixed, join on the
|
19
|
-
# thread.
|
20
|
-
@server_socket.close
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def make_server_socket
|
26
|
-
return TCPServer.new('localhost', 0)
|
27
|
-
end
|
28
|
-
|
29
|
-
def make_server_thread
|
30
|
-
Thread.new do
|
31
|
-
Thread.abort_on_exception = true
|
32
|
-
loop do
|
33
|
-
begin
|
34
|
-
begin
|
35
|
-
socket = accept
|
36
|
-
rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINVAL
|
37
|
-
IO.select([@server_socket])
|
38
|
-
sleep(0.2)
|
39
|
-
retry
|
40
|
-
end
|
41
|
-
begin
|
42
|
-
session(socket)
|
43
|
-
ensure
|
44
|
-
socket.close
|
45
|
-
end
|
46
|
-
rescue IOError
|
47
|
-
break
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def accept
|
54
|
-
@server_socket.accept
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
data/lib/ftpd/FakeTlsServer.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'openssl'
|
2
|
-
require File.expand_path('FakeServer', File.dirname(__FILE__))
|
3
|
-
require File.expand_path('ObjectUtil', File.dirname(__FILE__))
|
4
|
-
|
5
|
-
class FakeTlsServer < FakeServer
|
6
|
-
|
7
|
-
private
|
8
|
-
|
9
|
-
def make_server_socket
|
10
|
-
ssl_server_socket = OpenSSL::SSL::SSLServer.new(super, ssl_context);
|
11
|
-
ssl_server_socket.start_immediately = false
|
12
|
-
ssl_server_socket
|
13
|
-
end
|
14
|
-
|
15
|
-
def accept
|
16
|
-
socket = @server_socket.accept
|
17
|
-
add_tls_methods_to_socket(socket)
|
18
|
-
socket
|
19
|
-
end
|
20
|
-
|
21
|
-
def ssl_context
|
22
|
-
context = OpenSSL::SSL::SSLContext.new
|
23
|
-
File.open(certfile_path) do |certfile|
|
24
|
-
context.cert = OpenSSL::X509::Certificate.new(certfile)
|
25
|
-
certfile.rewind
|
26
|
-
context.key = OpenSSL::PKey::RSA.new(certfile)
|
27
|
-
end
|
28
|
-
context
|
29
|
-
end
|
30
|
-
once :ssl_context
|
31
|
-
|
32
|
-
def certfile_path
|
33
|
-
File.expand_path('../../insecure-test-cert.pem',
|
34
|
-
File.dirname(__FILE__))
|
35
|
-
end
|
36
|
-
|
37
|
-
def add_tls_methods_to_socket(socket)
|
38
|
-
context = ssl_context
|
39
|
-
class << socket
|
40
|
-
def ssl_context
|
41
|
-
context
|
42
|
-
end
|
43
|
-
def encrypted?
|
44
|
-
!!cipher
|
45
|
-
end
|
46
|
-
def encrypt
|
47
|
-
accept
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
data/lib/ftpd/ObjectUtil.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
require 'thread'
|
2
|
-
|
3
|
-
class Object
|
4
|
-
|
5
|
-
def deep_copy
|
6
|
-
Marshal.load(Marshal.dump(self))
|
7
|
-
end
|
8
|
-
|
9
|
-
# So that the tests for once can force thread-safety issues to come
|
10
|
-
# out of hiding
|
11
|
-
|
12
|
-
def once_hook_set_value
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
class Module
|
18
|
-
|
19
|
-
def implement_once(ids, variable_prefix)
|
20
|
-
for id in ids
|
21
|
-
alphanumeric_name = id.to_s.gsub('?', 'q')
|
22
|
-
new_name = "gen_#{alphanumeric_name}"
|
23
|
-
mutex_name = "mutex_#{alphanumeric_name}"
|
24
|
-
return if private_method_defined?(new_name)
|
25
|
-
module_eval <<-"end;"
|
26
|
-
alias_method :#{new_name}, :#{id}
|
27
|
-
private :#{new_name}
|
28
|
-
def #{id}(*args, &block)
|
29
|
-
Thread.exclusive do
|
30
|
-
@#{mutex_name} ||= Mutex.new
|
31
|
-
end
|
32
|
-
@#{mutex_name}.synchronize do
|
33
|
-
unless #{variable_prefix}#{new_name}
|
34
|
-
once_hook_set_value
|
35
|
-
#{variable_prefix}#{new_name} = [#{new_name}(*args, &block)]
|
36
|
-
end
|
37
|
-
#{variable_prefix}#{new_name}[0]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end;
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Modified from code in the Pickaxe book
|
45
|
-
#
|
46
|
-
# Warning: Does not work on inherited or redefined methods
|
47
|
-
|
48
|
-
def once(*ids)
|
49
|
-
implement_once(ids, '@')
|
50
|
-
end
|
51
|
-
|
52
|
-
# Modified from code in the Pickaxe book
|
53
|
-
#
|
54
|
-
# Warning: Does not work on inherited or redefined methods
|
55
|
-
|
56
|
-
def global_once(*ids)
|
57
|
-
implement_once(ids, '$')
|
58
|
-
end
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
module Kernel
|
63
|
-
def with(o, &block)
|
64
|
-
o.instance_eval(&block)
|
65
|
-
end
|
66
|
-
end
|
data/lib/ftpd/TempDir.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'tempfile'
|
2
|
-
|
3
|
-
class TempDir
|
4
|
-
|
5
|
-
attr_reader :path
|
6
|
-
|
7
|
-
class << self
|
8
|
-
|
9
|
-
def make(basename = nil)
|
10
|
-
temp_dir = TempDir.new(basename)
|
11
|
-
begin
|
12
|
-
yield(temp_dir)
|
13
|
-
ensure
|
14
|
-
temp_dir.rm unless temp_dir.kept
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
attr_reader :kept
|
21
|
-
|
22
|
-
def initialize(basename = nil)
|
23
|
-
@path = unique_path(basename)
|
24
|
-
@kept = false
|
25
|
-
ObjectSpace.define_finalizer(self, TempDir.cleanup(path))
|
26
|
-
Dir.mkdir(@path)
|
27
|
-
end
|
28
|
-
|
29
|
-
def keep
|
30
|
-
@kept = true
|
31
|
-
ObjectSpace.undefine_finalizer(self)
|
32
|
-
end
|
33
|
-
|
34
|
-
def rm
|
35
|
-
keep
|
36
|
-
system("rm -rf #{path.inspect}")
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def unique_path(basename)
|
42
|
-
tempfile = Tempfile.new(File.basename(basename || $0 || ''))
|
43
|
-
path = tempfile.path
|
44
|
-
tempfile.close!
|
45
|
-
path
|
46
|
-
end
|
47
|
-
|
48
|
-
def TempDir.cleanup(path)
|
49
|
-
proc { |id|
|
50
|
-
system("/bin/rm -rf #{path.inspect}")
|
51
|
-
}
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
data/lib/ftpd/q.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
if RUBY_VERSION >= '1.8'
|
2
|
-
require 'pp'
|
3
|
-
require 'yaml'
|
4
|
-
end
|
5
|
-
|
6
|
-
class Object
|
7
|
-
|
8
|
-
def tapq
|
9
|
-
tap do |o|
|
10
|
-
q o
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def tapqq
|
15
|
-
tap do |o|
|
16
|
-
qq o
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Mostly Like p, but writes to $stderr instead of $stdout But not
|
21
|
-
# exactly like p: you can give it a block that returns a list of
|
22
|
-
# expressions as strings or symbols. Those expressions will be
|
23
|
-
# evaluted and displayed with labels.
|
24
|
-
|
25
|
-
def q(*stuff, &block)
|
26
|
-
qprint(nil, *stuff, &block)
|
27
|
-
end
|
28
|
-
|
29
|
-
def ql(*stuff, &block)
|
30
|
-
qprint(process_caller_line(caller[0], true), *stuff, &block)
|
31
|
-
end
|
32
|
-
|
33
|
-
def qlf(*stuff, &block)
|
34
|
-
qprint(process_caller_line(caller[0], false), *stuff, &block)
|
35
|
-
end
|
36
|
-
|
37
|
-
def qprint(prefix, *stuff, &block)
|
38
|
-
if block
|
39
|
-
s = Array(block[]).collect do |expression|
|
40
|
-
value = eval(expression.to_s, block.binding).inspect
|
41
|
-
"#{expression} = #{value}"
|
42
|
-
end.join(', ')
|
43
|
-
s = "#{prefix} " + s if prefix
|
44
|
-
$stderr.puts s
|
45
|
-
else
|
46
|
-
if prefix
|
47
|
-
$stderr.print prefix
|
48
|
-
if stuff.empty?
|
49
|
-
$stderr.print "\n"
|
50
|
-
end
|
51
|
-
end
|
52
|
-
stuff.each_with_index do |thing, i|
|
53
|
-
s = thing.inspect + "\n"
|
54
|
-
if prefix
|
55
|
-
if i != 0
|
56
|
-
s = " " * prefix.size + s
|
57
|
-
end
|
58
|
-
s = " " + s
|
59
|
-
end
|
60
|
-
$stderr.print(s)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def process_caller_line(str, basename_only)
|
66
|
-
parts = str.split(':')[0..1]
|
67
|
-
if basename_only
|
68
|
-
parts[0] = File.basename(parts[0])
|
69
|
-
end
|
70
|
-
parts.join(':') + ":"
|
71
|
-
end
|
72
|
-
# like pp, but writes to $stderr instead of $stdout
|
73
|
-
|
74
|
-
if RUBY_VERSION >= '1.8'
|
75
|
-
def qq(*objs)
|
76
|
-
for obj in objs
|
77
|
-
PP.pp(obj, $stderr)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# like y, but writes to $stderr instead of $stdout
|
83
|
-
|
84
|
-
if RUBY_VERSION >= '1.8'
|
85
|
-
def yy(*objs)
|
86
|
-
for obj in objs
|
87
|
-
$stderr.puts obj.to_yaml(:SortKeys=>true)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|