puma 6.1.1 → 6.3.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +76 -1
- data/LICENSE +0 -0
- data/README.md +39 -4
- data/bin/puma-wild +0 -0
- data/docs/architecture.md +0 -0
- data/docs/compile_options.md +0 -0
- data/docs/deployment.md +0 -0
- 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 +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 +0 -0
- data/docs/testing_benchmarks_local_files.md +0 -0
- data/docs/testing_test_rackup_ci_files.md +0 -0
- data/ext/puma_http11/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +0 -0
- data/ext/puma_http11/http11_parser.c +0 -0
- 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 +0 -0
- data/ext/puma_http11/mini_ssl.c +30 -2
- 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 +0 -0
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +0 -0
- data/ext/puma_http11/puma_http11.c +0 -0
- data/lib/puma/app/status.rb +1 -1
- data/lib/puma/binder.rb +8 -6
- data/lib/puma/cli.rb +1 -1
- data/lib/puma/client.rb +18 -10
- data/lib/puma/cluster/worker.rb +0 -0
- data/lib/puma/cluster/worker_handle.rb +0 -0
- data/lib/puma/cluster.rb +0 -0
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +1 -0
- data/lib/puma/const.rb +58 -9
- data/lib/puma/control_cli.rb +0 -0
- data/lib/puma/detect.rb +0 -0
- data/lib/puma/dsl.rb +78 -2
- data/lib/puma/error_logger.rb +2 -1
- 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_serialization.rb +0 -0
- data/lib/puma/launcher/bundle_pruner.rb +0 -0
- data/lib/puma/launcher.rb +2 -0
- data/lib/puma/log_writer.rb +10 -4
- data/lib/puma/minissl/context_builder.rb +1 -0
- data/lib/puma/minissl.rb +17 -0
- data/lib/puma/plugin/systemd.rb +0 -0
- data/lib/puma/plugin/tmp_restart.rb +0 -0
- data/lib/puma/plugin.rb +0 -0
- data/lib/puma/rack/builder.rb +2 -2
- data/lib/puma/rack/urlmap.rb +0 -0
- data/lib/puma/rack_default.rb +1 -1
- data/lib/puma/reactor.rb +16 -7
- data/lib/puma/request.rb +64 -48
- data/lib/puma/runner.rb +0 -0
- data/lib/puma/sd_notify.rb +0 -0
- data/lib/puma/server.rb +16 -4
- data/lib/puma/single.rb +0 -0
- data/lib/puma/state_file.rb +0 -0
- data/lib/puma/thread_pool.rb +7 -3
- data/lib/puma/util.rb +0 -0
- data/lib/puma.rb +0 -0
- data/lib/rack/handler/puma.rb +12 -6
- data/tools/Dockerfile +0 -0
- data/tools/trickletest.rb +0 -0
- metadata +2 -2
data/lib/puma/request.rb
CHANGED
@@ -77,7 +77,9 @@ module Puma
|
|
77
77
|
if @early_hints
|
78
78
|
env[EARLY_HINTS] = lambda { |headers|
|
79
79
|
begin
|
80
|
-
|
80
|
+
unless (str = str_early_hints headers).empty?
|
81
|
+
fast_write_str socket, "HTTP/1.1 103 Early Hints\r\n#{str}\r\n"
|
82
|
+
end
|
81
83
|
rescue ConnectionError => e
|
82
84
|
@log_writer.debug_error e
|
83
85
|
# noop, if we lost the socket we just won't send the early hints
|
@@ -93,7 +95,7 @@ module Puma
|
|
93
95
|
env[RACK_AFTER_REPLY] ||= []
|
94
96
|
|
95
97
|
begin
|
96
|
-
if
|
98
|
+
if @supported_http_methods == :any || @supported_http_methods.key?(env[REQUEST_METHOD])
|
97
99
|
status, headers, app_body = @thread_pool.with_force_shutdown do
|
98
100
|
@app.call(env)
|
99
101
|
end
|
@@ -106,6 +108,7 @@ module Puma
|
|
106
108
|
# is called
|
107
109
|
res_body = app_body
|
108
110
|
|
111
|
+
# full hijack, app called env['rack.hijack']
|
109
112
|
return :async if client.hijacked
|
110
113
|
|
111
114
|
status = status.to_i
|
@@ -169,54 +172,55 @@ module Puma
|
|
169
172
|
resp_info = str_headers(env, status, headers, res_body, io_buffer, force_keep_alive)
|
170
173
|
|
171
174
|
close_body = false
|
175
|
+
response_hijack = nil
|
176
|
+
content_length = resp_info[:content_length]
|
177
|
+
keep_alive = resp_info[:keep_alive]
|
172
178
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
if
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
179
|
+
if res_body.respond_to?(:each) && !resp_info[:response_hijack]
|
180
|
+
# below converts app_body into body, dependent on app_body's characteristics, and
|
181
|
+
# content_length will be set if it can be determined
|
182
|
+
if !content_length && !resp_info[:transfer_encoding] && status != 204
|
183
|
+
if res_body.respond_to?(:to_ary) && (array_body = res_body.to_ary) &&
|
184
|
+
array_body.is_a?(Array)
|
185
|
+
body = array_body.compact
|
186
|
+
content_length = body.sum(&:bytesize)
|
187
|
+
elsif res_body.is_a?(File) && res_body.respond_to?(:size)
|
188
|
+
body = res_body
|
189
|
+
content_length = body.size
|
190
|
+
elsif res_body.respond_to?(:to_path) && File.readable?(fn = res_body.to_path)
|
191
|
+
body = File.open fn, 'rb'
|
192
|
+
content_length = body.size
|
193
|
+
close_body = true
|
194
|
+
else
|
195
|
+
body = res_body
|
196
|
+
end
|
197
|
+
elsif !res_body.is_a?(::File) && res_body.respond_to?(:to_path) &&
|
183
198
|
File.readable?(fn = res_body.to_path)
|
184
199
|
body = File.open fn, 'rb'
|
185
|
-
|
200
|
+
content_length = body.size
|
186
201
|
close_body = true
|
202
|
+
elsif !res_body.is_a?(::File) && res_body.respond_to?(:filename) &&
|
203
|
+
res_body.respond_to?(:bytesize) && File.readable?(fn = res_body.filename)
|
204
|
+
# Sprockets::Asset
|
205
|
+
content_length = res_body.bytesize unless content_length
|
206
|
+
if (body_str = res_body.to_hash[:source])
|
207
|
+
body = [body_str]
|
208
|
+
else # avoid each and use a File object
|
209
|
+
body = File.open fn, 'rb'
|
210
|
+
close_body = true
|
211
|
+
end
|
187
212
|
else
|
188
213
|
body = res_body
|
189
214
|
end
|
190
|
-
elsif !res_body.is_a?(::File) && res_body.respond_to?(:to_path) && res_body.respond_to?(:each) &&
|
191
|
-
File.readable?(fn = res_body.to_path)
|
192
|
-
body = File.open fn, 'rb'
|
193
|
-
resp_info[:content_length] = body.size
|
194
|
-
close_body = true
|
195
|
-
elsif !res_body.is_a?(::File) && res_body.respond_to?(:filename) && res_body.respond_to?(:each) &&
|
196
|
-
res_body.respond_to?(:bytesize) && File.readable?(fn = res_body.filename)
|
197
|
-
# Sprockets::Asset
|
198
|
-
resp_info[:content_length] = res_body.bytesize unless resp_info[:content_length]
|
199
|
-
if res_body.to_hash[:source] # use each to return @source
|
200
|
-
body = res_body
|
201
|
-
else # avoid each and use a File object
|
202
|
-
body = File.open fn, 'rb'
|
203
|
-
close_body = true
|
204
|
-
end
|
205
215
|
else
|
206
|
-
|
216
|
+
# partial hijack, from Rack spec:
|
217
|
+
# Servers must ignore the body part of the response tuple when the
|
218
|
+
# rack.hijack response header is present.
|
219
|
+
response_hijack = resp_info[:response_hijack] || res_body
|
207
220
|
end
|
208
221
|
|
209
222
|
line_ending = LINE_END
|
210
223
|
|
211
|
-
content_length = resp_info[:content_length]
|
212
|
-
keep_alive = resp_info[:keep_alive]
|
213
|
-
|
214
|
-
if res_body && !res_body.respond_to?(:each)
|
215
|
-
response_hijack = res_body
|
216
|
-
else
|
217
|
-
response_hijack = resp_info[:response_hijack]
|
218
|
-
end
|
219
|
-
|
220
224
|
cork_socket socket
|
221
225
|
|
222
226
|
if resp_info[:no_body]
|
@@ -244,6 +248,8 @@ module Puma
|
|
244
248
|
|
245
249
|
io_buffer << line_ending
|
246
250
|
|
251
|
+
# partial hijack, we write headers, then hand the socket to the app via
|
252
|
+
# response_hijack.call
|
247
253
|
if response_hijack
|
248
254
|
fast_write_str socket, io_buffer.read_and_reset
|
249
255
|
uncork_socket socket
|
@@ -358,16 +364,22 @@ module Puma
|
|
358
364
|
fast_write_str(socket, io_buffer.read_and_reset) unless io_buffer.length.zero?
|
359
365
|
else
|
360
366
|
# for enum bodies
|
361
|
-
fast_write_str socket, io_buffer.read_and_reset
|
362
367
|
if chunked
|
368
|
+
empty_body = true
|
363
369
|
body.each do |part|
|
364
|
-
next if (byte_size = part.bytesize).zero?
|
365
|
-
|
366
|
-
|
367
|
-
|
370
|
+
next if part.nil? || (byte_size = part.bytesize).zero?
|
371
|
+
empty_body = false
|
372
|
+
io_buffer.append byte_size.to_s(16), LINE_END, part, LINE_END
|
373
|
+
fast_write_str socket, io_buffer.read_and_reset
|
374
|
+
end
|
375
|
+
if empty_body
|
376
|
+
io_buffer << CLOSE_CHUNKED
|
377
|
+
fast_write_str socket, io_buffer.read_and_reset
|
378
|
+
else
|
379
|
+
fast_write_str socket, CLOSE_CHUNKED
|
368
380
|
end
|
369
|
-
fast_write_str socket, CLOSE_CHUNKED
|
370
381
|
else
|
382
|
+
fast_write_str socket, io_buffer.read_and_reset
|
371
383
|
body.each do |part|
|
372
384
|
next if part.bytesize.zero?
|
373
385
|
fast_write_str socket, part
|
@@ -408,7 +420,11 @@ module Puma
|
|
408
420
|
|
409
421
|
unless env[REQUEST_PATH]
|
410
422
|
# it might be a dumbass full host request header
|
411
|
-
uri =
|
423
|
+
uri = begin
|
424
|
+
URI.parse(env[REQUEST_URI])
|
425
|
+
rescue URI::InvalidURIError
|
426
|
+
raise Puma::HttpParserError
|
427
|
+
end
|
412
428
|
env[REQUEST_PATH] = uri.path
|
413
429
|
|
414
430
|
# A nil env value will cause a LintError (and fatal errors elsewhere),
|
@@ -515,7 +531,7 @@ module Puma
|
|
515
531
|
# @version 5.0.3
|
516
532
|
#
|
517
533
|
def str_early_hints(headers)
|
518
|
-
eh_str = +"
|
534
|
+
eh_str = +""
|
519
535
|
headers.each_pair do |k, vs|
|
520
536
|
next if illegal_header_key?(k)
|
521
537
|
|
@@ -524,11 +540,11 @@ module Puma
|
|
524
540
|
next if illegal_header_value?(v)
|
525
541
|
eh_str << "#{k}: #{v}\r\n"
|
526
542
|
end
|
527
|
-
|
543
|
+
elsif !(vs.to_s.empty? || !illegal_header_value?(vs))
|
528
544
|
eh_str << "#{k}: #{vs}\r\n"
|
529
545
|
end
|
530
546
|
end
|
531
|
-
|
547
|
+
eh_str.freeze
|
532
548
|
end
|
533
549
|
private :str_early_hints
|
534
550
|
|
data/lib/puma/runner.rb
CHANGED
File without changes
|
data/lib/puma/sd_notify.rb
CHANGED
File without changes
|
data/lib/puma/server.rb
CHANGED
@@ -51,7 +51,7 @@ module Puma
|
|
51
51
|
def_delegators :@binder, :add_tcp_listener, :add_ssl_listener,
|
52
52
|
:add_unix_listener, :connected_ports
|
53
53
|
|
54
|
-
|
54
|
+
THREAD_LOCAL_KEY = :puma_server
|
55
55
|
|
56
56
|
# Create a server for the rack app +app+.
|
57
57
|
#
|
@@ -97,6 +97,18 @@ module Puma
|
|
97
97
|
@io_selector_backend = @options[:io_selector_backend]
|
98
98
|
@http_content_length_limit = @options[:http_content_length_limit]
|
99
99
|
|
100
|
+
# make this a hash, since we prefer `key?` over `include?`
|
101
|
+
@supported_http_methods =
|
102
|
+
if @options[:supported_http_methods] == :any
|
103
|
+
:any
|
104
|
+
else
|
105
|
+
if (ary = @options[:supported_http_methods])
|
106
|
+
ary
|
107
|
+
else
|
108
|
+
SUPPORTED_HTTP_METHODS
|
109
|
+
end.sort.product([nil]).to_h.freeze
|
110
|
+
end
|
111
|
+
|
100
112
|
temp = !!(@options[:environment] =~ /\A(development|test)\z/)
|
101
113
|
@leak_stack_on_error = @options[:environment] ? temp : true
|
102
114
|
|
@@ -118,7 +130,7 @@ module Puma
|
|
118
130
|
class << self
|
119
131
|
# @!attribute [r] current
|
120
132
|
def current
|
121
|
-
Thread.current[
|
133
|
+
Thread.current[THREAD_LOCAL_KEY]
|
122
134
|
end
|
123
135
|
|
124
136
|
# :nodoc:
|
@@ -404,7 +416,7 @@ module Puma
|
|
404
416
|
# Return true if one or more requests were processed.
|
405
417
|
def process_client(client)
|
406
418
|
# Advertise this server into the thread
|
407
|
-
Thread.current[
|
419
|
+
Thread.current[THREAD_LOCAL_KEY] = self
|
408
420
|
|
409
421
|
clean_thread_locals = @options[:clean_thread_locals]
|
410
422
|
close_socket = true
|
@@ -566,7 +578,7 @@ module Puma
|
|
566
578
|
|
567
579
|
def notify_safely(message)
|
568
580
|
@notify << message
|
569
|
-
rescue IOError, NoMethodError, Errno::EPIPE
|
581
|
+
rescue IOError, NoMethodError, Errno::EPIPE, Errno::EBADF
|
570
582
|
# The server, in another thread, is shutting down
|
571
583
|
Puma::Util.purge_interrupt_queue
|
572
584
|
rescue RuntimeError => e
|
data/lib/puma/single.rb
CHANGED
File without changes
|
data/lib/puma/state_file.rb
CHANGED
File without changes
|
data/lib/puma/thread_pool.rb
CHANGED
@@ -44,6 +44,10 @@ module Puma
|
|
44
44
|
@name = name
|
45
45
|
@min = Integer(options[:min_threads])
|
46
46
|
@max = Integer(options[:max_threads])
|
47
|
+
# Not an 'exposed' option, options[:pool_shutdown_grace_time] is used in CI
|
48
|
+
# to shorten @shutdown_grace_time from SHUTDOWN_GRACE_TIME. Parallel CI
|
49
|
+
# makes stubbing constants difficult.
|
50
|
+
@shutdown_grace_time = Float(options[:pool_shutdown_grace_time] || SHUTDOWN_GRACE_TIME)
|
47
51
|
@block = block
|
48
52
|
@out_of_band = options[:out_of_band]
|
49
53
|
@clean_thread_locals = options[:clean_thread_locals]
|
@@ -344,8 +348,8 @@ module Puma
|
|
344
348
|
|
345
349
|
# Tell all threads in the pool to exit and wait for them to finish.
|
346
350
|
# Wait +timeout+ seconds then raise +ForceShutdown+ in remaining threads.
|
347
|
-
# Next, wait an extra +
|
348
|
-
# Finally, wait
|
351
|
+
# Next, wait an extra +@shutdown_grace_time+ seconds then force-kill remaining
|
352
|
+
# threads. Finally, wait 1 second for remaining threads to exit.
|
349
353
|
#
|
350
354
|
def shutdown(timeout=-1)
|
351
355
|
threads = with_mutex do
|
@@ -382,7 +386,7 @@ module Puma
|
|
382
386
|
t.raise ForceShutdown if t[:with_force_shutdown]
|
383
387
|
end
|
384
388
|
end
|
385
|
-
join.call(
|
389
|
+
join.call(@shutdown_grace_time)
|
386
390
|
|
387
391
|
# If threads are _still_ running, forcefully kill them and wait to finish.
|
388
392
|
threads.each(&:kill)
|
data/lib/puma/util.rb
CHANGED
File without changes
|
data/lib/puma.rb
CHANGED
File without changes
|
data/lib/rack/handler/puma.rb
CHANGED
@@ -27,10 +27,16 @@ module Puma
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
|
30
|
+
@events = options[:events] || ::Puma::Events.new
|
31
|
+
|
32
|
+
conf = ::Puma::Configuration.new(options, default_options.merge({events: @events})) do |user_config, file_config, default_config|
|
31
33
|
if options.delete(:Verbose)
|
32
|
-
|
33
|
-
|
34
|
+
begin
|
35
|
+
require 'rack/commonlogger' # Rack 1.x
|
36
|
+
rescue LoadError
|
37
|
+
require 'rack/common_logger' # Rack 2 and later
|
38
|
+
end
|
39
|
+
app = ::Rack::CommonLogger.new(app, STDOUT)
|
34
40
|
end
|
35
41
|
|
36
42
|
if options[:environment]
|
@@ -59,11 +65,11 @@ module Puma
|
|
59
65
|
end
|
60
66
|
|
61
67
|
def run(app, **options)
|
62
|
-
conf
|
68
|
+
conf = self.config(app, options)
|
63
69
|
|
64
70
|
log_writer = options.delete(:Silent) ? ::Puma::LogWriter.strings : ::Puma::LogWriter.stdio
|
65
71
|
|
66
|
-
launcher = ::Puma::Launcher.new(conf, :log_writer => log_writer)
|
72
|
+
launcher = ::Puma::Launcher.new(conf, :log_writer => log_writer, events: @events)
|
67
73
|
|
68
74
|
yield launcher if block_given?
|
69
75
|
begin
|
@@ -121,7 +127,7 @@ if Object.const_defined? :Rackup
|
|
121
127
|
end
|
122
128
|
end
|
123
129
|
else
|
124
|
-
do_register = Object.const_defined?(:Rack) && Rack
|
130
|
+
do_register = Object.const_defined?(:Rack) && Rack.release < '3'
|
125
131
|
module Rack
|
126
132
|
module Handler
|
127
133
|
module Puma
|
data/tools/Dockerfile
CHANGED
File without changes
|
data/tools/trickletest.rb
CHANGED
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Phoenix
|
@@ -145,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
145
|
- !ruby/object:Gem::Version
|
146
146
|
version: '0'
|
147
147
|
requirements: []
|
148
|
-
rubygems_version: 3.
|
148
|
+
rubygems_version: 3.4.12
|
149
149
|
signing_key:
|
150
150
|
specification_version: 4
|
151
151
|
summary: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server for
|