puma 5.6.5 → 6.4.2

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +338 -14
  3. data/LICENSE +0 -0
  4. data/README.md +79 -29
  5. data/bin/puma-wild +1 -1
  6. data/docs/architecture.md +0 -0
  7. data/docs/compile_options.md +34 -0
  8. data/docs/deployment.md +0 -0
  9. data/docs/fork_worker.md +1 -3
  10. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  11. data/docs/images/puma-connection-flow.png +0 -0
  12. data/docs/images/puma-general-arch.png +0 -0
  13. data/docs/jungle/README.md +0 -0
  14. data/docs/jungle/rc.d/README.md +0 -0
  15. data/docs/jungle/rc.d/puma.conf +0 -0
  16. data/docs/kubernetes.md +12 -0
  17. data/docs/nginx.md +1 -1
  18. data/docs/plugins.md +0 -0
  19. data/docs/rails_dev_mode.md +0 -0
  20. data/docs/restart.md +1 -0
  21. data/docs/signals.md +0 -0
  22. data/docs/stats.md +0 -0
  23. data/docs/systemd.md +3 -6
  24. data/docs/testing_benchmarks_local_files.md +150 -0
  25. data/docs/testing_test_rackup_ci_files.md +36 -0
  26. data/ext/puma_http11/PumaHttp11Service.java +0 -0
  27. data/ext/puma_http11/ext_help.h +0 -0
  28. data/ext/puma_http11/extconf.rb +16 -9
  29. data/ext/puma_http11/http11_parser.c +1 -1
  30. data/ext/puma_http11/http11_parser.h +1 -1
  31. data/ext/puma_http11/http11_parser.java.rl +2 -2
  32. data/ext/puma_http11/http11_parser.rl +2 -2
  33. data/ext/puma_http11/http11_parser_common.rl +2 -2
  34. data/ext/puma_http11/mini_ssl.c +127 -19
  35. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
  36. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  37. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
  38. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +157 -53
  39. data/ext/puma_http11/puma_http11.c +17 -9
  40. data/lib/puma/app/status.rb +4 -4
  41. data/lib/puma/binder.rb +50 -53
  42. data/lib/puma/cli.rb +16 -18
  43. data/lib/puma/client.rb +100 -26
  44. data/lib/puma/cluster/worker.rb +18 -11
  45. data/lib/puma/cluster/worker_handle.rb +4 -1
  46. data/lib/puma/cluster.rb +102 -40
  47. data/lib/puma/commonlogger.rb +21 -14
  48. data/lib/puma/configuration.rb +77 -59
  49. data/lib/puma/const.rb +129 -92
  50. data/lib/puma/control_cli.rb +15 -11
  51. data/lib/puma/detect.rb +7 -4
  52. data/lib/puma/dsl.rb +250 -56
  53. data/lib/puma/error_logger.rb +18 -9
  54. data/lib/puma/events.rb +6 -126
  55. data/lib/puma/io_buffer.rb +39 -4
  56. data/lib/puma/jruby_restart.rb +2 -1
  57. data/lib/puma/json_serialization.rb +0 -0
  58. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  59. data/lib/puma/launcher.rb +102 -175
  60. data/lib/puma/log_writer.rb +147 -0
  61. data/lib/puma/minissl/context_builder.rb +26 -12
  62. data/lib/puma/minissl.rb +104 -11
  63. data/lib/puma/null_io.rb +16 -2
  64. data/lib/puma/plugin/systemd.rb +90 -0
  65. data/lib/puma/plugin/tmp_restart.rb +1 -1
  66. data/lib/puma/plugin.rb +0 -0
  67. data/lib/puma/rack/builder.rb +6 -6
  68. data/lib/puma/rack/urlmap.rb +1 -1
  69. data/lib/puma/rack_default.rb +19 -4
  70. data/lib/puma/reactor.rb +19 -10
  71. data/lib/puma/request.rb +365 -170
  72. data/lib/puma/runner.rb +56 -20
  73. data/lib/puma/sd_notify.rb +149 -0
  74. data/lib/puma/server.rb +137 -89
  75. data/lib/puma/single.rb +13 -11
  76. data/lib/puma/state_file.rb +3 -6
  77. data/lib/puma/thread_pool.rb +57 -19
  78. data/lib/puma/util.rb +0 -11
  79. data/lib/puma.rb +12 -11
  80. data/lib/rack/handler/puma.rb +113 -86
  81. data/tools/Dockerfile +2 -2
  82. data/tools/trickletest.rb +0 -0
  83. metadata +11 -6
  84. data/lib/puma/queue_close.rb +0 -26
  85. 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,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