puma 5.2.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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +483 -4
  3. data/README.md +101 -20
  4. data/bin/puma-wild +1 -1
  5. data/docs/architecture.md +50 -16
  6. data/docs/compile_options.md +38 -2
  7. data/docs/deployment.md +53 -67
  8. data/docs/fork_worker.md +1 -3
  9. data/docs/jungle/rc.d/README.md +1 -1
  10. data/docs/kubernetes.md +1 -1
  11. data/docs/nginx.md +1 -1
  12. data/docs/plugins.md +15 -15
  13. data/docs/rails_dev_mode.md +2 -3
  14. data/docs/restart.md +7 -7
  15. data/docs/signals.md +11 -10
  16. data/docs/stats.md +8 -8
  17. data/docs/systemd.md +65 -69
  18. data/docs/testing_benchmarks_local_files.md +150 -0
  19. data/docs/testing_test_rackup_ci_files.md +36 -0
  20. data/ext/puma_http11/extconf.rb +44 -13
  21. data/ext/puma_http11/http11_parser.c +24 -11
  22. data/ext/puma_http11/http11_parser.h +2 -2
  23. data/ext/puma_http11/http11_parser.java.rl +2 -2
  24. data/ext/puma_http11/http11_parser.rl +2 -2
  25. data/ext/puma_http11/http11_parser_common.rl +3 -3
  26. data/ext/puma_http11/mini_ssl.c +150 -23
  27. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  28. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +50 -48
  29. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +188 -102
  30. data/ext/puma_http11/puma_http11.c +18 -10
  31. data/lib/puma/app/status.rb +10 -7
  32. data/lib/puma/binder.rb +112 -62
  33. data/lib/puma/cli.rb +24 -20
  34. data/lib/puma/client.rb +162 -36
  35. data/lib/puma/cluster/worker.rb +31 -27
  36. data/lib/puma/cluster/worker_handle.rb +12 -1
  37. data/lib/puma/cluster.rb +102 -61
  38. data/lib/puma/commonlogger.rb +21 -14
  39. data/lib/puma/configuration.rb +78 -54
  40. data/lib/puma/const.rb +135 -97
  41. data/lib/puma/control_cli.rb +25 -20
  42. data/lib/puma/detect.rb +12 -2
  43. data/lib/puma/dsl.rb +308 -58
  44. data/lib/puma/error_logger.rb +20 -11
  45. data/lib/puma/events.rb +6 -126
  46. data/lib/puma/io_buffer.rb +39 -4
  47. data/lib/puma/jruby_restart.rb +2 -1
  48. data/lib/puma/{json.rb → json_serialization.rb} +1 -1
  49. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  50. data/lib/puma/launcher.rb +114 -173
  51. data/lib/puma/log_writer.rb +147 -0
  52. data/lib/puma/minissl/context_builder.rb +30 -16
  53. data/lib/puma/minissl.rb +132 -38
  54. data/lib/puma/null_io.rb +5 -0
  55. data/lib/puma/plugin/systemd.rb +90 -0
  56. data/lib/puma/plugin/tmp_restart.rb +1 -1
  57. data/lib/puma/plugin.rb +2 -2
  58. data/lib/puma/rack/builder.rb +7 -7
  59. data/lib/puma/rack_default.rb +19 -4
  60. data/lib/puma/reactor.rb +19 -10
  61. data/lib/puma/request.rb +373 -153
  62. data/lib/puma/runner.rb +74 -28
  63. data/lib/puma/sd_notify.rb +149 -0
  64. data/lib/puma/server.rb +127 -136
  65. data/lib/puma/single.rb +13 -11
  66. data/lib/puma/state_file.rb +39 -7
  67. data/lib/puma/thread_pool.rb +33 -26
  68. data/lib/puma/util.rb +20 -15
  69. data/lib/puma.rb +28 -11
  70. data/lib/rack/handler/puma.rb +113 -86
  71. data/tools/Dockerfile +1 -1
  72. metadata +15 -10
  73. data/lib/puma/queue_close.rb +0 -26
  74. 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,92 +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
- with_unbundled_env do
323
- ENV['GEM_HOME'] = home
324
- ENV['BUNDLE_GEMFILE'] = bundle_gemfile
325
- ENV['PUMA_BUNDLER_PRUNED'] = '1'
326
- args = [Gem.ruby, puma_wild_location, '-I', dirs.join(':')] + @original_argv
327
- # Ruby 2.0+ defaults to true which breaks socket activation
328
- args += [{:close_others => false}]
329
- Kernel.exec(*args)
330
- end
331
- end
332
-
333
- #
334
- # Puma's systemd integration allows Puma to inform systemd:
335
- # 1. when it has successfully started
336
- # 2. when it is starting shutdown
337
- # 3. periodically for a liveness check with a watchdog thread
338
- #
339
-
340
- def integrate_with_systemd
341
- return unless ENV["NOTIFY_SOCKET"]
342
-
343
- begin
344
- require 'puma/systemd'
345
- rescue LoadError
346
- log "Systemd integration failed. It looks like you're trying to use systemd notify but don't have sd_notify gem installed"
347
- 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
348
315
  end
349
-
350
- log "* Enabling systemd notification integration"
351
-
352
- systemd = Systemd.new(@events)
353
- systemd.hook_events
354
- systemd.start_watchdog
355
316
  end
356
317
 
357
- def spec_for_gem(gem_name)
358
- Bundler.rubygems.loaded_specs(gem_name)
359
- end
360
-
361
- def require_paths_for_gem(gem_spec)
362
- gem_spec.full_require_paths
318
+ def reload_worker_directory
319
+ @runner.reload_worker_directory if @runner.respond_to?(:reload_worker_directory)
363
320
  end
364
321
 
365
322
  def log(str)
366
- @events.log str
323
+ @log_writer.log(str)
367
324
  end
368
325
 
369
326
  def clustered?
@@ -371,15 +328,10 @@ module Puma
371
328
  end
372
329
 
373
330
  def unsupported(str)
374
- @events.error(str)
331
+ @log_writer.error(str)
375
332
  raise UnsupportedOption
376
333
  end
377
334
 
378
- def graceful_stop
379
- @events.fire_on_stopped!
380
- @runner.stop_blocked
381
- end
382
-
383
335
  def set_process_title
384
336
  Process.respond_to?(:setproctitle) ? Process.setproctitle(title) : $0 = title
385
337
  end
@@ -405,6 +357,11 @@ module Puma
405
357
  @options[:prune_bundler] && clustered? && !@options[:preload_app]
406
358
  end
407
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
+
408
365
  def generate_restart_data
409
366
  if dir = @options[:directory]
410
367
  @restart_dir = dir
@@ -471,7 +428,8 @@ module Puma
471
428
 
472
429
  begin
473
430
  Signal.trap "SIGTERM" do
474
- graceful_stop
431
+ # Shortcut the control flow in case raise_exception_on_sigterm is true
432
+ do_graceful_stop
475
433
 
476
434
  raise(SignalException, "SIGTERM") if @options[:raise_exception_on_sigterm]
477
435
  end
@@ -503,8 +461,8 @@ module Puma
503
461
  unless Puma.jruby? # INFO in use by JVM already
504
462
  Signal.trap "SIGINFO" do
505
463
  thread_status do |name, backtrace|
506
- @events.log name
507
- @events.log backtrace.map { |bt| " #{bt}" }
464
+ @log_writer.log(name)
465
+ @log_writer.log(backtrace.map { |bt| " #{bt}" })
508
466
  end
509
467
  end
510
468
  end
@@ -514,23 +472,6 @@ module Puma
514
472
  end
515
473
  end
516
474
 
517
- def require_rubygems_min_version!(min_version, feature)
518
- return if min_version <= Gem::Version.new(Gem::VERSION)
519
-
520
- raise "#{feature} is not supported on your version of RubyGems. " \
521
- "You must have RubyGems #{min_version}+ to use this feature."
522
- end
523
-
524
- # @version 5.0.0
525
- def with_unbundled_env
526
- bundler_ver = Gem::Version.new(Bundler::VERSION)
527
- if bundler_ver < Gem::Version.new('2.1.0')
528
- Bundler.with_clean_env { yield }
529
- else
530
- Bundler.with_unbundled_env { yield }
531
- end
532
- end
533
-
534
475
  def log_config
535
476
  log "Configuration:"
536
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