puma 5.6.7 → 6.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +327 -16
  3. data/README.md +79 -29
  4. data/bin/puma-wild +1 -1
  5. data/docs/compile_options.md +34 -0
  6. data/docs/fork_worker.md +1 -3
  7. data/docs/kubernetes.md +12 -0
  8. data/docs/nginx.md +1 -1
  9. data/docs/restart.md +1 -0
  10. data/docs/systemd.md +3 -6
  11. data/docs/testing_benchmarks_local_files.md +150 -0
  12. data/docs/testing_test_rackup_ci_files.md +36 -0
  13. data/ext/puma_http11/extconf.rb +16 -9
  14. data/ext/puma_http11/http11_parser.c +1 -1
  15. data/ext/puma_http11/http11_parser.h +1 -1
  16. data/ext/puma_http11/http11_parser.java.rl +2 -2
  17. data/ext/puma_http11/http11_parser.rl +2 -2
  18. data/ext/puma_http11/http11_parser_common.rl +2 -2
  19. data/ext/puma_http11/mini_ssl.c +127 -19
  20. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  21. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
  22. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +157 -53
  23. data/ext/puma_http11/puma_http11.c +17 -9
  24. data/lib/puma/app/status.rb +4 -4
  25. data/lib/puma/binder.rb +50 -53
  26. data/lib/puma/cli.rb +16 -18
  27. data/lib/puma/client.rb +86 -19
  28. data/lib/puma/cluster/worker.rb +18 -11
  29. data/lib/puma/cluster/worker_handle.rb +4 -1
  30. data/lib/puma/cluster.rb +102 -40
  31. data/lib/puma/commonlogger.rb +21 -14
  32. data/lib/puma/configuration.rb +77 -59
  33. data/lib/puma/const.rb +129 -92
  34. data/lib/puma/control_cli.rb +15 -11
  35. data/lib/puma/detect.rb +7 -4
  36. data/lib/puma/dsl.rb +250 -56
  37. data/lib/puma/error_logger.rb +18 -9
  38. data/lib/puma/events.rb +6 -126
  39. data/lib/puma/io_buffer.rb +39 -4
  40. data/lib/puma/jruby_restart.rb +2 -1
  41. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  42. data/lib/puma/launcher.rb +102 -175
  43. data/lib/puma/log_writer.rb +147 -0
  44. data/lib/puma/minissl/context_builder.rb +26 -12
  45. data/lib/puma/minissl.rb +104 -11
  46. data/lib/puma/null_io.rb +16 -2
  47. data/lib/puma/plugin/systemd.rb +90 -0
  48. data/lib/puma/plugin/tmp_restart.rb +1 -1
  49. data/lib/puma/rack/builder.rb +6 -6
  50. data/lib/puma/rack/urlmap.rb +1 -1
  51. data/lib/puma/rack_default.rb +19 -4
  52. data/lib/puma/reactor.rb +19 -10
  53. data/lib/puma/request.rb +365 -170
  54. data/lib/puma/runner.rb +56 -20
  55. data/lib/puma/sd_notify.rb +149 -0
  56. data/lib/puma/server.rb +137 -89
  57. data/lib/puma/single.rb +13 -11
  58. data/lib/puma/state_file.rb +3 -6
  59. data/lib/puma/thread_pool.rb +57 -19
  60. data/lib/puma/util.rb +0 -11
  61. data/lib/puma.rb +9 -10
  62. data/lib/rack/handler/puma.rb +113 -86
  63. data/tools/Dockerfile +2 -2
  64. metadata +11 -7
  65. data/lib/puma/queue_close.rb +0 -26
  66. data/lib/puma/systemd.rb +0 -46
  67. data/lib/rack/version_restriction.rb +0 -15
data/lib/puma/launcher.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/events'
4
- require 'puma/detect'
5
- require 'puma/cluster'
6
- require 'puma/single'
7
- require 'puma/const'
8
- require 'puma/binder'
3
+ require_relative 'log_writer'
4
+ require_relative 'events'
5
+ require_relative 'detect'
6
+ require_relative 'cluster'
7
+ require_relative 'single'
8
+ require_relative 'const'
9
+ require_relative 'binder'
9
10
 
10
11
  module Puma
11
12
  # Puma::Launcher is the single entry point for starting a Puma server based on user
@@ -15,18 +16,14 @@ module Puma
15
16
  # It is responsible for either launching a cluster of Puma workers or a single
16
17
  # puma server.
17
18
  class Launcher
18
- # @deprecated 6.0.0
19
- KEYS_NOT_TO_PERSIST_IN_STATE = [
20
- :logger, :lowlevel_error_handler,
21
- :before_worker_shutdown, :before_worker_boot, :before_worker_fork,
22
- :after_worker_boot, :before_fork, :on_restart
23
- ]
19
+ autoload :BundlePruner, 'puma/launcher/bundle_pruner'
20
+
24
21
  # Returns an instance of Launcher
25
22
  #
26
23
  # +conf+ A Puma::Configuration object indicating how to run the server.
27
24
  #
28
25
  # +launcher_args+ A Hash that currently has one required key `:events`,
29
- # this is expected to hold an object similar to an `Puma::Events.stdio`,
26
+ # this is expected to hold an object similar to an `Puma::LogWriter.stdio`,
30
27
  # this object will be responsible for broadcasting Puma's internal state
31
28
  # to a logging destination. An optional key `:argv` can be supplied,
32
29
  # this should be an array of strings, these arguments are re-used when
@@ -40,25 +37,35 @@ module Puma
40
37
  # [200, {}, ["hello world"]]
41
38
  # end
42
39
  # end
43
- # Puma::Launcher.new(conf, events: Puma::Events.stdio).run
40
+ # Puma::Launcher.new(conf, log_writer: Puma::LogWriter.stdio).run
44
41
  def initialize(conf, launcher_args={})
45
42
  @runner = nil
46
- @events = launcher_args[:events] || Events::DEFAULT
43
+ @log_writer = launcher_args[:log_writer] || LogWriter::DEFAULT
44
+ @events = launcher_args[:events] || Events.new
47
45
  @argv = launcher_args[:argv] || []
48
46
  @original_argv = @argv.dup
49
47
  @config = conf
50
48
 
51
- @binder = Binder.new(@events, conf)
52
- @binder.create_inherited_fds(ENV).each { |k| ENV.delete k }
53
- @binder.create_activated_fds(ENV).each { |k| ENV.delete k }
54
-
55
- @environment = conf.environment
49
+ @config.options[:log_writer] = @log_writer
56
50
 
57
51
  # Advertise the Configuration
58
52
  Puma.cli_config = @config if defined?(Puma.cli_config)
59
53
 
60
54
  @config.load
61
55
 
56
+ @binder = Binder.new(@log_writer, conf)
57
+ @binder.create_inherited_fds(ENV).each { |k| ENV.delete k }
58
+ @binder.create_activated_fds(ENV).each { |k| ENV.delete k }
59
+
60
+ @environment = conf.environment
61
+
62
+ # Load the systemd integration if we detect systemd's NOTIFY_SOCKET.
63
+ # Skip this on JRuby though, because it is incompatible with the systemd
64
+ # integration due to https://github.com/jruby/jruby/issues/6504
65
+ if ENV["NOTIFY_SOCKET"] && !Puma.jruby?
66
+ @config.plugins.create('systemd')
67
+ end
68
+
62
69
  if @config.options[:bind_to_activated_sockets]
63
70
  @config.options[:binds] = @binder.synthesize_binds_from_activated_fs(
64
71
  @config.options[:binds],
@@ -69,8 +76,10 @@ module Puma
69
76
  @options = @config.options
70
77
  @config.clamp
71
78
 
72
- @events.formatter = Events::PidFormatter.new if clustered?
73
- @events.formatter = options[:log_formatter] if @options[:log_formatter]
79
+ @log_writer.formatter = LogWriter::PidFormatter.new if clustered?
80
+ @log_writer.formatter = options[:log_formatter] if @options[:log_formatter]
81
+
82
+ @log_writer.custom_logger = options[:custom_logger] if @options[:custom_logger]
74
83
 
75
84
  generate_restart_data
76
85
 
@@ -80,17 +89,17 @@ module Puma
80
89
 
81
90
  Dir.chdir(@restart_dir)
82
91
 
83
- prune_bundler if prune_bundler?
92
+ prune_bundler!
84
93
 
85
94
  @environment = @options[:environment] if @options[:environment]
86
95
  set_rack_environment
87
96
 
88
97
  if clustered?
89
- @options[:logger] = @events
98
+ @options[:logger] = @log_writer
90
99
 
91
- @runner = Cluster.new(self, @events)
100
+ @runner = Cluster.new(self)
92
101
  else
93
- @runner = Single.new(self, @events)
102
+ @runner = Single.new(self)
94
103
  end
95
104
  Puma.stats_object = @runner
96
105
 
@@ -99,7 +108,7 @@ module Puma
99
108
  log_config if ENV['PUMA_LOG_CONFIG']
100
109
  end
101
110
 
102
- attr_reader :binder, :events, :config, :options, :restart_dir
111
+ attr_reader :binder, :log_writer, :events, :config, :options, :restart_dir
103
112
 
104
113
  # Return stats about the server
105
114
  def stats
@@ -115,7 +124,7 @@ module Puma
115
124
  permission = @options[:state_permission]
116
125
  return unless path
117
126
 
118
- require 'puma/state_file'
127
+ require_relative 'state_file'
119
128
 
120
129
  sf = StateFile.new
121
130
  sf.pid = Process.pid
@@ -172,16 +181,7 @@ module Puma
172
181
 
173
182
  # Run the server. This blocks until the server is stopped
174
183
  def run
175
- previous_env =
176
- if defined?(Bundler)
177
- env = Bundler::ORIGINAL_ENV.dup
178
- # add -rbundler/setup so we load from Gemfile when restarting
179
- bundle = "-rbundler/setup"
180
- env["RUBYOPT"] = [env["RUBYOPT"], bundle].join(" ").lstrip unless env["RUBYOPT"].to_s.include?(bundle)
181
- env
182
- else
183
- ENV.to_h
184
- end
184
+ previous_env = get_env
185
185
 
186
186
  @config.clamp
187
187
 
@@ -189,24 +189,11 @@ module Puma
189
189
 
190
190
  setup_signals
191
191
  set_process_title
192
- integrate_with_systemd
192
+
193
+ # This blocks until the server is stopped
193
194
  @runner.run
194
195
 
195
- case @status
196
- when :halt
197
- log "* Stopping immediately!"
198
- @runner.stop_control
199
- when :run, :stop
200
- graceful_stop
201
- when :restart
202
- log "* Restarting..."
203
- ENV.replace(previous_env)
204
- @runner.stop_control
205
- restart!
206
- when :exit
207
- # nothing
208
- end
209
- close_binder_listeners unless @status == :restart
196
+ do_run_finished(previous_env)
210
197
  end
211
198
 
212
199
  # Return all tcp ports the launcher may be using, TCP or SSL
@@ -250,30 +237,56 @@ module Puma
250
237
 
251
238
  private
252
239
 
253
- # If configured, write the pid of the current process out
254
- # to a file.
255
- def write_pid
256
- path = @options[:pidfile]
257
- return unless path
258
- cur_pid = Process.pid
259
- File.write path, cur_pid, mode: 'wb:UTF-8'
260
- at_exit do
261
- delete_pidfile if cur_pid == Process.pid
240
+ def get_env
241
+ if defined?(Bundler)
242
+ env = Bundler::ORIGINAL_ENV.dup
243
+ # add -rbundler/setup so we load from Gemfile when restarting
244
+ bundle = "-rbundler/setup"
245
+ env["RUBYOPT"] = [env["RUBYOPT"], bundle].join(" ").lstrip unless env["RUBYOPT"].to_s.include?(bundle)
246
+ env
247
+ else
248
+ ENV.to_h
262
249
  end
263
250
  end
264
251
 
265
- def reload_worker_directory
266
- @runner.reload_worker_directory if @runner.respond_to?(:reload_worker_directory)
252
+ def do_run_finished(previous_env)
253
+ case @status
254
+ when :halt
255
+ do_forceful_stop
256
+ when :run, :stop
257
+ do_graceful_stop
258
+ when :restart
259
+ do_restart(previous_env)
260
+ end
261
+
262
+ close_binder_listeners unless @status == :restart
263
+ end
264
+
265
+ def do_forceful_stop
266
+ log "* Stopping immediately!"
267
+ @runner.stop_control
268
+ end
269
+
270
+ def do_graceful_stop
271
+ @events.fire_on_stopped!
272
+ @runner.stop_blocked
273
+ end
274
+
275
+ def do_restart(previous_env)
276
+ log "* Restarting..."
277
+ ENV.replace(previous_env)
278
+ @runner.stop_control
279
+ restart!
267
280
  end
268
281
 
269
282
  def restart!
270
283
  @events.fire_on_restart!
271
- @config.run_hooks :on_restart, self, @events
284
+ @config.run_hooks :on_restart, self, @log_writer
272
285
 
273
286
  if Puma.jruby?
274
287
  close_binder_listeners
275
288
 
276
- require 'puma/jruby_restart'
289
+ require_relative 'jruby_restart'
277
290
  JRubyRestart.chdir_exec(@restart_dir, restart_args)
278
291
  elsif Puma.windows?
279
292
  close_binder_listeners
@@ -290,94 +303,24 @@ module Puma
290
303
  end
291
304
  end
292
305
 
293
- # @!attribute [r] files_to_require_after_prune
294
- def files_to_require_after_prune
295
- puma = spec_for_gem("puma")
296
-
297
- require_paths_for_gem(puma) + extra_runtime_deps_directories
298
- end
299
-
300
- # @!attribute [r] extra_runtime_deps_directories
301
- def extra_runtime_deps_directories
302
- Array(@options[:extra_runtime_dependencies]).map do |d_name|
303
- if (spec = spec_for_gem(d_name))
304
- require_paths_for_gem(spec)
305
- else
306
- log "* Could not load extra dependency: #{d_name}"
307
- nil
308
- end
309
- end.flatten.compact
310
- end
311
-
312
- # @!attribute [r] puma_wild_location
313
- def puma_wild_location
314
- puma = spec_for_gem("puma")
315
- dirs = require_paths_for_gem(puma)
316
- puma_lib_dir = dirs.detect { |x| File.exist? File.join(x, '../bin/puma-wild') }
317
- File.expand_path(File.join(puma_lib_dir, "../bin/puma-wild"))
318
- end
319
-
320
- def prune_bundler
321
- return if ENV['PUMA_BUNDLER_PRUNED']
322
- return unless defined?(Bundler)
323
- require_rubygems_min_version!(Gem::Version.new("2.2"), "prune_bundler")
324
- unless puma_wild_location
325
- log "! Unable to prune Bundler environment, continuing"
326
- return
327
- end
328
-
329
- dirs = files_to_require_after_prune
330
-
331
- log '* Pruning Bundler environment'
332
- home = ENV['GEM_HOME']
333
- bundle_gemfile = Bundler.original_env['BUNDLE_GEMFILE']
334
- bundle_app_config = Bundler.original_env['BUNDLE_APP_CONFIG']
335
- with_unbundled_env do
336
- ENV['GEM_HOME'] = home
337
- ENV['BUNDLE_GEMFILE'] = bundle_gemfile
338
- ENV['PUMA_BUNDLER_PRUNED'] = '1'
339
- ENV["BUNDLE_APP_CONFIG"] = bundle_app_config
340
- args = [Gem.ruby, puma_wild_location, '-I', dirs.join(':')] + @original_argv
341
- # Ruby 2.0+ defaults to true which breaks socket activation
342
- args += [{:close_others => false}]
343
- Kernel.exec(*args)
344
- end
345
- end
346
-
347
- #
348
- # Puma's systemd integration allows Puma to inform systemd:
349
- # 1. when it has successfully started
350
- # 2. when it is starting shutdown
351
- # 3. periodically for a liveness check with a watchdog thread
352
- #
353
-
354
- def integrate_with_systemd
355
- return unless ENV["NOTIFY_SOCKET"]
356
-
357
- begin
358
- require 'puma/systemd'
359
- rescue LoadError
360
- log "Systemd integration failed. It looks like you're trying to use systemd notify but don't have sd_notify gem installed"
361
- return
306
+ # If configured, write the pid of the current process out
307
+ # to a file.
308
+ def write_pid
309
+ path = @options[:pidfile]
310
+ return unless path
311
+ cur_pid = Process.pid
312
+ File.write path, cur_pid, mode: 'wb:UTF-8'
313
+ at_exit do
314
+ delete_pidfile if cur_pid == Process.pid
362
315
  end
363
-
364
- log "* Enabling systemd notification integration"
365
-
366
- systemd = Systemd.new(@events)
367
- systemd.hook_events
368
- systemd.start_watchdog
369
- end
370
-
371
- def spec_for_gem(gem_name)
372
- Bundler.rubygems.loaded_specs(gem_name)
373
316
  end
374
317
 
375
- def require_paths_for_gem(gem_spec)
376
- gem_spec.full_require_paths
318
+ def reload_worker_directory
319
+ @runner.reload_worker_directory if @runner.respond_to?(:reload_worker_directory)
377
320
  end
378
321
 
379
322
  def log(str)
380
- @events.log str
323
+ @log_writer.log(str)
381
324
  end
382
325
 
383
326
  def clustered?
@@ -385,15 +328,10 @@ module Puma
385
328
  end
386
329
 
387
330
  def unsupported(str)
388
- @events.error(str)
331
+ @log_writer.error(str)
389
332
  raise UnsupportedOption
390
333
  end
391
334
 
392
- def graceful_stop
393
- @events.fire_on_stopped!
394
- @runner.stop_blocked
395
- end
396
-
397
335
  def set_process_title
398
336
  Process.respond_to?(:setproctitle) ? Process.setproctitle(title) : $0 = title
399
337
  end
@@ -419,6 +357,11 @@ module Puma
419
357
  @options[:prune_bundler] && clustered? && !@options[:preload_app]
420
358
  end
421
359
 
360
+ def prune_bundler!
361
+ return unless prune_bundler?
362
+ BundlePruner.new(@original_argv, @options[:extra_runtime_dependencies], @log_writer).prune
363
+ end
364
+
422
365
  def generate_restart_data
423
366
  if dir = @options[:directory]
424
367
  @restart_dir = dir
@@ -485,7 +428,8 @@ module Puma
485
428
 
486
429
  begin
487
430
  Signal.trap "SIGTERM" do
488
- graceful_stop
431
+ # Shortcut the control flow in case raise_exception_on_sigterm is true
432
+ do_graceful_stop
489
433
 
490
434
  raise(SignalException, "SIGTERM") if @options[:raise_exception_on_sigterm]
491
435
  end
@@ -517,8 +461,8 @@ module Puma
517
461
  unless Puma.jruby? # INFO in use by JVM already
518
462
  Signal.trap "SIGINFO" do
519
463
  thread_status do |name, backtrace|
520
- @events.log name
521
- @events.log backtrace.map { |bt| " #{bt}" }
464
+ @log_writer.log(name)
465
+ @log_writer.log(backtrace.map { |bt| " #{bt}" })
522
466
  end
523
467
  end
524
468
  end
@@ -528,23 +472,6 @@ module Puma
528
472
  end
529
473
  end
530
474
 
531
- def require_rubygems_min_version!(min_version, feature)
532
- return if min_version <= Gem::Version.new(Gem::VERSION)
533
-
534
- raise "#{feature} is not supported on your version of RubyGems. " \
535
- "You must have RubyGems #{min_version}+ to use this feature."
536
- end
537
-
538
- # @version 5.0.0
539
- def with_unbundled_env
540
- bundler_ver = Gem::Version.new(Bundler::VERSION)
541
- if bundler_ver < Gem::Version.new('2.1.0')
542
- Bundler.with_clean_env { yield }
543
- else
544
- Bundler.with_unbundled_env { yield }
545
- end
546
- end
547
-
548
475
  def log_config
549
476
  log "Configuration:"
550
477
 
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'null_io'
4
+ require_relative 'error_logger'
5
+ require 'stringio'
6
+ require 'io/wait' unless Puma::HAS_NATIVE_IO_WAIT
7
+
8
+ module Puma
9
+
10
+ # Handles logging concerns for both standard messages
11
+ # (+stdout+) and errors (+stderr+).
12
+ class LogWriter
13
+
14
+ class DefaultFormatter
15
+ def call(str)
16
+ str
17
+ end
18
+ end
19
+
20
+ class PidFormatter
21
+ def call(str)
22
+ "[#{$$}] #{str}"
23
+ end
24
+ end
25
+
26
+ LOG_QUEUE = Queue.new
27
+
28
+ attr_reader :stdout,
29
+ :stderr
30
+
31
+ attr_accessor :formatter, :custom_logger
32
+
33
+ # Create a LogWriter that prints to +stdout+ and +stderr+.
34
+ def initialize(stdout, stderr)
35
+ @formatter = DefaultFormatter.new
36
+ @custom_logger = nil
37
+ @stdout = stdout
38
+ @stderr = stderr
39
+
40
+ @debug = ENV.key?('PUMA_DEBUG')
41
+ @error_logger = ErrorLogger.new(@stderr)
42
+ end
43
+
44
+ DEFAULT = new(STDOUT, STDERR)
45
+
46
+ # Returns an LogWriter object which writes its status to
47
+ # two StringIO objects.
48
+ def self.strings
49
+ LogWriter.new(StringIO.new, StringIO.new)
50
+ end
51
+
52
+ def self.stdio
53
+ LogWriter.new($stdout, $stderr)
54
+ end
55
+
56
+ def self.null
57
+ n = NullIO.new
58
+ LogWriter.new(n, n)
59
+ end
60
+
61
+ # Write +str+ to +@stdout+
62
+ def log(str)
63
+ if @custom_logger&.respond_to?(:write)
64
+ @custom_logger.write(format(str))
65
+ else
66
+ internal_write "#{@formatter.call str}\n"
67
+ end
68
+ end
69
+
70
+ def write(str)
71
+ internal_write @formatter.call(str)
72
+ end
73
+
74
+ def internal_write(str)
75
+ LOG_QUEUE << str
76
+ while (w_str = LOG_QUEUE.pop(true)) do
77
+ begin
78
+ @stdout.is_a?(IO) and @stdout.wait_writable(1)
79
+ @stdout.write w_str
80
+ @stdout.flush unless @stdout.sync
81
+ rescue Errno::EPIPE, Errno::EBADF, IOError, Errno::EINVAL
82
+ # 'Invalid argument' (Errno::EINVAL) may be raised by flush
83
+ end
84
+ end
85
+ rescue ThreadError
86
+ end
87
+ private :internal_write
88
+
89
+ def debug?
90
+ @debug
91
+ end
92
+
93
+ def debug(str)
94
+ log("% #{str}") if @debug
95
+ end
96
+
97
+ # Write +str+ to +@stderr+
98
+ def error(str)
99
+ @error_logger.info(text: @formatter.call("ERROR: #{str}"))
100
+ exit 1
101
+ end
102
+
103
+ def format(str)
104
+ formatter.call(str)
105
+ end
106
+
107
+ # An HTTP connection error has occurred.
108
+ # +error+ a connection exception, +req+ the request,
109
+ # and +text+ additional info
110
+ # @version 5.0.0
111
+ def connection_error(error, req, text="HTTP connection error")
112
+ @error_logger.info(error: error, req: req, text: text)
113
+ end
114
+
115
+ # An HTTP parse error has occurred.
116
+ # +error+ a parsing exception,
117
+ # and +req+ the request.
118
+ def parse_error(error, req)
119
+ @error_logger.info(error: error, req: req, text: 'HTTP parse error, malformed request')
120
+ end
121
+
122
+ # An SSL error has occurred.
123
+ # @param error <Puma::MiniSSL::SSLError>
124
+ # @param ssl_socket <Puma::MiniSSL::Socket>
125
+ def ssl_error(error, ssl_socket)
126
+ peeraddr = ssl_socket.peeraddr.last rescue "<unknown>"
127
+ peercert = ssl_socket.peercert
128
+ subject = peercert&.subject
129
+ @error_logger.info(error: error, text: "SSL error, peer: #{peeraddr}, peer cert: #{subject}")
130
+ end
131
+
132
+ # An unknown error has occurred.
133
+ # +error+ an exception object, +req+ the request,
134
+ # and +text+ additional info
135
+ def unknown_error(error, req=nil, text="Unknown error")
136
+ @error_logger.info(error: error, req: req, text: text)
137
+ end
138
+
139
+ # Log occurred error debug dump.
140
+ # +error+ an exception object, +req+ the request,
141
+ # and +text+ additional info
142
+ # @version 5.0.0
143
+ def debug_error(error, req=nil, text="")
144
+ @error_logger.debug(error: error, req: req, text: text)
145
+ end
146
+ end
147
+ end
@@ -1,9 +1,9 @@
1
1
  module Puma
2
2
  module MiniSSL
3
3
  class ContextBuilder
4
- def initialize(params, events)
4
+ def initialize(params, log_writer)
5
5
  @params = params
6
- @events = events
6
+ @log_writer = log_writer
7
7
  end
8
8
 
9
9
  def context
@@ -11,27 +11,37 @@ module Puma
11
11
 
12
12
  if defined?(JRUBY_VERSION)
13
13
  unless params['keystore']
14
- events.error "Please specify the Java keystore via 'keystore='"
14
+ log_writer.error "Please specify the Java keystore via 'keystore='"
15
15
  end
16
16
 
17
17
  ctx.keystore = params['keystore']
18
18
 
19
19
  unless params['keystore-pass']
20
- events.error "Please specify the Java keystore password via 'keystore-pass='"
20
+ log_writer.error "Please specify the Java keystore password via 'keystore-pass='"
21
21
  end
22
22
 
23
23
  ctx.keystore_pass = params['keystore-pass']
24
- ctx.ssl_cipher_list = params['ssl_cipher_list'] if params['ssl_cipher_list']
24
+ ctx.keystore_type = params['keystore-type']
25
+
26
+ if truststore = params['truststore']
27
+ ctx.truststore = truststore.eql?('default') ? :default : truststore
28
+ ctx.truststore_pass = params['truststore-pass']
29
+ ctx.truststore_type = params['truststore-type']
30
+ end
31
+
32
+ ctx.cipher_suites = params['cipher_suites'] || params['ssl_cipher_list']
33
+ ctx.protocols = params['protocols'] if params['protocols']
25
34
  else
26
35
  if params['key'].nil? && params['key_pem'].nil?
27
- events.error "Please specify the SSL key via 'key=' or 'key_pem='"
36
+ log_writer.error "Please specify the SSL key via 'key=' or 'key_pem='"
28
37
  end
29
38
 
30
39
  ctx.key = params['key'] if params['key']
31
40
  ctx.key_pem = params['key_pem'] if params['key_pem']
41
+ ctx.key_password_command = params['key_password_command'] if params['key_password_command']
32
42
 
33
43
  if params['cert'].nil? && params['cert_pem'].nil?
34
- events.error "Please specify the SSL cert via 'cert=' or 'cert_pem='"
44
+ log_writer.error "Please specify the SSL cert via 'cert=' or 'cert_pem='"
35
45
  end
36
46
 
37
47
  ctx.cert = params['cert'] if params['cert']
@@ -39,16 +49,20 @@ module Puma
39
49
 
40
50
  if ['peer', 'force_peer'].include?(params['verify_mode'])
41
51
  unless params['ca']
42
- events.error "Please specify the SSL ca via 'ca='"
52
+ log_writer.error "Please specify the SSL ca via 'ca='"
43
53
  end
54
+ # needed for Puma::MiniSSL::Socket#peercert, env['puma.peercert']
55
+ require 'openssl'
44
56
  end
45
57
 
46
58
  ctx.ca = params['ca'] if params['ca']
47
59
  ctx.ssl_cipher_filter = params['ssl_cipher_filter'] if params['ssl_cipher_filter']
60
+
61
+ ctx.reuse = params['reuse'] if params['reuse']
48
62
  end
49
63
 
50
- ctx.no_tlsv1 = true if params['no_tlsv1'] == 'true'
51
- ctx.no_tlsv1_1 = true if params['no_tlsv1_1'] == 'true'
64
+ ctx.no_tlsv1 = params['no_tlsv1'] == 'true'
65
+ ctx.no_tlsv1_1 = params['no_tlsv1_1'] == 'true'
52
66
 
53
67
  if params['verify_mode']
54
68
  ctx.verify_mode = case params['verify_mode']
@@ -59,7 +73,7 @@ module Puma
59
73
  when "none"
60
74
  MiniSSL::VERIFY_NONE
61
75
  else
62
- events.error "Please specify a valid verify_mode="
76
+ log_writer.error "Please specify a valid verify_mode="
63
77
  MiniSSL::VERIFY_NONE
64
78
  end
65
79
  end
@@ -75,7 +89,7 @@ module Puma
75
89
 
76
90
  private
77
91
 
78
- attr_reader :params, :events
92
+ attr_reader :params, :log_writer
79
93
  end
80
94
  end
81
95
  end