puma 5.3.2 → 5.6.4
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 +148 -8
- data/LICENSE +0 -0
- data/README.md +47 -6
- data/bin/puma-wild +0 -0
- data/docs/architecture.md +49 -16
- data/docs/compile_options.md +4 -2
- data/docs/deployment.md +53 -67
- data/docs/fork_worker.md +0 -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 +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/ext/puma_http11/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +28 -5
- data/ext/puma_http11/http11_parser.c +23 -10
- data/ext/puma_http11/http11_parser.h +0 -0
- data/ext/puma_http11/http11_parser.java.rl +0 -0
- data/ext/puma_http11/http11_parser.rl +0 -0
- data/ext/puma_http11/http11_parser_common.rl +1 -1
- data/ext/puma_http11/mini_ssl.c +69 -9
- 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 +49 -47
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +28 -43
- data/ext/puma_http11/puma_http11.c +1 -1
- data/lib/puma/app/status.rb +4 -4
- data/lib/puma/binder.rb +50 -5
- data/lib/puma/cli.rb +14 -4
- data/lib/puma/client.rb +104 -20
- data/lib/puma/cluster/worker.rb +8 -18
- data/lib/puma/cluster/worker_handle.rb +4 -0
- data/lib/puma/cluster.rb +30 -24
- data/lib/puma/commonlogger.rb +0 -0
- data/lib/puma/configuration.rb +4 -1
- data/lib/puma/const.rb +9 -8
- data/lib/puma/control_cli.rb +1 -1
- data/lib/puma/detect.rb +8 -2
- data/lib/puma/dsl.rb +105 -11
- data/lib/puma/error_logger.rb +0 -0
- data/lib/puma/events.rb +0 -0
- data/lib/puma/io_buffer.rb +0 -0
- data/lib/puma/jruby_restart.rb +0 -0
- data/lib/puma/{json.rb → json_serialization.rb} +1 -1
- data/lib/puma/launcher.rb +4 -1
- data/lib/puma/minissl/context_builder.rb +8 -6
- data/lib/puma/minissl.rb +24 -23
- data/lib/puma/null_io.rb +0 -0
- data/lib/puma/plugin/tmp_restart.rb +0 -0
- data/lib/puma/plugin.rb +2 -2
- data/lib/puma/queue_close.rb +0 -0
- 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 +0 -0
- data/lib/puma/request.rb +14 -9
- data/lib/puma/runner.rb +22 -8
- data/lib/puma/server.rb +35 -29
- data/lib/puma/single.rb +0 -0
- data/lib/puma/state_file.rb +41 -7
- data/lib/puma/systemd.rb +0 -0
- data/lib/puma/thread_pool.rb +7 -5
- data/lib/puma/util.rb +8 -1
- data/lib/puma.rb +2 -2
- data/lib/rack/handler/puma.rb +0 -0
- data/tools/Dockerfile +1 -1
- data/tools/trickletest.rb +0 -0
- metadata +7 -7
data/lib/puma/server.rb
CHANGED
@@ -14,6 +14,7 @@ require 'puma/io_buffer'
|
|
14
14
|
require 'puma/request'
|
15
15
|
|
16
16
|
require 'socket'
|
17
|
+
require 'io/wait'
|
17
18
|
require 'forwardable'
|
18
19
|
|
19
20
|
module Puma
|
@@ -145,7 +146,7 @@ module Puma
|
|
145
146
|
begin
|
146
147
|
skt.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_CORK, 1) if skt.kind_of? TCPSocket
|
147
148
|
rescue IOError, SystemCallError
|
148
|
-
|
149
|
+
Puma::Util.purge_interrupt_queue
|
149
150
|
end
|
150
151
|
end
|
151
152
|
|
@@ -154,7 +155,7 @@ module Puma
|
|
154
155
|
begin
|
155
156
|
skt.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_CORK, 0) if skt.kind_of? TCPSocket
|
156
157
|
rescue IOError, SystemCallError
|
157
|
-
|
158
|
+
Puma::Util.purge_interrupt_queue
|
158
159
|
end
|
159
160
|
end
|
160
161
|
else
|
@@ -175,7 +176,7 @@ module Puma
|
|
175
176
|
begin
|
176
177
|
tcp_info = skt.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_INFO)
|
177
178
|
rescue IOError, SystemCallError
|
178
|
-
|
179
|
+
Puma::Util.purge_interrupt_queue
|
179
180
|
@precheck_closing = false
|
180
181
|
false
|
181
182
|
else
|
@@ -219,7 +220,7 @@ module Puma
|
|
219
220
|
# up in the background to handle requests. Otherwise requests
|
220
221
|
# are handled synchronously.
|
221
222
|
#
|
222
|
-
def run(background=true, thread_name: '
|
223
|
+
def run(background=true, thread_name: 'srv')
|
223
224
|
BasicSocket.do_not_reverse_lookup = true
|
224
225
|
|
225
226
|
@events.fire :state, :booting
|
@@ -227,6 +228,7 @@ module Puma
|
|
227
228
|
@status = :run
|
228
229
|
|
229
230
|
@thread_pool = ThreadPool.new(
|
231
|
+
thread_name,
|
230
232
|
@min_threads,
|
231
233
|
@max_threads,
|
232
234
|
::Puma::IOBuffer,
|
@@ -313,14 +315,15 @@ module Puma
|
|
313
315
|
queue_requests = @queue_requests
|
314
316
|
drain = @options[:drain_on_shutdown] ? 0 : nil
|
315
317
|
|
316
|
-
|
317
|
-
remote_addr_header = nil
|
318
|
-
|
319
|
-
case @options[:remote_address]
|
318
|
+
addr_send_name, addr_value = case @options[:remote_address]
|
320
319
|
when :value
|
321
|
-
|
320
|
+
[:peerip=, @options[:remote_address_value]]
|
322
321
|
when :header
|
323
|
-
remote_addr_header
|
322
|
+
[:remote_addr_header=, @options[:remote_address_header]]
|
323
|
+
when :proxy_protocol
|
324
|
+
[:expect_proxy_proto=, @options[:remote_address_proxy_protocol]]
|
325
|
+
else
|
326
|
+
[nil, nil]
|
324
327
|
end
|
325
328
|
|
326
329
|
while @status == :run || (drain && shutting_down?)
|
@@ -340,17 +343,16 @@ module Puma
|
|
340
343
|
next
|
341
344
|
end
|
342
345
|
drain += 1 if shutting_down?
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
elsif remote_addr_header
|
348
|
-
client.remote_addr_header = remote_addr_header
|
349
|
-
end
|
350
|
-
pool << client
|
346
|
+
pool << Client.new(io, @binder.env(sock)).tap { |c|
|
347
|
+
c.listener = sock
|
348
|
+
c.send(addr_send_name, addr_value) if addr_value
|
349
|
+
}
|
351
350
|
end
|
352
351
|
end
|
353
|
-
rescue
|
352
|
+
rescue IOError, Errno::EBADF
|
353
|
+
# In the case that any of the sockets are unexpectedly close.
|
354
|
+
raise
|
355
|
+
rescue StandardError => e
|
354
356
|
@events.unknown_error e, nil, "Listen loop"
|
355
357
|
end
|
356
358
|
end
|
@@ -366,13 +368,14 @@ module Puma
|
|
366
368
|
rescue Exception => e
|
367
369
|
@events.unknown_error e, nil, "Exception handling servers"
|
368
370
|
ensure
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
371
|
+
# RuntimeError is Ruby 2.2 issue, can't modify frozen IOError
|
372
|
+
# Errno::EBADF is infrequently raised
|
373
|
+
[@check, @notify].each do |io|
|
374
|
+
begin
|
375
|
+
io.close unless io.closed?
|
376
|
+
rescue Errno::EBADF, RuntimeError
|
377
|
+
end
|
374
378
|
end
|
375
|
-
@notify.close
|
376
379
|
@notify = nil
|
377
380
|
@check = nil
|
378
381
|
end
|
@@ -396,7 +399,7 @@ module Puma
|
|
396
399
|
return true
|
397
400
|
end
|
398
401
|
|
399
|
-
|
402
|
+
false
|
400
403
|
end
|
401
404
|
|
402
405
|
# Given a connection on +client+, handle the incoming requests,
|
@@ -482,7 +485,7 @@ module Puma
|
|
482
485
|
begin
|
483
486
|
client.close if close_socket
|
484
487
|
rescue IOError, SystemCallError
|
485
|
-
|
488
|
+
Puma::Util.purge_interrupt_queue
|
486
489
|
# Already closed
|
487
490
|
rescue StandardError => e
|
488
491
|
@events.unknown_error e, nil, "Client"
|
@@ -512,6 +515,9 @@ module Puma
|
|
512
515
|
when HttpParserError
|
513
516
|
client.write_error(400)
|
514
517
|
@events.parse_error e, client
|
518
|
+
when HttpParserError501
|
519
|
+
client.write_error(501)
|
520
|
+
@events.parse_error e, client
|
515
521
|
else
|
516
522
|
client.write_error(500)
|
517
523
|
@events.unknown_error e, nil, "Read"
|
@@ -574,11 +580,11 @@ module Puma
|
|
574
580
|
@notify << message
|
575
581
|
rescue IOError, NoMethodError, Errno::EPIPE
|
576
582
|
# The server, in another thread, is shutting down
|
577
|
-
|
583
|
+
Puma::Util.purge_interrupt_queue
|
578
584
|
rescue RuntimeError => e
|
579
585
|
# Temporary workaround for https://bugs.ruby-lang.org/issues/13239
|
580
586
|
if e.message.include?('IOError')
|
581
|
-
|
587
|
+
Puma::Util.purge_interrupt_queue
|
582
588
|
else
|
583
589
|
raise e
|
584
590
|
end
|
data/lib/puma/single.rb
CHANGED
File without changes
|
data/lib/puma/state_file.rb
CHANGED
@@ -1,15 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'yaml'
|
4
|
-
|
5
3
|
module Puma
|
4
|
+
|
5
|
+
# Puma::Launcher uses StateFile to write a yaml file for use with Puma::ControlCLI.
|
6
|
+
#
|
7
|
+
# In previous versions of Puma, YAML was used to read/write the state file.
|
8
|
+
# Since Puma is similar to Bundler/RubyGems in that it may load before one's app
|
9
|
+
# does, minimizing the dependencies that may be shared with the app is desired.
|
10
|
+
#
|
11
|
+
# At present, it only works with numeric and string values. It is still a valid
|
12
|
+
# yaml file, and the CI tests parse it with Psych.
|
13
|
+
#
|
6
14
|
class StateFile
|
15
|
+
|
16
|
+
ALLOWED_FIELDS = %w!control_url control_auth_token pid running_from!
|
17
|
+
|
18
|
+
# @deprecated 6.0.0
|
19
|
+
FIELDS = ALLOWED_FIELDS
|
20
|
+
|
7
21
|
def initialize
|
8
22
|
@options = {}
|
9
23
|
end
|
10
24
|
|
11
25
|
def save(path, permission = nil)
|
12
|
-
contents =
|
26
|
+
contents = "---\n".dup
|
27
|
+
@options.each do |k,v|
|
28
|
+
next unless ALLOWED_FIELDS.include? k
|
29
|
+
case v
|
30
|
+
when Numeric
|
31
|
+
contents << "#{k}: #{v}\n"
|
32
|
+
when String
|
33
|
+
next if v.strip.empty?
|
34
|
+
contents << (k == 'running_from' || v.to_s.include?(' ') ?
|
35
|
+
"#{k}: \"#{v}\"\n" : "#{k}: #{v}\n")
|
36
|
+
end
|
37
|
+
end
|
13
38
|
if permission
|
14
39
|
File.write path, contents, mode: 'wb:UTF-8'
|
15
40
|
else
|
@@ -18,12 +43,21 @@ module Puma
|
|
18
43
|
end
|
19
44
|
|
20
45
|
def load(path)
|
21
|
-
|
46
|
+
File.read(path).lines.each do |line|
|
47
|
+
next if line.start_with? '#'
|
48
|
+
k,v = line.split ':', 2
|
49
|
+
next unless v && ALLOWED_FIELDS.include?(k)
|
50
|
+
v = v.strip
|
51
|
+
@options[k] =
|
52
|
+
case v
|
53
|
+
when /\A\d+\z/ then v.to_i
|
54
|
+
when /\A\d+\.\d+\z/ then v.to_f
|
55
|
+
else v.gsub(/\A"|"\z/, '')
|
56
|
+
end
|
57
|
+
end
|
22
58
|
end
|
23
59
|
|
24
|
-
|
25
|
-
|
26
|
-
FIELDS.each do |f|
|
60
|
+
ALLOWED_FIELDS.each do |f|
|
27
61
|
define_method f do
|
28
62
|
@options[f]
|
29
63
|
end
|
data/lib/puma/systemd.rb
CHANGED
File without changes
|
data/lib/puma/thread_pool.rb
CHANGED
@@ -29,7 +29,7 @@ module Puma
|
|
29
29
|
# The block passed is the work that will be performed in each
|
30
30
|
# thread.
|
31
31
|
#
|
32
|
-
def initialize(min, max, *extra, &block)
|
32
|
+
def initialize(name, min, max, *extra, &block)
|
33
33
|
@not_empty = ConditionVariable.new
|
34
34
|
@not_full = ConditionVariable.new
|
35
35
|
@mutex = Mutex.new
|
@@ -39,6 +39,7 @@ module Puma
|
|
39
39
|
@spawned = 0
|
40
40
|
@waiting = 0
|
41
41
|
|
42
|
+
@name = name
|
42
43
|
@min = Integer(min)
|
43
44
|
@max = Integer(max)
|
44
45
|
@block = block
|
@@ -71,7 +72,7 @@ module Puma
|
|
71
72
|
attr_accessor :out_of_band_hook # @version 5.0.0
|
72
73
|
|
73
74
|
def self.clean_thread_locals
|
74
|
-
Thread.current.keys.each do |key| # rubocop: disable
|
75
|
+
Thread.current.keys.each do |key| # rubocop: disable Style/HashEachMethods
|
75
76
|
Thread.current[key] = nil unless key == :__recursive_key__
|
76
77
|
end
|
77
78
|
end
|
@@ -101,7 +102,7 @@ module Puma
|
|
101
102
|
@spawned += 1
|
102
103
|
|
103
104
|
th = Thread.new(@spawned) do |spawned|
|
104
|
-
Puma.set_thread_name '
|
105
|
+
Puma.set_thread_name '%s tp %03i' % [@name, spawned]
|
105
106
|
todo = @todo
|
106
107
|
block = @block
|
107
108
|
mutex = @mutex
|
@@ -119,6 +120,7 @@ module Puma
|
|
119
120
|
@trim_requested -= 1
|
120
121
|
@spawned -= 1
|
121
122
|
@workers.delete th
|
123
|
+
not_full.signal
|
122
124
|
Thread.exit
|
123
125
|
end
|
124
126
|
|
@@ -318,12 +320,12 @@ module Puma
|
|
318
320
|
end
|
319
321
|
|
320
322
|
def auto_trim!(timeout=30)
|
321
|
-
@auto_trim = Automaton.new(self, timeout, "threadpool trimmer", :trim)
|
323
|
+
@auto_trim = Automaton.new(self, timeout, "#{@name} threadpool trimmer", :trim)
|
322
324
|
@auto_trim.start!
|
323
325
|
end
|
324
326
|
|
325
327
|
def auto_reap!(timeout=5)
|
326
|
-
@reaper = Automaton.new(self, timeout, "threadpool reaper", :reap)
|
328
|
+
@reaper = Automaton.new(self, timeout, "#{@name} threadpool reaper", :reap)
|
327
329
|
@reaper.start!
|
328
330
|
end
|
329
331
|
|
data/lib/puma/util.rb
CHANGED
@@ -10,6 +10,13 @@ module Puma
|
|
10
10
|
IO.pipe
|
11
11
|
end
|
12
12
|
|
13
|
+
# An instance method on Thread has been provided to address https://bugs.ruby-lang.org/issues/13632,
|
14
|
+
# which currently effects some older versions of Ruby: 2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1
|
15
|
+
# Additional context: https://github.com/puma/puma/pull/1345
|
16
|
+
def purge_interrupt_queue
|
17
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
18
|
+
end
|
19
|
+
|
13
20
|
# Unescapes a URI escaped string with +encoding+. +encoding+ will be the
|
14
21
|
# target encoding of the string returned, and it defaults to UTF-8
|
15
22
|
if defined?(::Encoding)
|
@@ -61,7 +68,7 @@ module Puma
|
|
61
68
|
end
|
62
69
|
end
|
63
70
|
|
64
|
-
|
71
|
+
params
|
65
72
|
end
|
66
73
|
|
67
74
|
# A case-insensitive Hash that preserves the original case of a
|
data/lib/puma.rb
CHANGED
@@ -12,7 +12,7 @@ require 'thread'
|
|
12
12
|
|
13
13
|
require 'puma/puma_http11'
|
14
14
|
require 'puma/detect'
|
15
|
-
require 'puma/
|
15
|
+
require 'puma/json_serialization'
|
16
16
|
|
17
17
|
module Puma
|
18
18
|
autoload :Const, 'puma/const'
|
@@ -60,7 +60,7 @@ module Puma
|
|
60
60
|
|
61
61
|
# @!attribute [rw] stats_object
|
62
62
|
def self.stats
|
63
|
-
Puma::
|
63
|
+
Puma::JSONSerialization.generate @get_stats.stats
|
64
64
|
end
|
65
65
|
|
66
66
|
# @!attribute [r] stats_hash
|
data/lib/rack/handler/puma.rb
CHANGED
File without changes
|
data/tools/Dockerfile
CHANGED
data/tools/trickletest.rb
CHANGED
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Phoenix
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 1980-01-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nio4r
|
@@ -24,9 +24,9 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.0'
|
27
|
-
description: Puma is a simple, fast, threaded, and highly
|
27
|
+
description: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server
|
28
28
|
for Ruby/Rack applications. Puma is intended for use in both development and production
|
29
|
-
environments. It's great for highly
|
29
|
+
environments. It's great for highly parallel Ruby implementations such as Rubinius
|
30
30
|
and JRuby as well as as providing process worker support to support CRuby well.
|
31
31
|
email:
|
32
32
|
- evan@phx.io
|
@@ -94,7 +94,7 @@ files:
|
|
94
94
|
- lib/puma/events.rb
|
95
95
|
- lib/puma/io_buffer.rb
|
96
96
|
- lib/puma/jruby_restart.rb
|
97
|
-
- lib/puma/
|
97
|
+
- lib/puma/json_serialization.rb
|
98
98
|
- lib/puma/launcher.rb
|
99
99
|
- lib/puma/minissl.rb
|
100
100
|
- lib/puma/minissl/context_builder.rb
|
@@ -140,9 +140,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
140
|
- !ruby/object:Gem::Version
|
141
141
|
version: '0'
|
142
142
|
requirements: []
|
143
|
-
rubygems_version: 3.2.
|
143
|
+
rubygems_version: 3.2.26
|
144
144
|
signing_key:
|
145
145
|
specification_version: 4
|
146
|
-
summary: Puma is a simple, fast, threaded, and highly
|
146
|
+
summary: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server for
|
147
147
|
Ruby/Rack applications
|
148
148
|
test_files: []
|