ftpd 1.1.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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