puma 5.3.2 → 6.0.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 +284 -11
- data/LICENSE +0 -0
- data/README.md +61 -16
- data/bin/puma-wild +1 -1
- data/docs/architecture.md +49 -16
- data/docs/compile_options.md +38 -2
- data/docs/deployment.md +53 -67
- 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 +0 -0
- data/docs/plugins.md +15 -15
- data/docs/rails_dev_mode.md +2 -3
- data/docs/restart.md +6 -6
- data/docs/signals.md +11 -10
- data/docs/stats.md +8 -8
- data/docs/systemd.md +64 -67
- 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 +44 -13
- data/ext/puma_http11/http11_parser.c +24 -11
- 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 +3 -3
- data/ext/puma_http11/mini_ssl.c +122 -23
- 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 +50 -48
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +188 -102
- data/ext/puma_http11/puma_http11.c +18 -10
- data/lib/puma/app/status.rb +9 -6
- data/lib/puma/binder.rb +81 -42
- data/lib/puma/cli.rb +23 -19
- data/lib/puma/client.rb +124 -30
- data/lib/puma/cluster/worker.rb +21 -29
- data/lib/puma/cluster/worker_handle.rb +8 -1
- data/lib/puma/cluster.rb +57 -48
- data/lib/puma/commonlogger.rb +0 -0
- data/lib/puma/configuration.rb +74 -55
- data/lib/puma/const.rb +21 -24
- data/lib/puma/control_cli.rb +22 -19
- data/lib/puma/detect.rb +10 -2
- data/lib/puma/dsl.rb +196 -57
- data/lib/puma/error_logger.rb +17 -9
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +29 -4
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/{json.rb → json_serialization.rb} +1 -1
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +108 -154
- data/lib/puma/log_writer.rb +137 -0
- data/lib/puma/minissl/context_builder.rb +29 -16
- data/lib/puma/minissl.rb +115 -38
- data/lib/puma/null_io.rb +5 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +2 -2
- data/lib/puma/rack/builder.rb +5 -5
- data/lib/puma/rack/urlmap.rb +0 -0
- data/lib/puma/rack_default.rb +1 -1
- data/lib/puma/reactor.rb +3 -3
- data/lib/puma/request.rb +293 -153
- data/lib/puma/runner.rb +63 -28
- data/lib/puma/server.rb +83 -88
- data/lib/puma/single.rb +10 -10
- data/lib/puma/state_file.rb +39 -7
- data/lib/puma/systemd.rb +3 -2
- data/lib/puma/thread_pool.rb +22 -17
- data/lib/puma/util.rb +20 -15
- data/lib/puma.rb +12 -9
- data/lib/rack/handler/puma.rb +9 -9
- data/tools/Dockerfile +1 -1
- data/tools/trickletest.rb +0 -0
- metadata +13 -9
- data/lib/puma/queue_close.rb +0 -26
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,25 +63,58 @@ 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)
|
67
|
+
|
68
|
+
backlog_str = opts[:backlog] ? "&backlog=#{Integer(opts[:backlog])}" : ''
|
50
69
|
|
51
70
|
if defined?(JRUBY_VERSION)
|
52
|
-
|
53
|
-
|
71
|
+
cipher_suites = opts[:ssl_cipher_list] ? "&ssl_cipher_list=#{opts[:ssl_cipher_list]}" : nil # old name
|
72
|
+
cipher_suites = "#{cipher_suites}&cipher_suites=#{opts[:cipher_suites]}" if opts[:cipher_suites]
|
73
|
+
protocols = opts[:protocols] ? "&protocols=#{opts[:protocols]}" : nil
|
54
74
|
|
55
75
|
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
76
|
+
keystore_additions = "#{keystore_additions}&keystore-type=#{opts[:keystore_type]}" if opts[:keystore_type]
|
77
|
+
if opts[:truststore]
|
78
|
+
truststore_additions = "&truststore=#{opts[:truststore]}"
|
79
|
+
truststore_additions = "#{truststore_additions}&truststore-pass=#{opts[:truststore_pass]}" if opts[:truststore_pass]
|
80
|
+
truststore_additions = "#{truststore_additions}&truststore-type=#{opts[:truststore_type]}" if opts[:truststore_type]
|
81
|
+
end
|
56
82
|
|
57
|
-
"ssl://#{host}:#{port}?#{keystore_additions}#{
|
58
|
-
"&verify_mode=#{verify}#{tls_str}#{ca_additions}"
|
83
|
+
"ssl://#{host}:#{port}?#{keystore_additions}#{truststore_additions}#{cipher_suites}#{protocols}" \
|
84
|
+
"&verify_mode=#{verify}#{tls_str}#{ca_additions}#{backlog_str}"
|
59
85
|
else
|
60
|
-
ssl_cipher_filter = opts[:ssl_cipher_filter] ?
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
86
|
+
ssl_cipher_filter = opts[:ssl_cipher_filter] ? "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" : nil
|
87
|
+
v_flags = (ary = opts[:verification_flags]) ? "&verification_flags=#{Array(ary).join ','}" : nil
|
88
|
+
|
89
|
+
cert_flags = (cert = opts[:cert]) ? "cert=#{Puma::Util.escape(cert)}" : nil
|
90
|
+
key_flags = (key = opts[:key]) ? "&key=#{Puma::Util.escape(key)}" : nil
|
91
|
+
|
92
|
+
reuse_flag =
|
93
|
+
if (reuse = opts[:reuse])
|
94
|
+
if reuse == true
|
95
|
+
'&reuse=dflt'
|
96
|
+
elsif reuse.is_a?(Hash) && (reuse.key?(:size) || reuse.key?(:timeout))
|
97
|
+
val = +''
|
98
|
+
if (size = reuse[:size]) && Integer === size
|
99
|
+
val << size.to_s
|
100
|
+
end
|
101
|
+
if (timeout = reuse[:timeout]) && Integer === timeout
|
102
|
+
val << ",#{timeout}"
|
103
|
+
end
|
104
|
+
if val.empty?
|
105
|
+
nil
|
106
|
+
else
|
107
|
+
"&reuse=#{val}"
|
108
|
+
end
|
109
|
+
else
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
else
|
113
|
+
nil
|
114
|
+
end
|
65
115
|
|
66
|
-
"ssl://#{host}:#{port}
|
67
|
-
"#{
|
116
|
+
"ssl://#{host}:#{port}?#{cert_flags}#{key_flags}#{ssl_cipher_filter}" \
|
117
|
+
"#{reuse_flag}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}#{backlog_str}"
|
68
118
|
end
|
69
119
|
end
|
70
120
|
|
@@ -100,7 +150,7 @@ module Puma
|
|
100
150
|
end
|
101
151
|
|
102
152
|
def default_host
|
103
|
-
@options[:default_host] || Configuration::
|
153
|
+
@options[:default_host] || Configuration::DEFAULTS[:tcp_host]
|
104
154
|
end
|
105
155
|
|
106
156
|
def inject(&blk)
|
@@ -191,7 +241,7 @@ module Puma
|
|
191
241
|
end
|
192
242
|
|
193
243
|
# Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
|
194
|
-
# accepted protocols. Multiple urls can be bound to, calling
|
244
|
+
# accepted protocols. Multiple urls can be bound to, calling +bind+ does
|
195
245
|
# not overwrite previous bindings.
|
196
246
|
#
|
197
247
|
# The default is "tcp://0.0.0.0:9292".
|
@@ -381,6 +431,13 @@ module Puma
|
|
381
431
|
@options[:rackup] ||= path.to_s
|
382
432
|
end
|
383
433
|
|
434
|
+
# Allows setting `env['rack.url_scheme']`.
|
435
|
+
# Only necessary if X-Forwarded-Proto is not being set by your proxy
|
436
|
+
# Normal values are 'http' or 'https'.
|
437
|
+
def rack_url_scheme(scheme=nil)
|
438
|
+
@options[:rack_url_scheme] = scheme
|
439
|
+
end
|
440
|
+
|
384
441
|
def early_hints(answer=true)
|
385
442
|
@options[:early_hints] = answer
|
386
443
|
end
|
@@ -429,8 +486,19 @@ module Puma
|
|
429
486
|
@options[:max_threads] = max
|
430
487
|
end
|
431
488
|
|
432
|
-
# Instead of
|
433
|
-
#
|
489
|
+
# Instead of using +bind+ and manually constructing a URI like:
|
490
|
+
#
|
491
|
+
# bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'
|
492
|
+
#
|
493
|
+
# you can use the this method.
|
494
|
+
#
|
495
|
+
# When binding on localhost you don't need to specify +cert+ and +key+,
|
496
|
+
# Puma will assume you are using the +localhost+ gem and try to load the
|
497
|
+
# appropriate files.
|
498
|
+
#
|
499
|
+
# When using the options hash parameter, the `reuse:` value is either
|
500
|
+
# `true`, which sets reuse 'on' with default values, or a hash, with `:size`
|
501
|
+
# and/or `:timeout` keys, each with integer values.
|
434
502
|
#
|
435
503
|
# @example
|
436
504
|
# ssl_bind '127.0.0.1', '9292', {
|
@@ -439,15 +507,28 @@ module Puma
|
|
439
507
|
# ssl_cipher_filter: cipher_filter, # optional
|
440
508
|
# verify_mode: verify_mode, # default 'none'
|
441
509
|
# verification_flags: flags, # optional, not supported by JRuby
|
510
|
+
# reuse: true # optional
|
442
511
|
# }
|
443
|
-
#
|
512
|
+
#
|
513
|
+
# @example Using self-signed certificate with the +localhost+ gem:
|
514
|
+
# ssl_bind '127.0.0.1', '9292'
|
515
|
+
#
|
516
|
+
# @example Alternatively, you can provide +cert_pem+ and +key_pem+:
|
517
|
+
# ssl_bind '127.0.0.1', '9292', {
|
518
|
+
# cert_pem: File.read(path_to_cert),
|
519
|
+
# key_pem: File.read(path_to_key),
|
520
|
+
# reuse: {size: 2_000, timeout: 20} # optional
|
521
|
+
# }
|
522
|
+
#
|
523
|
+
# @example For JRuby, two keys are required: +keystore+ & +keystore_pass+
|
444
524
|
# ssl_bind '127.0.0.1', '9292', {
|
445
525
|
# keystore: path_to_keystore,
|
446
526
|
# keystore_pass: password,
|
447
527
|
# ssl_cipher_list: cipher_list, # optional
|
448
528
|
# verify_mode: verify_mode # default 'none'
|
449
529
|
# }
|
450
|
-
def ssl_bind(host, port, opts)
|
530
|
+
def ssl_bind(host, port, opts = {})
|
531
|
+
add_pem_values_to_options_store(opts)
|
451
532
|
bind self.class.ssl_bind_str(host, port, opts)
|
452
533
|
end
|
453
534
|
|
@@ -529,9 +610,8 @@ module Puma
|
|
529
610
|
# on_worker_boot do
|
530
611
|
# puts 'Before worker boot...'
|
531
612
|
# end
|
532
|
-
def on_worker_boot(&block)
|
533
|
-
|
534
|
-
@options[:before_worker_boot] << block
|
613
|
+
def on_worker_boot(key = nil, &block)
|
614
|
+
process_hook :before_worker_boot, key, block, 'on_worker_boot'
|
535
615
|
end
|
536
616
|
|
537
617
|
# Code to run immediately before a worker shuts
|
@@ -546,9 +626,8 @@ module Puma
|
|
546
626
|
# on_worker_shutdown do
|
547
627
|
# puts 'On worker shutdown...'
|
548
628
|
# end
|
549
|
-
def on_worker_shutdown(&block)
|
550
|
-
|
551
|
-
@options[:before_worker_shutdown] << block
|
629
|
+
def on_worker_shutdown(key = nil, &block)
|
630
|
+
process_hook :before_worker_shutdown, key, block, 'on_worker_shutdown'
|
552
631
|
end
|
553
632
|
|
554
633
|
# Code to run in the master right before a worker is started. The worker's
|
@@ -562,8 +641,7 @@ module Puma
|
|
562
641
|
# puts 'Before worker fork...'
|
563
642
|
# end
|
564
643
|
def on_worker_fork(&block)
|
565
|
-
|
566
|
-
@options[:before_worker_fork] << block
|
644
|
+
process_hook :before_worker_fork, nil, block, 'on_worker_fork'
|
567
645
|
end
|
568
646
|
|
569
647
|
# Code to run in the master after a worker has been started. The worker's
|
@@ -577,8 +655,7 @@ module Puma
|
|
577
655
|
# puts 'After worker fork...'
|
578
656
|
# end
|
579
657
|
def after_worker_fork(&block)
|
580
|
-
|
581
|
-
@options[:after_worker_fork] = block
|
658
|
+
process_hook :after_worker_fork, nil, block, 'after_worker_fork'
|
582
659
|
end
|
583
660
|
|
584
661
|
alias_method :after_worker_boot, :after_worker_fork
|
@@ -601,9 +678,8 @@ module Puma
|
|
601
678
|
# end
|
602
679
|
# @version 5.0.0
|
603
680
|
#
|
604
|
-
def on_refork(&block)
|
605
|
-
|
606
|
-
@options[:before_refork] << block
|
681
|
+
def on_refork(key = nil, &block)
|
682
|
+
process_hook :before_refork, key, block, 'on_refork'
|
607
683
|
end
|
608
684
|
|
609
685
|
# Code to run out-of-band when the worker is idle.
|
@@ -616,8 +692,7 @@ module Puma
|
|
616
692
|
#
|
617
693
|
# This can be called multiple times to add several hooks.
|
618
694
|
def out_of_band(&block)
|
619
|
-
|
620
|
-
@options[:out_of_band] << block
|
695
|
+
process_hook :out_of_band, nil, block, 'out_of_band'
|
621
696
|
end
|
622
697
|
|
623
698
|
# The directory to operate out of.
|
@@ -720,6 +795,19 @@ module Puma
|
|
720
795
|
@options[:tag] = string.to_s
|
721
796
|
end
|
722
797
|
|
798
|
+
# Change the default interval for checking workers.
|
799
|
+
#
|
800
|
+
# The default value is 5 seconds.
|
801
|
+
#
|
802
|
+
# @note Cluster mode only.
|
803
|
+
# @example
|
804
|
+
# worker_check_interval 5
|
805
|
+
# @see Puma::Cluster#check_workers
|
806
|
+
#
|
807
|
+
def worker_check_interval(interval)
|
808
|
+
@options[:worker_check_interval] = Integer(interval)
|
809
|
+
end
|
810
|
+
|
723
811
|
# Verifies that all workers have checked in to the master process within
|
724
812
|
# the given timeout. If not the worker process will be restarted. This is
|
725
813
|
# not a request timeout, it is to protect against a hung or dead process.
|
@@ -734,7 +822,7 @@ module Puma
|
|
734
822
|
#
|
735
823
|
def worker_timeout(timeout)
|
736
824
|
timeout = Integer(timeout)
|
737
|
-
min =
|
825
|
+
min = @options.fetch(:worker_check_interval, Configuration::DEFAULTS[:worker_check_interval])
|
738
826
|
|
739
827
|
if timeout <= min
|
740
828
|
raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
|
@@ -766,6 +854,30 @@ module Puma
|
|
766
854
|
@options[:worker_shutdown_timeout] = Integer(timeout)
|
767
855
|
end
|
768
856
|
|
857
|
+
# Set the strategy for worker culling.
|
858
|
+
#
|
859
|
+
# There are two possible values:
|
860
|
+
#
|
861
|
+
# 1. **:youngest** - the youngest workers (i.e. the workers that were
|
862
|
+
# the most recently started) will be culled.
|
863
|
+
# 2. **:oldest** - the oldest workers (i.e. the workers that were started
|
864
|
+
# the longest time ago) will be culled.
|
865
|
+
#
|
866
|
+
# @note Cluster mode only.
|
867
|
+
# @example
|
868
|
+
# worker_culling_strategy :oldest
|
869
|
+
# @see Puma::Cluster#cull_workers
|
870
|
+
#
|
871
|
+
def worker_culling_strategy(strategy)
|
872
|
+
stategy = strategy.to_sym
|
873
|
+
|
874
|
+
if ![:youngest, :oldest].include?(strategy)
|
875
|
+
raise "Invalid value for worker_culling_strategy - #{stategy}"
|
876
|
+
end
|
877
|
+
|
878
|
+
@options[:worker_culling_strategy] = strategy
|
879
|
+
end
|
880
|
+
|
769
881
|
# When set to true (the default), workers accept all requests
|
770
882
|
# and queue them before passing them to the handlers.
|
771
883
|
# When set to false, each worker process accepts exactly as
|
@@ -811,17 +923,23 @@ module Puma
|
|
811
923
|
# a kernel syscall is required which for very fast rack handlers
|
812
924
|
# slows down the handling significantly.
|
813
925
|
#
|
814
|
-
# There are
|
926
|
+
# There are 5 possible values:
|
815
927
|
#
|
816
928
|
# 1. **:socket** (the default) - read the peername from the socket using the
|
817
|
-
# syscall. This is the normal behavior.
|
929
|
+
# syscall. This is the normal behavior. If this fails for any reason (e.g.,
|
930
|
+
# if the peer disconnects between the connection being accepted and the getpeername
|
931
|
+
# system call), Puma will return "0.0.0.0"
|
818
932
|
# 2. **:localhost** - set the remote address to "127.0.0.1"
|
819
933
|
# 3. **header: <http_header>**- set the remote address to the value of the
|
820
934
|
# provided http header. For instance:
|
821
935
|
# `set_remote_address header: "X-Real-IP"`.
|
822
936
|
# Only the first word (as separated by spaces or comma) is used, allowing
|
823
|
-
# headers such as X-Forwarded-For to be used as well.
|
824
|
-
#
|
937
|
+
# headers such as X-Forwarded-For to be used as well. If this header is absent,
|
938
|
+
# Puma will fall back to the behavior of :socket
|
939
|
+
# 4. **proxy_protocol: :v1**- set the remote address to the value read from the
|
940
|
+
# HAproxy PROXY protocol, version 1. If the request does not have the PROXY
|
941
|
+
# protocol attached to it, will fall back to :socket
|
942
|
+
# 5. **\<Any string\>** - this allows you to hardcode remote address to any value
|
825
943
|
# you wish. Because Puma never uses this field anyway, it's format is
|
826
944
|
# entirely in your hands.
|
827
945
|
#
|
@@ -839,6 +957,13 @@ module Puma
|
|
839
957
|
if hdr = val[:header]
|
840
958
|
@options[:remote_address] = :header
|
841
959
|
@options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
|
960
|
+
elsif protocol_version = val[:proxy_protocol]
|
961
|
+
@options[:remote_address] = :proxy_protocol
|
962
|
+
protocol_version = protocol_version.downcase.to_sym
|
963
|
+
unless [:v1].include?(protocol_version)
|
964
|
+
raise "Invalid value for proxy_protocol - #{protocol_version.inspect}"
|
965
|
+
end
|
966
|
+
@options[:remote_address_proxy_protocol] = protocol_version
|
842
967
|
else
|
843
968
|
raise "Invalid value for set_remote_address - #{val.inspect}"
|
844
969
|
end
|
@@ -864,23 +989,6 @@ module Puma
|
|
864
989
|
@options[:fork_worker] = Integer(after_requests)
|
865
990
|
end
|
866
991
|
|
867
|
-
# When enabled, Puma will GC 4 times before forking workers.
|
868
|
-
# If available (Ruby 2.7+), we will also call GC.compact.
|
869
|
-
# Not recommended for non-MRI Rubies.
|
870
|
-
#
|
871
|
-
# Based on the work of Koichi Sasada and Aaron Patterson, this option may
|
872
|
-
# decrease memory utilization of preload-enabled cluster-mode Pumas. It will
|
873
|
-
# also increase time to boot and fork. See your logs for details on how much
|
874
|
-
# time this adds to your boot process. For most apps, it will be less than one
|
875
|
-
# second.
|
876
|
-
#
|
877
|
-
# @see Puma::Cluster#nakayoshi_gc
|
878
|
-
# @version 5.0.0
|
879
|
-
#
|
880
|
-
def nakayoshi_fork(enabled=true)
|
881
|
-
@options[:nakayoshi_fork] = enabled
|
882
|
-
end
|
883
|
-
|
884
992
|
# The number of requests to attempt inline before sending a client back to
|
885
993
|
# the reactor to be subject to normal ordering.
|
886
994
|
#
|
@@ -910,5 +1018,36 @@ module Puma
|
|
910
1018
|
def mutate_stdout_and_stderr_to_sync_on_write(enabled=true)
|
911
1019
|
@options[:mutate_stdout_and_stderr_to_sync_on_write] = enabled
|
912
1020
|
end
|
1021
|
+
|
1022
|
+
private
|
1023
|
+
|
1024
|
+
# To avoid adding cert_pem and key_pem as URI params, we store them on the
|
1025
|
+
# options[:store] from where Puma binder knows how to find and extract them.
|
1026
|
+
def add_pem_values_to_options_store(opts)
|
1027
|
+
return if defined?(JRUBY_VERSION)
|
1028
|
+
|
1029
|
+
@options[:store] ||= []
|
1030
|
+
|
1031
|
+
# Store cert_pem and key_pem to options[:store] if present
|
1032
|
+
[:cert, :key].each do |v|
|
1033
|
+
opt_key = :"#{v}_pem"
|
1034
|
+
if opts[opt_key]
|
1035
|
+
index = @options[:store].length
|
1036
|
+
@options[:store] << opts[opt_key]
|
1037
|
+
opts[v] = "store:#{index}"
|
1038
|
+
end
|
1039
|
+
end
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
def process_hook(options_key, key, block, meth)
|
1043
|
+
@options[options_key] ||= []
|
1044
|
+
if ON_WORKER_KEY.include? key.class
|
1045
|
+
@options[options_key] << [block, key.to_sym]
|
1046
|
+
elsif key.nil?
|
1047
|
+
@options[options_key] << block
|
1048
|
+
else
|
1049
|
+
raise "'#{method}' key must be String or Symbol"
|
1050
|
+
end
|
1051
|
+
end
|
913
1052
|
end
|
914
1053
|
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,18 @@ 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
|
106
|
+
end
|
107
|
+
end
|
108
|
+
rescue ThreadError
|
102
109
|
end
|
110
|
+
private :internal_write
|
103
111
|
end
|
104
112
|
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,36 @@
|
|
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?
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset
|
16
|
+
truncate 0
|
17
|
+
rewind
|
7
18
|
end
|
8
19
|
|
9
|
-
|
20
|
+
def to_s
|
21
|
+
rewind
|
22
|
+
read
|
23
|
+
end
|
24
|
+
|
25
|
+
alias_method :clear, :reset
|
26
|
+
|
27
|
+
# before Ruby 2.5, `write` would only take one argument
|
28
|
+
if RUBY_VERSION >= '2.5' && RUBY_ENGINE != 'truffleruby'
|
29
|
+
alias_method :append, :write
|
30
|
+
else
|
31
|
+
def append(*strs)
|
32
|
+
strs.each { |str| write str }
|
33
|
+
end
|
34
|
+
end
|
10
35
|
end
|
11
36
|
end
|
data/lib/puma/jruby_restart.rb
CHANGED
@@ -17,7 +17,7 @@ module Puma
|
|
17
17
|
# be particularly full-featured or fast. It just has to handle the few places
|
18
18
|
# where Puma relies on JSON serialization internally.
|
19
19
|
|
20
|
-
module
|
20
|
+
module JSONSerialization
|
21
21
|
QUOTE = /"/
|
22
22
|
BACKSLASH = /\\/
|
23
23
|
CONTROL_CHAR_TO_ESCAPE = /[\x00-\x1F]/ # As required by ECMA-404
|