puma 5.5.2 → 6.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +336 -3
  3. data/README.md +61 -16
  4. data/bin/puma-wild +1 -1
  5. data/docs/architecture.md +4 -4
  6. data/docs/compile_options.md +34 -0
  7. data/docs/fork_worker.md +1 -3
  8. data/docs/nginx.md +1 -1
  9. data/docs/signals.md +1 -0
  10. data/docs/systemd.md +1 -2
  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 +28 -14
  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 +135 -23
  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 +188 -102
  23. data/ext/puma_http11/puma_http11.c +18 -10
  24. data/lib/puma/app/status.rb +7 -4
  25. data/lib/puma/binder.rb +62 -51
  26. data/lib/puma/cli.rb +19 -20
  27. data/lib/puma/client.rb +108 -26
  28. data/lib/puma/cluster/worker.rb +23 -16
  29. data/lib/puma/cluster/worker_handle.rb +8 -1
  30. data/lib/puma/cluster.rb +62 -41
  31. data/lib/puma/commonlogger.rb +21 -14
  32. data/lib/puma/configuration.rb +76 -55
  33. data/lib/puma/const.rb +133 -97
  34. data/lib/puma/control_cli.rb +21 -18
  35. data/lib/puma/detect.rb +12 -2
  36. data/lib/puma/dsl.rb +270 -55
  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 +114 -175
  43. data/lib/puma/log_writer.rb +147 -0
  44. data/lib/puma/minissl/context_builder.rb +30 -16
  45. data/lib/puma/minissl.rb +126 -17
  46. data/lib/puma/null_io.rb +5 -0
  47. data/lib/puma/plugin/systemd.rb +90 -0
  48. data/lib/puma/plugin/tmp_restart.rb +1 -1
  49. data/lib/puma/plugin.rb +1 -1
  50. data/lib/puma/rack/builder.rb +6 -6
  51. data/lib/puma/rack_default.rb +19 -4
  52. data/lib/puma/reactor.rb +19 -10
  53. data/lib/puma/request.rb +365 -161
  54. data/lib/puma/runner.rb +55 -22
  55. data/lib/puma/sd_notify.rb +149 -0
  56. data/lib/puma/server.rb +91 -94
  57. data/lib/puma/single.rb +13 -11
  58. data/lib/puma/state_file.rb +39 -7
  59. data/lib/puma/thread_pool.rb +25 -21
  60. data/lib/puma/util.rb +12 -14
  61. data/lib/puma.rb +12 -11
  62. data/lib/rack/handler/puma.rb +113 -86
  63. data/tools/Dockerfile +1 -1
  64. metadata +11 -6
  65. data/lib/puma/queue_close.rb +0 -26
  66. data/lib/puma/systemd.rb +0 -46
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,17 +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
- KEYS_NOT_TO_PERSIST_IN_STATE = [
19
- :logger, :lowlevel_error_handler,
20
- :before_worker_shutdown, :before_worker_boot, :before_worker_fork,
21
- :after_worker_boot, :before_fork, :on_restart
22
- ]
19
+ autoload :BundlePruner, 'puma/launcher/bundle_pruner'
20
+
23
21
  # Returns an instance of Launcher
24
22
  #
25
23
  # +conf+ A Puma::Configuration object indicating how to run the server.
26
24
  #
27
25
  # +launcher_args+ A Hash that currently has one required key `:events`,
28
- # 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`,
29
27
  # this object will be responsible for broadcasting Puma's internal state
30
28
  # to a logging destination. An optional key `:argv` can be supplied,
31
29
  # this should be an array of strings, these arguments are re-used when
@@ -39,25 +37,35 @@ module Puma
39
37
  # [200, {}, ["hello world"]]
40
38
  # end
41
39
  # end
42
- # Puma::Launcher.new(conf, events: Puma::Events.stdio).run
40
+ # Puma::Launcher.new(conf, log_writer: Puma::LogWriter.stdio).run
43
41
  def initialize(conf, launcher_args={})
44
42
  @runner = nil
45
- @events = launcher_args[:events] || Events::DEFAULT
43
+ @log_writer = launcher_args[:log_writer] || LogWriter::DEFAULT
44
+ @events = launcher_args[:events] || Events.new
46
45
  @argv = launcher_args[:argv] || []
47
46
  @original_argv = @argv.dup
48
47
  @config = conf
49
48
 
50
- @binder = Binder.new(@events, conf)
51
- @binder.create_inherited_fds(ENV).each { |k| ENV.delete k }
52
- @binder.create_activated_fds(ENV).each { |k| ENV.delete k }
53
-
54
- @environment = conf.environment
49
+ @config.options[:log_writer] = @log_writer
55
50
 
56
51
  # Advertise the Configuration
57
52
  Puma.cli_config = @config if defined?(Puma.cli_config)
58
53
 
59
54
  @config.load
60
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
+
61
69
  if @config.options[:bind_to_activated_sockets]
62
70
  @config.options[:binds] = @binder.synthesize_binds_from_activated_fs(
63
71
  @config.options[:binds],
@@ -68,28 +76,30 @@ module Puma
68
76
  @options = @config.options
69
77
  @config.clamp
70
78
 
71
- @events.formatter = Events::PidFormatter.new if clustered?
72
- @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]
73
83
 
74
84
  generate_restart_data
75
85
 
76
- if clustered? && !Process.respond_to?(:fork)
86
+ if clustered? && !Puma.forkable?
77
87
  unsupported "worker mode not supported on #{RUBY_ENGINE} on this platform"
78
88
  end
79
89
 
80
90
  Dir.chdir(@restart_dir)
81
91
 
82
- prune_bundler if prune_bundler?
92
+ prune_bundler!
83
93
 
84
94
  @environment = @options[:environment] if @options[:environment]
85
95
  set_rack_environment
86
96
 
87
97
  if clustered?
88
- @options[:logger] = @events
98
+ @options[:logger] = @log_writer
89
99
 
90
- @runner = Cluster.new(self, @events)
100
+ @runner = Cluster.new(self)
91
101
  else
92
- @runner = Single.new(self, @events)
102
+ @runner = Single.new(self)
93
103
  end
94
104
  Puma.stats_object = @runner
95
105
 
@@ -98,7 +108,7 @@ module Puma
98
108
  log_config if ENV['PUMA_LOG_CONFIG']
99
109
  end
100
110
 
101
- attr_reader :binder, :events, :config, :options, :restart_dir
111
+ attr_reader :binder, :log_writer, :events, :config, :options, :restart_dir
102
112
 
103
113
  # Return stats about the server
104
114
  def stats
@@ -114,7 +124,7 @@ module Puma
114
124
  permission = @options[:state_permission]
115
125
  return unless path
116
126
 
117
- require 'puma/state_file'
127
+ require_relative 'state_file'
118
128
 
119
129
  sf = StateFile.new
120
130
  sf.pid = Process.pid
@@ -158,18 +168,20 @@ module Puma
158
168
  true
159
169
  end
160
170
 
171
+ # Begin a refork if supported
172
+ def refork
173
+ if clustered? && @runner.respond_to?(:fork_worker!) && @options[:fork_worker]
174
+ @runner.fork_worker!
175
+ true
176
+ else
177
+ log "* refork called but not available."
178
+ false
179
+ end
180
+ end
181
+
161
182
  # Run the server. This blocks until the server is stopped
162
183
  def run
163
- previous_env =
164
- if defined?(Bundler)
165
- env = Bundler::ORIGINAL_ENV.dup
166
- # add -rbundler/setup so we load from Gemfile when restarting
167
- bundle = "-rbundler/setup"
168
- env["RUBYOPT"] = [env["RUBYOPT"], bundle].join(" ").lstrip unless env["RUBYOPT"].to_s.include?(bundle)
169
- env
170
- else
171
- ENV.to_h
172
- end
184
+ previous_env = get_env
173
185
 
174
186
  @config.clamp
175
187
 
@@ -177,24 +189,11 @@ module Puma
177
189
 
178
190
  setup_signals
179
191
  set_process_title
180
- integrate_with_systemd
192
+
193
+ # This blocks until the server is stopped
181
194
  @runner.run
182
195
 
183
- case @status
184
- when :halt
185
- log "* Stopping immediately!"
186
- @runner.stop_control
187
- when :run, :stop
188
- graceful_stop
189
- when :restart
190
- log "* Restarting..."
191
- ENV.replace(previous_env)
192
- @runner.stop_control
193
- restart!
194
- when :exit
195
- # nothing
196
- end
197
- close_binder_listeners unless @status == :restart
196
+ do_run_finished(previous_env)
198
197
  end
199
198
 
200
199
  # Return all tcp ports the launcher may be using, TCP or SSL
@@ -238,30 +237,56 @@ module Puma
238
237
 
239
238
  private
240
239
 
241
- # If configured, write the pid of the current process out
242
- # to a file.
243
- def write_pid
244
- path = @options[:pidfile]
245
- return unless path
246
- cur_pid = Process.pid
247
- File.write path, cur_pid, mode: 'wb:UTF-8'
248
- at_exit do
249
- 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
250
249
  end
251
250
  end
252
251
 
253
- def reload_worker_directory
254
- @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!
255
280
  end
256
281
 
257
282
  def restart!
258
283
  @events.fire_on_restart!
259
- @config.run_hooks :on_restart, self, @events
284
+ @config.run_hooks :on_restart, self, @log_writer
260
285
 
261
286
  if Puma.jruby?
262
287
  close_binder_listeners
263
288
 
264
- require 'puma/jruby_restart'
289
+ require_relative 'jruby_restart'
265
290
  JRubyRestart.chdir_exec(@restart_dir, restart_args)
266
291
  elsif Puma.windows?
267
292
  close_binder_listeners
@@ -278,94 +303,24 @@ module Puma
278
303
  end
279
304
  end
280
305
 
281
- # @!attribute [r] files_to_require_after_prune
282
- def files_to_require_after_prune
283
- puma = spec_for_gem("puma")
284
-
285
- require_paths_for_gem(puma) + extra_runtime_deps_directories
286
- end
287
-
288
- # @!attribute [r] extra_runtime_deps_directories
289
- def extra_runtime_deps_directories
290
- Array(@options[:extra_runtime_dependencies]).map do |d_name|
291
- if (spec = spec_for_gem(d_name))
292
- require_paths_for_gem(spec)
293
- else
294
- log "* Could not load extra dependency: #{d_name}"
295
- nil
296
- end
297
- end.flatten.compact
298
- end
299
-
300
- # @!attribute [r] puma_wild_location
301
- def puma_wild_location
302
- puma = spec_for_gem("puma")
303
- dirs = require_paths_for_gem(puma)
304
- puma_lib_dir = dirs.detect { |x| File.exist? File.join(x, '../bin/puma-wild') }
305
- File.expand_path(File.join(puma_lib_dir, "../bin/puma-wild"))
306
- end
307
-
308
- def prune_bundler
309
- return if ENV['PUMA_BUNDLER_PRUNED']
310
- return unless defined?(Bundler)
311
- require_rubygems_min_version!(Gem::Version.new("2.2"), "prune_bundler")
312
- unless puma_wild_location
313
- log "! Unable to prune Bundler environment, continuing"
314
- return
315
- end
316
-
317
- dirs = files_to_require_after_prune
318
-
319
- log '* Pruning Bundler environment'
320
- home = ENV['GEM_HOME']
321
- bundle_gemfile = Bundler.original_env['BUNDLE_GEMFILE']
322
- bundle_app_config = Bundler.original_env['BUNDLE_APP_CONFIG']
323
- with_unbundled_env do
324
- ENV['GEM_HOME'] = home
325
- ENV['BUNDLE_GEMFILE'] = bundle_gemfile
326
- ENV['PUMA_BUNDLER_PRUNED'] = '1'
327
- ENV["BUNDLE_APP_CONFIG"] = bundle_app_config
328
- args = [Gem.ruby, puma_wild_location, '-I', dirs.join(':')] + @original_argv
329
- # Ruby 2.0+ defaults to true which breaks socket activation
330
- args += [{:close_others => false}]
331
- Kernel.exec(*args)
332
- end
333
- end
334
-
335
- #
336
- # Puma's systemd integration allows Puma to inform systemd:
337
- # 1. when it has successfully started
338
- # 2. when it is starting shutdown
339
- # 3. periodically for a liveness check with a watchdog thread
340
- #
341
-
342
- def integrate_with_systemd
343
- return unless ENV["NOTIFY_SOCKET"]
344
-
345
- begin
346
- require 'puma/systemd'
347
- rescue LoadError
348
- log "Systemd integration failed. It looks like you're trying to use systemd notify but don't have sd_notify gem installed"
349
- 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
350
315
  end
351
-
352
- log "* Enabling systemd notification integration"
353
-
354
- systemd = Systemd.new(@events)
355
- systemd.hook_events
356
- systemd.start_watchdog
357
316
  end
358
317
 
359
- def spec_for_gem(gem_name)
360
- Bundler.rubygems.loaded_specs(gem_name)
361
- end
362
-
363
- def require_paths_for_gem(gem_spec)
364
- gem_spec.full_require_paths
318
+ def reload_worker_directory
319
+ @runner.reload_worker_directory if @runner.respond_to?(:reload_worker_directory)
365
320
  end
366
321
 
367
322
  def log(str)
368
- @events.log str
323
+ @log_writer.log(str)
369
324
  end
370
325
 
371
326
  def clustered?
@@ -373,15 +328,10 @@ module Puma
373
328
  end
374
329
 
375
330
  def unsupported(str)
376
- @events.error(str)
331
+ @log_writer.error(str)
377
332
  raise UnsupportedOption
378
333
  end
379
334
 
380
- def graceful_stop
381
- @events.fire_on_stopped!
382
- @runner.stop_blocked
383
- end
384
-
385
335
  def set_process_title
386
336
  Process.respond_to?(:setproctitle) ? Process.setproctitle(title) : $0 = title
387
337
  end
@@ -407,6 +357,11 @@ module Puma
407
357
  @options[:prune_bundler] && clustered? && !@options[:preload_app]
408
358
  end
409
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
+
410
365
  def generate_restart_data
411
366
  if dir = @options[:directory]
412
367
  @restart_dir = dir
@@ -473,7 +428,8 @@ module Puma
473
428
 
474
429
  begin
475
430
  Signal.trap "SIGTERM" do
476
- graceful_stop
431
+ # Shortcut the control flow in case raise_exception_on_sigterm is true
432
+ do_graceful_stop
477
433
 
478
434
  raise(SignalException, "SIGTERM") if @options[:raise_exception_on_sigterm]
479
435
  end
@@ -505,8 +461,8 @@ module Puma
505
461
  unless Puma.jruby? # INFO in use by JVM already
506
462
  Signal.trap "SIGINFO" do
507
463
  thread_status do |name, backtrace|
508
- @events.log name
509
- @events.log backtrace.map { |bt| " #{bt}" }
464
+ @log_writer.log(name)
465
+ @log_writer.log(backtrace.map { |bt| " #{bt}" })
510
466
  end
511
467
  end
512
468
  end
@@ -516,23 +472,6 @@ module Puma
516
472
  end
517
473
  end
518
474
 
519
- def require_rubygems_min_version!(min_version, feature)
520
- return if min_version <= Gem::Version.new(Gem::VERSION)
521
-
522
- raise "#{feature} is not supported on your version of RubyGems. " \
523
- "You must have RubyGems #{min_version}+ to use this feature."
524
- end
525
-
526
- # @version 5.0.0
527
- def with_unbundled_env
528
- bundler_ver = Gem::Version.new(Bundler::VERSION)
529
- if bundler_ver < Gem::Version.new('2.1.0')
530
- Bundler.with_clean_env { yield }
531
- else
532
- Bundler.with_unbundled_env { yield }
533
- end
534
- end
535
-
536
475
  def log_config
537
476
  log "Configuration:"
538
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,42 +11,56 @@ 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
- unless params['key']
27
- events.error "Please specify the SSL key via 'key='"
35
+ if params['key'].nil? && params['key_pem'].nil?
36
+ log_writer.error "Please specify the SSL key via 'key=' or 'key_pem='"
28
37
  end
29
38
 
30
- ctx.key = params['key']
39
+ ctx.key = params['key'] if params['key']
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']
31
42
 
32
- unless params['cert']
33
- events.error "Please specify the SSL cert via 'cert='"
43
+ if params['cert'].nil? && params['cert_pem'].nil?
44
+ log_writer.error "Please specify the SSL cert via 'cert=' or 'cert_pem='"
34
45
  end
35
46
 
36
- ctx.cert = params['cert']
47
+ ctx.cert = params['cert'] if params['cert']
48
+ ctx.cert_pem = params['cert_pem'] if params['cert_pem']
37
49
 
38
50
  if ['peer', 'force_peer'].include?(params['verify_mode'])
39
51
  unless params['ca']
40
- events.error "Please specify the SSL ca via 'ca='"
52
+ log_writer.error "Please specify the SSL ca via 'ca='"
41
53
  end
42
54
  end
43
55
 
44
56
  ctx.ca = params['ca'] if params['ca']
45
57
  ctx.ssl_cipher_filter = params['ssl_cipher_filter'] if params['ssl_cipher_filter']
58
+
59
+ ctx.reuse = params['reuse'] if params['reuse']
46
60
  end
47
61
 
48
- ctx.no_tlsv1 = true if params['no_tlsv1'] == 'true'
49
- ctx.no_tlsv1_1 = true if params['no_tlsv1_1'] == 'true'
62
+ ctx.no_tlsv1 = params['no_tlsv1'] == 'true'
63
+ ctx.no_tlsv1_1 = params['no_tlsv1_1'] == 'true'
50
64
 
51
65
  if params['verify_mode']
52
66
  ctx.verify_mode = case params['verify_mode']
@@ -57,7 +71,7 @@ module Puma
57
71
  when "none"
58
72
  MiniSSL::VERIFY_NONE
59
73
  else
60
- events.error "Please specify a valid verify_mode="
74
+ log_writer.error "Please specify a valid verify_mode="
61
75
  MiniSSL::VERIFY_NONE
62
76
  end
63
77
  end
@@ -73,7 +87,7 @@ module Puma
73
87
 
74
88
  private
75
89
 
76
- attr_reader :params, :events
90
+ attr_reader :params, :log_writer
77
91
  end
78
92
  end
79
93
  end