ftpd 1.1.1 → 2.0.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.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/Changelog.md +15 -0
  4. data/Gemfile +2 -2
  5. data/Gemfile.lock +57 -48
  6. data/README.md +8 -1
  7. data/VERSION +1 -1
  8. data/examples/example.rb +12 -0
  9. data/features/example/step_definitions/example_server.rb +2 -0
  10. data/features/ftp_server/eprt.feature +1 -0
  11. data/features/ftp_server/epsv.feature +1 -0
  12. data/features/ftp_server/get_ipv6.feature +3 -0
  13. data/features/ftp_server/pasv.feature +10 -3
  14. data/features/ftp_server/step_definitions/logging.rb +2 -0
  15. data/features/ftp_server/step_definitions/test_server.rb +6 -0
  16. data/features/step_definitions/append.rb +2 -0
  17. data/features/step_definitions/client.rb +3 -0
  18. data/features/step_definitions/client_and_server_files.rb +2 -0
  19. data/features/step_definitions/client_files.rb +2 -0
  20. data/features/step_definitions/command.rb +2 -0
  21. data/features/step_definitions/connect.rb +2 -0
  22. data/features/step_definitions/delete.rb +2 -0
  23. data/features/step_definitions/directory_navigation.rb +2 -0
  24. data/features/step_definitions/error_replies.rb +2 -0
  25. data/features/step_definitions/features.rb +2 -0
  26. data/features/step_definitions/file_structure.rb +2 -0
  27. data/features/step_definitions/generic_send.rb +2 -0
  28. data/features/step_definitions/get.rb +2 -0
  29. data/features/step_definitions/help.rb +2 -0
  30. data/features/step_definitions/invalid_commands.rb +2 -0
  31. data/features/step_definitions/ipv6.rb +11 -0
  32. data/features/step_definitions/line_endings.rb +2 -0
  33. data/features/step_definitions/list.rb +2 -0
  34. data/features/step_definitions/login.rb +2 -0
  35. data/features/step_definitions/mkdir.rb +2 -0
  36. data/features/step_definitions/mode.rb +2 -0
  37. data/features/step_definitions/mtime.rb +2 -0
  38. data/features/step_definitions/noop.rb +2 -0
  39. data/features/step_definitions/options.rb +2 -0
  40. data/features/step_definitions/passive.rb +7 -0
  41. data/features/step_definitions/pending.rb +2 -0
  42. data/features/step_definitions/port.rb +2 -0
  43. data/features/step_definitions/put.rb +2 -0
  44. data/features/step_definitions/quit.rb +2 -0
  45. data/features/step_definitions/rename.rb +2 -0
  46. data/features/step_definitions/rmdir.rb +2 -0
  47. data/features/step_definitions/server_files.rb +2 -0
  48. data/features/step_definitions/server_title.rb +2 -0
  49. data/features/step_definitions/size.rb +2 -0
  50. data/features/step_definitions/status.rb +2 -0
  51. data/features/step_definitions/success_replies.rb +2 -0
  52. data/features/step_definitions/system.rb +5 -0
  53. data/features/step_definitions/timing.rb +2 -0
  54. data/features/step_definitions/type.rb +2 -0
  55. data/features/support/env.rb +2 -0
  56. data/features/support/example_server.rb +3 -1
  57. data/features/support/test_client.rb +27 -19
  58. data/features/support/test_file_templates.rb +2 -0
  59. data/features/support/test_server.rb +31 -20
  60. data/features/support/test_server_files.rb +2 -0
  61. data/ftpd.gemspec +17 -11
  62. data/lib/ftpd.rb +2 -0
  63. data/lib/ftpd/auth_levels.rb +2 -0
  64. data/lib/ftpd/cmd_abor.rb +2 -0
  65. data/lib/ftpd/cmd_allo.rb +2 -0
  66. data/lib/ftpd/cmd_appe.rb +2 -0
  67. data/lib/ftpd/cmd_auth.rb +2 -0
  68. data/lib/ftpd/cmd_cdup.rb +2 -0
  69. data/lib/ftpd/cmd_cwd.rb +2 -0
  70. data/lib/ftpd/cmd_dele.rb +2 -0
  71. data/lib/ftpd/cmd_eprt.rb +2 -0
  72. data/lib/ftpd/cmd_epsv.rb +4 -2
  73. data/lib/ftpd/cmd_feat.rb +2 -0
  74. data/lib/ftpd/cmd_help.rb +2 -0
  75. data/lib/ftpd/cmd_list.rb +2 -0
  76. data/lib/ftpd/cmd_login.rb +2 -0
  77. data/lib/ftpd/cmd_mdtm.rb +2 -0
  78. data/lib/ftpd/cmd_mkd.rb +2 -0
  79. data/lib/ftpd/cmd_mode.rb +2 -0
  80. data/lib/ftpd/cmd_nlst.rb +2 -0
  81. data/lib/ftpd/cmd_noop.rb +2 -0
  82. data/lib/ftpd/cmd_opts.rb +2 -0
  83. data/lib/ftpd/cmd_pasv.rb +5 -3
  84. data/lib/ftpd/cmd_pbsz.rb +2 -0
  85. data/lib/ftpd/cmd_port.rb +2 -0
  86. data/lib/ftpd/cmd_prot.rb +2 -0
  87. data/lib/ftpd/cmd_pwd.rb +2 -0
  88. data/lib/ftpd/cmd_quit.rb +2 -0
  89. data/lib/ftpd/cmd_rein.rb +2 -0
  90. data/lib/ftpd/cmd_rename.rb +2 -0
  91. data/lib/ftpd/cmd_rest.rb +2 -0
  92. data/lib/ftpd/cmd_retr.rb +2 -0
  93. data/lib/ftpd/cmd_rmd.rb +2 -0
  94. data/lib/ftpd/cmd_site.rb +2 -0
  95. data/lib/ftpd/cmd_size.rb +2 -0
  96. data/lib/ftpd/cmd_smnt.rb +2 -0
  97. data/lib/ftpd/cmd_stat.rb +2 -0
  98. data/lib/ftpd/cmd_stor.rb +2 -0
  99. data/lib/ftpd/cmd_stou.rb +2 -0
  100. data/lib/ftpd/cmd_stru.rb +2 -0
  101. data/lib/ftpd/cmd_syst.rb +2 -0
  102. data/lib/ftpd/cmd_type.rb +2 -0
  103. data/lib/ftpd/command_handler.rb +3 -0
  104. data/lib/ftpd/command_handler_factory.rb +2 -0
  105. data/lib/ftpd/command_handlers.rb +2 -0
  106. data/lib/ftpd/command_loop.rb +2 -0
  107. data/lib/ftpd/command_sequence_checker.rb +2 -0
  108. data/lib/ftpd/config.rb +2 -0
  109. data/lib/ftpd/connection_throttle.rb +2 -0
  110. data/lib/ftpd/connection_tracker.rb +2 -0
  111. data/lib/ftpd/data_connection_helper.rb +2 -0
  112. data/lib/ftpd/data_server_factory.rb +44 -0
  113. data/lib/ftpd/data_server_factory/random_ephemeral_port.rb +26 -0
  114. data/lib/ftpd/data_server_factory/specific_port_range.rb +37 -0
  115. data/lib/ftpd/disk_file_system.rb +2 -0
  116. data/lib/ftpd/error.rb +2 -0
  117. data/lib/ftpd/exception_translator.rb +2 -0
  118. data/lib/ftpd/exceptions.rb +2 -0
  119. data/lib/ftpd/file_info.rb +2 -0
  120. data/lib/ftpd/file_system_helper.rb +2 -0
  121. data/lib/ftpd/ftp_server.rb +27 -0
  122. data/lib/ftpd/gets_peer_address.rb +2 -0
  123. data/lib/ftpd/insecure_certificate.rb +2 -0
  124. data/lib/ftpd/list_format/eplf.rb +2 -0
  125. data/lib/ftpd/list_format/ls.rb +2 -0
  126. data/lib/ftpd/list_path.rb +2 -0
  127. data/lib/ftpd/null_logger.rb +2 -0
  128. data/lib/ftpd/protocols.rb +2 -0
  129. data/lib/ftpd/read_only_disk_file_system.rb +2 -0
  130. data/lib/ftpd/server.rb +2 -0
  131. data/lib/ftpd/session.rb +7 -0
  132. data/lib/ftpd/session_config.rb +26 -2
  133. data/lib/ftpd/stream.rb +2 -0
  134. data/lib/ftpd/telnet.rb +3 -2
  135. data/lib/ftpd/temp_dir.rb +2 -0
  136. data/lib/ftpd/tls_server.rb +2 -0
  137. data/lib/ftpd/translate_exceptions.rb +2 -0
  138. data/spec/command_sequence_checker_spec.rb +2 -0
  139. data/spec/connection_throttle_spec.rb +2 -0
  140. data/spec/connection_tracker_spec.rb +2 -0
  141. data/spec/data_server_factory_spec.rb +104 -0
  142. data/spec/disk_file_system_spec.rb +2 -0
  143. data/spec/exception_translator_spec.rb +2 -0
  144. data/spec/file_info_spec.rb +2 -0
  145. data/spec/ftp_server_error_spec.rb +2 -0
  146. data/spec/list_format/eplf_spec.rb +2 -0
  147. data/spec/list_format/ls_spec.rb +2 -0
  148. data/spec/list_path_spec.rb +2 -0
  149. data/spec/null_logger_spec.rb +2 -0
  150. data/spec/protocols_spec.rb +58 -38
  151. data/spec/server_spec.rb +2 -0
  152. data/spec/spec_helper.rb +2 -0
  153. data/spec/telnet_spec.rb +2 -0
  154. data/spec/translate_exceptions_spec.rb +2 -0
  155. data/testlib/network.rb +17 -0
  156. metadata +13 -7
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully requests features$/ do
2
4
  @feature_reply = client.raw "FEAT"
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully sets file structure "(.*?)"$/ do
2
4
  |file_structure|
3
5
  client.raw 'STRU', file_structure
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully sends "(.*?)"$/ do |command|
2
4
  @reply = client.raw command
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully gets (text|binary) "(.*?)"$/ \
2
4
  do |mode, remote_path|
3
5
  client.get mode, remote_path
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully asks for help(?: for "(.*?)")?$/ do
2
4
  |command|
3
5
  @help_reply = client.help(command)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client sends an empty command$/ do
2
4
  capture_error do
3
5
  client.raw ''
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../testlib/network"
4
+
5
+ include TestLib::Network
6
+
7
+ Given /^the stack supports ipv6$/ do
8
+ unless ipv6_supported?
9
+ pending "Test skipped: stack does not support ipv6"
10
+ end
11
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  def line_ending_type(s)
2
4
  if s =~ /\r\n/
3
5
  :windows
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class FileList
2
4
 
3
5
  def initialize(lines)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  def logged_in?
2
4
  step "the client lists the directory"
3
5
  @error.nil?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client makes directory "(.*?)"$/ do |path|
2
4
  capture_error do
3
5
  step %Q(the client successfully makes directory "#{path}")
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully sets mode "(.*?)"$/ do |mode|
2
4
  client.raw 'MODE', mode
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'date'
2
4
 
3
5
  When /^the client successfully gets mtime of "(.*?)"$/ \
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the( \w+)? client successfully does nothing( with a parameter)?$/ do
2
4
  |client_name, with_param|
3
5
  if with_param
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully sets option "(.*?)"$/ do |option|
2
4
  client.set_option option
3
5
  end
@@ -1,3 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Given /^the client is in (passive|active) mode$/ do |mode|
2
4
  client.passive = mode == 'passive'
3
5
  end
6
+
7
+ Then(/^the server advertises passive IP (\S+)$/) do |ip|
8
+ quads = @reply.scan(/\d+/)[1..4].join(".")
9
+ expect(quads).to eq ip
10
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Given /^PENDING/ do
2
4
  pending
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client sends PORT "(.*?)"$/ do |param|
2
4
  capture_error do
3
5
  client.raw 'PORT', param
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully puts (text|binary) "(.*?)"$/ do
2
4
  |mode, local_path|
3
5
  client.put mode, local_path
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully quits$/ do
2
4
  client.quit
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client renames "(.*?)" to "(.*?)"$/ do
2
4
  |from_path, to_path|
3
5
  capture_error do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client removes directory "(.*?)"$/ do |path|
2
4
  capture_error do
3
5
  step %Q(the client successfully removes directory "#{path}")
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'date'
2
4
 
3
5
  Given /^the server has directory "(.*?)"$/ do |remote_path|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Then /^the server returns its title$/ do
2
4
  step 'the server returns its name'
3
5
  step 'the server returns its version'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully gets size of (text|binary) "(.*?)"$/ \
2
4
  do |mode, remote_path|
3
5
  @size = client.get_size mode, remote_path
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully requests status$/ do
2
4
  @response = client.status
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Then /^the server returns a "(.*?)" reply$/ do |reply|
2
4
  expect(@reply).to eq reply + "\n"
3
5
  end
@@ -1,5 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully queries system ID$/ do
2
4
  @reply = client.system
5
+ # Prior to ruby-2.3.0, the #system call returned a string ending in
6
+ # a new-line.
7
+ @reply += "\n" unless @reply =~ /\n$/
3
8
  end
4
9
 
5
10
  Then /^the server returns a system ID reply$/ do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Before do
2
4
  @start_time = Time.now
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  When /^the client successfully sets type "(.*?)"$/ do |type|
2
4
  client.raw 'TYPE', type
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  $LOAD_PATH << File.expand_path('../../lib', File.dirname(__FILE__))
2
4
 
3
5
  require 'ftpd'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fileutils'
2
4
  require 'forwardable'
3
5
  require File.expand_path('test_server_files',
@@ -50,7 +52,7 @@ class ExampleServer
50
52
  private
51
53
 
52
54
  def read_output
53
- output = ''
55
+ output = ''.dup
54
56
  loop do
55
57
  line = @io.gets
56
58
  break if line.nil?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'double_bag_ftps'
2
4
  require 'net/ftp'
3
5
 
@@ -20,10 +22,11 @@ class TestClient
20
22
 
21
23
  def close
22
24
  return unless @ftp
23
- @ftp.close
25
+ ftp.close
26
+ @ftp = nil
24
27
  end
25
28
 
26
- def_delegators :@ftp,
29
+ def_delegators :ftp,
27
30
  :chdir,
28
31
  :connect,
29
32
  :delete,
@@ -54,33 +57,33 @@ class TestClient
54
57
  socket.connect(out_addr)
55
58
  decorate_socket socket
56
59
  @ftp = make_ftp
57
- @ftp.set_socket(socket)
60
+ ftp.set_socket(socket)
58
61
  end
59
62
 
60
63
  def raw(*command)
61
- @ftp.sendcmd command.compact.join(' ')
64
+ ftp.sendcmd command.compact.join(' ')
62
65
  end
63
66
 
64
67
  def get(mode, remote_path)
65
68
  method = "get#{mode}file"
66
- @ftp.send method, remote_path, local_path(remote_path)
69
+ ftp.send method, remote_path, local_path(remote_path)
67
70
  end
68
71
 
69
72
  def put(mode, remote_path)
70
73
  method = "put#{mode}file"
71
- @ftp.send method, local_path(remote_path), remote_path
74
+ ftp.send method, local_path(remote_path), remote_path
72
75
  end
73
76
 
74
77
  def get_size(mode, remote_path)
75
78
  raise unless ['binary', 'text'].include?(mode)
76
- @ftp.binary = mode == 'binary'
79
+ ftp.binary = mode == 'binary'
77
80
  override_with_binary do
78
- @ftp.size(remote_path)
81
+ ftp.size(remote_path)
79
82
  end
80
83
  end
81
84
 
82
85
  def get_mtime(remote_path)
83
- @ftp.mtime(remote_path)
86
+ ftp.mtime(remote_path)
84
87
  end
85
88
 
86
89
  def add_file(path)
@@ -100,34 +103,34 @@ class TestClient
100
103
  end
101
104
 
102
105
  def xpwd
103
- response = @ftp.sendcmd('XPWD')
106
+ response = ftp.sendcmd('XPWD')
104
107
  response[/"(.+)"/, 1]
105
108
  end
106
109
 
107
110
  def store_unique(local_path, remote_path)
108
111
  command = ['STOU', remote_path].compact.join(' ')
109
112
  File.open(temp_path(local_path), 'rb') do |file|
110
- @ftp.storbinary command, file, Net::FTP::DEFAULT_BLOCKSIZE
113
+ ftp.storbinary command, file, Net::FTP::DEFAULT_BLOCKSIZE
111
114
  end
112
115
  end
113
116
 
114
117
  def append_binary(local_path, remote_path)
115
118
  command = ['APPE', remote_path].compact.join(' ')
116
119
  File.open(temp_path(local_path), 'rb') do |file|
117
- @ftp.storbinary command, file, Net::FTP::DEFAULT_BLOCKSIZE
120
+ ftp.storbinary command, file, Net::FTP::DEFAULT_BLOCKSIZE
118
121
  end
119
122
  end
120
123
 
121
124
  def append_text(local_path, remote_path)
122
125
  command = ['APPE', remote_path].compact.join(' ')
123
126
  File.open(temp_path(local_path), 'rb') do |file|
124
- @ftp.storlines command, file
127
+ ftp.storlines command, file
125
128
  end
126
129
  end
127
130
 
128
131
  def connected?
129
132
  begin
130
- @ftp.noop
133
+ ftp.noop
131
134
  true
132
135
  rescue Net::FTPTempError => e
133
136
  !!e.to_s =~ /^421/
@@ -137,13 +140,18 @@ class TestClient
137
140
  end
138
141
 
139
142
  def set_option(option)
140
- @ftp.sendcmd "OPTS #{option}"
143
+ ftp.sendcmd "OPTS #{option}"
141
144
  end
142
145
 
143
146
  private
144
-
147
+
145
148
  RAW_METHOD_REGEX = /^send_(.*)$/
146
149
 
150
+ def ftp
151
+ raise "Not started" unless @ftp
152
+ @ftp
153
+ end
154
+
147
155
  def local_path(remote_path)
148
156
  temp_path(File.basename(remote_path))
149
157
  end
@@ -207,12 +215,12 @@ class TestClient
207
215
  end
208
216
 
209
217
  def override_with_binary
210
- orig = @ftp.override_with_binary
218
+ orig = ftp.override_with_binary
211
219
  begin
212
- @ftp.override_with_binary = true
220
+ ftp.override_with_binary = true
213
221
  yield
214
222
  ensure
215
- @ftp.override_with_binary = orig
223
+ ftp.override_with_binary = orig
216
224
  end
217
225
  end
218
226
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class TestFileTemplates
2
4
 
3
5
  def [](filename)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fileutils'
2
4
  require 'forwardable'
3
5
  require 'stringio'
@@ -209,24 +211,22 @@ class TestServer
209
211
  @temp_dir = Ftpd::TempDir.make
210
212
  @log_device = StringIO.new
211
213
  @driver = TestServerDriver.new(@temp_dir)
212
- @server = Ftpd::FtpServer.new(@driver)
213
- @server.certfile_path = insecure_certfile_path
214
214
  @templates = TestFileTemplates.new
215
- self.tls = :off
216
215
  end
217
216
 
218
- def_delegator :@server, :'allow_low_data_ports='
219
- def_delegator :@server, :'auth_level'
220
- def_delegator :@server, :'auth_level='
221
- def_delegator :@server, :'failed_login_delay='
222
- def_delegator :@server, :'interface='
223
- def_delegator :@server, :'max_connections='
224
- def_delegator :@server, :'max_connections_per_ip='
225
- def_delegator :@server, :'max_failed_logins='
226
- def_delegator :@server, :'server_name'
227
- def_delegator :@server, :'server_name='
228
- def_delegator :@server, :'session_timeout='
229
- def_delegator :@server, :'tls='
217
+ def_delegator :server, :'allow_low_data_ports='
218
+ def_delegator :server, :'auth_level'
219
+ def_delegator :server, :'auth_level='
220
+ def_delegator :server, :'failed_login_delay='
221
+ def_delegator :server, :'interface='
222
+ def_delegator :server, :'max_connections='
223
+ def_delegator :server, :'max_connections_per_ip='
224
+ def_delegator :server, :'max_failed_logins='
225
+ def_delegator :server, :'nat_ip='
226
+ def_delegator :server, :'server_name'
227
+ def_delegator :server, :'server_name='
228
+ def_delegator :server, :'session_timeout='
229
+ def_delegator :server, :'tls='
230
230
 
231
231
  def_delegator :@driver, :'append='
232
232
  def_delegator :@driver, :'delete='
@@ -242,16 +242,16 @@ class TestServer
242
242
  end
243
243
 
244
244
  def start
245
- @server.log = make_log
246
- @server.start
245
+ server.log = make_log
246
+ server.start
247
247
  end
248
248
 
249
249
  def stop
250
- @server.stop
250
+ server.stop
251
251
  end
252
252
 
253
253
  def host
254
- @server.interface
254
+ server.interface
255
255
  end
256
256
 
257
257
  def user
@@ -267,7 +267,7 @@ class TestServer
267
267
  end
268
268
 
269
269
  def port
270
- @server.bound_port
270
+ server.bound_port
271
271
  end
272
272
 
273
273
  def template(path)
@@ -276,6 +276,17 @@ class TestServer
276
276
 
277
277
  private
278
278
 
279
+ def server
280
+ @server ||= make_server
281
+ end
282
+
283
+ def make_server
284
+ s = Ftpd::FtpServer.new(@driver)
285
+ s.certfile_path = insecure_certfile_path
286
+ s.tls = :off
287
+ s
288
+ end
289
+
279
290
  def temp_dir
280
291
  @temp_dir
281
292
  end