puma 5.0.4 → 5.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +322 -48
- data/LICENSE +0 -0
- data/README.md +95 -24
- data/bin/puma-wild +0 -0
- data/docs/architecture.md +57 -20
- data/docs/compile_options.md +21 -0
- data/docs/deployment.md +53 -67
- data/docs/fork_worker.md +2 -0
- 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 +1 -1
- data/docs/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +66 -0
- data/docs/nginx.md +0 -0
- data/docs/plugins.md +15 -15
- data/docs/rails_dev_mode.md +28 -0
- data/docs/restart.md +7 -7
- data/docs/signals.md +11 -10
- data/docs/stats.md +142 -0
- data/docs/systemd.md +85 -66
- data/ext/puma_http11/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +42 -6
- data/ext/puma_http11/http11_parser.c +68 -57
- data/ext/puma_http11/http11_parser.h +1 -1
- data/ext/puma_http11/http11_parser.java.rl +1 -1
- data/ext/puma_http11/http11_parser.rl +1 -1
- data/ext/puma_http11/http11_parser_common.rl +1 -1
- data/ext/puma_http11/mini_ssl.c +226 -88
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +0 -0
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +51 -51
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +28 -43
- data/ext/puma_http11/puma_http11.c +9 -3
- data/lib/puma/app/status.rb +4 -7
- data/lib/puma/binder.rb +138 -49
- data/lib/puma/cli.rb +18 -4
- data/lib/puma/client.rb +113 -31
- data/lib/puma/cluster/worker.rb +22 -19
- data/lib/puma/cluster/worker_handle.rb +13 -2
- data/lib/puma/cluster.rb +75 -33
- data/lib/puma/commonlogger.rb +0 -0
- data/lib/puma/configuration.rb +21 -2
- data/lib/puma/const.rb +17 -8
- data/lib/puma/control_cli.rb +76 -71
- data/lib/puma/detect.rb +19 -9
- data/lib/puma/dsl.rb +225 -31
- data/lib/puma/error_logger.rb +12 -5
- data/lib/puma/events.rb +18 -3
- data/lib/puma/io_buffer.rb +0 -0
- data/lib/puma/jruby_restart.rb +0 -0
- data/lib/puma/json_serialization.rb +96 -0
- data/lib/puma/launcher.rb +56 -7
- data/lib/puma/minissl/context_builder.rb +14 -6
- data/lib/puma/minissl.rb +72 -40
- data/lib/puma/null_io.rb +12 -0
- data/lib/puma/plugin/tmp_restart.rb +0 -0
- data/lib/puma/plugin.rb +2 -2
- data/lib/puma/queue_close.rb +7 -7
- data/lib/puma/rack/builder.rb +1 -1
- data/lib/puma/rack/urlmap.rb +0 -0
- data/lib/puma/rack_default.rb +0 -0
- data/lib/puma/reactor.rb +19 -12
- data/lib/puma/request.rb +55 -21
- data/lib/puma/runner.rb +39 -13
- data/lib/puma/server.rb +78 -142
- data/lib/puma/single.rb +0 -0
- data/lib/puma/state_file.rb +45 -9
- data/lib/puma/systemd.rb +46 -0
- data/lib/puma/thread_pool.rb +11 -8
- data/lib/puma/util.rb +8 -1
- data/lib/puma.rb +36 -10
- data/lib/rack/handler/puma.rb +1 -0
- data/tools/Dockerfile +1 -1
- data/tools/trickletest.rb +0 -0
- metadata +15 -9
data/lib/puma/dsl.rb
CHANGED
@@ -34,6 +34,42 @@ module Puma
|
|
34
34
|
class DSL
|
35
35
|
include ConfigDefault
|
36
36
|
|
37
|
+
# convenience method so logic can be used in CI
|
38
|
+
# @see ssl_bind
|
39
|
+
#
|
40
|
+
def self.ssl_bind_str(host, port, opts)
|
41
|
+
verify = opts.fetch(:verify_mode, 'none').to_s
|
42
|
+
|
43
|
+
tls_str =
|
44
|
+
if opts[:no_tlsv1_1] then '&no_tlsv1_1=true'
|
45
|
+
elsif opts[:no_tlsv1] then '&no_tlsv1=true'
|
46
|
+
else ''
|
47
|
+
end
|
48
|
+
|
49
|
+
ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
|
50
|
+
|
51
|
+
backlog_str = opts[:backlog] ? "&backlog=#{Integer(opts[:backlog])}" : ''
|
52
|
+
|
53
|
+
if defined?(JRUBY_VERSION)
|
54
|
+
ssl_cipher_list = opts[:ssl_cipher_list] ?
|
55
|
+
"&ssl_cipher_list=#{opts[:ssl_cipher_list]}" : nil
|
56
|
+
|
57
|
+
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
58
|
+
|
59
|
+
"ssl://#{host}:#{port}?#{keystore_additions}#{ssl_cipher_list}" \
|
60
|
+
"&verify_mode=#{verify}#{tls_str}#{ca_additions}#{backlog_str}"
|
61
|
+
else
|
62
|
+
ssl_cipher_filter = opts[:ssl_cipher_filter] ?
|
63
|
+
"&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" : nil
|
64
|
+
|
65
|
+
v_flags = (ary = opts[:verification_flags]) ?
|
66
|
+
"&verification_flags=#{Array(ary).join ','}" : nil
|
67
|
+
|
68
|
+
"ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}" \
|
69
|
+
"#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}#{backlog_str}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
37
73
|
def initialize(options, config)
|
38
74
|
@config = config
|
39
75
|
@options = options
|
@@ -157,7 +193,7 @@ module Puma
|
|
157
193
|
end
|
158
194
|
|
159
195
|
# Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
|
160
|
-
# accepted protocols. Multiple urls can be bound to, calling
|
196
|
+
# accepted protocols. Multiple urls can be bound to, calling +bind+ does
|
161
197
|
# not overwrite previous bindings.
|
162
198
|
#
|
163
199
|
# The default is "tcp://0.0.0.0:9292".
|
@@ -167,7 +203,7 @@ module Puma
|
|
167
203
|
# * Set the socket backlog depth with +backlog+, default is 1024.
|
168
204
|
# * Set up an SSL certificate with +key+ & +cert+.
|
169
205
|
# * Set whether to optimize for low latency instead of throughput with
|
170
|
-
# +low_latency+, default is to optimize for low latency. This is done
|
206
|
+
# +low_latency+, default is to not optimize for low latency. This is done
|
171
207
|
# via +Socket::TCP_NODELAY+.
|
172
208
|
# * Set socket permissions with +umask+.
|
173
209
|
#
|
@@ -191,13 +227,39 @@ module Puma
|
|
191
227
|
@options[:binds] = []
|
192
228
|
end
|
193
229
|
|
230
|
+
# Bind to (systemd) activated sockets, regardless of configured binds.
|
231
|
+
#
|
232
|
+
# Systemd can present sockets as file descriptors that are already opened.
|
233
|
+
# By default Puma will use these but only if it was explicitly told to bind
|
234
|
+
# to the socket. If not, it will close the activated sockets. This means
|
235
|
+
# all configuration is duplicated.
|
236
|
+
#
|
237
|
+
# Binds can contain additional configuration, but only SSL config is really
|
238
|
+
# relevant since the unix and TCP socket options are ignored.
|
239
|
+
#
|
240
|
+
# This means there is a lot of duplicated configuration for no additional
|
241
|
+
# value in most setups. This method tells the launcher to bind to all
|
242
|
+
# activated sockets, regardless of existing bind.
|
243
|
+
#
|
244
|
+
# To clear configured binds, the value only can be passed. This will clear
|
245
|
+
# out any binds that may have been configured.
|
246
|
+
#
|
247
|
+
# @example Use any systemd activated sockets as well as configured binds
|
248
|
+
# bind_to_activated_sockets
|
249
|
+
#
|
250
|
+
# @example Only bind to systemd activated sockets, ignoring other binds
|
251
|
+
# bind_to_activated_sockets 'only'
|
252
|
+
def bind_to_activated_sockets(bind=true)
|
253
|
+
@options[:bind_to_activated_sockets] = bind
|
254
|
+
end
|
255
|
+
|
194
256
|
# Define the TCP port to bind to. Use +bind+ for more advanced options.
|
195
257
|
#
|
196
258
|
# @example
|
197
259
|
# port 9292
|
198
260
|
def port(port, host=nil)
|
199
261
|
host ||= default_host
|
200
|
-
bind
|
262
|
+
bind URI::Generic.build(scheme: 'tcp', host: host, port: Integer(port)).to_s
|
201
263
|
end
|
202
264
|
|
203
265
|
# Define how long persistent connections can be idle before Puma closes them.
|
@@ -321,6 +383,13 @@ module Puma
|
|
321
383
|
@options[:rackup] ||= path.to_s
|
322
384
|
end
|
323
385
|
|
386
|
+
# Allows setting `env['rack.url_scheme']`.
|
387
|
+
# Only necessary if X-Forwarded-Proto is not being set by your proxy
|
388
|
+
# Normal values are 'http' or 'https'.
|
389
|
+
def rack_url_scheme(scheme=nil)
|
390
|
+
@options[:rack_url_scheme] = scheme
|
391
|
+
end
|
392
|
+
|
324
393
|
def early_hints(answer=true)
|
325
394
|
@options[:early_hints] = answer
|
326
395
|
end
|
@@ -345,7 +414,10 @@ module Puma
|
|
345
414
|
# Configure +min+ to be the minimum number of threads to use to answer
|
346
415
|
# requests and +max+ the maximum.
|
347
416
|
#
|
348
|
-
# The default is
|
417
|
+
# The default is the environment variables +PUMA_MIN_THREADS+ / +PUMA_MAX_THREADS+
|
418
|
+
# (or +MIN_THREADS+ / +MAX_THREADS+ if the +PUMA_+ variables aren't set).
|
419
|
+
#
|
420
|
+
# If these environment variables aren't set, the default is "0, 5" in MRI or "0, 16" for other interpreters.
|
349
421
|
#
|
350
422
|
# @example
|
351
423
|
# threads 0, 16
|
@@ -366,8 +438,15 @@ module Puma
|
|
366
438
|
@options[:max_threads] = max
|
367
439
|
end
|
368
440
|
|
369
|
-
# Instead of
|
370
|
-
#
|
441
|
+
# Instead of using +bind+ and manually constructing a URI like:
|
442
|
+
#
|
443
|
+
# bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'
|
444
|
+
#
|
445
|
+
# you can use the this method.
|
446
|
+
#
|
447
|
+
# When binding on localhost you don't need to specify +cert+ and +key+,
|
448
|
+
# Puma will assume you are using the +localhost+ gem and try to load the
|
449
|
+
# appropriate files.
|
371
450
|
#
|
372
451
|
# @example
|
373
452
|
# ssl_bind '127.0.0.1', '9292', {
|
@@ -375,29 +454,28 @@ module Puma
|
|
375
454
|
# key: path_to_key,
|
376
455
|
# ssl_cipher_filter: cipher_filter, # optional
|
377
456
|
# verify_mode: verify_mode, # default 'none'
|
457
|
+
# verification_flags: flags, # optional, not supported by JRuby
|
378
458
|
# }
|
379
|
-
#
|
459
|
+
#
|
460
|
+
# @example Using self-signed certificate with the +localhost+ gem:
|
461
|
+
# ssl_bind '127.0.0.1', '9292'
|
462
|
+
#
|
463
|
+
# @example Alternatively, you can provide +cert_pem+ and +key_pem+:
|
464
|
+
# ssl_bind '127.0.0.1', '9292', {
|
465
|
+
# cert_pem: File.read(path_to_cert),
|
466
|
+
# key_pem: File.read(path_to_key),
|
467
|
+
# }
|
468
|
+
#
|
469
|
+
# @example For JRuby, two keys are required: +keystore+ & +keystore_pass+
|
380
470
|
# ssl_bind '127.0.0.1', '9292', {
|
381
|
-
# cert: path_to_cert,
|
382
|
-
# key: path_to_key,
|
383
|
-
# ssl_cipher_filter: cipher_filter, # optional
|
384
|
-
# verify_mode: verify_mode, # default 'none'
|
385
471
|
# keystore: path_to_keystore,
|
386
|
-
# keystore_pass: password
|
472
|
+
# keystore_pass: password,
|
473
|
+
# ssl_cipher_list: cipher_list, # optional
|
474
|
+
# verify_mode: verify_mode # default 'none'
|
387
475
|
# }
|
388
|
-
def ssl_bind(host, port, opts)
|
389
|
-
|
390
|
-
|
391
|
-
no_tlsv1_1 = opts.fetch(:no_tlsv1_1, 'false')
|
392
|
-
ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
|
393
|
-
|
394
|
-
if defined?(JRUBY_VERSION)
|
395
|
-
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
396
|
-
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}"
|
397
|
-
else
|
398
|
-
ssl_cipher_filter = "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" if opts[:ssl_cipher_filter]
|
399
|
-
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}"
|
400
|
-
end
|
476
|
+
def ssl_bind(host, port, opts = {})
|
477
|
+
add_pem_values_to_options_store(opts)
|
478
|
+
bind self.class.ssl_bind_str(host, port, opts)
|
401
479
|
end
|
402
480
|
|
403
481
|
# Use +path+ as the file to store the server info state. This is
|
@@ -422,7 +500,8 @@ module Puma
|
|
422
500
|
# How many worker processes to run. Typically this is set to
|
423
501
|
# the number of available cores.
|
424
502
|
#
|
425
|
-
# The default is
|
503
|
+
# The default is the value of the environment variable +WEB_CONCURRENCY+ if
|
504
|
+
# set, otherwise 0.
|
426
505
|
#
|
427
506
|
# @note Cluster mode only.
|
428
507
|
# @see Puma::Cluster
|
@@ -430,6 +509,24 @@ module Puma
|
|
430
509
|
@options[:workers] = count.to_i
|
431
510
|
end
|
432
511
|
|
512
|
+
# Disable warning message when running in cluster mode with a single worker.
|
513
|
+
#
|
514
|
+
# Cluster mode has some overhead of running an additional 'control' process
|
515
|
+
# in order to manage the cluster. If only running a single worker it is
|
516
|
+
# likely not worth paying that overhead vs running in single mode with
|
517
|
+
# additional threads instead.
|
518
|
+
#
|
519
|
+
# There are some scenarios where running cluster mode with a single worker
|
520
|
+
# may still be warranted and valid under certain deployment scenarios, see
|
521
|
+
# https://github.com/puma/puma/issues/2534
|
522
|
+
#
|
523
|
+
# Moving from workers = 1 to workers = 0 will save 10-30% of memory use.
|
524
|
+
#
|
525
|
+
# @note Cluster mode only.
|
526
|
+
def silence_single_worker_warning
|
527
|
+
@options[:silence_single_worker_warning] = true
|
528
|
+
end
|
529
|
+
|
433
530
|
# Code to run immediately before master process
|
434
531
|
# forks workers (once on boot). These hooks can block if necessary
|
435
532
|
# to wait for background operations unknown to Puma to finish before
|
@@ -508,7 +605,7 @@ module Puma
|
|
508
605
|
# end
|
509
606
|
def after_worker_fork(&block)
|
510
607
|
@options[:after_worker_fork] ||= []
|
511
|
-
@options[:after_worker_fork]
|
608
|
+
@options[:after_worker_fork] << block
|
512
609
|
end
|
513
610
|
|
514
611
|
alias_method :after_worker_boot, :after_worker_fork
|
@@ -561,7 +658,7 @@ module Puma
|
|
561
658
|
end
|
562
659
|
|
563
660
|
# Preload the application before starting the workers; this conflicts with
|
564
|
-
# phased restart feature.
|
661
|
+
# phased restart feature. On by default if your app uses more than 1 worker.
|
565
662
|
#
|
566
663
|
# @note Cluster mode only.
|
567
664
|
# @example
|
@@ -650,6 +747,19 @@ module Puma
|
|
650
747
|
@options[:tag] = string.to_s
|
651
748
|
end
|
652
749
|
|
750
|
+
# Change the default interval for checking workers.
|
751
|
+
#
|
752
|
+
# The default value is 5 seconds.
|
753
|
+
#
|
754
|
+
# @note Cluster mode only.
|
755
|
+
# @example
|
756
|
+
# worker_check_interval 5
|
757
|
+
# @see Puma::Cluster#check_workers
|
758
|
+
#
|
759
|
+
def worker_check_interval(interval)
|
760
|
+
@options[:worker_check_interval] = Integer(interval)
|
761
|
+
end
|
762
|
+
|
653
763
|
# Verifies that all workers have checked in to the master process within
|
654
764
|
# the given timeout. If not the worker process will be restarted. This is
|
655
765
|
# not a request timeout, it is to protect against a hung or dead process.
|
@@ -664,7 +774,7 @@ module Puma
|
|
664
774
|
#
|
665
775
|
def worker_timeout(timeout)
|
666
776
|
timeout = Integer(timeout)
|
667
|
-
min =
|
777
|
+
min = @options.fetch(:worker_check_interval, Puma::ConfigDefault::DefaultWorkerCheckInterval)
|
668
778
|
|
669
779
|
if timeout <= min
|
670
780
|
raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
|
@@ -696,6 +806,30 @@ module Puma
|
|
696
806
|
@options[:worker_shutdown_timeout] = Integer(timeout)
|
697
807
|
end
|
698
808
|
|
809
|
+
# Set the strategy for worker culling.
|
810
|
+
#
|
811
|
+
# There are two possible values:
|
812
|
+
#
|
813
|
+
# 1. **:youngest** - the youngest workers (i.e. the workers that were
|
814
|
+
# the most recently started) will be culled.
|
815
|
+
# 2. **:oldest** - the oldest workers (i.e. the workers that were started
|
816
|
+
# the longest time ago) will be culled.
|
817
|
+
#
|
818
|
+
# @note Cluster mode only.
|
819
|
+
# @example
|
820
|
+
# worker_culling_strategy :oldest
|
821
|
+
# @see Puma::Cluster#cull_workers
|
822
|
+
#
|
823
|
+
def worker_culling_strategy(strategy)
|
824
|
+
stategy = strategy.to_sym
|
825
|
+
|
826
|
+
if ![:youngest, :oldest].include?(strategy)
|
827
|
+
raise "Invalid value for worker_culling_strategy - #{stategy}"
|
828
|
+
end
|
829
|
+
|
830
|
+
@options[:worker_culling_strategy] = strategy
|
831
|
+
end
|
832
|
+
|
699
833
|
# When set to true (the default), workers accept all requests
|
700
834
|
# and queue them before passing them to the handlers.
|
701
835
|
# When set to false, each worker process accepts exactly as
|
@@ -741,7 +875,7 @@ module Puma
|
|
741
875
|
# a kernel syscall is required which for very fast rack handlers
|
742
876
|
# slows down the handling significantly.
|
743
877
|
#
|
744
|
-
# There are
|
878
|
+
# There are 5 possible values:
|
745
879
|
#
|
746
880
|
# 1. **:socket** (the default) - read the peername from the socket using the
|
747
881
|
# syscall. This is the normal behavior.
|
@@ -751,7 +885,10 @@ module Puma
|
|
751
885
|
# `set_remote_address header: "X-Real-IP"`.
|
752
886
|
# Only the first word (as separated by spaces or comma) is used, allowing
|
753
887
|
# headers such as X-Forwarded-For to be used as well.
|
754
|
-
# 4.
|
888
|
+
# 4. **proxy_protocol: :v1**- set the remote address to the value read from the
|
889
|
+
# HAproxy PROXY protocol, version 1. If the request does not have the PROXY
|
890
|
+
# protocol attached to it, will fall back to :socket
|
891
|
+
# 5. **\<Any string\>** - this allows you to hardcode remote address to any value
|
755
892
|
# you wish. Because Puma never uses this field anyway, it's format is
|
756
893
|
# entirely in your hands.
|
757
894
|
#
|
@@ -769,6 +906,13 @@ module Puma
|
|
769
906
|
if hdr = val[:header]
|
770
907
|
@options[:remote_address] = :header
|
771
908
|
@options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
|
909
|
+
elsif protocol_version = val[:proxy_protocol]
|
910
|
+
@options[:remote_address] = :proxy_protocol
|
911
|
+
protocol_version = protocol_version.downcase.to_sym
|
912
|
+
unless [:v1].include?(protocol_version)
|
913
|
+
raise "Invalid value for proxy_protocol - #{protocol_version.inspect}"
|
914
|
+
end
|
915
|
+
@options[:remote_address_proxy_protocol] = protocol_version
|
772
916
|
else
|
773
917
|
raise "Invalid value for set_remote_address - #{val.inspect}"
|
774
918
|
end
|
@@ -810,5 +954,55 @@ module Puma
|
|
810
954
|
def nakayoshi_fork(enabled=true)
|
811
955
|
@options[:nakayoshi_fork] = enabled
|
812
956
|
end
|
957
|
+
|
958
|
+
# The number of requests to attempt inline before sending a client back to
|
959
|
+
# the reactor to be subject to normal ordering.
|
960
|
+
#
|
961
|
+
def max_fast_inline(num_of_requests)
|
962
|
+
@options[:max_fast_inline] = Float(num_of_requests)
|
963
|
+
end
|
964
|
+
|
965
|
+
# Specify the backend for the IO selector.
|
966
|
+
#
|
967
|
+
# Provided values will be passed directly to +NIO::Selector.new+, with the
|
968
|
+
# exception of +:auto+ which will let nio4r choose the backend.
|
969
|
+
#
|
970
|
+
# Check the documentation of +NIO::Selector.backends+ for the list of valid
|
971
|
+
# options. Note that the available options on your system will depend on the
|
972
|
+
# operating system. If you want to use the pure Ruby backend (not
|
973
|
+
# recommended due to its comparatively low performance), set environment
|
974
|
+
# variable +NIO4R_PURE+ to +true+.
|
975
|
+
#
|
976
|
+
# The default is +:auto+.
|
977
|
+
#
|
978
|
+
# @see https://github.com/socketry/nio4r/blob/master/lib/nio/selector.rb
|
979
|
+
#
|
980
|
+
def io_selector_backend(backend)
|
981
|
+
@options[:io_selector_backend] = backend.to_sym
|
982
|
+
end
|
983
|
+
|
984
|
+
def mutate_stdout_and_stderr_to_sync_on_write(enabled=true)
|
985
|
+
@options[:mutate_stdout_and_stderr_to_sync_on_write] = enabled
|
986
|
+
end
|
987
|
+
|
988
|
+
private
|
989
|
+
|
990
|
+
# To avoid adding cert_pem and key_pem as URI params, we store them on the
|
991
|
+
# options[:store] from where Puma binder knows how to find and extract them.
|
992
|
+
def add_pem_values_to_options_store(opts)
|
993
|
+
return if defined?(JRUBY_VERSION)
|
994
|
+
|
995
|
+
@options[:store] ||= []
|
996
|
+
|
997
|
+
# Store cert_pem and key_pem to options[:store] if present
|
998
|
+
[:cert, :key].each do |v|
|
999
|
+
opt_key = :"#{v}_pem"
|
1000
|
+
if opts[opt_key]
|
1001
|
+
index = @options[:store].length
|
1002
|
+
@options[:store] << opts[opt_key]
|
1003
|
+
opts[v] = "store:#{index}"
|
1004
|
+
end
|
1005
|
+
end
|
1006
|
+
end
|
813
1007
|
end
|
814
1008
|
end
|
data/lib/puma/error_logger.rb
CHANGED
@@ -15,7 +15,6 @@ module Puma
|
|
15
15
|
|
16
16
|
def initialize(ioerr)
|
17
17
|
@ioerr = ioerr
|
18
|
-
@ioerr.sync = true
|
19
18
|
|
20
19
|
@debug = ENV.key? 'PUMA_DEBUG'
|
21
20
|
end
|
@@ -24,7 +23,7 @@ module Puma
|
|
24
23
|
new $stderr
|
25
24
|
end
|
26
25
|
|
27
|
-
# Print
|
26
|
+
# Print occurred error details.
|
28
27
|
# +options+ hash with additional options:
|
29
28
|
# - +error+ is an exception object
|
30
29
|
# - +req+ the http request
|
@@ -32,10 +31,10 @@ module Puma
|
|
32
31
|
# and before all remaining info.
|
33
32
|
#
|
34
33
|
def info(options={})
|
35
|
-
|
34
|
+
log title(options)
|
36
35
|
end
|
37
36
|
|
38
|
-
# Print
|
37
|
+
# Print occurred error details only if
|
39
38
|
# environment variable PUMA_DEBUG is defined.
|
40
39
|
# +options+ hash with additional options:
|
41
40
|
# - +error+ is an exception object
|
@@ -54,7 +53,7 @@ module Puma
|
|
54
53
|
string_block << request_dump(req) if request_parsed?(req)
|
55
54
|
string_block << error.backtrace if error
|
56
55
|
|
57
|
-
|
56
|
+
log string_block.join("\n")
|
58
57
|
end
|
59
58
|
|
60
59
|
def title(options={})
|
@@ -93,5 +92,13 @@ module Puma
|
|
93
92
|
def request_parsed?(req)
|
94
93
|
req && req.env[REQUEST_METHOD]
|
95
94
|
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def log(str)
|
99
|
+
ioerr.puts str
|
100
|
+
|
101
|
+
ioerr.flush unless ioerr.sync
|
102
|
+
end
|
96
103
|
end
|
97
104
|
end
|
data/lib/puma/events.rb
CHANGED
@@ -30,9 +30,6 @@ module Puma
|
|
30
30
|
@stdout = stdout
|
31
31
|
@stderr = stderr
|
32
32
|
|
33
|
-
@stdout.sync = true
|
34
|
-
@stderr.sync = true
|
35
|
-
|
36
33
|
@debug = ENV.key? 'PUMA_DEBUG'
|
37
34
|
@error_logger = ErrorLogger.new(@stderr)
|
38
35
|
|
@@ -66,6 +63,8 @@ module Puma
|
|
66
63
|
#
|
67
64
|
def log(str)
|
68
65
|
@stdout.puts format(str) if @stdout.respond_to? :puts
|
66
|
+
|
67
|
+
@stdout.flush unless @stdout.sync
|
69
68
|
rescue Errno::EPIPE
|
70
69
|
end
|
71
70
|
|
@@ -137,10 +136,26 @@ module Puma
|
|
137
136
|
register(:on_booted, &block)
|
138
137
|
end
|
139
138
|
|
139
|
+
def on_restart(&block)
|
140
|
+
register(:on_restart, &block)
|
141
|
+
end
|
142
|
+
|
143
|
+
def on_stopped(&block)
|
144
|
+
register(:on_stopped, &block)
|
145
|
+
end
|
146
|
+
|
140
147
|
def fire_on_booted!
|
141
148
|
fire(:on_booted)
|
142
149
|
end
|
143
150
|
|
151
|
+
def fire_on_restart!
|
152
|
+
fire(:on_restart)
|
153
|
+
end
|
154
|
+
|
155
|
+
def fire_on_stopped!
|
156
|
+
fire(:on_stopped)
|
157
|
+
end
|
158
|
+
|
144
159
|
DEFAULT = new(STDOUT, STDERR)
|
145
160
|
|
146
161
|
# Returns an Events object which writes its status to 2 StringIO
|
data/lib/puma/io_buffer.rb
CHANGED
File without changes
|
data/lib/puma/jruby_restart.rb
CHANGED
File without changes
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
module Puma
|
5
|
+
|
6
|
+
# Puma deliberately avoids the use of the json gem and instead performs JSON
|
7
|
+
# serialization without any external dependencies. In a puma cluster, loading
|
8
|
+
# any gem into the puma master process means that operators cannot use a
|
9
|
+
# phased restart to upgrade their application if the new version of that
|
10
|
+
# application uses a different version of that gem. The json gem in
|
11
|
+
# particular is additionally problematic because it leverages native
|
12
|
+
# extensions. If the puma master process relies on a gem with native
|
13
|
+
# extensions and operators remove gems from disk related to old releases,
|
14
|
+
# subsequent phased restarts can fail.
|
15
|
+
#
|
16
|
+
# The implementation of JSON serialization in this module is not designed to
|
17
|
+
# be particularly full-featured or fast. It just has to handle the few places
|
18
|
+
# where Puma relies on JSON serialization internally.
|
19
|
+
|
20
|
+
module JSONSerialization
|
21
|
+
QUOTE = /"/
|
22
|
+
BACKSLASH = /\\/
|
23
|
+
CONTROL_CHAR_TO_ESCAPE = /[\x00-\x1F]/ # As required by ECMA-404
|
24
|
+
CHAR_TO_ESCAPE = Regexp.union QUOTE, BACKSLASH, CONTROL_CHAR_TO_ESCAPE
|
25
|
+
|
26
|
+
class SerializationError < StandardError; end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def generate(value)
|
30
|
+
StringIO.open do |io|
|
31
|
+
serialize_value io, value
|
32
|
+
io.string
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def serialize_value(output, value)
|
39
|
+
case value
|
40
|
+
when Hash
|
41
|
+
output << '{'
|
42
|
+
value.each_with_index do |(k, v), index|
|
43
|
+
output << ',' if index != 0
|
44
|
+
serialize_object_key output, k
|
45
|
+
output << ':'
|
46
|
+
serialize_value output, v
|
47
|
+
end
|
48
|
+
output << '}'
|
49
|
+
when Array
|
50
|
+
output << '['
|
51
|
+
value.each_with_index do |member, index|
|
52
|
+
output << ',' if index != 0
|
53
|
+
serialize_value output, member
|
54
|
+
end
|
55
|
+
output << ']'
|
56
|
+
when Integer, Float
|
57
|
+
output << value.to_s
|
58
|
+
when String
|
59
|
+
serialize_string output, value
|
60
|
+
when true
|
61
|
+
output << 'true'
|
62
|
+
when false
|
63
|
+
output << 'false'
|
64
|
+
when nil
|
65
|
+
output << 'null'
|
66
|
+
else
|
67
|
+
raise SerializationError, "Unexpected value of type #{value.class}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def serialize_string(output, value)
|
72
|
+
output << '"'
|
73
|
+
output << value.gsub(CHAR_TO_ESCAPE) do |character|
|
74
|
+
case character
|
75
|
+
when BACKSLASH
|
76
|
+
'\\\\'
|
77
|
+
when QUOTE
|
78
|
+
'\\"'
|
79
|
+
when CONTROL_CHAR_TO_ESCAPE
|
80
|
+
'\u%.4X' % character.ord
|
81
|
+
end
|
82
|
+
end
|
83
|
+
output << '"'
|
84
|
+
end
|
85
|
+
|
86
|
+
def serialize_object_key(output, value)
|
87
|
+
case value
|
88
|
+
when Symbol, String
|
89
|
+
serialize_string output, value.to_s
|
90
|
+
else
|
91
|
+
raise SerializationError, "Could not serialize object of type #{value.class} as object key"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|