puma 5.6.4 → 6.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +372 -6
  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 +22 -10
  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 +153 -27
  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 +167 -65
  39. data/ext/puma_http11/puma_http11.c +17 -9
  40. data/lib/puma/app/status.rb +7 -4
  41. data/lib/puma/binder.rb +51 -54
  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 +33 -23
  51. data/lib/puma/detect.rb +7 -4
  52. data/lib/puma/dsl.rb +251 -53
  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 +113 -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 +113 -15
  63. data/lib/puma/null_io.rb +21 -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 -166
  72. data/lib/puma/runner.rb +56 -20
  73. data/lib/puma/sd_notify.rb +149 -0
  74. data/lib/puma/server.rb +137 -87
  75. data/lib/puma/single.rb +13 -11
  76. data/lib/puma/state_file.rb +4 -6
  77. data/lib/puma/thread_pool.rb +57 -19
  78. data/lib/puma/util.rb +12 -14
  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
@@ -159,18 +168,20 @@ module Puma
159
168
  true
160
169
  end
161
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
+
162
182
  # Run the server. This blocks until the server is stopped
163
183
  def run
164
- previous_env =
165
- if defined?(Bundler)
166
- env = Bundler::ORIGINAL_ENV.dup
167
- # add -rbundler/setup so we load from Gemfile when restarting
168
- bundle = "-rbundler/setup"
169
- env["RUBYOPT"] = [env["RUBYOPT"], bundle].join(" ").lstrip unless env["RUBYOPT"].to_s.include?(bundle)
170
- env
171
- else
172
- ENV.to_h
173
- end
184
+ previous_env = get_env
174
185
 
175
186
  @config.clamp
176
187
 
@@ -178,24 +189,11 @@ module Puma
178
189
 
179
190
  setup_signals
180
191
  set_process_title
181
- integrate_with_systemd
192
+
193
+ # This blocks until the server is stopped
182
194
  @runner.run
183
195
 
184
- case @status
185
- when :halt
186
- log "* Stopping immediately!"
187
- @runner.stop_control
188
- when :run, :stop
189
- graceful_stop
190
- when :restart
191
- log "* Restarting..."
192
- ENV.replace(previous_env)
193
- @runner.stop_control
194
- restart!
195
- when :exit
196
- # nothing
197
- end
198
- close_binder_listeners unless @status == :restart
196
+ do_run_finished(previous_env)
199
197
  end
200
198
 
201
199
  # Return all tcp ports the launcher may be using, TCP or SSL
@@ -239,30 +237,56 @@ module Puma
239
237
 
240
238
  private
241
239
 
242
- # If configured, write the pid of the current process out
243
- # to a file.
244
- def write_pid
245
- path = @options[:pidfile]
246
- return unless path
247
- cur_pid = Process.pid
248
- File.write path, cur_pid, mode: 'wb:UTF-8'
249
- at_exit do
250
- 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
251
249
  end
252
250
  end
253
251
 
254
- def reload_worker_directory
255
- @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!
256
280
  end
257
281
 
258
282
  def restart!
259
283
  @events.fire_on_restart!
260
- @config.run_hooks :on_restart, self, @events
284
+ @config.run_hooks :on_restart, self, @log_writer
261
285
 
262
286
  if Puma.jruby?
263
287
  close_binder_listeners
264
288
 
265
- require 'puma/jruby_restart'
289
+ require_relative 'jruby_restart'
266
290
  JRubyRestart.chdir_exec(@restart_dir, restart_args)
267
291
  elsif Puma.windows?
268
292
  close_binder_listeners
@@ -279,94 +303,24 @@ module Puma
279
303
  end
280
304
  end
281
305
 
282
- # @!attribute [r] files_to_require_after_prune
283
- def files_to_require_after_prune
284
- puma = spec_for_gem("puma")
285
-
286
- require_paths_for_gem(puma) + extra_runtime_deps_directories
287
- end
288
-
289
- # @!attribute [r] extra_runtime_deps_directories
290
- def extra_runtime_deps_directories
291
- Array(@options[:extra_runtime_dependencies]).map do |d_name|
292
- if (spec = spec_for_gem(d_name))
293
- require_paths_for_gem(spec)
294
- else
295
- log "* Could not load extra dependency: #{d_name}"
296
- nil
297
- end
298
- end.flatten.compact
299
- end
300
-
301
- # @!attribute [r] puma_wild_location
302
- def puma_wild_location
303
- puma = spec_for_gem("puma")
304
- dirs = require_paths_for_gem(puma)
305
- puma_lib_dir = dirs.detect { |x| File.exist? File.join(x, '../bin/puma-wild') }
306
- File.expand_path(File.join(puma_lib_dir, "../bin/puma-wild"))
307
- end
308
-
309
- def prune_bundler
310
- return if ENV['PUMA_BUNDLER_PRUNED']
311
- return unless defined?(Bundler)
312
- require_rubygems_min_version!(Gem::Version.new("2.2"), "prune_bundler")
313
- unless puma_wild_location
314
- log "! Unable to prune Bundler environment, continuing"
315
- return
316
- end
317
-
318
- dirs = files_to_require_after_prune
319
-
320
- log '* Pruning Bundler environment'
321
- home = ENV['GEM_HOME']
322
- bundle_gemfile = Bundler.original_env['BUNDLE_GEMFILE']
323
- bundle_app_config = Bundler.original_env['BUNDLE_APP_CONFIG']
324
- with_unbundled_env do
325
- ENV['GEM_HOME'] = home
326
- ENV['BUNDLE_GEMFILE'] = bundle_gemfile
327
- ENV['PUMA_BUNDLER_PRUNED'] = '1'
328
- ENV["BUNDLE_APP_CONFIG"] = bundle_app_config
329
- args = [Gem.ruby, puma_wild_location, '-I', dirs.join(':')] + @original_argv
330
- # Ruby 2.0+ defaults to true which breaks socket activation
331
- args += [{:close_others => false}]
332
- Kernel.exec(*args)
333
- end
334
- end
335
-
336
- #
337
- # Puma's systemd integration allows Puma to inform systemd:
338
- # 1. when it has successfully started
339
- # 2. when it is starting shutdown
340
- # 3. periodically for a liveness check with a watchdog thread
341
- #
342
-
343
- def integrate_with_systemd
344
- return unless ENV["NOTIFY_SOCKET"]
345
-
346
- begin
347
- require 'puma/systemd'
348
- rescue LoadError
349
- log "Systemd integration failed. It looks like you're trying to use systemd notify but don't have sd_notify gem installed"
350
- 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
351
315
  end
352
-
353
- log "* Enabling systemd notification integration"
354
-
355
- systemd = Systemd.new(@events)
356
- systemd.hook_events
357
- systemd.start_watchdog
358
316
  end
359
317
 
360
- def spec_for_gem(gem_name)
361
- Bundler.rubygems.loaded_specs(gem_name)
362
- end
363
-
364
- def require_paths_for_gem(gem_spec)
365
- gem_spec.full_require_paths
318
+ def reload_worker_directory
319
+ @runner.reload_worker_directory if @runner.respond_to?(:reload_worker_directory)
366
320
  end
367
321
 
368
322
  def log(str)
369
- @events.log str
323
+ @log_writer.log(str)
370
324
  end
371
325
 
372
326
  def clustered?
@@ -374,15 +328,10 @@ module Puma
374
328
  end
375
329
 
376
330
  def unsupported(str)
377
- @events.error(str)
331
+ @log_writer.error(str)
378
332
  raise UnsupportedOption
379
333
  end
380
334
 
381
- def graceful_stop
382
- @events.fire_on_stopped!
383
- @runner.stop_blocked
384
- end
385
-
386
335
  def set_process_title
387
336
  Process.respond_to?(:setproctitle) ? Process.setproctitle(title) : $0 = title
388
337
  end
@@ -408,6 +357,11 @@ module Puma
408
357
  @options[:prune_bundler] && clustered? && !@options[:preload_app]
409
358
  end
410
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
+
411
365
  def generate_restart_data
412
366
  if dir = @options[:directory]
413
367
  @restart_dir = dir
@@ -474,7 +428,8 @@ module Puma
474
428
 
475
429
  begin
476
430
  Signal.trap "SIGTERM" do
477
- graceful_stop
431
+ # Shortcut the control flow in case raise_exception_on_sigterm is true
432
+ do_graceful_stop
478
433
 
479
434
  raise(SignalException, "SIGTERM") if @options[:raise_exception_on_sigterm]
480
435
  end
@@ -506,8 +461,8 @@ module Puma
506
461
  unless Puma.jruby? # INFO in use by JVM already
507
462
  Signal.trap "SIGINFO" do
508
463
  thread_status do |name, backtrace|
509
- @events.log name
510
- @events.log backtrace.map { |bt| " #{bt}" }
464
+ @log_writer.log(name)
465
+ @log_writer.log(backtrace.map { |bt| " #{bt}" })
511
466
  end
512
467
  end
513
468
  end
@@ -517,23 +472,6 @@ module Puma
517
472
  end
518
473
  end
519
474
 
520
- def require_rubygems_min_version!(min_version, feature)
521
- return if min_version <= Gem::Version.new(Gem::VERSION)
522
-
523
- raise "#{feature} is not supported on your version of RubyGems. " \
524
- "You must have RubyGems #{min_version}+ to use this feature."
525
- end
526
-
527
- # @version 5.0.0
528
- def with_unbundled_env
529
- bundler_ver = Gem::Version.new(Bundler::VERSION)
530
- if bundler_ver < Gem::Version.new('2.1.0')
531
- Bundler.with_clean_env { yield }
532
- else
533
- Bundler.with_unbundled_env { yield }
534
- end
535
- end
536
-
537
475
  def log_config
538
476
  log "Configuration:"
539
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