puma 4.3.12 → 6.3.1

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 (96) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1729 -521
  3. data/LICENSE +23 -20
  4. data/README.md +169 -45
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +63 -26
  7. data/docs/compile_options.md +55 -0
  8. data/docs/deployment.md +60 -69
  9. data/docs/fork_worker.md +31 -0
  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 +9 -0
  14. data/{tools → docs}/jungle/rc.d/README.md +1 -1
  15. data/{tools → docs}/jungle/rc.d/puma +2 -2
  16. data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  17. data/docs/kubernetes.md +66 -0
  18. data/docs/nginx.md +2 -2
  19. data/docs/plugins.md +15 -15
  20. data/docs/rails_dev_mode.md +28 -0
  21. data/docs/restart.md +46 -23
  22. data/docs/signals.md +13 -11
  23. data/docs/stats.md +142 -0
  24. data/docs/systemd.md +84 -128
  25. data/docs/testing_benchmarks_local_files.md +150 -0
  26. data/docs/testing_test_rackup_ci_files.md +36 -0
  27. data/ext/puma_http11/PumaHttp11Service.java +2 -4
  28. data/ext/puma_http11/ext_help.h +1 -1
  29. data/ext/puma_http11/extconf.rb +49 -12
  30. data/ext/puma_http11/http11_parser.c +46 -48
  31. data/ext/puma_http11/http11_parser.h +2 -2
  32. data/ext/puma_http11/http11_parser.java.rl +3 -3
  33. data/ext/puma_http11/http11_parser.rl +3 -3
  34. data/ext/puma_http11/http11_parser_common.rl +2 -2
  35. data/ext/puma_http11/mini_ssl.c +278 -93
  36. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  37. data/ext/puma_http11/org/jruby/puma/Http11.java +6 -6
  38. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +4 -6
  39. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +241 -96
  40. data/ext/puma_http11/puma_http11.c +46 -57
  41. data/lib/puma/app/status.rb +53 -39
  42. data/lib/puma/binder.rb +237 -121
  43. data/lib/puma/cli.rb +34 -34
  44. data/lib/puma/client.rb +172 -98
  45. data/lib/puma/cluster/worker.rb +180 -0
  46. data/lib/puma/cluster/worker_handle.rb +97 -0
  47. data/lib/puma/cluster.rb +226 -231
  48. data/lib/puma/commonlogger.rb +21 -14
  49. data/lib/puma/configuration.rb +114 -87
  50. data/lib/puma/const.rb +139 -95
  51. data/lib/puma/control_cli.rb +99 -79
  52. data/lib/puma/detect.rb +33 -2
  53. data/lib/puma/dsl.rb +516 -110
  54. data/lib/puma/error_logger.rb +113 -0
  55. data/lib/puma/events.rb +16 -115
  56. data/lib/puma/io_buffer.rb +44 -2
  57. data/lib/puma/jruby_restart.rb +2 -59
  58. data/lib/puma/json_serialization.rb +96 -0
  59. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  60. data/lib/puma/launcher.rb +164 -155
  61. data/lib/puma/log_writer.rb +147 -0
  62. data/lib/puma/minissl/context_builder.rb +36 -19
  63. data/lib/puma/minissl.rb +230 -55
  64. data/lib/puma/null_io.rb +18 -1
  65. data/lib/puma/plugin/systemd.rb +90 -0
  66. data/lib/puma/plugin/tmp_restart.rb +1 -1
  67. data/lib/puma/plugin.rb +3 -12
  68. data/lib/puma/rack/builder.rb +7 -11
  69. data/lib/puma/rack/urlmap.rb +0 -0
  70. data/lib/puma/rack_default.rb +19 -4
  71. data/lib/puma/reactor.rb +93 -368
  72. data/lib/puma/request.rb +671 -0
  73. data/lib/puma/runner.rb +92 -75
  74. data/lib/puma/sd_notify.rb +149 -0
  75. data/lib/puma/server.rb +321 -794
  76. data/lib/puma/single.rb +20 -74
  77. data/lib/puma/state_file.rb +45 -8
  78. data/lib/puma/thread_pool.rb +140 -68
  79. data/lib/puma/util.rb +21 -4
  80. data/lib/puma.rb +54 -7
  81. data/lib/rack/handler/puma.rb +113 -87
  82. data/tools/{docker/Dockerfile → Dockerfile} +1 -1
  83. data/tools/trickletest.rb +0 -0
  84. metadata +33 -24
  85. data/docs/tcp_mode.md +0 -96
  86. data/ext/puma_http11/io_buffer.c +0 -155
  87. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  88. data/lib/puma/accept_nonblock.rb +0 -29
  89. data/lib/puma/tcp_logger.rb +0 -41
  90. data/tools/jungle/README.md +0 -19
  91. data/tools/jungle/init.d/README.md +0 -61
  92. data/tools/jungle/init.d/puma +0 -421
  93. data/tools/jungle/init.d/run-puma +0 -18
  94. data/tools/jungle/upstart/README.md +0 -61
  95. data/tools/jungle/upstart/puma-manager.conf +0 -31
  96. data/tools/jungle/upstart/puma.conf +0 -69
data/lib/puma/dsl.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/const'
3
+ require_relative 'const'
4
+ require_relative 'util'
4
5
 
5
6
  module Puma
6
7
  # The methods that are available for use inside the configuration file.
@@ -14,24 +15,110 @@ module Puma
14
15
  # end
15
16
  # config.load
16
17
  #
17
- # puts config.options[:binds]
18
- # "tcp://127.0.0.1:3001"
18
+ # puts config.options[:binds] # => "tcp://127.0.0.1:3001"
19
19
  #
20
20
  # Used to load file:
21
21
  #
22
22
  # $ cat puma_config.rb
23
- # port 3002
23
+ # port 3002
24
+ #
25
+ # Resulting configuration:
24
26
  #
25
27
  # config = Configuration.new(config_file: "puma_config.rb")
26
28
  # config.load
27
29
  #
28
- # puts config.options[:binds]
29
- # # => "tcp://127.0.0.1:3002"
30
+ # puts config.options[:binds] # => "tcp://127.0.0.1:3002"
30
31
  #
31
32
  # You can also find many examples being used by the test suite in
32
33
  # +test/config+.
34
+ #
35
+ # Puma v6 adds the option to specify a key name (String or Symbol) to the
36
+ # hooks that run inside the forked workers. All the hooks run inside the
37
+ # {Puma::Cluster::Worker#run} method.
38
+ #
39
+ # Previously, the worker index and the LogWriter instance were passed to the
40
+ # hook blocks/procs. If a key name is specified, a hash is passed as the last
41
+ # parameter. This allows storage of data, typically objects that are created
42
+ # before the worker that need to be passed to the hook when the worker is shutdown.
43
+ #
44
+ # The following hooks have been updated:
45
+ #
46
+ # | DSL Method | Options Key | Fork Block Location |
47
+ # | on_worker_boot | :before_worker_boot | inside, before |
48
+ # | on_worker_shutdown | :before_worker_shutdown | inside, after |
49
+ # | on_refork | :before_refork | inside |
50
+ #
33
51
  class DSL
34
- include ConfigDefault
52
+ ON_WORKER_KEY = [String, Symbol].freeze
53
+
54
+ # convenience method so logic can be used in CI
55
+ # @see ssl_bind
56
+ #
57
+ def self.ssl_bind_str(host, port, opts)
58
+ verify = opts.fetch(:verify_mode, 'none').to_s
59
+
60
+ tls_str =
61
+ if opts[:no_tlsv1_1] then '&no_tlsv1_1=true'
62
+ elsif opts[:no_tlsv1] then '&no_tlsv1=true'
63
+ else ''
64
+ end
65
+
66
+ ca_additions = "&ca=#{Puma::Util.escape(opts[:ca])}" if ['peer', 'force_peer'].include?(verify)
67
+
68
+ low_latency_str = opts.key?(:low_latency) ? "&low_latency=#{opts[:low_latency]}" : ''
69
+ backlog_str = opts[:backlog] ? "&backlog=#{Integer(opts[:backlog])}" : ''
70
+
71
+ if defined?(JRUBY_VERSION)
72
+ cipher_suites = opts[:ssl_cipher_list] ? "&ssl_cipher_list=#{opts[:ssl_cipher_list]}" : nil # old name
73
+ cipher_suites = "#{cipher_suites}&cipher_suites=#{opts[:cipher_suites]}" if opts[:cipher_suites]
74
+ protocols = opts[:protocols] ? "&protocols=#{opts[:protocols]}" : nil
75
+
76
+ keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
77
+ keystore_additions = "#{keystore_additions}&keystore-type=#{opts[:keystore_type]}" if opts[:keystore_type]
78
+ if opts[:truststore]
79
+ truststore_additions = "&truststore=#{opts[:truststore]}"
80
+ truststore_additions = "#{truststore_additions}&truststore-pass=#{opts[:truststore_pass]}" if opts[:truststore_pass]
81
+ truststore_additions = "#{truststore_additions}&truststore-type=#{opts[:truststore_type]}" if opts[:truststore_type]
82
+ end
83
+
84
+ "ssl://#{host}:#{port}?#{keystore_additions}#{truststore_additions}#{cipher_suites}#{protocols}" \
85
+ "&verify_mode=#{verify}#{tls_str}#{ca_additions}#{backlog_str}"
86
+ else
87
+ ssl_cipher_filter = opts[:ssl_cipher_filter] ? "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" : nil
88
+ v_flags = (ary = opts[:verification_flags]) ? "&verification_flags=#{Array(ary).join ','}" : nil
89
+
90
+ cert_flags = (cert = opts[:cert]) ? "cert=#{Puma::Util.escape(cert)}" : nil
91
+ key_flags = (key = opts[:key]) ? "&key=#{Puma::Util.escape(key)}" : nil
92
+ password_flags = (password_command = opts[:key_password_command]) ? "&key_password_command=#{Puma::Util.escape(password_command)}" : nil
93
+
94
+ reuse_flag =
95
+ if (reuse = opts[:reuse])
96
+ if reuse == true
97
+ '&reuse=dflt'
98
+ elsif reuse.is_a?(Hash) && (reuse.key?(:size) || reuse.key?(:timeout))
99
+ val = +''
100
+ if (size = reuse[:size]) && Integer === size
101
+ val << size.to_s
102
+ end
103
+ if (timeout = reuse[:timeout]) && Integer === timeout
104
+ val << ",#{timeout}"
105
+ end
106
+ if val.empty?
107
+ nil
108
+ else
109
+ "&reuse=#{val}"
110
+ end
111
+ else
112
+ nil
113
+ end
114
+ else
115
+ nil
116
+ end
117
+
118
+ "ssl://#{host}:#{port}?#{cert_flags}#{key_flags}#{password_flags}#{ssl_cipher_filter}" \
119
+ "#{reuse_flag}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}#{backlog_str}#{low_latency_str}"
120
+ end
121
+ end
35
122
 
36
123
  def initialize(options, config)
37
124
  @config = config
@@ -65,7 +152,7 @@ module Puma
65
152
  end
66
153
 
67
154
  def default_host
68
- @options[:default_host] || Configuration::DefaultTCPHost
155
+ @options[:default_host] || Configuration::DEFAULTS[:tcp_host]
69
156
  end
70
157
 
71
158
  def inject(&blk)
@@ -98,6 +185,9 @@ module Puma
98
185
  # [body]
99
186
  # ]
100
187
  # end
188
+ #
189
+ # @see Puma::Configuration#app
190
+ #
101
191
  def app(obj=nil, &block)
102
192
  obj ||= block
103
193
 
@@ -153,28 +243,34 @@ module Puma
153
243
  end
154
244
 
155
245
  # Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
156
- # accepted protocols. Multiple urls can be bound to, calling `bind` does
246
+ # accepted protocols. Multiple urls can be bound to, calling +bind+ does
157
247
  # not overwrite previous bindings.
158
248
  #
159
249
  # The default is "tcp://0.0.0.0:9292".
160
250
  #
161
251
  # You can use query parameters within the url to specify options:
162
252
  #
163
- # - Set the socket backlog depth with +backlog+, default is 1024.
164
- # - Set up an SSL certificate with +key+ & +cert+.
165
- # - Set whether to optimize for low latency instead of throughput with
166
- # +low_latency+, default is to optimize for low latency. This is done
167
- # via +Socket::TCP_NODELAY+.
168
- # - Set socket permissions with +umask+.
253
+ # * Set the socket backlog depth with +backlog+, default is 1024.
254
+ # * Set up an SSL certificate with +key+ & +cert+.
255
+ # * Set up an SSL certificate for mTLS with +key+, +cert+, +ca+ and +verify_mode+.
256
+ # * Set whether to optimize for low latency instead of throughput with
257
+ # +low_latency+, default is to not optimize for low latency. This is done
258
+ # via +Socket::TCP_NODELAY+.
259
+ # * Set socket permissions with +umask+.
169
260
  #
170
261
  # @example Backlog depth
171
262
  # bind 'unix:///var/run/puma.sock?backlog=512'
172
263
  # @example SSL cert
173
264
  # bind 'ssl://127.0.0.1:9292?key=key.key&cert=cert.pem'
265
+ # @example SSL cert for mutual TLS (mTLS)
266
+ # bind 'ssl://127.0.0.1:9292?key=key.key&cert=cert.pem&ca=ca.pem&verify_mode=force_peer'
174
267
  # @example Disable optimization for low latency
175
268
  # bind 'tcp://0.0.0.0:9292?low_latency=false'
176
269
  # @example Socket permissions
177
270
  # bind 'unix:///var/run/puma.sock?umask=0111'
271
+ # @see Puma::Runner#load_and_bind
272
+ # @see Puma::Cluster#run
273
+ #
178
274
  def bind(url)
179
275
  @options[:binds] ||= []
180
276
  @options[:binds] << url
@@ -184,22 +280,49 @@ module Puma
184
280
  @options[:binds] = []
185
281
  end
186
282
 
283
+ # Bind to (systemd) activated sockets, regardless of configured binds.
284
+ #
285
+ # Systemd can present sockets as file descriptors that are already opened.
286
+ # By default Puma will use these but only if it was explicitly told to bind
287
+ # to the socket. If not, it will close the activated sockets. This means
288
+ # all configuration is duplicated.
289
+ #
290
+ # Binds can contain additional configuration, but only SSL config is really
291
+ # relevant since the unix and TCP socket options are ignored.
292
+ #
293
+ # This means there is a lot of duplicated configuration for no additional
294
+ # value in most setups. This method tells the launcher to bind to all
295
+ # activated sockets, regardless of existing bind.
296
+ #
297
+ # To clear configured binds, the value only can be passed. This will clear
298
+ # out any binds that may have been configured.
299
+ #
300
+ # @example Use any systemd activated sockets as well as configured binds
301
+ # bind_to_activated_sockets
302
+ #
303
+ # @example Only bind to systemd activated sockets, ignoring other binds
304
+ # bind_to_activated_sockets 'only'
305
+ def bind_to_activated_sockets(bind=true)
306
+ @options[:bind_to_activated_sockets] = bind
307
+ end
308
+
187
309
  # Define the TCP port to bind to. Use +bind+ for more advanced options.
188
310
  #
189
311
  # @example
190
312
  # port 9292
191
313
  def port(port, host=nil)
192
314
  host ||= default_host
193
- bind "tcp://#{host}:#{port}"
315
+ bind URI::Generic.build(scheme: 'tcp', host: host, port: Integer(port)).to_s
194
316
  end
195
317
 
196
- # Define how long persistent connections can be idle before Puma closes
197
- # them.
318
+ # Define how long persistent connections can be idle before Puma closes them.
319
+ # @see Puma::Server.new
198
320
  def persistent_timeout(seconds)
199
321
  @options[:persistent_timeout] = Integer(seconds)
200
322
  end
201
323
 
202
324
  # Define how long the tcp socket stays open, if no data has been received.
325
+ # @see Puma::Server.new
203
326
  def first_data_timeout(seconds)
204
327
  @options[:first_data_timeout] = Integer(seconds)
205
328
  end
@@ -210,24 +333,11 @@ module Puma
210
333
  @options[:clean_thread_locals] = which
211
334
  end
212
335
 
213
- # Daemonize the server into the background. It's highly recommended to
214
- # use this in combination with +pidfile+ and +stdout_redirect+.
215
- #
216
- # The default is "false".
336
+ # When shutting down, drain the accept socket of pending connections and
337
+ # process them. This loops over the accept socket until there are no more
338
+ # read events and then stops looking and waits for the requests to finish.
339
+ # @see Puma::Server#graceful_shutdown
217
340
  #
218
- # @example
219
- # daemonize
220
- #
221
- # @example
222
- # daemonize false
223
- def daemonize(which=true)
224
- @options[:daemon] = which
225
- end
226
-
227
- # When shutting down, drain the accept socket of pending
228
- # connections and process them. This loops over the accept
229
- # socket until there are no more read events and then stops
230
- # looking and waits for the requests to finish.
231
341
  def drain_on_shutdown(which=true)
232
342
  @options[:drain_on_shutdown] = which
233
343
  end
@@ -250,6 +360,7 @@ module Puma
250
360
  #
251
361
  # Puma always waits a few seconds after killing a thread for it to try
252
362
  # to finish up it's work, even in :immediately mode.
363
+ # @see Puma::Server#graceful_shutdown
253
364
  def force_shutdown_after(val=:forever)
254
365
  i = case val
255
366
  when :forever
@@ -257,7 +368,7 @@ module Puma
257
368
  when :immediately
258
369
  0
259
370
  else
260
- Integer(val)
371
+ Float(val)
261
372
  end
262
373
 
263
374
  @options[:force_shutdown_after] = i
@@ -309,6 +420,11 @@ module Puma
309
420
  @options[:log_requests] = which
310
421
  end
311
422
 
423
+ # Pass in a custom logging class instance
424
+ def custom_logger(custom_logger)
425
+ @options[:custom_logger] = custom_logger
426
+ end
427
+
312
428
  # Show debugging info
313
429
  #
314
430
  def debug
@@ -322,20 +438,21 @@ module Puma
322
438
  # @example
323
439
  # rackup '/u/apps/lolcat/config.ru'
324
440
  def rackup(path)
325
- @options[:rackup] = path.to_s
441
+ @options[:rackup] ||= path.to_s
326
442
  end
327
443
 
328
- # Run Puma in TCP mode
329
- #
330
- def tcp_mode!
331
- @options[:mode] = :tcp
444
+ # Allows setting `env['rack.url_scheme']`.
445
+ # Only necessary if X-Forwarded-Proto is not being set by your proxy
446
+ # Normal values are 'http' or 'https'.
447
+ def rack_url_scheme(scheme=nil)
448
+ @options[:rack_url_scheme] = scheme
332
449
  end
333
450
 
334
451
  def early_hints(answer=true)
335
452
  @options[:early_hints] = answer
336
453
  end
337
454
 
338
- # Redirect STDOUT and STDERR to files specified. The +append+ parameter
455
+ # Redirect +STDOUT+ and +STDERR+ to files specified. The +append+ parameter
339
456
  # specifies whether the output is appended, the default is +false+.
340
457
  #
341
458
  # @example
@@ -355,7 +472,10 @@ module Puma
355
472
  # Configure +min+ to be the minimum number of threads to use to answer
356
473
  # requests and +max+ the maximum.
357
474
  #
358
- # The default is "0, 16".
475
+ # The default is the environment variables +PUMA_MIN_THREADS+ / +PUMA_MAX_THREADS+
476
+ # (or +MIN_THREADS+ / +MAX_THREADS+ if the +PUMA_+ variables aren't set).
477
+ #
478
+ # If these environment variables aren't set, the default is "0, 5" in MRI or "0, 16" for other interpreters.
359
479
  #
360
480
  # @example
361
481
  # threads 0, 16
@@ -376,8 +496,19 @@ module Puma
376
496
  @options[:max_threads] = max
377
497
  end
378
498
 
379
- # Instead of "bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'" you
380
- # can also use the "ssl_bind" option.
499
+ # Instead of using +bind+ and manually constructing a URI like:
500
+ #
501
+ # bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'
502
+ #
503
+ # you can use the this method.
504
+ #
505
+ # When binding on localhost you don't need to specify +cert+ and +key+,
506
+ # Puma will assume you are using the +localhost+ gem and try to load the
507
+ # appropriate files.
508
+ #
509
+ # When using the options hash parameter, the `reuse:` value is either
510
+ # `true`, which sets reuse 'on' with default values, or a hash, with `:size`
511
+ # and/or `:timeout` keys, each with integer values.
381
512
  #
382
513
  # @example
383
514
  # ssl_bind '127.0.0.1', '9292', {
@@ -385,29 +516,30 @@ module Puma
385
516
  # key: path_to_key,
386
517
  # ssl_cipher_filter: cipher_filter, # optional
387
518
  # verify_mode: verify_mode, # default 'none'
519
+ # verification_flags: flags, # optional, not supported by JRuby
520
+ # reuse: true # optional
388
521
  # }
389
- # @example For JRuby additional keys are required: keystore & keystore_pass.
522
+ #
523
+ # @example Using self-signed certificate with the +localhost+ gem:
524
+ # ssl_bind '127.0.0.1', '9292'
525
+ #
526
+ # @example Alternatively, you can provide +cert_pem+ and +key_pem+:
527
+ # ssl_bind '127.0.0.1', '9292', {
528
+ # cert_pem: File.read(path_to_cert),
529
+ # key_pem: File.read(path_to_key),
530
+ # reuse: {size: 2_000, timeout: 20} # optional
531
+ # }
532
+ #
533
+ # @example For JRuby, two keys are required: +keystore+ & +keystore_pass+
390
534
  # ssl_bind '127.0.0.1', '9292', {
391
- # cert: path_to_cert,
392
- # key: path_to_key,
393
- # ssl_cipher_filter: cipher_filter, # optional
394
- # verify_mode: verify_mode, # default 'none'
395
535
  # keystore: path_to_keystore,
396
- # keystore_pass: password
536
+ # keystore_pass: password,
537
+ # ssl_cipher_list: cipher_list, # optional
538
+ # verify_mode: verify_mode # default 'none'
397
539
  # }
398
- def ssl_bind(host, port, opts)
399
- verify = opts.fetch(:verify_mode, 'none').to_s
400
- no_tlsv1 = opts.fetch(:no_tlsv1, 'false')
401
- no_tlsv1_1 = opts.fetch(:no_tlsv1_1, 'false')
402
- ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
403
-
404
- if defined?(JRUBY_VERSION)
405
- keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
406
- bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}&no_tlsv1_1=#{no_tlsv1_1}#{ca_additions}"
407
- else
408
- ssl_cipher_filter = "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" if opts[:ssl_cipher_filter]
409
- bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}#{ssl_cipher_filter}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}&no_tlsv1_1=#{no_tlsv1_1}#{ca_additions}"
410
- end
540
+ def ssl_bind(host, port, opts = {})
541
+ add_pem_values_to_options_store(opts)
542
+ bind self.class.ssl_bind_str(host, port, opts)
411
543
  end
412
544
 
413
545
  # Use +path+ as the file to store the server info state. This is
@@ -419,16 +551,51 @@ module Puma
419
551
  @options[:state] = path.to_s
420
552
  end
421
553
 
554
+ # Use +permission+ to restrict permissions for the state file.
555
+ #
556
+ # @example
557
+ # state_permission 0600
558
+ # @version 5.0.0
559
+ #
560
+ def state_permission(permission)
561
+ @options[:state_permission] = permission
562
+ end
563
+
422
564
  # How many worker processes to run. Typically this is set to
423
- # to the number of available cores.
565
+ # the number of available cores.
424
566
  #
425
- # The default is 0.
567
+ # The default is the value of the environment variable +WEB_CONCURRENCY+ if
568
+ # set, otherwise 0.
426
569
  #
427
570
  # @note Cluster mode only.
571
+ # @see Puma::Cluster
428
572
  def workers(count)
429
573
  @options[:workers] = count.to_i
430
574
  end
431
575
 
576
+ # Disable warning message when running in cluster mode with a single worker.
577
+ #
578
+ # Cluster mode has some overhead of running an additional 'control' process
579
+ # in order to manage the cluster. If only running a single worker it is
580
+ # likely not worth paying that overhead vs running in single mode with
581
+ # additional threads instead.
582
+ #
583
+ # There are some scenarios where running cluster mode with a single worker
584
+ # may still be warranted and valid under certain deployment scenarios, see
585
+ # https://github.com/puma/puma/issues/2534
586
+ #
587
+ # Moving from workers = 1 to workers = 0 will save 10-30% of memory use.
588
+ #
589
+ # @note Cluster mode only.
590
+ def silence_single_worker_warning
591
+ @options[:silence_single_worker_warning] = true
592
+ end
593
+
594
+ # Disable warning message when running single mode with callback hook defined.
595
+ def silence_fork_callback_warning
596
+ @options[:silence_fork_callback_warning] = true
597
+ end
598
+
432
599
  # Code to run immediately before master process
433
600
  # forks workers (once on boot). These hooks can block if necessary
434
601
  # to wait for background operations unknown to Puma to finish before
@@ -444,6 +611,8 @@ module Puma
444
611
  # puts "Starting workers..."
445
612
  # end
446
613
  def before_fork(&block)
614
+ warn_if_in_single_mode('before_fork')
615
+
447
616
  @options[:before_fork] ||= []
448
617
  @options[:before_fork] << block
449
618
  end
@@ -455,12 +624,13 @@ module Puma
455
624
  #
456
625
  # @note Cluster mode only.
457
626
  # @example
458
- # on_worker_fork do
459
- # puts 'Before worker fork...'
627
+ # on_worker_boot do
628
+ # puts 'Before worker boot...'
460
629
  # end
461
- def on_worker_boot(&block)
462
- @options[:before_worker_boot] ||= []
463
- @options[:before_worker_boot] << block
630
+ def on_worker_boot(key = nil, &block)
631
+ warn_if_in_single_mode('on_worker_boot')
632
+
633
+ process_hook :before_worker_boot, key, block, 'on_worker_boot'
464
634
  end
465
635
 
466
636
  # Code to run immediately before a worker shuts
@@ -475,9 +645,10 @@ module Puma
475
645
  # on_worker_shutdown do
476
646
  # puts 'On worker shutdown...'
477
647
  # end
478
- def on_worker_shutdown(&block)
479
- @options[:before_worker_shutdown] ||= []
480
- @options[:before_worker_shutdown] << block
648
+ def on_worker_shutdown(key = nil, &block)
649
+ warn_if_in_single_mode('on_worker_shutdown')
650
+
651
+ process_hook :before_worker_shutdown, key, block, 'on_worker_shutdown'
481
652
  end
482
653
 
483
654
  # Code to run in the master right before a worker is started. The worker's
@@ -491,8 +662,9 @@ module Puma
491
662
  # puts 'Before worker fork...'
492
663
  # end
493
664
  def on_worker_fork(&block)
494
- @options[:before_worker_fork] ||= []
495
- @options[:before_worker_fork] << block
665
+ warn_if_in_single_mode('on_worker_fork')
666
+
667
+ process_hook :before_worker_fork, nil, block, 'on_worker_fork'
496
668
  end
497
669
 
498
670
  # Code to run in the master after a worker has been started. The worker's
@@ -506,12 +678,45 @@ module Puma
506
678
  # puts 'After worker fork...'
507
679
  # end
508
680
  def after_worker_fork(&block)
509
- @options[:after_worker_fork] ||= []
510
- @options[:after_worker_fork] = block
681
+ warn_if_in_single_mode('after_worker_fork')
682
+
683
+ process_hook :after_worker_fork, nil, block, 'after_worker_fork'
511
684
  end
512
685
 
513
686
  alias_method :after_worker_boot, :after_worker_fork
514
687
 
688
+ # Code to run after puma is booted (works for both: single and clustered)
689
+ #
690
+ # @example
691
+ # on_booted do
692
+ # puts 'After booting...'
693
+ # end
694
+ def on_booted(&block)
695
+ @config.options[:events].on_booted(&block)
696
+ end
697
+
698
+ # When `fork_worker` is enabled, code to run in Worker 0
699
+ # before all other workers are re-forked from this process,
700
+ # after the server has temporarily stopped serving requests
701
+ # (once per complete refork cycle).
702
+ #
703
+ # This can be used to trigger extra garbage-collection to maximize
704
+ # copy-on-write efficiency, or close any connections to remote servers
705
+ # (database, Redis, ...) that were opened while the server was running.
706
+ #
707
+ # This can be called multiple times to add several hooks.
708
+ #
709
+ # @note Cluster mode with `fork_worker` enabled only.
710
+ # @example
711
+ # on_refork do
712
+ # 3.times {GC.start}
713
+ # end
714
+ # @version 5.0.0
715
+ #
716
+ def on_refork(key = nil, &block)
717
+ process_hook :before_refork, key, block, 'on_refork'
718
+ end
719
+
515
720
  # Code to run out-of-band when the worker is idle.
516
721
  # These hooks run immediately after a request has finished
517
722
  # processing and there are no busy threads on the worker.
@@ -522,8 +727,7 @@ module Puma
522
727
  #
523
728
  # This can be called multiple times to add several hooks.
524
729
  def out_of_band(&block)
525
- @options[:out_of_band] ||= []
526
- @options[:out_of_band] << block
730
+ process_hook :out_of_band, nil, block, 'out_of_band'
527
731
  end
528
732
 
529
733
  # The directory to operate out of.
@@ -536,19 +740,8 @@ module Puma
536
740
  @options[:directory] = dir.to_s
537
741
  end
538
742
 
539
- # DEPRECATED: The directory to operate out of.
540
- def worker_directory(dir)
541
- $stderr.puts "worker_directory is deprecated. Please use `directory`"
542
- directory dir
543
- end
544
-
545
- # Run the app as a raw TCP app instead of an HTTP rack app.
546
- def tcp_mode
547
- @options[:mode] = :tcp
548
- end
549
-
550
743
  # Preload the application before starting the workers; this conflicts with
551
- # phased restart feature. This is off by default.
744
+ # phased restart feature. On by default if your app uses more than 1 worker.
552
745
  #
553
746
  # @note Cluster mode only.
554
747
  # @example
@@ -583,7 +776,7 @@ module Puma
583
776
  # new Bundler context and thus can float around as the release
584
777
  # dictates.
585
778
  #
586
- # See also: extra_runtime_dependencies
779
+ # @see extra_runtime_dependencies
587
780
  #
588
781
  # @note This is incompatible with +preload_app!+.
589
782
  # @note This is only supported for RubyGems 2.2+
@@ -600,6 +793,9 @@ module Puma
600
793
  #
601
794
  # @example
602
795
  # raise_exception_on_sigterm false
796
+ # @see Puma::Launcher#setup_signals
797
+ # @see Puma::Cluster#setup_signals
798
+ #
603
799
  def raise_exception_on_sigterm(answer=true)
604
800
  @options[:raise_exception_on_sigterm] = answer
605
801
  end
@@ -615,6 +811,8 @@ module Puma
615
811
  # extra_runtime_dependencies ['gem_name_1', 'gem_name_2']
616
812
  # @example
617
813
  # extra_runtime_dependencies ['puma_worker_killer', 'puma-heroku']
814
+ # @see Puma::Launcher#extra_runtime_deps_directories
815
+ #
618
816
  def extra_runtime_dependencies(answer = [])
619
817
  @options[:extra_runtime_dependencies] = Array(answer)
620
818
  end
@@ -632,6 +830,19 @@ module Puma
632
830
  @options[:tag] = string.to_s
633
831
  end
634
832
 
833
+ # Change the default interval for checking workers.
834
+ #
835
+ # The default value is 5 seconds.
836
+ #
837
+ # @note Cluster mode only.
838
+ # @example
839
+ # worker_check_interval 5
840
+ # @see Puma::Cluster#check_workers
841
+ #
842
+ def worker_check_interval(interval)
843
+ @options[:worker_check_interval] = Integer(interval)
844
+ end
845
+
635
846
  # Verifies that all workers have checked in to the master process within
636
847
  # the given timeout. If not the worker process will be restarted. This is
637
848
  # not a request timeout, it is to protect against a hung or dead process.
@@ -642,9 +853,11 @@ module Puma
642
853
  # @note Cluster mode only.
643
854
  # @example
644
855
  # worker_timeout 60
856
+ # @see Puma::Cluster::Worker#ping_timeout
857
+ #
645
858
  def worker_timeout(timeout)
646
859
  timeout = Integer(timeout)
647
- min = Const::WORKER_CHECK_INTERVAL
860
+ min = @options.fetch(:worker_check_interval, Configuration::DEFAULTS[:worker_check_interval])
648
861
 
649
862
  if timeout <= min
650
863
  raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
@@ -658,19 +871,48 @@ module Puma
658
871
  # If unspecified, this defaults to the value of worker_timeout.
659
872
  #
660
873
  # @note Cluster mode only.
661
- # @example:
874
+ #
875
+ # @example
662
876
  # worker_boot_timeout 60
877
+ # @see Puma::Cluster::Worker#ping_timeout
878
+ #
663
879
  def worker_boot_timeout(timeout)
664
880
  @options[:worker_boot_timeout] = Integer(timeout)
665
881
  end
666
882
 
667
- # Set the timeout for worker shutdown
883
+ # Set the timeout for worker shutdown.
668
884
  #
669
885
  # @note Cluster mode only.
886
+ # @see Puma::Cluster::Worker#term
887
+ #
670
888
  def worker_shutdown_timeout(timeout)
671
889
  @options[:worker_shutdown_timeout] = Integer(timeout)
672
890
  end
673
891
 
892
+ # Set the strategy for worker culling.
893
+ #
894
+ # There are two possible values:
895
+ #
896
+ # 1. **:youngest** - the youngest workers (i.e. the workers that were
897
+ # the most recently started) will be culled.
898
+ # 2. **:oldest** - the oldest workers (i.e. the workers that were started
899
+ # the longest time ago) will be culled.
900
+ #
901
+ # @note Cluster mode only.
902
+ # @example
903
+ # worker_culling_strategy :oldest
904
+ # @see Puma::Cluster#cull_workers
905
+ #
906
+ def worker_culling_strategy(strategy)
907
+ stategy = strategy.to_sym
908
+
909
+ if ![:youngest, :oldest].include?(strategy)
910
+ raise "Invalid value for worker_culling_strategy - #{stategy}"
911
+ end
912
+
913
+ @options[:worker_culling_strategy] = strategy
914
+ end
915
+
674
916
  # When set to true (the default), workers accept all requests
675
917
  # and queue them before passing them to the handlers.
676
918
  # When set to false, each worker process accepts exactly as
@@ -684,6 +926,7 @@ module Puma
684
926
  # slow clients will occupy a handler thread while the request
685
927
  # is being sent. A reverse proxy, such as nginx, can handle
686
928
  # slow clients and queue requests before they reach Puma.
929
+ # @see Puma::Server
687
930
  def queue_requests(answer=true)
688
931
  @options[:queue_requests] = answer
689
932
  end
@@ -691,29 +934,50 @@ module Puma
691
934
  # When a shutdown is requested, the backtraces of all the
692
935
  # threads will be written to $stdout. This can help figure
693
936
  # out why shutdown is hanging.
937
+ #
694
938
  def shutdown_debug(val=true)
695
939
  @options[:shutdown_debug] = val
696
940
  end
697
941
 
942
+
943
+ # Attempts to route traffic to less-busy workers by causing them to delay
944
+ # listening on the socket, allowing workers which are not processing any
945
+ # requests to pick up new requests first.
946
+ #
947
+ # Only works on MRI. For all other interpreters, this setting does nothing.
948
+ # @see Puma::Server#handle_servers
949
+ # @see Puma::ThreadPool#wait_for_less_busy_worker
950
+ # @version 5.0.0
951
+ #
952
+ def wait_for_less_busy_worker(val=0.005)
953
+ @options[:wait_for_less_busy_worker] = val.to_f
954
+ end
955
+
698
956
  # Control how the remote address of the connection is set. This
699
957
  # is configurable because to calculate the true socket peer address
700
958
  # a kernel syscall is required which for very fast rack handlers
701
959
  # slows down the handling significantly.
702
960
  #
703
- # There are 4 possible values:
704
- #
705
- # * :socket (the default) - read the peername from the socket using the
706
- # syscall. This is the normal behavior.
707
- # * :localhost - set the remote address to "127.0.0.1"
708
- # * header: http_header - set the remote address to the value of the
709
- # provided http header. For instance:
710
- # `set_remote_address header: "X-Real-IP"`.
711
- # Only the first word (as separated by spaces or comma)
712
- # is used, allowing headers such as X-Forwarded-For
713
- # to be used as well.
714
- # * Any string - this allows you to hardcode remote address to any value
715
- # you wish. Because Puma never uses this field anyway, it's
716
- # format is entirely in your hands.
961
+ # There are 5 possible values:
962
+ #
963
+ # 1. **:socket** (the default) - read the peername from the socket using the
964
+ # syscall. This is the normal behavior. If this fails for any reason (e.g.,
965
+ # if the peer disconnects between the connection being accepted and the getpeername
966
+ # system call), Puma will return "0.0.0.0"
967
+ # 2. **:localhost** - set the remote address to "127.0.0.1"
968
+ # 3. **header: <http_header>**- set the remote address to the value of the
969
+ # provided http header. For instance:
970
+ # `set_remote_address header: "X-Real-IP"`.
971
+ # Only the first word (as separated by spaces or comma) is used, allowing
972
+ # headers such as X-Forwarded-For to be used as well. If this header is absent,
973
+ # Puma will fall back to the behavior of :socket
974
+ # 4. **proxy_protocol: :v1**- set the remote address to the value read from the
975
+ # HAproxy PROXY protocol, version 1. If the request does not have the PROXY
976
+ # protocol attached to it, will fall back to :socket
977
+ # 5. **\<Any string\>** - this allows you to hardcode remote address to any value
978
+ # you wish. Because Puma never uses this field anyway, it's format is
979
+ # entirely in your hands.
980
+ #
717
981
  def set_remote_address(val=:socket)
718
982
  case val
719
983
  when :socket
@@ -728,6 +992,13 @@ module Puma
728
992
  if hdr = val[:header]
729
993
  @options[:remote_address] = :header
730
994
  @options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
995
+ elsif protocol_version = val[:proxy_protocol]
996
+ @options[:remote_address] = :proxy_protocol
997
+ protocol_version = protocol_version.downcase.to_sym
998
+ unless [:v1].include?(protocol_version)
999
+ raise "Invalid value for proxy_protocol - #{protocol_version.inspect}"
1000
+ end
1001
+ @options[:remote_address_proxy_protocol] = protocol_version
731
1002
  else
732
1003
  raise "Invalid value for set_remote_address - #{val.inspect}"
733
1004
  end
@@ -736,5 +1007,140 @@ module Puma
736
1007
  end
737
1008
  end
738
1009
 
1010
+ # When enabled, workers will be forked from worker 0 instead of from the master process.
1011
+ # This option is similar to `preload_app` because the app is preloaded before forking,
1012
+ # but it is compatible with phased restart.
1013
+ #
1014
+ # This option also enables the `refork` command (SIGURG), which optimizes copy-on-write performance
1015
+ # in a running app.
1016
+ #
1017
+ # A refork will automatically trigger once after the specified number of requests
1018
+ # (default 1000), or pass 0 to disable auto refork.
1019
+ #
1020
+ # @note Cluster mode only.
1021
+ # @version 5.0.0
1022
+ #
1023
+ def fork_worker(after_requests=1000)
1024
+ @options[:fork_worker] = Integer(after_requests)
1025
+ end
1026
+
1027
+ # The number of requests to attempt inline before sending a client back to
1028
+ # the reactor to be subject to normal ordering.
1029
+ #
1030
+ def max_fast_inline(num_of_requests)
1031
+ @options[:max_fast_inline] = Float(num_of_requests)
1032
+ end
1033
+
1034
+ # Specify the backend for the IO selector.
1035
+ #
1036
+ # Provided values will be passed directly to +NIO::Selector.new+, with the
1037
+ # exception of +:auto+ which will let nio4r choose the backend.
1038
+ #
1039
+ # Check the documentation of +NIO::Selector.backends+ for the list of valid
1040
+ # options. Note that the available options on your system will depend on the
1041
+ # operating system. If you want to use the pure Ruby backend (not
1042
+ # recommended due to its comparatively low performance), set environment
1043
+ # variable +NIO4R_PURE+ to +true+.
1044
+ #
1045
+ # The default is +:auto+.
1046
+ #
1047
+ # @see https://github.com/socketry/nio4r/blob/master/lib/nio/selector.rb
1048
+ #
1049
+ def io_selector_backend(backend)
1050
+ @options[:io_selector_backend] = backend.to_sym
1051
+ end
1052
+
1053
+ def mutate_stdout_and_stderr_to_sync_on_write(enabled=true)
1054
+ @options[:mutate_stdout_and_stderr_to_sync_on_write] = enabled
1055
+ end
1056
+
1057
+ # Specify how big the request payload should be, in bytes.
1058
+ # This limit is compared against Content-Length HTTP header.
1059
+ # If the payload size (CONTENT_LENGTH) is larger than http_content_length_limit,
1060
+ # HTTP 413 status code is returned.
1061
+ #
1062
+ # When no Content-Length http header is present, it is compared against the
1063
+ # size of the body of the request.
1064
+ #
1065
+ # The default value for http_content_length_limit is nil.
1066
+ def http_content_length_limit(limit)
1067
+ @options[:http_content_length_limit] = limit
1068
+ end
1069
+
1070
+ # Supported http methods, which will replace `Puma::Const::SUPPORTED_HTTP_METHODS`.
1071
+ # The value of `:any` will allows all methods, otherwise, the value must be
1072
+ # an array of strings. Note that methods are all uppercase.
1073
+ #
1074
+ # `Puma::Const::SUPPORTED_HTTP_METHODS` is conservative, if you want a
1075
+ # complete set of methods, the methods defined by the
1076
+ # [IANA Method Registry](https://www.iana.org/assignments/http-methods/http-methods.xhtml)
1077
+ # are pre-defined as the constant `Puma::Const::IANA_HTTP_METHODS`.
1078
+ #
1079
+ # @note If the `methods` value is `:any`, no method check with be performed,
1080
+ # similar to Puma v5 and earlier.
1081
+ #
1082
+ # @example Adds 'PROPFIND' to existing supported methods
1083
+ # supported_http_methods(Puma::Const::SUPPORTED_HTTP_METHODS + ['PROPFIND'])
1084
+ # @example Restricts methods to the array elements
1085
+ # supported_http_methods %w[HEAD GET POST PUT DELETE OPTIONS PROPFIND]
1086
+ # @example Restricts methods to the methods in the IANA Registry
1087
+ # supported_http_methods Puma::Const::IANA_HTTP_METHODS
1088
+ # @example Allows any method
1089
+ # supported_http_methods :any
1090
+ #
1091
+ def supported_http_methods(methods)
1092
+ if methods == :any
1093
+ @options[:supported_http_methods] = :any
1094
+ elsif Array === methods && methods == (ary = methods.grep(String).uniq) &&
1095
+ !ary.empty?
1096
+ @options[:supported_http_methods] = ary
1097
+ else
1098
+ raise "supported_http_methods must be ':any' or a unique array of strings"
1099
+ end
1100
+ end
1101
+
1102
+ private
1103
+
1104
+ # To avoid adding cert_pem and key_pem as URI params, we store them on the
1105
+ # options[:store] from where Puma binder knows how to find and extract them.
1106
+ def add_pem_values_to_options_store(opts)
1107
+ return if defined?(JRUBY_VERSION)
1108
+
1109
+ @options[:store] ||= []
1110
+
1111
+ # Store cert_pem and key_pem to options[:store] if present
1112
+ [:cert, :key].each do |v|
1113
+ opt_key = :"#{v}_pem"
1114
+ if opts[opt_key]
1115
+ index = @options[:store].length
1116
+ @options[:store] << opts[opt_key]
1117
+ opts[v] = "store:#{index}"
1118
+ end
1119
+ end
1120
+ end
1121
+
1122
+ def process_hook(options_key, key, block, meth)
1123
+ @options[options_key] ||= []
1124
+ if ON_WORKER_KEY.include? key.class
1125
+ @options[options_key] << [block, key.to_sym]
1126
+ elsif key.nil?
1127
+ @options[options_key] << block
1128
+ else
1129
+ raise "'#{meth}' key must be String or Symbol"
1130
+ end
1131
+ end
1132
+
1133
+ def warn_if_in_single_mode(hook_name)
1134
+ return if @options[:silence_fork_callback_warning]
1135
+
1136
+ if (@options[:workers] || 0) == 0
1137
+ log_string =
1138
+ "Warning: You specified code to run in a `#{hook_name}` block, " \
1139
+ "but Puma is not configured to run in cluster mode (worker count > 0 ), " \
1140
+ "so your `#{hook_name}` block did not run"
1141
+
1142
+ LogWriter.stdio.log(log_string)
1143
+ end
1144
+ end
739
1145
  end
740
1146
  end