jun-puma 1.0.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/History.md +2897 -0
  3. data/LICENSE +29 -0
  4. data/README.md +475 -0
  5. data/bin/puma +10 -0
  6. data/bin/puma-wild +25 -0
  7. data/bin/pumactl +12 -0
  8. data/docs/architecture.md +74 -0
  9. data/docs/compile_options.md +55 -0
  10. data/docs/deployment.md +102 -0
  11. data/docs/fork_worker.md +35 -0
  12. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  13. data/docs/images/puma-connection-flow.png +0 -0
  14. data/docs/images/puma-general-arch.png +0 -0
  15. data/docs/jungle/README.md +9 -0
  16. data/docs/jungle/rc.d/README.md +74 -0
  17. data/docs/jungle/rc.d/puma +61 -0
  18. data/docs/jungle/rc.d/puma.conf +10 -0
  19. data/docs/kubernetes.md +78 -0
  20. data/docs/nginx.md +80 -0
  21. data/docs/plugins.md +38 -0
  22. data/docs/rails_dev_mode.md +28 -0
  23. data/docs/restart.md +65 -0
  24. data/docs/signals.md +98 -0
  25. data/docs/stats.md +142 -0
  26. data/docs/systemd.md +253 -0
  27. data/docs/testing_benchmarks_local_files.md +150 -0
  28. data/docs/testing_test_rackup_ci_files.md +36 -0
  29. data/ext/puma_http11/PumaHttp11Service.java +17 -0
  30. data/ext/puma_http11/ext_help.h +15 -0
  31. data/ext/puma_http11/extconf.rb +80 -0
  32. data/ext/puma_http11/http11_parser.c +1057 -0
  33. data/ext/puma_http11/http11_parser.h +65 -0
  34. data/ext/puma_http11/http11_parser.java.rl +145 -0
  35. data/ext/puma_http11/http11_parser.rl +149 -0
  36. data/ext/puma_http11/http11_parser_common.rl +54 -0
  37. data/ext/puma_http11/mini_ssl.c +842 -0
  38. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  39. data/ext/puma_http11/org/jruby/puma/Http11.java +228 -0
  40. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +455 -0
  41. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +509 -0
  42. data/ext/puma_http11/puma_http11.c +495 -0
  43. data/lib/puma/app/status.rb +96 -0
  44. data/lib/puma/binder.rb +502 -0
  45. data/lib/puma/cli.rb +247 -0
  46. data/lib/puma/client.rb +682 -0
  47. data/lib/puma/cluster/worker.rb +180 -0
  48. data/lib/puma/cluster/worker_handle.rb +96 -0
  49. data/lib/puma/cluster.rb +616 -0
  50. data/lib/puma/commonlogger.rb +115 -0
  51. data/lib/puma/configuration.rb +390 -0
  52. data/lib/puma/const.rb +307 -0
  53. data/lib/puma/control_cli.rb +316 -0
  54. data/lib/puma/detect.rb +45 -0
  55. data/lib/puma/dsl.rb +1425 -0
  56. data/lib/puma/error_logger.rb +113 -0
  57. data/lib/puma/events.rb +57 -0
  58. data/lib/puma/io_buffer.rb +46 -0
  59. data/lib/puma/jruby_restart.rb +11 -0
  60. data/lib/puma/json_serialization.rb +96 -0
  61. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  62. data/lib/puma/launcher.rb +488 -0
  63. data/lib/puma/log_writer.rb +147 -0
  64. data/lib/puma/minissl/context_builder.rb +96 -0
  65. data/lib/puma/minissl.rb +459 -0
  66. data/lib/puma/null_io.rb +84 -0
  67. data/lib/puma/plugin/systemd.rb +90 -0
  68. data/lib/puma/plugin/tmp_restart.rb +36 -0
  69. data/lib/puma/plugin.rb +111 -0
  70. data/lib/puma/puma_http11.jar +0 -0
  71. data/lib/puma/rack/builder.rb +297 -0
  72. data/lib/puma/rack/urlmap.rb +93 -0
  73. data/lib/puma/rack_default.rb +24 -0
  74. data/lib/puma/reactor.rb +125 -0
  75. data/lib/puma/request.rb +688 -0
  76. data/lib/puma/runner.rb +213 -0
  77. data/lib/puma/sd_notify.rb +149 -0
  78. data/lib/puma/server.rb +680 -0
  79. data/lib/puma/single.rb +69 -0
  80. data/lib/puma/state_file.rb +68 -0
  81. data/lib/puma/thread_pool.rb +434 -0
  82. data/lib/puma/util.rb +141 -0
  83. data/lib/puma.rb +78 -0
  84. data/lib/rack/handler/puma.rb +144 -0
  85. data/tools/Dockerfile +16 -0
  86. data/tools/trickletest.rb +44 -0
  87. metadata +153 -0
@@ -0,0 +1,488 @@
1
+ # frozen_string_literal: true
2
+
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'
10
+
11
+ module Puma
12
+ # Puma::Launcher is the single entry point for starting a Puma server based on user
13
+ # configuration. It is responsible for taking user supplied arguments and resolving them
14
+ # with configuration in `config/puma.rb` or `config/puma/<env>.rb`.
15
+ #
16
+ # It is responsible for either launching a cluster of Puma workers or a single
17
+ # puma server.
18
+ class Launcher
19
+ autoload :BundlePruner, 'puma/launcher/bundle_pruner'
20
+
21
+ # Returns an instance of Launcher
22
+ #
23
+ # +conf+ A Puma::Configuration object indicating how to run the server.
24
+ #
25
+ # +launcher_args+ A Hash that currently has one required key `:events`,
26
+ # this is expected to hold an object similar to an `Puma::LogWriter.stdio`,
27
+ # this object will be responsible for broadcasting Puma's internal state
28
+ # to a logging destination. An optional key `:argv` can be supplied,
29
+ # this should be an array of strings, these arguments are re-used when
30
+ # restarting the puma server.
31
+ #
32
+ # Examples:
33
+ #
34
+ # conf = Puma::Configuration.new do |user_config|
35
+ # user_config.threads 1, 10
36
+ # user_config.app do |env|
37
+ # [200, {}, ["hello world"]]
38
+ # end
39
+ # end
40
+ # Puma::Launcher.new(conf, log_writer: Puma::LogWriter.stdio).run
41
+ def initialize(conf, launcher_args={})
42
+ @runner = nil
43
+ @log_writer = launcher_args[:log_writer] || LogWriter::DEFAULT
44
+ @events = launcher_args[:events] || Events.new
45
+ @argv = launcher_args[:argv] || []
46
+ @original_argv = @argv.dup
47
+ @config = conf
48
+
49
+ env = launcher_args.delete(:env) || ENV
50
+
51
+ @config.options[:log_writer] = @log_writer
52
+
53
+ # Advertise the Configuration
54
+ Puma.cli_config = @config if defined?(Puma.cli_config)
55
+
56
+ @config.load
57
+
58
+ @binder = Binder.new(@log_writer, conf)
59
+ @binder.create_inherited_fds(ENV).each { |k| ENV.delete k }
60
+ @binder.create_activated_fds(ENV).each { |k| ENV.delete k }
61
+
62
+ @environment = conf.environment
63
+
64
+ # Load the systemd integration if we detect systemd's NOTIFY_SOCKET.
65
+ # Skip this on JRuby though, because it is incompatible with the systemd
66
+ # integration due to https://github.com/jruby/jruby/issues/6504
67
+ if ENV["NOTIFY_SOCKET"] && !Puma.jruby? && !ENV["PUMA_SKIP_SYSTEMD"]
68
+ @config.plugins.create('systemd')
69
+ end
70
+
71
+ if @config.options[:bind_to_activated_sockets]
72
+ @config.options[:binds] = @binder.synthesize_binds_from_activated_fs(
73
+ @config.options[:binds],
74
+ @config.options[:bind_to_activated_sockets] == 'only'
75
+ )
76
+ end
77
+
78
+ @options = @config.options
79
+ @config.clamp
80
+
81
+ @log_writer.formatter = LogWriter::PidFormatter.new if clustered?
82
+ @log_writer.formatter = options[:log_formatter] if @options[:log_formatter]
83
+
84
+ @log_writer.custom_logger = options[:custom_logger] if @options[:custom_logger]
85
+
86
+ generate_restart_data
87
+
88
+ if clustered? && !Puma.forkable?
89
+ unsupported "worker mode not supported on #{RUBY_ENGINE} on this platform"
90
+ end
91
+
92
+ Dir.chdir(@restart_dir)
93
+
94
+ prune_bundler!
95
+
96
+ @environment = @options[:environment] if @options[:environment]
97
+ set_rack_environment
98
+
99
+ if clustered?
100
+ @options[:logger] = @log_writer
101
+
102
+ @runner = Cluster.new(self)
103
+ else
104
+ @runner = Single.new(self)
105
+ end
106
+ Puma.stats_object = @runner
107
+
108
+ @status = :run
109
+
110
+ log_config if env['PUMA_LOG_CONFIG']
111
+ end
112
+
113
+ attr_reader :binder, :log_writer, :events, :config, :options, :restart_dir
114
+
115
+ # Return stats about the server
116
+ def stats
117
+ @runner.stats
118
+ end
119
+
120
+ # Write a state file that can be used by pumactl to control
121
+ # the server
122
+ def write_state
123
+ write_pid
124
+
125
+ path = @options[:state]
126
+ permission = @options[:state_permission]
127
+ return unless path
128
+
129
+ require_relative 'state_file'
130
+
131
+ sf = StateFile.new
132
+ sf.pid = Process.pid
133
+ sf.control_url = @options[:control_url]
134
+ sf.control_auth_token = @options[:control_auth_token]
135
+ sf.running_from = File.expand_path('.')
136
+
137
+ sf.save path, permission
138
+ end
139
+
140
+ # Delete the configured pidfile
141
+ def delete_pidfile
142
+ path = @options[:pidfile]
143
+ File.unlink(path) if path && File.exist?(path)
144
+ end
145
+
146
+ # Begin async shutdown of the server
147
+ def halt
148
+ @status = :halt
149
+ @runner.halt
150
+ end
151
+
152
+ # Begin async shutdown of the server gracefully
153
+ def stop
154
+ @status = :stop
155
+ @runner.stop
156
+ end
157
+
158
+ # Begin async restart of the server
159
+ def restart
160
+ @status = :restart
161
+ @runner.restart
162
+ end
163
+
164
+ # Begin a phased restart if supported
165
+ def phased_restart
166
+ unless @runner.respond_to?(:phased_restart) and @runner.phased_restart
167
+ log "* phased-restart called but not available, restarting normally."
168
+ return restart
169
+ end
170
+ true
171
+ end
172
+
173
+ # Begin a refork if supported
174
+ def refork
175
+ if clustered? && @runner.respond_to?(:fork_worker!) && @options[:fork_worker]
176
+ @runner.fork_worker!
177
+ true
178
+ else
179
+ log "* refork called but not available."
180
+ false
181
+ end
182
+ end
183
+
184
+ # Run the server. This blocks until the server is stopped
185
+ def run
186
+ previous_env = get_env
187
+
188
+ @config.clamp
189
+
190
+ @config.plugins.fire_starts self
191
+
192
+ setup_signals
193
+ set_process_title
194
+
195
+ # This blocks until the server is stopped
196
+ @runner.run
197
+
198
+ do_run_finished(previous_env)
199
+ end
200
+
201
+ # Return all tcp ports the launcher may be using, TCP or SSL
202
+ # @!attribute [r] connected_ports
203
+ # @version 5.0.0
204
+ def connected_ports
205
+ @binder.connected_ports
206
+ end
207
+
208
+ # @!attribute [r] restart_args
209
+ def restart_args
210
+ cmd = @options[:restart_cmd]
211
+ if cmd
212
+ cmd.split(' ') + @original_argv
213
+ else
214
+ @restart_argv
215
+ end
216
+ end
217
+
218
+ def close_binder_listeners
219
+ @runner.close_control_listeners
220
+ @binder.close_listeners
221
+ unless @status == :restart
222
+ log "=== puma shutdown: #{Time.now} ==="
223
+ log "- Goodbye!"
224
+ end
225
+ end
226
+
227
+ # @!attribute [r] thread_status
228
+ # @version 5.0.0
229
+ def thread_status
230
+ Thread.list.each do |thread|
231
+ name = "Thread: TID-#{thread.object_id.to_s(36)}"
232
+ name += " #{thread['label']}" if thread['label']
233
+ name += " #{thread.name}" if thread.respond_to?(:name) && thread.name
234
+ backtrace = thread.backtrace || ["<no backtrace available>"]
235
+
236
+ yield name, backtrace
237
+ end
238
+ end
239
+
240
+ private
241
+
242
+ def get_env
243
+ if defined?(Bundler)
244
+ env = Bundler::ORIGINAL_ENV.dup
245
+ # add -rbundler/setup so we load from Gemfile when restarting
246
+ bundle = "-rbundler/setup"
247
+ env["RUBYOPT"] = [env["RUBYOPT"], bundle].join(" ").lstrip unless env["RUBYOPT"].to_s.include?(bundle)
248
+ env
249
+ else
250
+ ENV.to_h
251
+ end
252
+ end
253
+
254
+ def do_run_finished(previous_env)
255
+ case @status
256
+ when :halt
257
+ do_forceful_stop
258
+ when :run, :stop
259
+ do_graceful_stop
260
+ when :restart
261
+ do_restart(previous_env)
262
+ end
263
+
264
+ close_binder_listeners unless @status == :restart
265
+ end
266
+
267
+ def do_forceful_stop
268
+ log "* Stopping immediately!"
269
+ @runner.stop_control
270
+ end
271
+
272
+ def do_graceful_stop
273
+ @events.fire_on_stopped!
274
+ @runner.stop_blocked
275
+ end
276
+
277
+ def do_restart(previous_env)
278
+ log "* Restarting..."
279
+ ENV.replace(previous_env)
280
+ @runner.stop_control
281
+ restart!
282
+ end
283
+
284
+ def restart!
285
+ @events.fire_on_restart!
286
+ @config.run_hooks :on_restart, self, @log_writer
287
+
288
+ if Puma.jruby?
289
+ close_binder_listeners
290
+
291
+ require_relative 'jruby_restart'
292
+ argv = restart_args
293
+ JRubyRestart.chdir(@restart_dir)
294
+ Kernel.exec(*argv)
295
+ elsif Puma.windows?
296
+ close_binder_listeners
297
+
298
+ argv = restart_args
299
+ Dir.chdir(@restart_dir)
300
+ Kernel.exec(*argv)
301
+ else
302
+ argv = restart_args
303
+ Dir.chdir(@restart_dir)
304
+ ENV.update(@binder.redirects_for_restart_env)
305
+ argv += [@binder.redirects_for_restart]
306
+ Kernel.exec(*argv)
307
+ end
308
+ end
309
+
310
+ # If configured, write the pid of the current process out
311
+ # to a file.
312
+ def write_pid
313
+ path = @options[:pidfile]
314
+ return unless path
315
+ cur_pid = Process.pid
316
+ File.write path, cur_pid, mode: 'wb:UTF-8'
317
+ at_exit do
318
+ delete_pidfile if cur_pid == Process.pid
319
+ end
320
+ end
321
+
322
+ def reload_worker_directory
323
+ @runner.reload_worker_directory if @runner.respond_to?(:reload_worker_directory)
324
+ end
325
+
326
+ def log(str)
327
+ @log_writer.log(str)
328
+ end
329
+
330
+ def clustered?
331
+ (@options[:workers] || 0) > 0
332
+ end
333
+
334
+ def unsupported(str)
335
+ @log_writer.error(str)
336
+ raise UnsupportedOption
337
+ end
338
+
339
+ def set_process_title
340
+ Process.respond_to?(:setproctitle) ? Process.setproctitle(title) : $0 = title
341
+ end
342
+
343
+ # @!attribute [r] title
344
+ def title
345
+ buffer = "puma #{Puma::Const::VERSION} (#{@options[:binds].join(',')})"
346
+ buffer += " [#{@options[:tag]}]" if @options[:tag] && !@options[:tag].empty?
347
+ buffer
348
+ end
349
+
350
+ def set_rack_environment
351
+ @options[:environment] = environment
352
+ ENV['RACK_ENV'] = environment
353
+ end
354
+
355
+ # @!attribute [r] environment
356
+ def environment
357
+ @environment
358
+ end
359
+
360
+ def prune_bundler?
361
+ @options[:prune_bundler] && clustered? && !@options[:preload_app]
362
+ end
363
+
364
+ def prune_bundler!
365
+ return unless prune_bundler?
366
+ BundlePruner.new(@original_argv, @options[:extra_runtime_dependencies], @log_writer).prune
367
+ end
368
+
369
+ def generate_restart_data
370
+ if dir = @options[:directory]
371
+ @restart_dir = dir
372
+
373
+ elsif Puma.windows?
374
+ # I guess the value of PWD is garbage on windows so don't bother
375
+ # using it.
376
+ @restart_dir = Dir.pwd
377
+
378
+ # Use the same trick as unicorn, namely favor PWD because
379
+ # it will contain an unresolved symlink, useful for when
380
+ # the pwd is /data/releases/current.
381
+ elsif dir = ENV['PWD']
382
+ s_env = File.stat(dir)
383
+ s_pwd = File.stat(Dir.pwd)
384
+
385
+ if s_env.ino == s_pwd.ino and (Puma.jruby? or s_env.dev == s_pwd.dev)
386
+ @restart_dir = dir
387
+ end
388
+ end
389
+
390
+ @restart_dir ||= Dir.pwd
391
+
392
+ # if $0 is a file in the current directory, then restart
393
+ # it the same, otherwise add -S on there because it was
394
+ # picked up in PATH.
395
+ #
396
+ if File.exist?($0)
397
+ arg0 = [Gem.ruby, $0]
398
+ else
399
+ arg0 = [Gem.ruby, "-S", $0]
400
+ end
401
+
402
+ # Detect and reinject -Ilib from the command line, used for testing without bundler
403
+ # cruby has an expanded path, jruby has just "lib"
404
+ lib = File.expand_path "lib"
405
+ arg0[1,0] = ["-I", lib] if [lib, "lib"].include?($LOAD_PATH[0])
406
+
407
+ if defined? Puma::WILD_ARGS
408
+ @restart_argv = arg0 + Puma::WILD_ARGS + @original_argv
409
+ else
410
+ @restart_argv = arg0 + @original_argv
411
+ end
412
+ end
413
+
414
+ def setup_signals
415
+ begin
416
+ Signal.trap "SIGUSR2" do
417
+ restart
418
+ end
419
+ rescue Exception
420
+ log "*** SIGUSR2 not implemented, signal based restart unavailable!"
421
+ end
422
+
423
+ unless Puma.jruby?
424
+ begin
425
+ Signal.trap "SIGUSR1" do
426
+ phased_restart
427
+ end
428
+ rescue Exception
429
+ log "*** SIGUSR1 not implemented, signal based restart unavailable!"
430
+ end
431
+ end
432
+
433
+ begin
434
+ Signal.trap "SIGTERM" do
435
+ # Shortcut the control flow in case raise_exception_on_sigterm is true
436
+ do_graceful_stop
437
+
438
+ raise(SignalException, "SIGTERM") if @options[:raise_exception_on_sigterm]
439
+ end
440
+ rescue Exception
441
+ log "*** SIGTERM not implemented, signal based gracefully stopping unavailable!"
442
+ end
443
+
444
+ begin
445
+ Signal.trap "SIGINT" do
446
+ stop
447
+ end
448
+ rescue Exception
449
+ log "*** SIGINT not implemented, signal based gracefully stopping unavailable!"
450
+ end
451
+
452
+ begin
453
+ Signal.trap "SIGHUP" do
454
+ if @runner.redirected_io?
455
+ @runner.redirect_io
456
+ else
457
+ stop
458
+ end
459
+ end
460
+ rescue Exception
461
+ log "*** SIGHUP not implemented, signal based logs reopening unavailable!"
462
+ end
463
+
464
+ begin
465
+ unless Puma.jruby? # INFO in use by JVM already
466
+ Signal.trap "SIGINFO" do
467
+ thread_status do |name, backtrace|
468
+ @log_writer.log(name)
469
+ @log_writer.log(backtrace.map { |bt| " #{bt}" })
470
+ end
471
+ end
472
+ end
473
+ rescue Exception
474
+ # Not going to log this one, as SIGINFO is *BSD only and would be pretty annoying
475
+ # to see this constantly on Linux.
476
+ end
477
+ end
478
+
479
+ def log_config
480
+ log "Configuration:"
481
+
482
+ @config.final_options
483
+ .each { |config_key, value| log "- #{config_key}: #{value}" }
484
+
485
+ log "\n"
486
+ end
487
+ end
488
+ end
@@ -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, env: ENV)
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, env: env)
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(env: ENV)
49
+ LogWriter.new(StringIO.new, StringIO.new, env: env)
50
+ end
51
+
52
+ def self.stdio(env: ENV)
53
+ LogWriter.new($stdout, $stderr, env: env)
54
+ end
55
+
56
+ def self.null(env: ENV)
57
+ n = NullIO.new
58
+ LogWriter.new(n, n, env: env)
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