ftpd 1.0.1 → 1.1.0
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.
- checksums.yaml +5 -13
- data/Changelog.md +5 -0
- data/Gemfile.lock +6 -6
- data/README.md +2 -6
- data/VERSION +1 -1
- data/ftpd.gemspec +5 -4
- data/lib/ftpd/command_loop.rb +3 -0
- data/lib/ftpd/connection_tracker.rb +15 -43
- data/lib/ftpd/ftp_server.rb +17 -0
- data/lib/ftpd/gets_peer_address.rb +41 -0
- data/lib/ftpd/server.rb +8 -0
- data/lib/ftpd/session_config.rb +8 -0
- data/spec/connection_tracker_spec.rb +30 -65
- data/spec/server_spec.rb +15 -0
- metadata +28 -27
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
MDEwOTRkNjJkY2QwMGVkNTg3NzU0ZGU1ZmE0ZDYzOWYzYWViNzJjMQ==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 189a61ebfe79058fbf8ab5079be2e57dad494898
|
4
|
+
data.tar.gz: a4e2b09abc12890a8b2729e44a1e172aa4201fac
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
NTRmODI4ZWU4MTJiMmFiN2Q3NDBkNmQ5NzhhZDE5OGMyNjZjY2E5NzhmMTM0
|
11
|
-
ODc4OTA3M2VjMjc0YWY2NzJmMTM0NTI4ZmQ1ZWQ3ODc1ZDlmOWU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
MzU5MjIzOGZlZjE0ZGVhZGI2NGUxNmZlZDUzMDhkOWQwYjZhY2I0NWE0N2E0
|
14
|
-
ZjQ3NTgyNjM2NTMzYTljZmIwMGZiYThlOTEwZmE4NzY5MTU4MDBjMjA1YTc0
|
15
|
-
OWU4ODRiZmQ1OGU3NWRkZmVjZTk5MTY0OTAzMzY0YzA1NzhjOTE=
|
6
|
+
metadata.gz: ab7e3e91a03ce1c0c5ad9d116e5c88166a872351ee10c428ce57ae086380fbb2dcfa49cc9c486d23b5c82e6aa6e5a02f50be418cbc62eb09cd2457af840e2260
|
7
|
+
data.tar.gz: db4c4e093358a41d1c12194f440b413160ed4a9aa0fd5cfbdef7b7d52f29dc5ec1d0d0e08beecd713468b562ea19576e5571e779ee06de5bd78ec6ded3374bd0
|
data/Changelog.md
CHANGED
@@ -2,6 +2,11 @@ This is the change log for the main branch of ftpd, which supports
|
|
2
2
|
Ruby 1.9 and greater. For ruby 1.8.7, please use the latest version
|
3
3
|
before 0.8.0.
|
4
4
|
|
5
|
+
### development
|
6
|
+
|
7
|
+
* Added Server#exception_handler= (thanks akelmanson)
|
8
|
+
* Added Server#join (thanks akelmanson)
|
9
|
+
|
5
10
|
### 1.0.1
|
6
11
|
|
7
12
|
* Less strict gem dependencies
|
data/Gemfile.lock
CHANGED
@@ -3,7 +3,7 @@ GEM
|
|
3
3
|
specs:
|
4
4
|
addressable (2.3.6)
|
5
5
|
builder (3.2.2)
|
6
|
-
cucumber (1.3.
|
6
|
+
cucumber (1.3.17)
|
7
7
|
builder (>= 2.1.2)
|
8
8
|
diff-lcs (>= 1.1.3)
|
9
9
|
gherkin (~> 2.12)
|
@@ -55,24 +55,24 @@ GEM
|
|
55
55
|
rack (~> 1.2)
|
56
56
|
rack (1.5.2)
|
57
57
|
rake (10.3.2)
|
58
|
-
rdoc (4.1.
|
58
|
+
rdoc (4.1.2)
|
59
59
|
json (~> 1.4)
|
60
60
|
redcarpet (3.1.2)
|
61
61
|
rspec (3.1.0)
|
62
62
|
rspec-core (~> 3.1.0)
|
63
63
|
rspec-expectations (~> 3.1.0)
|
64
64
|
rspec-mocks (~> 3.1.0)
|
65
|
-
rspec-core (3.1.
|
65
|
+
rspec-core (3.1.4)
|
66
66
|
rspec-support (~> 3.1.0)
|
67
|
-
rspec-expectations (3.1.
|
67
|
+
rspec-expectations (3.1.2)
|
68
68
|
diff-lcs (>= 1.2.0, < 2.0)
|
69
69
|
rspec-support (~> 3.1.0)
|
70
70
|
rspec-its (1.0.1)
|
71
71
|
rspec-core (>= 2.99.0.beta1)
|
72
72
|
rspec-expectations (>= 2.99.0.beta1)
|
73
|
-
rspec-mocks (3.1.
|
73
|
+
rspec-mocks (3.1.2)
|
74
74
|
rspec-support (~> 3.1.0)
|
75
|
-
rspec-support (3.1.
|
75
|
+
rspec-support (3.1.1)
|
76
76
|
thread_safe (0.3.4)
|
77
77
|
timecop (0.7.1)
|
78
78
|
yard (0.8.7.4)
|
data/README.md
CHANGED
@@ -27,12 +27,6 @@ probability that it contains critical flaws (or even security
|
|
27
27
|
vulnarabilities) that have not been discovered in its use as a test
|
28
28
|
harness.
|
29
29
|
|
30
|
-
In this 0.X.X release, the API is changing at least a little with
|
31
|
-
almost every release. If you need to keep those changes from
|
32
|
-
impacting you (or at least want to let many of them build up before
|
33
|
-
you have to deal with them), then lock your Gemfile down to a minor
|
34
|
-
release (e.g. :version => '~> 0.5.0').
|
35
|
-
|
36
30
|
## Hello World
|
37
31
|
|
38
32
|
This is examples/hello_world.rb, a bare minimum FTP server. It allows
|
@@ -183,6 +177,7 @@ You can set any of these attributes before starting the server:
|
|
183
177
|
|
184
178
|
* {Ftpd::FtpServer#allow_low_data_ports}
|
185
179
|
* {Ftpd::FtpServer#auth_level}
|
180
|
+
* {Ftpd::FtpServer#exception_handler}
|
186
181
|
* {Ftpd::FtpServer#failed_login_delay}
|
187
182
|
* {Ftpd::FtpServer#list_formatter}
|
188
183
|
* {Ftpd::FtpServer#log}
|
@@ -355,6 +350,7 @@ and granted permission to donate it to the community.
|
|
355
350
|
Among those who have improved ftpd are:
|
356
351
|
|
357
352
|
* Alfonso Cora
|
353
|
+
* André Aizim Kelmanson
|
358
354
|
* Bjoern B. Dorra
|
359
355
|
* Joshua Rutherford
|
360
356
|
* Larry. W. Cashdollar
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
data/ftpd.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: ftpd 1.0
|
5
|
+
# stub: ftpd 1.1.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "ftpd"
|
9
|
-
s.version = "1.0
|
9
|
+
s.version = "1.1.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Wayne Conrad"]
|
14
|
-
s.date = "2014-
|
14
|
+
s.date = "2014-11-22"
|
15
15
|
s.description = "ftpd is a pure Ruby FTP server library. It supports implicit and explicit TLS, IPV6, passive and active mode, and is unconditionally compliant per RFC-1123. It can be used as part of a test fixture or embedded in a program."
|
16
16
|
s.email = "wconrad@yagni.com"
|
17
17
|
s.extra_rdoc_files = [
|
@@ -197,6 +197,7 @@ Gem::Specification.new do |s|
|
|
197
197
|
"lib/ftpd/file_info.rb",
|
198
198
|
"lib/ftpd/file_system_helper.rb",
|
199
199
|
"lib/ftpd/ftp_server.rb",
|
200
|
+
"lib/ftpd/gets_peer_address.rb",
|
200
201
|
"lib/ftpd/insecure_certificate.rb",
|
201
202
|
"lib/ftpd/list_format/eplf.rb",
|
202
203
|
"lib/ftpd/list_format/ls.rb",
|
@@ -237,7 +238,7 @@ Gem::Specification.new do |s|
|
|
237
238
|
]
|
238
239
|
s.homepage = "http://github.com/wconrad/ftpd"
|
239
240
|
s.licenses = ["MIT"]
|
240
|
-
s.rubygems_version = "2.
|
241
|
+
s.rubygems_version = "2.4.4"
|
241
242
|
s.summary = "Pure Ruby FTP server library"
|
242
243
|
|
243
244
|
if s.respond_to? :specification_version then
|
data/lib/ftpd/command_loop.rb
CHANGED
@@ -27,6 +27,9 @@ module Ftpd
|
|
27
27
|
execute_command command, argument
|
28
28
|
rescue FtpServerError => e
|
29
29
|
reply e.message_with_code
|
30
|
+
rescue => e
|
31
|
+
reply "451 Requested action aborted. Local error in processing."
|
32
|
+
config.exception_handler.call(e) unless config.exception_handler.nil?
|
30
33
|
end
|
31
34
|
end
|
32
35
|
rescue Errno::ECONNRESET, Errno::EPIPE
|
@@ -1,9 +1,13 @@
|
|
1
|
+
require_relative "gets_peer_address"
|
2
|
+
|
1
3
|
module Ftpd
|
2
4
|
|
3
5
|
# This class keeps track of connections
|
4
6
|
|
5
7
|
class ConnectionTracker
|
6
8
|
|
9
|
+
include GetsPeerAddress
|
10
|
+
|
7
11
|
def initialize
|
8
12
|
@mutex = Mutex.new
|
9
13
|
@connections = {}
|
@@ -18,7 +22,7 @@ module Ftpd
|
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
21
|
-
# Return the number of connections for a socket
|
25
|
+
# Return the number of connections for a socket's peer IP
|
22
26
|
|
23
27
|
def connections_for(socket)
|
24
28
|
@mutex.synchronize do
|
@@ -39,18 +43,6 @@ module Ftpd
|
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
42
|
-
# Return the number of known IPs. This exists for the benefit of
|
43
|
-
# the test, so that it can know the tracker has properly forgotten
|
44
|
-
# about an IP with no connections.
|
45
|
-
|
46
|
-
def known_ip_count
|
47
|
-
@mutex.synchronize do
|
48
|
-
@connections.size
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
46
|
# Start tracking a connection
|
55
47
|
|
56
48
|
def start_track(socket)
|
@@ -73,37 +65,17 @@ module Ftpd
|
|
73
65
|
end
|
74
66
|
end
|
75
67
|
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
# * Ruby 1.8.7
|
84
|
-
# * #peeraddr, which does not take the "reverse lookup"
|
85
|
-
# argument, relying instead using
|
86
|
-
# BasicSocket.do_not_reverse_lookup.
|
87
|
-
# * #getpeername, which does not do a reverse lookup. It is a
|
88
|
-
# little uglier than #peeraddr.
|
89
|
-
# * Ruby >=1.9.3
|
90
|
-
# * #peeraddr, which takes the "reverse lookup" argument.
|
91
|
-
# * #getpeername - same as 1.8.7
|
92
|
-
|
93
|
-
# @return [String] IP address
|
94
|
-
|
95
|
-
def peer_ip(socket)
|
96
|
-
if socket.respond_to?(:getpeername)
|
97
|
-
# Non SSL
|
98
|
-
sockaddr = socket.getpeername
|
99
|
-
port, host = Socket.unpack_sockaddr_in(sockaddr)
|
100
|
-
host
|
101
|
-
else
|
102
|
-
# SSL
|
103
|
-
BasicSocket.do_not_reverse_lookup = true
|
104
|
-
socket.peeraddr.last
|
68
|
+
# Return the number of known IPs. This exists for the benefit of
|
69
|
+
# the test, so that it can know the tracker has properly forgotten
|
70
|
+
# about an IP with no connections.
|
71
|
+
|
72
|
+
def known_ip_count
|
73
|
+
@mutex.synchronize do
|
74
|
+
@connections.size
|
105
75
|
end
|
106
|
-
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
107
79
|
|
108
80
|
end
|
109
81
|
|
data/lib/ftpd/ftp_server.rb
CHANGED
@@ -127,6 +127,22 @@ module Ftpd
|
|
127
127
|
|
128
128
|
attr_accessor :session_timeout
|
129
129
|
|
130
|
+
# The exception handler. When there is an unknown exception,
|
131
|
+
# server replies 451 and calls exception_handler. If nil,
|
132
|
+
# then it's ignored.
|
133
|
+
#
|
134
|
+
# Set this before calling #start.
|
135
|
+
#
|
136
|
+
# @return [Proc]
|
137
|
+
|
138
|
+
attr_accessor :exception_handler
|
139
|
+
|
140
|
+
# Defines the exception_handler.
|
141
|
+
|
142
|
+
def on_exception(&block)
|
143
|
+
self.exception_handler = block
|
144
|
+
end
|
145
|
+
|
130
146
|
# Create a new FTP server. The server won't start until the
|
131
147
|
# #start method is called.
|
132
148
|
#
|
@@ -183,6 +199,7 @@ module Ftpd
|
|
183
199
|
config.server_version = @server_version
|
184
200
|
config.session_timeout = @session_timeout
|
185
201
|
config.tls = @tls
|
202
|
+
config.exception_handler = exception_handler
|
186
203
|
session = Session.new(config, socket)
|
187
204
|
session.run
|
188
205
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative "gets_peer_address"
|
2
|
+
|
3
|
+
module Ftpd
|
4
|
+
|
5
|
+
module GetsPeerAddress
|
6
|
+
|
7
|
+
# Obtain the IP that the client connected _from_.
|
8
|
+
#
|
9
|
+
# How this is done depends upon which type of socket (SSL or not)
|
10
|
+
# and what version of Ruby.
|
11
|
+
#
|
12
|
+
# * SSL socket
|
13
|
+
# * #peeraddr. Uses BasicSocket.do_not_reverse_lookup.
|
14
|
+
# * Ruby 1.8.7
|
15
|
+
# * #peeraddr, which does not take the "reverse lookup"
|
16
|
+
# argument, relying instead using
|
17
|
+
# BasicSocket.do_not_reverse_lookup.
|
18
|
+
# * #getpeername, which does not do a reverse lookup. It is a
|
19
|
+
# little uglier than #peeraddr.
|
20
|
+
# * Ruby >=1.9.3
|
21
|
+
# * #peeraddr, which takes the "reverse lookup" argument.
|
22
|
+
# * #getpeername - same as 1.8.7
|
23
|
+
#
|
24
|
+
# @return [String] IP address
|
25
|
+
|
26
|
+
def peer_ip(socket)
|
27
|
+
if socket.respond_to?(:getpeername)
|
28
|
+
# Non SSL
|
29
|
+
sockaddr = socket.getpeername
|
30
|
+
port, host = Socket.unpack_sockaddr_in(sockaddr)
|
31
|
+
host
|
32
|
+
else
|
33
|
+
# SSL
|
34
|
+
BasicSocket.do_not_reverse_lookup = true
|
35
|
+
socket.peeraddr.last
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/lib/ftpd/server.rb
CHANGED
@@ -37,6 +37,14 @@ module Ftpd
|
|
37
37
|
@server_socket.addr[1]
|
38
38
|
end
|
39
39
|
|
40
|
+
# The calling thread will suspend execution until the server is
|
41
|
+
# stopped.
|
42
|
+
|
43
|
+
def join
|
44
|
+
raise 'Server is not started!' if @server_thread.nil?
|
45
|
+
@server_thread.join
|
46
|
+
end
|
47
|
+
|
40
48
|
# Start the server. This creates the server socket, and the
|
41
49
|
# thread to service it.
|
42
50
|
|
data/lib/ftpd/session_config.rb
CHANGED
@@ -98,6 +98,14 @@ module Ftpd
|
|
98
98
|
|
99
99
|
attr_accessor :tls
|
100
100
|
|
101
|
+
# The exception handler. When there is an unknown exception,
|
102
|
+
# server replies 451 and calls exception_handler. If nil,
|
103
|
+
# then it's ignored.
|
104
|
+
#
|
105
|
+
# @return [Proc]
|
106
|
+
|
107
|
+
attr_accessor :exception_handler
|
108
|
+
|
101
109
|
end
|
102
110
|
|
103
111
|
end
|
@@ -17,53 +17,6 @@ module Ftpd
|
|
17
17
|
socket
|
18
18
|
end
|
19
19
|
|
20
|
-
# Since the connection tracker only keeps track of a connection
|
21
|
-
# until the block to which it yields returns, we need a way to
|
22
|
-
# keep a block active.
|
23
|
-
|
24
|
-
class Connector
|
25
|
-
|
26
|
-
# Enable the rspec expect syntax in this class.
|
27
|
-
# This uses an internal API of rspec-mock.
|
28
|
-
# See: http://stackoverflow.com/q/25692786/238886
|
29
|
-
RSpec::Mocks::Syntax.enable_expect self
|
30
|
-
|
31
|
-
def initialize(connection_tracker)
|
32
|
-
@connection_tracker = connection_tracker
|
33
|
-
@tracked = Queue.new
|
34
|
-
@end_session = Queue.new
|
35
|
-
@session_ended = Queue.new
|
36
|
-
end
|
37
|
-
|
38
|
-
# Start tracking a connection. Does not return until it is
|
39
|
-
# being tracked.
|
40
|
-
|
41
|
-
def start_session(socket)
|
42
|
-
Thread.new do
|
43
|
-
@connection_tracker.track(socket) do
|
44
|
-
@tracked.enq :go
|
45
|
-
command = @end_session.deq
|
46
|
-
if command == :close
|
47
|
-
allow(socket).to receive(:getpeername)
|
48
|
-
.and_raise(RuntimeError, "Socket closed")
|
49
|
-
end
|
50
|
-
end
|
51
|
-
@session_ended.enq :go
|
52
|
-
end
|
53
|
-
@tracked.deq
|
54
|
-
end
|
55
|
-
|
56
|
-
# Stop tracking a connection. Does not return until it is no
|
57
|
-
# longer tracked.
|
58
|
-
|
59
|
-
def end_session(command = :normally)
|
60
|
-
@end_session.enq command
|
61
|
-
@session_ended.deq
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
let(:connector) {Connector.new(connection_tracker)}
|
67
20
|
subject(:connection_tracker) {ConnectionTracker.new}
|
68
21
|
|
69
22
|
describe '#connections' do
|
@@ -74,21 +27,9 @@ module Ftpd
|
|
74
27
|
|
75
28
|
it 'should track the total number of connection' do
|
76
29
|
expect(connection_tracker.connections).to eq 0
|
77
|
-
|
30
|
+
connection_tracker.start_track socket
|
78
31
|
expect(connection_tracker.connections).to eq 1
|
79
|
-
|
80
|
-
expect(connection_tracker.connections).to eq 0
|
81
|
-
end
|
82
|
-
|
83
|
-
end
|
84
|
-
|
85
|
-
context '(socket disconnected during session)' do
|
86
|
-
|
87
|
-
it 'should track the total number of connection' do
|
88
|
-
expect(connection_tracker.connections).to eq 0
|
89
|
-
connector.start_session socket
|
90
|
-
expect(connection_tracker.connections).to eq 1
|
91
|
-
connector.end_session :close
|
32
|
+
connection_tracker.stop_track socket
|
92
33
|
expect(connection_tracker.connections).to eq 0
|
93
34
|
end
|
94
35
|
|
@@ -103,10 +44,10 @@ module Ftpd
|
|
103
44
|
socket2 = socket_bound_to('127.0.0.2')
|
104
45
|
expect(connection_tracker.connections_for(socket1)).to eq 0
|
105
46
|
expect(connection_tracker.connections_for(socket2)).to eq 0
|
106
|
-
|
47
|
+
connection_tracker.start_track socket1
|
107
48
|
expect(connection_tracker.connections_for(socket1)).to eq 1
|
108
49
|
expect(connection_tracker.connections_for(socket2)).to eq 0
|
109
|
-
|
50
|
+
connection_tracker.stop_track socket1
|
110
51
|
expect(connection_tracker.connections_for(socket1)).to eq 0
|
111
52
|
expect(connection_tracker.connections_for(socket2)).to eq 0
|
112
53
|
end
|
@@ -119,14 +60,38 @@ module Ftpd
|
|
119
60
|
|
120
61
|
it 'should forget about an IP that has no connection' do
|
121
62
|
expect(connection_tracker.known_ip_count).to eq 0
|
122
|
-
|
63
|
+
connection_tracker.start_track socket
|
123
64
|
expect(connection_tracker.known_ip_count).to eq 1
|
124
|
-
|
65
|
+
connection_tracker.stop_track socket
|
125
66
|
expect(connection_tracker.known_ip_count).to eq 0
|
126
67
|
end
|
127
68
|
|
128
69
|
end
|
129
70
|
|
71
|
+
describe '#track' do
|
72
|
+
|
73
|
+
let(:socket) {socket_bound_to('127.0.0.1')}
|
74
|
+
|
75
|
+
context '(session ends normally)' do
|
76
|
+
specify do
|
77
|
+
expect(connection_tracker.connections_for(socket)).to eq 0
|
78
|
+
connection_tracker.track(socket) do
|
79
|
+
expect(connection_tracker.connections_for(socket)).to eq 1
|
80
|
+
end
|
81
|
+
expect(connection_tracker.connections_for(socket)).to eq 0
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context '(session ends with exception)' do
|
86
|
+
specify do
|
87
|
+
expect(connection_tracker.connections_for(socket)).to eq 0
|
88
|
+
connection_tracker.track(socket) { raise } rescue
|
89
|
+
expect(connection_tracker.connections_for(socket)).to eq 0
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
130
95
|
end
|
131
96
|
|
132
97
|
end
|
data/spec/server_spec.rb
CHANGED
@@ -4,6 +4,21 @@ module Ftpd
|
|
4
4
|
|
5
5
|
describe Server do
|
6
6
|
|
7
|
+
describe '#join' do
|
8
|
+
it 'calls server_thread#join' do
|
9
|
+
expect_any_instance_of(Thread).to receive(:join)
|
10
|
+
server = Server.new
|
11
|
+
server.start
|
12
|
+
server.join
|
13
|
+
end
|
14
|
+
context 'when server is not started' do
|
15
|
+
it 'raises an error' do
|
16
|
+
server = Server.new
|
17
|
+
expect { server.join }.to raise_error('Server is not started!')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
7
22
|
describe 'reuse explicit port (github #23)' do
|
8
23
|
|
9
24
|
# The bug being tested involves a race condition. Monkey patch
|
metadata
CHANGED
@@ -1,153 +1,153 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ftpd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wayne Conrad
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: memoizer
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: cucumber
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '1.3'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: double-bag-ftps
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0.1'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0.1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: jeweler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '2.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '2.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - ~>
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '10.3'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - ~>
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '10.3'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: redcarpet
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - ~>
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '3.1'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - ~>
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '3.1'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: rspec
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - ~>
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '3.1'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - ~>
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '3.1'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: rspec-its
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- - ~>
|
115
|
+
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
117
|
version: '1.0'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- - ~>
|
122
|
+
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '1.0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: timecop
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
|
-
- - ~>
|
129
|
+
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
131
|
version: '0.7'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
|
-
- - ~>
|
136
|
+
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0.7'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: yard
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
|
-
- - ~>
|
143
|
+
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
145
|
version: 0.8.7
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
|
-
- - ~>
|
150
|
+
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: 0.8.7
|
153
153
|
description: ftpd is a pure Ruby FTP server library. It supports implicit and explicit
|
@@ -160,8 +160,8 @@ extra_rdoc_files:
|
|
160
160
|
- LICENSE.md
|
161
161
|
- README.md
|
162
162
|
files:
|
163
|
-
- .travis.yml
|
164
|
-
- .yardopts
|
163
|
+
- ".travis.yml"
|
164
|
+
- ".yardopts"
|
165
165
|
- Changelog.md
|
166
166
|
- Gemfile
|
167
167
|
- Gemfile.lock
|
@@ -338,6 +338,7 @@ files:
|
|
338
338
|
- lib/ftpd/file_info.rb
|
339
339
|
- lib/ftpd/file_system_helper.rb
|
340
340
|
- lib/ftpd/ftp_server.rb
|
341
|
+
- lib/ftpd/gets_peer_address.rb
|
341
342
|
- lib/ftpd/insecure_certificate.rb
|
342
343
|
- lib/ftpd/list_format/eplf.rb
|
343
344
|
- lib/ftpd/list_format/ls.rb
|
@@ -385,17 +386,17 @@ require_paths:
|
|
385
386
|
- lib
|
386
387
|
required_ruby_version: !ruby/object:Gem::Requirement
|
387
388
|
requirements:
|
388
|
-
- -
|
389
|
+
- - ">="
|
389
390
|
- !ruby/object:Gem::Version
|
390
391
|
version: '0'
|
391
392
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
392
393
|
requirements:
|
393
|
-
- -
|
394
|
+
- - ">="
|
394
395
|
- !ruby/object:Gem::Version
|
395
396
|
version: '0'
|
396
397
|
requirements: []
|
397
398
|
rubyforge_project:
|
398
|
-
rubygems_version: 2.
|
399
|
+
rubygems_version: 2.4.4
|
399
400
|
signing_key:
|
400
401
|
specification_version: 4
|
401
402
|
summary: Pure Ruby FTP server library
|