puma 5.6.4 → 6.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +270 -4
- data/LICENSE +0 -0
- data/README.md +60 -20
- data/bin/puma-wild +1 -1
- data/docs/architecture.md +0 -0
- data/docs/compile_options.md +34 -0
- data/docs/deployment.md +0 -0
- data/docs/fork_worker.md +1 -3
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/jungle/README.md +0 -0
- data/docs/jungle/rc.d/README.md +0 -0
- data/docs/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +0 -0
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +0 -0
- data/docs/rails_dev_mode.md +0 -0
- data/docs/restart.md +0 -0
- data/docs/signals.md +0 -0
- data/docs/stats.md +0 -0
- data/docs/systemd.md +1 -2
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +18 -10
- data/ext/puma_http11/http11_parser.c +1 -1
- data/ext/puma_http11/http11_parser.h +1 -1
- data/ext/puma_http11/http11_parser.java.rl +2 -2
- data/ext/puma_http11/http11_parser.rl +2 -2
- data/ext/puma_http11/http11_parser_common.rl +2 -2
- data/ext/puma_http11/mini_ssl.c +93 -26
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +166 -65
- data/ext/puma_http11/puma_http11.c +17 -9
- data/lib/puma/app/status.rb +7 -4
- data/lib/puma/binder.rb +49 -52
- data/lib/puma/cli.rb +12 -18
- data/lib/puma/client.rb +55 -16
- data/lib/puma/cluster/worker.rb +18 -11
- data/lib/puma/cluster/worker_handle.rb +4 -1
- data/lib/puma/cluster.rb +33 -30
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +76 -58
- data/lib/puma/const.rb +129 -92
- data/lib/puma/control_cli.rb +21 -18
- data/lib/puma/detect.rb +4 -0
- data/lib/puma/dsl.rb +187 -49
- data/lib/puma/error_logger.rb +18 -9
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +39 -4
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/json_serialization.rb +0 -0
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +113 -175
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +24 -12
- data/lib/puma/minissl.rb +108 -15
- data/lib/puma/null_io.rb +5 -0
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +0 -0
- data/lib/puma/rack/builder.rb +6 -6
- data/lib/puma/rack/urlmap.rb +0 -0
- data/lib/puma/rack_default.rb +19 -4
- data/lib/puma/reactor.rb +19 -10
- data/lib/puma/request.rb +365 -166
- data/lib/puma/runner.rb +52 -20
- data/lib/puma/sd_notify.rb +149 -0
- data/lib/puma/server.rb +73 -73
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +2 -4
- data/lib/puma/thread_pool.rb +23 -19
- data/lib/puma/util.rb +12 -14
- data/lib/puma.rb +12 -11
- data/lib/rack/handler/puma.rb +113 -86
- data/tools/Dockerfile +0 -0
- data/tools/trickletest.rb +0 -0
- metadata +10 -5
- data/lib/puma/queue_close.rb +0 -26
- data/lib/puma/systemd.rb +0 -46
data/lib/puma/dsl.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
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.
|
@@ -31,8 +32,24 @@ module Puma
|
|
31
32
|
# You can also find many examples being used by the test suite in
|
32
33
|
# +test/config+.
|
33
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
|
+
#
|
34
51
|
class DSL
|
35
|
-
|
52
|
+
ON_WORKER_KEY = [String, Symbol].freeze
|
36
53
|
|
37
54
|
# convenience method so logic can be used in CI
|
38
55
|
# @see ssl_bind
|
@@ -46,27 +63,60 @@ module Puma
|
|
46
63
|
else ''
|
47
64
|
end
|
48
65
|
|
49
|
-
ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
|
66
|
+
ca_additions = "&ca=#{Puma::Util.escape(opts[:ca])}" if ['peer', 'force_peer'].include?(verify)
|
50
67
|
|
68
|
+
low_latency_str = opts.key?(:low_latency) ? "&low_latency=#{opts[:low_latency]}" : ''
|
51
69
|
backlog_str = opts[:backlog] ? "&backlog=#{Integer(opts[:backlog])}" : ''
|
52
70
|
|
53
71
|
if defined?(JRUBY_VERSION)
|
54
|
-
|
55
|
-
|
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
|
56
75
|
|
57
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
|
58
83
|
|
59
|
-
"ssl://#{host}:#{port}?#{keystore_additions}#{
|
84
|
+
"ssl://#{host}:#{port}?#{keystore_additions}#{truststore_additions}#{cipher_suites}#{protocols}" \
|
60
85
|
"&verify_mode=#{verify}#{tls_str}#{ca_additions}#{backlog_str}"
|
61
86
|
else
|
62
|
-
ssl_cipher_filter = opts[:ssl_cipher_filter] ?
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
67
117
|
|
68
|
-
"ssl://#{host}:#{port}
|
69
|
-
"#{
|
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}"
|
70
120
|
end
|
71
121
|
end
|
72
122
|
|
@@ -102,7 +152,7 @@ module Puma
|
|
102
152
|
end
|
103
153
|
|
104
154
|
def default_host
|
105
|
-
@options[:default_host] || Configuration::
|
155
|
+
@options[:default_host] || Configuration::DEFAULTS[:tcp_host]
|
106
156
|
end
|
107
157
|
|
108
158
|
def inject(&blk)
|
@@ -202,6 +252,7 @@ module Puma
|
|
202
252
|
#
|
203
253
|
# * Set the socket backlog depth with +backlog+, default is 1024.
|
204
254
|
# * Set up an SSL certificate with +key+ & +cert+.
|
255
|
+
# * Set up an SSL certificate for mTLS with +key+, +cert+, +ca+ and +verify_mode+.
|
205
256
|
# * Set whether to optimize for low latency instead of throughput with
|
206
257
|
# +low_latency+, default is to not optimize for low latency. This is done
|
207
258
|
# via +Socket::TCP_NODELAY+.
|
@@ -211,6 +262,8 @@ module Puma
|
|
211
262
|
# bind 'unix:///var/run/puma.sock?backlog=512'
|
212
263
|
# @example SSL cert
|
213
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'
|
214
267
|
# @example Disable optimization for low latency
|
215
268
|
# bind 'tcp://0.0.0.0:9292?low_latency=false'
|
216
269
|
# @example Socket permissions
|
@@ -367,6 +420,11 @@ module Puma
|
|
367
420
|
@options[:log_requests] = which
|
368
421
|
end
|
369
422
|
|
423
|
+
# Pass in a custom logging class instance
|
424
|
+
def custom_logger(custom_logger)
|
425
|
+
@options[:custom_logger] = custom_logger
|
426
|
+
end
|
427
|
+
|
370
428
|
# Show debugging info
|
371
429
|
#
|
372
430
|
def debug
|
@@ -448,6 +506,10 @@ module Puma
|
|
448
506
|
# Puma will assume you are using the +localhost+ gem and try to load the
|
449
507
|
# appropriate files.
|
450
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.
|
512
|
+
#
|
451
513
|
# @example
|
452
514
|
# ssl_bind '127.0.0.1', '9292', {
|
453
515
|
# cert: path_to_cert,
|
@@ -455,6 +517,7 @@ module Puma
|
|
455
517
|
# ssl_cipher_filter: cipher_filter, # optional
|
456
518
|
# verify_mode: verify_mode, # default 'none'
|
457
519
|
# verification_flags: flags, # optional, not supported by JRuby
|
520
|
+
# reuse: true # optional
|
458
521
|
# }
|
459
522
|
#
|
460
523
|
# @example Using self-signed certificate with the +localhost+ gem:
|
@@ -464,6 +527,7 @@ module Puma
|
|
464
527
|
# ssl_bind '127.0.0.1', '9292', {
|
465
528
|
# cert_pem: File.read(path_to_cert),
|
466
529
|
# key_pem: File.read(path_to_key),
|
530
|
+
# reuse: {size: 2_000, timeout: 20} # optional
|
467
531
|
# }
|
468
532
|
#
|
469
533
|
# @example For JRuby, two keys are required: +keystore+ & +keystore_pass+
|
@@ -527,6 +591,11 @@ module Puma
|
|
527
591
|
@options[:silence_single_worker_warning] = true
|
528
592
|
end
|
529
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
|
+
|
530
599
|
# Code to run immediately before master process
|
531
600
|
# forks workers (once on boot). These hooks can block if necessary
|
532
601
|
# to wait for background operations unknown to Puma to finish before
|
@@ -542,6 +611,8 @@ module Puma
|
|
542
611
|
# puts "Starting workers..."
|
543
612
|
# end
|
544
613
|
def before_fork(&block)
|
614
|
+
warn_if_in_single_mode('before_fork')
|
615
|
+
|
545
616
|
@options[:before_fork] ||= []
|
546
617
|
@options[:before_fork] << block
|
547
618
|
end
|
@@ -556,9 +627,10 @@ module Puma
|
|
556
627
|
# on_worker_boot do
|
557
628
|
# puts 'Before worker boot...'
|
558
629
|
# end
|
559
|
-
def on_worker_boot(&block)
|
560
|
-
|
561
|
-
|
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'
|
562
634
|
end
|
563
635
|
|
564
636
|
# Code to run immediately before a worker shuts
|
@@ -573,9 +645,10 @@ module Puma
|
|
573
645
|
# on_worker_shutdown do
|
574
646
|
# puts 'On worker shutdown...'
|
575
647
|
# end
|
576
|
-
def on_worker_shutdown(&block)
|
577
|
-
|
578
|
-
|
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'
|
579
652
|
end
|
580
653
|
|
581
654
|
# Code to run in the master right before a worker is started. The worker's
|
@@ -589,8 +662,9 @@ module Puma
|
|
589
662
|
# puts 'Before worker fork...'
|
590
663
|
# end
|
591
664
|
def on_worker_fork(&block)
|
592
|
-
|
593
|
-
|
665
|
+
warn_if_in_single_mode('on_worker_fork')
|
666
|
+
|
667
|
+
process_hook :before_worker_fork, nil, block, 'on_worker_fork'
|
594
668
|
end
|
595
669
|
|
596
670
|
# Code to run in the master after a worker has been started. The worker's
|
@@ -604,12 +678,23 @@ module Puma
|
|
604
678
|
# puts 'After worker fork...'
|
605
679
|
# end
|
606
680
|
def after_worker_fork(&block)
|
607
|
-
|
608
|
-
|
681
|
+
warn_if_in_single_mode('after_worker_fork')
|
682
|
+
|
683
|
+
process_hook :after_worker_fork, nil, block, 'after_worker_fork'
|
609
684
|
end
|
610
685
|
|
611
686
|
alias_method :after_worker_boot, :after_worker_fork
|
612
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
|
+
|
613
698
|
# When `fork_worker` is enabled, code to run in Worker 0
|
614
699
|
# before all other workers are re-forked from this process,
|
615
700
|
# after the server has temporarily stopped serving requests
|
@@ -628,9 +713,8 @@ module Puma
|
|
628
713
|
# end
|
629
714
|
# @version 5.0.0
|
630
715
|
#
|
631
|
-
def on_refork(&block)
|
632
|
-
|
633
|
-
@options[:before_refork] << block
|
716
|
+
def on_refork(key = nil, &block)
|
717
|
+
process_hook :before_refork, key, block, 'on_refork'
|
634
718
|
end
|
635
719
|
|
636
720
|
# Code to run out-of-band when the worker is idle.
|
@@ -643,8 +727,7 @@ module Puma
|
|
643
727
|
#
|
644
728
|
# This can be called multiple times to add several hooks.
|
645
729
|
def out_of_band(&block)
|
646
|
-
|
647
|
-
@options[:out_of_band] << block
|
730
|
+
process_hook :out_of_band, nil, block, 'out_of_band'
|
648
731
|
end
|
649
732
|
|
650
733
|
# The directory to operate out of.
|
@@ -774,7 +857,7 @@ module Puma
|
|
774
857
|
#
|
775
858
|
def worker_timeout(timeout)
|
776
859
|
timeout = Integer(timeout)
|
777
|
-
min = @options.fetch(:worker_check_interval,
|
860
|
+
min = @options.fetch(:worker_check_interval, Configuration::DEFAULTS[:worker_check_interval])
|
778
861
|
|
779
862
|
if timeout <= min
|
780
863
|
raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
|
@@ -878,13 +961,16 @@ module Puma
|
|
878
961
|
# There are 5 possible values:
|
879
962
|
#
|
880
963
|
# 1. **:socket** (the default) - read the peername from the socket using the
|
881
|
-
# syscall. This is the normal behavior.
|
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"
|
882
967
|
# 2. **:localhost** - set the remote address to "127.0.0.1"
|
883
968
|
# 3. **header: <http_header>**- set the remote address to the value of the
|
884
969
|
# provided http header. For instance:
|
885
970
|
# `set_remote_address header: "X-Real-IP"`.
|
886
971
|
# Only the first word (as separated by spaces or comma) is used, allowing
|
887
|
-
# headers such as X-Forwarded-For to be used as well.
|
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
|
888
974
|
# 4. **proxy_protocol: :v1**- set the remote address to the value read from the
|
889
975
|
# HAproxy PROXY protocol, version 1. If the request does not have the PROXY
|
890
976
|
# protocol attached to it, will fall back to :socket
|
@@ -938,23 +1024,6 @@ module Puma
|
|
938
1024
|
@options[:fork_worker] = Integer(after_requests)
|
939
1025
|
end
|
940
1026
|
|
941
|
-
# When enabled, Puma will GC 4 times before forking workers.
|
942
|
-
# If available (Ruby 2.7+), we will also call GC.compact.
|
943
|
-
# Not recommended for non-MRI Rubies.
|
944
|
-
#
|
945
|
-
# Based on the work of Koichi Sasada and Aaron Patterson, this option may
|
946
|
-
# decrease memory utilization of preload-enabled cluster-mode Pumas. It will
|
947
|
-
# also increase time to boot and fork. See your logs for details on how much
|
948
|
-
# time this adds to your boot process. For most apps, it will be less than one
|
949
|
-
# second.
|
950
|
-
#
|
951
|
-
# @see Puma::Cluster#nakayoshi_gc
|
952
|
-
# @version 5.0.0
|
953
|
-
#
|
954
|
-
def nakayoshi_fork(enabled=true)
|
955
|
-
@options[:nakayoshi_fork] = enabled
|
956
|
-
end
|
957
|
-
|
958
1027
|
# The number of requests to attempt inline before sending a client back to
|
959
1028
|
# the reactor to be subject to normal ordering.
|
960
1029
|
#
|
@@ -985,6 +1054,51 @@ module Puma
|
|
985
1054
|
@options[:mutate_stdout_and_stderr_to_sync_on_write] = enabled
|
986
1055
|
end
|
987
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
|
+
|
988
1102
|
private
|
989
1103
|
|
990
1104
|
# To avoid adding cert_pem and key_pem as URI params, we store them on the
|
@@ -1004,5 +1118,29 @@ module Puma
|
|
1004
1118
|
end
|
1005
1119
|
end
|
1006
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
|
1007
1145
|
end
|
1008
1146
|
end
|
data/lib/puma/error_logger.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'const'
|
4
4
|
|
5
5
|
module Puma
|
6
6
|
# The implementation of a detailed error logging.
|
@@ -13,6 +13,8 @@ module Puma
|
|
13
13
|
|
14
14
|
REQUEST_FORMAT = %{"%s %s%s" - (%s)}
|
15
15
|
|
16
|
+
LOG_QUEUE = Queue.new
|
17
|
+
|
16
18
|
def initialize(ioerr)
|
17
19
|
@ioerr = ioerr
|
18
20
|
|
@@ -31,7 +33,7 @@ module Puma
|
|
31
33
|
# and before all remaining info.
|
32
34
|
#
|
33
35
|
def info(options={})
|
34
|
-
|
36
|
+
internal_write title(options)
|
35
37
|
end
|
36
38
|
|
37
39
|
# Print occurred error details only if
|
@@ -53,7 +55,7 @@ module Puma
|
|
53
55
|
string_block << request_dump(req) if request_parsed?(req)
|
54
56
|
string_block << error.backtrace if error
|
55
57
|
|
56
|
-
|
58
|
+
internal_write string_block.join("\n")
|
57
59
|
end
|
58
60
|
|
59
61
|
def title(options={})
|
@@ -93,12 +95,19 @@ module Puma
|
|
93
95
|
req && req.env[REQUEST_METHOD]
|
94
96
|
end
|
95
97
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
98
|
+
def internal_write(str)
|
99
|
+
LOG_QUEUE << str
|
100
|
+
while (w_str = LOG_QUEUE.pop(true)) do
|
101
|
+
begin
|
102
|
+
@ioerr.is_a?(IO) and @ioerr.wait_writable(1)
|
103
|
+
@ioerr.write "#{w_str}\n"
|
104
|
+
@ioerr.flush unless @ioerr.sync
|
105
|
+
rescue Errno::EPIPE, Errno::EBADF, IOError, Errno::EINVAL
|
106
|
+
# 'Invalid argument' (Errno::EINVAL) may be raised by flush
|
107
|
+
end
|
108
|
+
end
|
109
|
+
rescue ThreadError
|
102
110
|
end
|
111
|
+
private :internal_write
|
103
112
|
end
|
104
113
|
end
|
data/lib/puma/events.rb
CHANGED
@@ -1,52 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "puma/null_io"
|
4
|
-
require 'puma/error_logger'
|
5
|
-
require 'stringio'
|
6
|
-
|
7
3
|
module Puma
|
8
|
-
# The default implement of an event sink object used by Server
|
9
|
-
# for when certain kinds of events occur in the life of the server.
|
10
|
-
#
|
11
|
-
# The methods available are the events that the Server fires.
|
12
|
-
#
|
13
|
-
class Events
|
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
|
-
# Create an Events object that prints to +stdout+ and +stderr+.
|
27
|
-
#
|
28
|
-
def initialize(stdout, stderr)
|
29
|
-
@formatter = DefaultFormatter.new
|
30
|
-
@stdout = stdout
|
31
|
-
@stderr = stderr
|
32
4
|
|
33
|
-
|
34
|
-
|
5
|
+
# This is an event sink used by `Puma::Server` to handle
|
6
|
+
# lifecycle events such as :on_booted, :on_restart, and :on_stopped.
|
7
|
+
# Using `Puma::DSL` it is possible to register callback hooks
|
8
|
+
# for each event type.
|
9
|
+
class Events
|
35
10
|
|
11
|
+
def initialize
|
36
12
|
@hooks = Hash.new { |h,k| h[k] = [] }
|
37
13
|
end
|
38
14
|
|
39
|
-
attr_reader :stdout, :stderr
|
40
|
-
attr_accessor :formatter
|
41
|
-
|
42
15
|
# Fire callbacks for the named hook
|
43
|
-
#
|
44
16
|
def fire(hook, *args)
|
45
17
|
@hooks[hook].each { |t| t.call(*args) }
|
46
18
|
end
|
47
19
|
|
48
20
|
# Register a callback for a given hook
|
49
|
-
#
|
50
21
|
def register(hook, obj=nil, &blk)
|
51
22
|
if obj and blk
|
52
23
|
raise "Specify either an object or a block, not both"
|
@@ -59,79 +30,6 @@ module Puma
|
|
59
30
|
h
|
60
31
|
end
|
61
32
|
|
62
|
-
# Write +str+ to +@stdout+
|
63
|
-
#
|
64
|
-
def log(str)
|
65
|
-
@stdout.puts format(str) if @stdout.respond_to? :puts
|
66
|
-
|
67
|
-
@stdout.flush unless @stdout.sync
|
68
|
-
rescue Errno::EPIPE
|
69
|
-
end
|
70
|
-
|
71
|
-
def write(str)
|
72
|
-
@stdout.write format(str)
|
73
|
-
end
|
74
|
-
|
75
|
-
def debug(str)
|
76
|
-
log("% #{str}") if @debug
|
77
|
-
end
|
78
|
-
|
79
|
-
# Write +str+ to +@stderr+
|
80
|
-
#
|
81
|
-
def error(str)
|
82
|
-
@error_logger.info(text: format("ERROR: #{str}"))
|
83
|
-
exit 1
|
84
|
-
end
|
85
|
-
|
86
|
-
def format(str)
|
87
|
-
formatter.call(str)
|
88
|
-
end
|
89
|
-
|
90
|
-
# An HTTP connection error has occurred.
|
91
|
-
# +error+ a connection exception, +req+ the request,
|
92
|
-
# and +text+ additional info
|
93
|
-
# @version 5.0.0
|
94
|
-
#
|
95
|
-
def connection_error(error, req, text="HTTP connection error")
|
96
|
-
@error_logger.info(error: error, req: req, text: text)
|
97
|
-
end
|
98
|
-
|
99
|
-
# An HTTP parse error has occurred.
|
100
|
-
# +error+ a parsing exception,
|
101
|
-
# and +req+ the request.
|
102
|
-
#
|
103
|
-
def parse_error(error, req)
|
104
|
-
@error_logger.info(error: error, req: req, text: 'HTTP parse error, malformed request')
|
105
|
-
end
|
106
|
-
|
107
|
-
# An SSL error has occurred.
|
108
|
-
# @param error <Puma::MiniSSL::SSLError>
|
109
|
-
# @param ssl_socket <Puma::MiniSSL::Socket>
|
110
|
-
#
|
111
|
-
def ssl_error(error, ssl_socket)
|
112
|
-
peeraddr = ssl_socket.peeraddr.last rescue "<unknown>"
|
113
|
-
peercert = ssl_socket.peercert
|
114
|
-
subject = peercert ? peercert.subject : nil
|
115
|
-
@error_logger.info(error: error, text: "SSL error, peer: #{peeraddr}, peer cert: #{subject}")
|
116
|
-
end
|
117
|
-
|
118
|
-
# An unknown error has occurred.
|
119
|
-
# +error+ an exception object, +req+ the request,
|
120
|
-
# and +text+ additional info
|
121
|
-
#
|
122
|
-
def unknown_error(error, req=nil, text="Unknown error")
|
123
|
-
@error_logger.info(error: error, req: req, text: text)
|
124
|
-
end
|
125
|
-
|
126
|
-
# Log occurred error debug dump.
|
127
|
-
# +error+ an exception object, +req+ the request,
|
128
|
-
# and +text+ additional info
|
129
|
-
# @version 5.0.0
|
130
|
-
#
|
131
|
-
def debug_error(error, req=nil, text="")
|
132
|
-
@error_logger.debug(error: error, req: req, text: text)
|
133
|
-
end
|
134
|
-
|
135
33
|
def on_booted(&block)
|
136
34
|
register(:on_booted, &block)
|
137
35
|
end
|
@@ -155,23 +53,5 @@ module Puma
|
|
155
53
|
def fire_on_stopped!
|
156
54
|
fire(:on_stopped)
|
157
55
|
end
|
158
|
-
|
159
|
-
DEFAULT = new(STDOUT, STDERR)
|
160
|
-
|
161
|
-
# Returns an Events object which writes its status to 2 StringIO
|
162
|
-
# objects.
|
163
|
-
#
|
164
|
-
def self.strings
|
165
|
-
Events.new StringIO.new, StringIO.new
|
166
|
-
end
|
167
|
-
|
168
|
-
def self.stdio
|
169
|
-
Events.new $stdout, $stderr
|
170
|
-
end
|
171
|
-
|
172
|
-
def self.null
|
173
|
-
n = NullIO.new
|
174
|
-
Events.new n, n
|
175
|
-
end
|
176
56
|
end
|
177
57
|
end
|
data/lib/puma/io_buffer.rb
CHANGED
@@ -1,11 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'stringio'
|
4
|
+
|
3
5
|
module Puma
|
4
|
-
class IOBuffer <
|
5
|
-
def
|
6
|
-
|
6
|
+
class IOBuffer < StringIO
|
7
|
+
def initialize
|
8
|
+
super.binmode
|
9
|
+
end
|
10
|
+
|
11
|
+
def empty?
|
12
|
+
length.zero?
|
7
13
|
end
|
8
14
|
|
9
|
-
|
15
|
+
def reset
|
16
|
+
truncate 0
|
17
|
+
rewind
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
rewind
|
22
|
+
read
|
23
|
+
end
|
24
|
+
|
25
|
+
# Read & Reset - returns contents and resets
|
26
|
+
# @return [String] StringIO contents
|
27
|
+
def read_and_reset
|
28
|
+
rewind
|
29
|
+
str = read
|
30
|
+
truncate 0
|
31
|
+
rewind
|
32
|
+
str
|
33
|
+
end
|
34
|
+
|
35
|
+
alias_method :clear, :reset
|
36
|
+
|
37
|
+
# before Ruby 2.5, `write` would only take one argument
|
38
|
+
if RUBY_VERSION >= '2.5' && RUBY_ENGINE != 'truffleruby'
|
39
|
+
alias_method :append, :write
|
40
|
+
else
|
41
|
+
def append(*strs)
|
42
|
+
strs.each { |str| write str }
|
43
|
+
end
|
44
|
+
end
|
10
45
|
end
|
11
46
|
end
|
data/lib/puma/jruby_restart.rb
CHANGED
File without changes
|