puma 6.6.1 → 7.2.0
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.
- checksums.yaml +4 -4
- data/History.md +224 -4
- data/README.md +34 -34
- data/docs/deployment.md +58 -23
- data/docs/fork_worker.md +5 -5
- data/docs/jungle/README.md +1 -1
- data/docs/kubernetes.md +11 -16
- data/docs/plugins.md +2 -2
- data/docs/restart.md +2 -2
- data/docs/signals.md +19 -19
- data/docs/stats.md +4 -3
- data/docs/systemd.md +3 -3
- data/ext/puma_http11/extconf.rb +2 -17
- data/ext/puma_http11/mini_ssl.c +18 -8
- data/ext/puma_http11/org/jruby/puma/Http11.java +9 -1
- data/ext/puma_http11/puma_http11.c +122 -118
- data/lib/puma/app/status.rb +10 -2
- data/lib/puma/binder.rb +10 -8
- data/lib/puma/cli.rb +3 -5
- data/lib/puma/client.rb +52 -56
- data/lib/puma/cluster/worker.rb +17 -17
- data/lib/puma/cluster/worker_handle.rb +38 -7
- data/lib/puma/cluster.rb +23 -23
- data/lib/puma/cluster_accept_loop_delay.rb +91 -0
- data/lib/puma/commonlogger.rb +3 -3
- data/lib/puma/configuration.rb +104 -51
- data/lib/puma/const.rb +9 -10
- data/lib/puma/control_cli.rb +6 -2
- data/lib/puma/detect.rb +2 -0
- data/lib/puma/dsl.rb +149 -91
- data/lib/puma/error_logger.rb +3 -1
- data/lib/puma/events.rb +25 -10
- data/lib/puma/io_buffer.rb +8 -4
- data/lib/puma/launcher/bundle_pruner.rb +1 -1
- data/lib/puma/launcher.rb +54 -49
- data/lib/puma/minissl.rb +0 -1
- data/lib/puma/plugin/systemd.rb +3 -3
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/reactor.rb +19 -13
- data/lib/puma/request.rb +42 -31
- data/lib/puma/runner.rb +9 -18
- data/lib/puma/server.rb +114 -64
- data/lib/puma/single.rb +6 -3
- data/lib/puma/state_file.rb +3 -2
- data/lib/puma/thread_pool.rb +47 -82
- data/lib/puma/util.rb +0 -7
- data/lib/puma.rb +10 -0
- data/lib/rack/handler/puma.rb +2 -2
- data/tools/Dockerfile +13 -5
- metadata +6 -5
- data/ext/puma_http11/ext_help.h +0 -15
data/lib/puma/launcher.rb
CHANGED
|
@@ -22,12 +22,15 @@ module Puma
|
|
|
22
22
|
#
|
|
23
23
|
# +conf+ A Puma::Configuration object indicating how to run the server.
|
|
24
24
|
#
|
|
25
|
-
# +launcher_args+ A Hash that
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
25
|
+
# +launcher_args+ A Hash that has a few optional keys.
|
|
26
|
+
# - +:log_writer+:: Expected to hold an object similar to `Puma::LogWriter.stdio`.
|
|
27
|
+
# This object will be responsible for broadcasting Puma's internal state
|
|
28
|
+
# to a logging destination.
|
|
29
|
+
# - +:events+:: Expected to hold an object similar to `Puma::Events`.
|
|
30
|
+
# - +:argv+:: Expected to be an array of strings.
|
|
31
|
+
# - +:env+:: Expected to hold a hash of environment variables.
|
|
32
|
+
#
|
|
33
|
+
# These arguments are re-used when restarting the puma server.
|
|
31
34
|
#
|
|
32
35
|
# Examples:
|
|
33
36
|
#
|
|
@@ -39,27 +42,44 @@ module Puma
|
|
|
39
42
|
# end
|
|
40
43
|
# Puma::Launcher.new(conf, log_writer: Puma::LogWriter.stdio).run
|
|
41
44
|
def initialize(conf, launcher_args={})
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
@
|
|
45
|
-
|
|
45
|
+
## Minimal initialization before potential early restart (e.g. from bundle pruning)
|
|
46
|
+
|
|
47
|
+
@config = conf
|
|
48
|
+
# Advertise the CLI Configuration before config files are loaded
|
|
49
|
+
Puma.cli_config = @config if defined?(Puma.cli_config)
|
|
50
|
+
@config.clamp
|
|
51
|
+
|
|
52
|
+
@options = @config.options
|
|
53
|
+
|
|
54
|
+
@log_writer = launcher_args[:log_writer] || LogWriter::DEFAULT
|
|
55
|
+
@log_writer.formatter = LogWriter::PidFormatter.new if clustered?
|
|
56
|
+
@log_writer.formatter = @options[:log_formatter] if @options[:log_formatter]
|
|
57
|
+
@log_writer.custom_logger = @options[:custom_logger] if @options[:custom_logger]
|
|
58
|
+
@options[:log_writer] = @log_writer
|
|
59
|
+
@options[:logger] = @log_writer if clustered?
|
|
60
|
+
|
|
61
|
+
@events = launcher_args[:events] || Events.new
|
|
62
|
+
|
|
63
|
+
@argv = launcher_args[:argv] || []
|
|
46
64
|
@original_argv = @argv.dup
|
|
47
|
-
@config = conf
|
|
48
65
|
|
|
49
|
-
|
|
66
|
+
## End minimal initialization
|
|
50
67
|
|
|
51
|
-
|
|
68
|
+
generate_restart_data
|
|
69
|
+
Dir.chdir(@restart_dir)
|
|
52
70
|
|
|
53
|
-
|
|
54
|
-
|
|
71
|
+
prune_bundler!
|
|
72
|
+
|
|
73
|
+
env = launcher_args.delete(:env) || ENV
|
|
55
74
|
|
|
56
|
-
|
|
75
|
+
# Log after prune_bundler! to avoid duplicate logging if a restart occurs
|
|
76
|
+
log_config if env['PUMA_LOG_CONFIG']
|
|
57
77
|
|
|
58
|
-
@binder
|
|
59
|
-
@binder.create_inherited_fds(
|
|
60
|
-
@binder.create_activated_fds(
|
|
78
|
+
@binder = Binder.new(@log_writer, @options)
|
|
79
|
+
@binder.create_inherited_fds(env).each { |k| env.delete k }
|
|
80
|
+
@binder.create_activated_fds(env).each { |k| env.delete k }
|
|
61
81
|
|
|
62
|
-
@environment =
|
|
82
|
+
@environment = @config.environment
|
|
63
83
|
|
|
64
84
|
# Load the systemd integration if we detect systemd's NOTIFY_SOCKET.
|
|
65
85
|
# Skip this on JRuby though, because it is incompatible with the systemd
|
|
@@ -68,37 +88,21 @@ module Puma
|
|
|
68
88
|
@config.plugins.create('systemd')
|
|
69
89
|
end
|
|
70
90
|
|
|
71
|
-
if @
|
|
72
|
-
@
|
|
73
|
-
@
|
|
74
|
-
@
|
|
91
|
+
if @options[:bind_to_activated_sockets]
|
|
92
|
+
@options[:binds] = @binder.synthesize_binds_from_activated_fs(
|
|
93
|
+
@options[:binds],
|
|
94
|
+
@options[:bind_to_activated_sockets] == 'only'
|
|
75
95
|
)
|
|
76
96
|
end
|
|
77
97
|
|
|
78
|
-
@options = @config.options
|
|
79
|
-
@config.clamp
|
|
80
|
-
|
|
81
|
-
@log_writer.formatter = LogWriter::PidFormatter.new if clustered?
|
|
82
|
-
@log_writer.formatter = options[:log_formatter] if @options[:log_formatter]
|
|
83
|
-
|
|
84
|
-
@log_writer.custom_logger = options[:custom_logger] if @options[:custom_logger]
|
|
85
|
-
|
|
86
|
-
generate_restart_data
|
|
87
|
-
|
|
88
98
|
if clustered? && !Puma.forkable?
|
|
89
99
|
unsupported "worker mode not supported on #{RUBY_ENGINE} on this platform"
|
|
90
100
|
end
|
|
91
101
|
|
|
92
|
-
Dir.chdir(@restart_dir)
|
|
93
|
-
|
|
94
|
-
prune_bundler!
|
|
95
|
-
|
|
96
102
|
@environment = @options[:environment] if @options[:environment]
|
|
97
103
|
set_rack_environment
|
|
98
104
|
|
|
99
105
|
if clustered?
|
|
100
|
-
@options[:logger] = @log_writer
|
|
101
|
-
|
|
102
106
|
@runner = Cluster.new(self)
|
|
103
107
|
else
|
|
104
108
|
@runner = Single.new(self)
|
|
@@ -106,8 +110,6 @@ module Puma
|
|
|
106
110
|
Puma.stats_object = @runner
|
|
107
111
|
|
|
108
112
|
@status = :run
|
|
109
|
-
|
|
110
|
-
log_config if env['PUMA_LOG_CONFIG']
|
|
111
113
|
end
|
|
112
114
|
|
|
113
115
|
attr_reader :binder, :log_writer, :events, :config, :options, :restart_dir
|
|
@@ -140,7 +142,10 @@ module Puma
|
|
|
140
142
|
# Delete the configured pidfile
|
|
141
143
|
def delete_pidfile
|
|
142
144
|
path = @options[:pidfile]
|
|
143
|
-
|
|
145
|
+
begin
|
|
146
|
+
File.unlink(path) if path
|
|
147
|
+
rescue Errno::ENOENT
|
|
148
|
+
end
|
|
144
149
|
end
|
|
145
150
|
|
|
146
151
|
# Begin async shutdown of the server
|
|
@@ -277,7 +282,7 @@ module Puma
|
|
|
277
282
|
end
|
|
278
283
|
|
|
279
284
|
def do_graceful_stop
|
|
280
|
-
@events.
|
|
285
|
+
@events.fire_after_stopped!
|
|
281
286
|
@runner.stop_blocked
|
|
282
287
|
end
|
|
283
288
|
|
|
@@ -289,8 +294,8 @@ module Puma
|
|
|
289
294
|
end
|
|
290
295
|
|
|
291
296
|
def restart!
|
|
292
|
-
@events.
|
|
293
|
-
@config.run_hooks :
|
|
297
|
+
@events.fire_before_restart!
|
|
298
|
+
@config.run_hooks :before_restart, self, @log_writer
|
|
294
299
|
|
|
295
300
|
if Puma.jruby?
|
|
296
301
|
close_binder_listeners
|
|
@@ -382,9 +387,9 @@ module Puma
|
|
|
382
387
|
# using it.
|
|
383
388
|
@restart_dir = Dir.pwd
|
|
384
389
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
390
|
+
# Use the same trick as unicorn, namely favor PWD because
|
|
391
|
+
# it will contain an unresolved symlink, useful for when
|
|
392
|
+
# the pwd is /data/releases/current.
|
|
388
393
|
elsif dir = ENV['PWD']
|
|
389
394
|
s_env = File.stat(dir)
|
|
390
395
|
s_pwd = File.stat(Dir.pwd)
|
data/lib/puma/minissl.rb
CHANGED
data/lib/puma/plugin/systemd.rb
CHANGED
|
@@ -14,9 +14,9 @@ Puma::Plugin.create do
|
|
|
14
14
|
launcher.log_writer.log "* Enabling systemd notification integration"
|
|
15
15
|
|
|
16
16
|
# hook_events
|
|
17
|
-
launcher.events.
|
|
18
|
-
launcher.events.
|
|
19
|
-
launcher.events.
|
|
17
|
+
launcher.events.after_booted { Puma::SdNotify.ready }
|
|
18
|
+
launcher.events.after_stopped { Puma::SdNotify.stopping }
|
|
19
|
+
launcher.events.before_restart { Puma::SdNotify.reloading }
|
|
20
20
|
|
|
21
21
|
# start watchdog
|
|
22
22
|
if Puma::SdNotify.watchdog?
|
data/lib/puma/rack/urlmap.rb
CHANGED
|
@@ -70,7 +70,7 @@ module Puma::Rack
|
|
|
70
70
|
return app.call(env)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
[404, {'
|
|
73
|
+
[404, {'content-type' => "text/plain", "x-cascade" => "pass"}, ["Not Found: #{path}"]]
|
|
74
74
|
|
|
75
75
|
ensure
|
|
76
76
|
env['PATH_INFO'] = path
|
data/lib/puma/reactor.rb
CHANGED
|
@@ -15,6 +15,12 @@ module Puma
|
|
|
15
15
|
#
|
|
16
16
|
# The implementation uses a Queue to synchronize adding new objects from the internal select loop.
|
|
17
17
|
class Reactor
|
|
18
|
+
|
|
19
|
+
# @!attribute [rw] reactor_max
|
|
20
|
+
# Maximum number of clients in the selector. Reset with calls to `Server.stats`.
|
|
21
|
+
attr_accessor :reactor_max
|
|
22
|
+
attr_reader :reactor_size
|
|
23
|
+
|
|
18
24
|
# Create a new Reactor to monitor IO objects added by #add.
|
|
19
25
|
# The provided block will be invoked when an IO has data available to read,
|
|
20
26
|
# its timeout elapses, or when the Reactor shuts down.
|
|
@@ -29,6 +35,8 @@ module Puma
|
|
|
29
35
|
@input = Queue.new
|
|
30
36
|
@timeouts = []
|
|
31
37
|
@block = block
|
|
38
|
+
@reactor_size = 0
|
|
39
|
+
@reactor_max = 0
|
|
32
40
|
end
|
|
33
41
|
|
|
34
42
|
# Run the internal select loop, using a background thread by default.
|
|
@@ -67,17 +75,18 @@ module Puma
|
|
|
67
75
|
private
|
|
68
76
|
|
|
69
77
|
def select_loop
|
|
70
|
-
close_selector = true
|
|
71
78
|
begin
|
|
72
79
|
until @input.closed? && @input.empty?
|
|
73
80
|
# Wakeup any registered object that receives incoming data.
|
|
74
81
|
# Block until the earliest timeout or Selector#wakeup is called.
|
|
75
82
|
timeout = (earliest = @timeouts.first) && earliest.timeout
|
|
76
|
-
@selector.select(timeout)
|
|
83
|
+
@selector.select(timeout) do |monitor|
|
|
84
|
+
wakeup!(monitor.value)
|
|
85
|
+
end
|
|
77
86
|
|
|
78
87
|
# Wakeup all objects that timed out.
|
|
79
|
-
timed_out = @timeouts.take_while {|
|
|
80
|
-
timed_out.each { |
|
|
88
|
+
timed_out = @timeouts.take_while { |client| client.timeout == 0 }
|
|
89
|
+
timed_out.each { |client| wakeup!(client) }
|
|
81
90
|
|
|
82
91
|
unless @input.empty?
|
|
83
92
|
until @input.empty?
|
|
@@ -91,23 +100,19 @@ module Puma
|
|
|
91
100
|
STDERR.puts "Error in reactor loop escaped: #{e.message} (#{e.class})"
|
|
92
101
|
STDERR.puts e.backtrace
|
|
93
102
|
|
|
94
|
-
|
|
95
|
-
# is odd. Regardless, it may continue for thousands of calls if retried.
|
|
96
|
-
# Also, when it raises, @selector.close also raises an error.
|
|
97
|
-
if NoMethodError === e
|
|
98
|
-
close_selector = false
|
|
99
|
-
else
|
|
100
|
-
retry
|
|
101
|
-
end
|
|
103
|
+
retry
|
|
102
104
|
end
|
|
105
|
+
|
|
103
106
|
# Wakeup all remaining objects on shutdown.
|
|
104
107
|
@timeouts.each(&@block)
|
|
105
|
-
@selector.close
|
|
108
|
+
@selector.close
|
|
106
109
|
end
|
|
107
110
|
|
|
108
111
|
# Start monitoring the object.
|
|
109
112
|
def register(client)
|
|
110
113
|
@selector.register(client.to_io, :r).value = client
|
|
114
|
+
@reactor_size += 1
|
|
115
|
+
@reactor_max = @reactor_size if @reactor_max < @reactor_size
|
|
111
116
|
@timeouts << client
|
|
112
117
|
rescue ArgumentError
|
|
113
118
|
# unreadable clients raise error when processed by NIO
|
|
@@ -118,6 +123,7 @@ module Puma
|
|
|
118
123
|
def wakeup!(client)
|
|
119
124
|
if @block.call client
|
|
120
125
|
@selector.deregister client.to_io
|
|
126
|
+
@reactor_size -= 1
|
|
121
127
|
@timeouts.delete client
|
|
122
128
|
end
|
|
123
129
|
end
|
data/lib/puma/request.rb
CHANGED
|
@@ -36,24 +36,27 @@ module Puma
|
|
|
36
36
|
# Takes the request contained in +client+, invokes the Rack application to construct
|
|
37
37
|
# the response and writes it back to +client.io+.
|
|
38
38
|
#
|
|
39
|
-
# It'll return +
|
|
39
|
+
# It'll return +:close+ when the connection is closed, this doesn't mean
|
|
40
40
|
# that the response wasn't successful.
|
|
41
41
|
#
|
|
42
|
+
# It'll return +:keep_alive+ if the connection is a pipeline or keep-alive connection.
|
|
43
|
+
# Which may contain additional requests.
|
|
44
|
+
#
|
|
42
45
|
# It'll return +:async+ if the connection remains open but will be handled
|
|
43
46
|
# elsewhere, i.e. the connection has been hijacked by the Rack application.
|
|
44
47
|
#
|
|
45
48
|
# Finally, it'll return +true+ on keep-alive connections.
|
|
46
49
|
# @param client [Puma::Client]
|
|
47
50
|
# @param requests [Integer]
|
|
48
|
-
# @return [
|
|
49
|
-
#
|
|
51
|
+
# @return [:close, :keep_alive, :async]
|
|
50
52
|
def handle_request(client, requests)
|
|
51
53
|
env = client.env
|
|
52
54
|
io_buffer = client.io_buffer
|
|
53
55
|
socket = client.io # io may be a MiniSSL::Socket
|
|
54
56
|
app_body = nil
|
|
57
|
+
error = nil
|
|
55
58
|
|
|
56
|
-
return
|
|
59
|
+
return :close if closed_socket?(socket)
|
|
57
60
|
|
|
58
61
|
if client.http_content_length_limit_exceeded
|
|
59
62
|
return prepare_response(413, {}, ["Payload Too Large"], requests, client)
|
|
@@ -68,7 +71,7 @@ module Puma
|
|
|
68
71
|
end
|
|
69
72
|
|
|
70
73
|
env[HIJACK_P] = true
|
|
71
|
-
env[HIJACK] = client
|
|
74
|
+
env[HIJACK] = client.method :full_hijack
|
|
72
75
|
|
|
73
76
|
env[RACK_INPUT] = client.body
|
|
74
77
|
env[RACK_URL_SCHEME] ||= default_server_port(env) == PORT_443 ? HTTPS : HTTP
|
|
@@ -92,6 +95,7 @@ module Puma
|
|
|
92
95
|
# array, we will invoke them when the request is done.
|
|
93
96
|
#
|
|
94
97
|
env[RACK_AFTER_REPLY] ||= []
|
|
98
|
+
env[RACK_RESPONSE_FINISHED] ||= []
|
|
95
99
|
|
|
96
100
|
begin
|
|
97
101
|
if @supported_http_methods == :any || @supported_http_methods.key?(env[REQUEST_METHOD])
|
|
@@ -119,15 +123,15 @@ module Puma
|
|
|
119
123
|
|
|
120
124
|
return :async
|
|
121
125
|
end
|
|
122
|
-
rescue ThreadPool::ForceShutdown =>
|
|
123
|
-
@log_writer.unknown_error
|
|
126
|
+
rescue ThreadPool::ForceShutdown => error
|
|
127
|
+
@log_writer.unknown_error error, client, "Rack app"
|
|
124
128
|
@log_writer.log "Detected force shutdown of a thread"
|
|
125
129
|
|
|
126
|
-
status, headers, res_body = lowlevel_error(
|
|
127
|
-
rescue Exception =>
|
|
128
|
-
@log_writer.unknown_error
|
|
130
|
+
status, headers, res_body = lowlevel_error(error, env, 503)
|
|
131
|
+
rescue Exception => error
|
|
132
|
+
@log_writer.unknown_error error, client, "Rack app"
|
|
129
133
|
|
|
130
|
-
status, headers, res_body = lowlevel_error(
|
|
134
|
+
status, headers, res_body = lowlevel_error(error, env, 500)
|
|
131
135
|
end
|
|
132
136
|
prepare_response(status, headers, res_body, requests, client)
|
|
133
137
|
ensure
|
|
@@ -144,6 +148,16 @@ module Puma
|
|
|
144
148
|
end
|
|
145
149
|
end
|
|
146
150
|
end
|
|
151
|
+
|
|
152
|
+
if response_finished = env[RACK_RESPONSE_FINISHED]
|
|
153
|
+
response_finished.reverse_each do |o|
|
|
154
|
+
begin
|
|
155
|
+
o.call(env, status, headers, error)
|
|
156
|
+
rescue StandardError => e
|
|
157
|
+
@log_writer.debug_error e
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
147
161
|
end
|
|
148
162
|
|
|
149
163
|
# Assembles the headers and prepares the body for actually sending the
|
|
@@ -155,26 +169,16 @@ module Puma
|
|
|
155
169
|
# a call to `Server#lowlevel_error`
|
|
156
170
|
# @param requests [Integer] number of inline requests handled
|
|
157
171
|
# @param client [Puma::Client]
|
|
158
|
-
# @return [
|
|
172
|
+
# @return [:close, :keep_alive, :async]
|
|
159
173
|
def prepare_response(status, headers, res_body, requests, client)
|
|
160
174
|
env = client.env
|
|
161
175
|
socket = client.io
|
|
162
176
|
io_buffer = client.io_buffer
|
|
163
177
|
|
|
164
|
-
return
|
|
178
|
+
return :close if closed_socket?(socket)
|
|
165
179
|
|
|
166
180
|
# Close the connection after a reasonable number of inline requests
|
|
167
|
-
|
|
168
|
-
# This allows Puma to service connections fairly when the number
|
|
169
|
-
# of concurrent connections exceeds the size of the threadpool.
|
|
170
|
-
force_keep_alive = if @enable_keep_alives
|
|
171
|
-
requests < @max_fast_inline ||
|
|
172
|
-
@thread_pool.busy_threads < @max_threads ||
|
|
173
|
-
!client.listener.to_io.wait_readable(0)
|
|
174
|
-
else
|
|
175
|
-
# Always set force_keep_alive to false if the server has keep-alives not enabled.
|
|
176
|
-
false
|
|
177
|
-
end
|
|
181
|
+
force_keep_alive = @enable_keep_alives && client.requests_served < @max_keep_alive
|
|
178
182
|
|
|
179
183
|
resp_info = str_headers(env, status, headers, res_body, io_buffer, force_keep_alive)
|
|
180
184
|
|
|
@@ -242,7 +246,7 @@ module Puma
|
|
|
242
246
|
io_buffer << LINE_END
|
|
243
247
|
fast_write_str socket, io_buffer.read_and_reset
|
|
244
248
|
socket.flush
|
|
245
|
-
return keep_alive
|
|
249
|
+
return keep_alive ? :keep_alive : :close
|
|
246
250
|
end
|
|
247
251
|
else
|
|
248
252
|
if content_length
|
|
@@ -267,14 +271,21 @@ module Puma
|
|
|
267
271
|
|
|
268
272
|
fast_write_response socket, body, io_buffer, chunked, content_length.to_i
|
|
269
273
|
body.close if close_body
|
|
270
|
-
keep_alive
|
|
274
|
+
# if we're shutting down, close keep_alive connections
|
|
275
|
+
!shutting_down? && keep_alive ? :keep_alive : :close
|
|
271
276
|
end
|
|
272
277
|
|
|
278
|
+
HTTP_ON_VALUES = { "on" => true, HTTPS => true }
|
|
279
|
+
private_constant :HTTP_ON_VALUES
|
|
280
|
+
|
|
273
281
|
# @param env [Hash] see Puma::Client#env, from request
|
|
274
282
|
# @return [Puma::Const::PORT_443,Puma::Const::PORT_80]
|
|
275
283
|
#
|
|
276
284
|
def default_server_port(env)
|
|
277
|
-
if [
|
|
285
|
+
if HTTP_ON_VALUES[env[HTTPS_KEY]] ||
|
|
286
|
+
env[HTTP_X_FORWARDED_PROTO]&.start_with?(HTTPS) ||
|
|
287
|
+
env[HTTP_X_FORWARDED_SCHEME] == HTTPS ||
|
|
288
|
+
env[HTTP_X_FORWARDED_SSL] == "on"
|
|
278
289
|
PORT_443
|
|
279
290
|
else
|
|
280
291
|
PORT_80
|
|
@@ -478,7 +489,7 @@ module Puma
|
|
|
478
489
|
|
|
479
490
|
# The legacy HTTP_VERSION header can be sent as a client header.
|
|
480
491
|
# Rack v4 may remove using HTTP_VERSION. If so, remove this line.
|
|
481
|
-
env[HTTP_VERSION] = env[SERVER_PROTOCOL]
|
|
492
|
+
env[HTTP_VERSION] = env[SERVER_PROTOCOL] if @env_set_http_version
|
|
482
493
|
end
|
|
483
494
|
private :normalize_env
|
|
484
495
|
|
|
@@ -585,7 +596,7 @@ module Puma
|
|
|
585
596
|
# response body
|
|
586
597
|
# @param io_buffer [Puma::IOBuffer] modified inn place
|
|
587
598
|
# @param force_keep_alive [Boolean] 'anded' with keep_alive, based on system
|
|
588
|
-
# status and `@
|
|
599
|
+
# status and `@max_keep_alive`
|
|
589
600
|
# @return [Hash] resp_info
|
|
590
601
|
# @version 5.0.3
|
|
591
602
|
#
|
|
@@ -668,10 +679,10 @@ module Puma
|
|
|
668
679
|
if ary
|
|
669
680
|
ary.each do |v|
|
|
670
681
|
next if illegal_header_value?(v)
|
|
671
|
-
io_buffer.append k, colon, v, line_ending
|
|
682
|
+
io_buffer.append k.downcase, colon, v, line_ending
|
|
672
683
|
end
|
|
673
684
|
else
|
|
674
|
-
io_buffer.append k, colon, line_ending
|
|
685
|
+
io_buffer.append k.downcase, colon, line_ending
|
|
675
686
|
end
|
|
676
687
|
end
|
|
677
688
|
|
data/lib/puma/runner.rb
CHANGED
|
@@ -33,7 +33,6 @@ module Puma
|
|
|
33
33
|
@wakeup.write PIPE_WAKEUP unless @wakeup.closed?
|
|
34
34
|
|
|
35
35
|
rescue SystemCallError, IOError
|
|
36
|
-
Puma::Util.purge_interrupt_queue
|
|
37
36
|
end
|
|
38
37
|
|
|
39
38
|
def development?
|
|
@@ -71,7 +70,7 @@ module Puma
|
|
|
71
70
|
token = nil if token.empty? || token == 'none'
|
|
72
71
|
end
|
|
73
72
|
|
|
74
|
-
app = Puma::App::Status.new @launcher, token
|
|
73
|
+
app = Puma::App::Status.new @launcher, token: token, data_only: @options[:control_data_only]
|
|
75
74
|
|
|
76
75
|
# A Reactor is not created and nio4r is not loaded when 'queue_requests: false'
|
|
77
76
|
# Use `nil` for events, no hooks in control server
|
|
@@ -93,22 +92,6 @@ module Puma
|
|
|
93
92
|
@control.binder.close_listeners if @control
|
|
94
93
|
end
|
|
95
94
|
|
|
96
|
-
# @!attribute [r] ruby_engine
|
|
97
|
-
# @deprecated Use `RUBY_DESCRIPTION` instead
|
|
98
|
-
def ruby_engine
|
|
99
|
-
warn "Puma::Runner#ruby_engine is deprecated; use RUBY_DESCRIPTION instead. It will be removed in puma v7."
|
|
100
|
-
|
|
101
|
-
if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
|
|
102
|
-
"ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
|
|
103
|
-
else
|
|
104
|
-
if defined?(RUBY_ENGINE_VERSION)
|
|
105
|
-
"#{RUBY_ENGINE} #{RUBY_ENGINE_VERSION} - ruby #{RUBY_VERSION}"
|
|
106
|
-
else
|
|
107
|
-
"#{RUBY_ENGINE} #{RUBY_VERSION}"
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
95
|
def output_header(mode)
|
|
113
96
|
min_t = @options[:min_threads]
|
|
114
97
|
max_t = @options[:max_threads]
|
|
@@ -128,6 +111,14 @@ module Puma
|
|
|
128
111
|
end
|
|
129
112
|
end
|
|
130
113
|
|
|
114
|
+
def warn_ruby_mn_threads
|
|
115
|
+
return if !ENV.key?('RUBY_MN_THREADS')
|
|
116
|
+
|
|
117
|
+
log "! WARNING: Detected `RUBY_MN_THREADS=#{ENV['RUBY_MN_THREADS']}`"
|
|
118
|
+
log "! This setting is known to cause performance regressions with Puma."
|
|
119
|
+
log "! Consider disabling this environment variable: https://github.com/puma/puma/issues/3720"
|
|
120
|
+
end
|
|
121
|
+
|
|
131
122
|
def redirected_io?
|
|
132
123
|
@options[:redirect_stdout] || @options[:redirect_stderr]
|
|
133
124
|
end
|