ftpd 0.0.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (62) hide show
  1. data/Gemfile +9 -0
  2. data/Gemfile.lock +43 -0
  3. data/LICENSE.md +9 -0
  4. data/README.md +57 -0
  5. data/Rakefile +8 -0
  6. data/VERSION +1 -0
  7. data/features/command_errors.feature +33 -0
  8. data/features/delete.feature +34 -0
  9. data/features/directory_navigation.feature +34 -0
  10. data/features/file_structure.feature +40 -0
  11. data/features/get.feature +62 -0
  12. data/features/list.feature +77 -0
  13. data/features/login.feature +54 -0
  14. data/features/mode.feature +40 -0
  15. data/features/name_list.feature +77 -0
  16. data/features/noop.feature +14 -0
  17. data/features/port.feature +25 -0
  18. data/features/put.feature +65 -0
  19. data/features/quit.feature +20 -0
  20. data/features/step_definitions/client_and_server_files.rb +24 -0
  21. data/features/step_definitions/client_files.rb +9 -0
  22. data/features/step_definitions/command.rb +5 -0
  23. data/features/step_definitions/connect.rb +15 -0
  24. data/features/step_definitions/delete.rb +15 -0
  25. data/features/step_definitions/directories.rb +22 -0
  26. data/features/step_definitions/error.rb +87 -0
  27. data/features/step_definitions/file_structure.rb +16 -0
  28. data/features/step_definitions/get.rb +16 -0
  29. data/features/step_definitions/invalid_commands.rb +11 -0
  30. data/features/step_definitions/line_endings.rb +7 -0
  31. data/features/step_definitions/list.rb +46 -0
  32. data/features/step_definitions/login.rb +69 -0
  33. data/features/step_definitions/mode.rb +15 -0
  34. data/features/step_definitions/noop.rb +13 -0
  35. data/features/step_definitions/passive.rb +3 -0
  36. data/features/step_definitions/port.rb +5 -0
  37. data/features/step_definitions/put.rb +16 -0
  38. data/features/step_definitions/quit.rb +15 -0
  39. data/features/step_definitions/server.rb +7 -0
  40. data/features/step_definitions/server_files.rb +18 -0
  41. data/features/step_definitions/type.rb +15 -0
  42. data/features/support/env.rb +4 -0
  43. data/features/support/file_templates/ascii_unix +4 -0
  44. data/features/support/file_templates/ascii_windows +4 -0
  45. data/features/support/file_templates/binary +0 -0
  46. data/features/support/test_client.rb +89 -0
  47. data/features/support/test_file_templates.rb +33 -0
  48. data/features/support/test_server.rb +52 -0
  49. data/features/syntax_errors.feature +15 -0
  50. data/features/type.feature +53 -0
  51. data/ftpd.gemspec +112 -0
  52. data/insecure-test-cert.pem +29 -0
  53. data/lib/ftpd.rb +6 -0
  54. data/lib/ftpd/FakeFtpServer.rb +736 -0
  55. data/lib/ftpd/FakeServer.rb +57 -0
  56. data/lib/ftpd/FakeTlsServer.rb +52 -0
  57. data/lib/ftpd/ObjectUtil.rb +66 -0
  58. data/lib/ftpd/TempDir.rb +54 -0
  59. data/lib/ftpd/q.rb +92 -0
  60. data/rake_tasks/cucumber.rake +7 -0
  61. data/rake_tasks/jeweler.rake +25 -0
  62. metadata +164 -0
@@ -0,0 +1,57 @@
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
@@ -0,0 +1,52 @@
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
@@ -0,0 +1,66 @@
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
@@ -0,0 +1,54 @@
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 ADDED
@@ -0,0 +1,92 @@
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
@@ -0,0 +1,7 @@
1
+ require 'cucumber/rake/task'
2
+
3
+ Cucumber::Rake::Task.new(:features) do |t|
4
+ t.fork = true
5
+ end
6
+
7
+ task :cucumber => [:features]
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ require 'jeweler'
4
+
5
+ README_PATH = File.expand_path('../README.md', File.dirname(__FILE__))
6
+
7
+ def extract_description_from_readme
8
+ readme = File.open(README_PATH, 'r', &:read)
9
+ s = readme[/^# FTPD\n+((?:.*\n)+?)\n*##/, 1]
10
+ s.gsub(/\n/, ' ').strip
11
+ end
12
+
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see
15
+ # http://docs.rubygems.org/read/chapter/20 for more options
16
+ gem.name = 'ftpd'
17
+ gem.homepage = 'http://github.com/wconrad/ftpd'
18
+ gem.license = 'MIT'
19
+ gem.summary = %Q{Pure Ruby FTP server library}
20
+ gem.description = extract_description_from_readme
21
+ gem.email = 'wconrad@yagni.com'
22
+ gem.authors = ['Wayne Conrad']
23
+ # dependencies defined in Gemfile
24
+ end
25
+ Jeweler::RubygemsDotOrgTasks.new
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ftpd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0.pre1
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Wayne Conrad
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cucumber
16
+ requirement: &68632020 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.2.1
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *68632020
25
+ - !ruby/object:Gem::Dependency
26
+ name: double-bag-ftps
27
+ requirement: &68631220 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.1.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *68631220
36
+ - !ruby/object:Gem::Dependency
37
+ name: jeweler
38
+ requirement: &68630210 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.8.4
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *68630210
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: &68629160 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 10.0.3
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *68629160
58
+ - !ruby/object:Gem::Dependency
59
+ name: rspec
60
+ requirement: &68627620 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 2.0.1
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *68627620
69
+ description: ftpd is a pure Ruby FTP server library. It supports implicit and explicit
70
+ TLS, and can be used by a text fixture or FTP daemon.
71
+ email: wconrad@yagni.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files:
75
+ - LICENSE.md
76
+ - README.md
77
+ files:
78
+ - Gemfile
79
+ - Gemfile.lock
80
+ - LICENSE.md
81
+ - README.md
82
+ - Rakefile
83
+ - VERSION
84
+ - features/command_errors.feature
85
+ - features/delete.feature
86
+ - features/directory_navigation.feature
87
+ - features/file_structure.feature
88
+ - features/get.feature
89
+ - features/list.feature
90
+ - features/login.feature
91
+ - features/mode.feature
92
+ - features/name_list.feature
93
+ - features/noop.feature
94
+ - features/port.feature
95
+ - features/put.feature
96
+ - features/quit.feature
97
+ - features/step_definitions/client_and_server_files.rb
98
+ - features/step_definitions/client_files.rb
99
+ - features/step_definitions/command.rb
100
+ - features/step_definitions/connect.rb
101
+ - features/step_definitions/delete.rb
102
+ - features/step_definitions/directories.rb
103
+ - features/step_definitions/error.rb
104
+ - features/step_definitions/file_structure.rb
105
+ - features/step_definitions/get.rb
106
+ - features/step_definitions/invalid_commands.rb
107
+ - features/step_definitions/line_endings.rb
108
+ - features/step_definitions/list.rb
109
+ - features/step_definitions/login.rb
110
+ - features/step_definitions/mode.rb
111
+ - features/step_definitions/noop.rb
112
+ - features/step_definitions/passive.rb
113
+ - features/step_definitions/port.rb
114
+ - features/step_definitions/put.rb
115
+ - features/step_definitions/quit.rb
116
+ - features/step_definitions/server.rb
117
+ - features/step_definitions/server_files.rb
118
+ - features/step_definitions/type.rb
119
+ - features/support/env.rb
120
+ - features/support/file_templates/ascii_unix
121
+ - features/support/file_templates/ascii_windows
122
+ - features/support/file_templates/binary
123
+ - features/support/test_client.rb
124
+ - features/support/test_file_templates.rb
125
+ - features/support/test_server.rb
126
+ - features/syntax_errors.feature
127
+ - features/type.feature
128
+ - ftpd.gemspec
129
+ - insecure-test-cert.pem
130
+ - lib/ftpd.rb
131
+ - lib/ftpd/FakeFtpServer.rb
132
+ - lib/ftpd/FakeServer.rb
133
+ - lib/ftpd/FakeTlsServer.rb
134
+ - lib/ftpd/ObjectUtil.rb
135
+ - lib/ftpd/TempDir.rb
136
+ - lib/ftpd/q.rb
137
+ - rake_tasks/cucumber.rake
138
+ - rake_tasks/jeweler.rake
139
+ homepage: http://github.com/wconrad/ftpd
140
+ licenses:
141
+ - MIT
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ! '>='
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>'
156
+ - !ruby/object:Gem::Version
157
+ version: 1.3.1
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 1.8.17
161
+ signing_key:
162
+ specification_version: 3
163
+ summary: Pure Ruby FTP server library
164
+ test_files: []