puma 5.6.4 → 6.1.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 +199 -3
- data/README.md +22 -17
- data/bin/puma-wild +1 -1
- data/docs/compile_options.md +34 -0
- data/docs/fork_worker.md +1 -3
- data/docs/nginx.md +1 -1
- data/docs/systemd.md +1 -2
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/extconf.rb +18 -10
- data/ext/puma_http11/http11_parser.c +1 -1
- 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 +2 -2
- data/ext/puma_http11/mini_ssl.c +63 -24
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +166 -65
- data/ext/puma_http11/puma_http11.c +17 -9
- data/lib/puma/app/status.rb +6 -3
- data/lib/puma/binder.rb +41 -46
- data/lib/puma/cli.rb +11 -17
- data/lib/puma/client.rb +54 -16
- data/lib/puma/cluster/worker.rb +18 -11
- data/lib/puma/cluster/worker_handle.rb +4 -1
- data/lib/puma/cluster.rb +33 -30
- data/lib/puma/configuration.rb +75 -58
- data/lib/puma/const.rb +76 -88
- data/lib/puma/control_cli.rb +21 -18
- data/lib/puma/detect.rb +4 -0
- data/lib/puma/dsl.rb +111 -49
- data/lib/puma/error_logger.rb +17 -9
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +39 -4
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +111 -175
- data/lib/puma/log_writer.rb +141 -0
- data/lib/puma/minissl/context_builder.rb +23 -12
- data/lib/puma/minissl.rb +91 -15
- data/lib/puma/null_io.rb +5 -0
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/rack/builder.rb +4 -4
- data/lib/puma/rack_default.rb +19 -4
- data/lib/puma/reactor.rb +4 -4
- data/lib/puma/request.rb +344 -161
- data/lib/puma/runner.rb +52 -20
- data/lib/puma/sd_notify.rb +149 -0
- data/lib/puma/server.rb +57 -69
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +2 -4
- data/lib/puma/thread_pool.rb +16 -16
- data/lib/puma/util.rb +12 -14
- data/lib/puma.rb +12 -11
- data/lib/rack/handler/puma.rb +115 -94
- metadata +10 -5
- data/lib/puma/queue_close.rb +0 -26
- data/lib/puma/systemd.rb +0 -46
data/lib/puma/runner.rb
CHANGED
@@ -1,23 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
require_relative 'server'
|
4
|
+
require_relative 'const'
|
5
5
|
|
6
6
|
module Puma
|
7
7
|
# Generic class that is used by `Puma::Cluster` and `Puma::Single` to
|
8
8
|
# serve requests. This class spawns a new instance of `Puma::Server` via
|
9
9
|
# a call to `start_server`.
|
10
10
|
class Runner
|
11
|
-
def initialize(
|
12
|
-
@launcher =
|
13
|
-
@
|
14
|
-
@
|
11
|
+
def initialize(launcher)
|
12
|
+
@launcher = launcher
|
13
|
+
@log_writer = launcher.log_writer
|
14
|
+
@events = launcher.events
|
15
|
+
@config = launcher.config
|
16
|
+
@options = launcher.options
|
15
17
|
@app = nil
|
16
18
|
@control = nil
|
17
19
|
@started_at = Time.now
|
18
20
|
@wakeup = nil
|
19
21
|
end
|
20
22
|
|
23
|
+
# Returns the hash of configuration options.
|
24
|
+
# @return [Puma::UserFileDefaultOptions]
|
25
|
+
attr_reader :options
|
26
|
+
|
21
27
|
def wakeup!
|
22
28
|
return unless @wakeup
|
23
29
|
|
@@ -36,27 +42,27 @@ module Puma
|
|
36
42
|
end
|
37
43
|
|
38
44
|
def log(str)
|
39
|
-
@
|
45
|
+
@log_writer.log str
|
40
46
|
end
|
41
47
|
|
42
48
|
# @version 5.0.0
|
43
49
|
def stop_control
|
44
|
-
@control
|
50
|
+
@control&.stop true
|
45
51
|
end
|
46
52
|
|
47
53
|
def error(str)
|
48
|
-
@
|
54
|
+
@log_writer.error str
|
49
55
|
end
|
50
56
|
|
51
57
|
def debug(str)
|
52
|
-
@
|
58
|
+
@log_writer.log "- #{str}" if @options[:debug]
|
53
59
|
end
|
54
60
|
|
55
61
|
def start_control
|
56
62
|
str = @options[:control_url]
|
57
63
|
return unless str
|
58
64
|
|
59
|
-
|
65
|
+
require_relative 'app/status'
|
60
66
|
|
61
67
|
if token = @options[:control_auth_token]
|
62
68
|
token = nil if token.empty? || token == 'none'
|
@@ -64,10 +70,12 @@ module Puma
|
|
64
70
|
|
65
71
|
app = Puma::App::Status.new @launcher, token
|
66
72
|
|
67
|
-
|
68
|
-
|
73
|
+
# A Reactor is not created aand nio4r is not loaded when 'queue_requests: false'
|
74
|
+
# Use `nil` for events, no hooks in control server
|
75
|
+
control = Puma::Server.new app, nil,
|
76
|
+
{ min_threads: 0, max_threads: 1, queue_requests: false, log_writer: @log_writer }
|
69
77
|
|
70
|
-
control.binder.parse [str],
|
78
|
+
control.binder.parse [str], nil, 'Starting control server'
|
71
79
|
|
72
80
|
control.run thread_name: 'ctl'
|
73
81
|
@control = control
|
@@ -141,29 +149,29 @@ module Puma
|
|
141
149
|
end
|
142
150
|
|
143
151
|
def load_and_bind
|
144
|
-
unless @
|
152
|
+
unless @config.app_configured?
|
145
153
|
error "No application configured, nothing to run"
|
146
154
|
exit 1
|
147
155
|
end
|
148
156
|
|
149
157
|
begin
|
150
|
-
@app = @
|
158
|
+
@app = @config.app
|
151
159
|
rescue Exception => e
|
152
160
|
log "! Unable to load application: #{e.class}: #{e.message}"
|
153
161
|
raise e
|
154
162
|
end
|
155
163
|
|
156
|
-
@launcher.binder.parse @options[:binds]
|
164
|
+
@launcher.binder.parse @options[:binds]
|
157
165
|
end
|
158
166
|
|
159
167
|
# @!attribute [r] app
|
160
168
|
def app
|
161
|
-
@app ||= @
|
169
|
+
@app ||= @config.app
|
162
170
|
end
|
163
171
|
|
164
172
|
def start_server
|
165
|
-
server = Puma::Server.new
|
166
|
-
server.inherit_binder
|
173
|
+
server = Puma::Server.new(app, @events, @options)
|
174
|
+
server.inherit_binder(@launcher.binder)
|
167
175
|
server
|
168
176
|
end
|
169
177
|
|
@@ -173,5 +181,29 @@ module Puma
|
|
173
181
|
raise "Cannot redirect #{io_name} to #{path}"
|
174
182
|
end
|
175
183
|
end
|
184
|
+
|
185
|
+
def utc_iso8601(val)
|
186
|
+
"#{val.utc.strftime '%FT%T'}Z"
|
187
|
+
end
|
188
|
+
|
189
|
+
def stats
|
190
|
+
{
|
191
|
+
versions: {
|
192
|
+
puma: Puma::Const::PUMA_VERSION,
|
193
|
+
ruby: {
|
194
|
+
engine: RUBY_ENGINE,
|
195
|
+
version: RUBY_VERSION,
|
196
|
+
patchlevel: RUBY_PATCHLEVEL
|
197
|
+
}
|
198
|
+
}
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
# this method call should always be guarded by `@log_writer.debug?`
|
203
|
+
def debug_loaded_extensions(str)
|
204
|
+
@log_writer.debug "────────────────────────────────── #{str}"
|
205
|
+
re_ext = /\.#{RbConfig::CONFIG['DLEXT']}\z/i
|
206
|
+
$LOADED_FEATURES.grep(re_ext).each { |f| @log_writer.debug(" #{f}") }
|
207
|
+
end
|
176
208
|
end
|
177
209
|
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "socket"
|
4
|
+
|
5
|
+
module Puma
|
6
|
+
# The MIT License
|
7
|
+
#
|
8
|
+
# Copyright (c) 2017-2022 Agis Anastasopoulos
|
9
|
+
#
|
10
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
11
|
+
# this software and associated documentation files (the "Software"), to deal in
|
12
|
+
# the Software without restriction, including without limitation the rights to
|
13
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
14
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
15
|
+
# subject to the following conditions:
|
16
|
+
#
|
17
|
+
# The above copyright notice and this permission notice shall be included in all
|
18
|
+
# copies or substantial portions of the Software.
|
19
|
+
#
|
20
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
21
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
22
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
23
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
24
|
+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
25
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
26
|
+
#
|
27
|
+
# This is a copy of https://github.com/agis/ruby-sdnotify as of commit cca575c
|
28
|
+
# The only changes made was "rehoming" it within the Puma module to avoid
|
29
|
+
# namespace collisions and applying standard's code formatting style.
|
30
|
+
#
|
31
|
+
# SdNotify is a pure-Ruby implementation of sd_notify(3). It can be used to
|
32
|
+
# notify systemd about state changes. Methods of this package are no-op on
|
33
|
+
# non-systemd systems (eg. Darwin).
|
34
|
+
#
|
35
|
+
# The API maps closely to the original implementation of sd_notify(3),
|
36
|
+
# therefore be sure to check the official man pages prior to using SdNotify.
|
37
|
+
#
|
38
|
+
# @see https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
39
|
+
module SdNotify
|
40
|
+
# Exception raised when there's an error writing to the notification socket
|
41
|
+
class NotifyError < RuntimeError; end
|
42
|
+
|
43
|
+
READY = "READY=1"
|
44
|
+
RELOADING = "RELOADING=1"
|
45
|
+
STOPPING = "STOPPING=1"
|
46
|
+
STATUS = "STATUS="
|
47
|
+
ERRNO = "ERRNO="
|
48
|
+
MAINPID = "MAINPID="
|
49
|
+
WATCHDOG = "WATCHDOG=1"
|
50
|
+
FDSTORE = "FDSTORE=1"
|
51
|
+
|
52
|
+
def self.ready(unset_env=false)
|
53
|
+
notify(READY, unset_env)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.reloading(unset_env=false)
|
57
|
+
notify(RELOADING, unset_env)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.stopping(unset_env=false)
|
61
|
+
notify(STOPPING, unset_env)
|
62
|
+
end
|
63
|
+
|
64
|
+
# @param status [String] a custom status string that describes the current
|
65
|
+
# state of the service
|
66
|
+
def self.status(status, unset_env=false)
|
67
|
+
notify("#{STATUS}#{status}", unset_env)
|
68
|
+
end
|
69
|
+
|
70
|
+
# @param errno [Integer]
|
71
|
+
def self.errno(errno, unset_env=false)
|
72
|
+
notify("#{ERRNO}#{errno}", unset_env)
|
73
|
+
end
|
74
|
+
|
75
|
+
# @param pid [Integer]
|
76
|
+
def self.mainpid(pid, unset_env=false)
|
77
|
+
notify("#{MAINPID}#{pid}", unset_env)
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.watchdog(unset_env=false)
|
81
|
+
notify(WATCHDOG, unset_env)
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.fdstore(unset_env=false)
|
85
|
+
notify(FDSTORE, unset_env)
|
86
|
+
end
|
87
|
+
|
88
|
+
# @param [Boolean] true if the service manager expects watchdog keep-alive
|
89
|
+
# notification messages to be sent from this process.
|
90
|
+
#
|
91
|
+
# If the $WATCHDOG_USEC environment variable is set,
|
92
|
+
# and the $WATCHDOG_PID variable is unset or set to the PID of the current
|
93
|
+
# process
|
94
|
+
#
|
95
|
+
# @note Unlike sd_watchdog_enabled(3), this method does not mutate the
|
96
|
+
# environment.
|
97
|
+
def self.watchdog?
|
98
|
+
wd_usec = ENV["WATCHDOG_USEC"]
|
99
|
+
wd_pid = ENV["WATCHDOG_PID"]
|
100
|
+
|
101
|
+
return false if !wd_usec
|
102
|
+
|
103
|
+
begin
|
104
|
+
wd_usec = Integer(wd_usec)
|
105
|
+
rescue
|
106
|
+
return false
|
107
|
+
end
|
108
|
+
|
109
|
+
return false if wd_usec <= 0
|
110
|
+
return true if !wd_pid || wd_pid == $$.to_s
|
111
|
+
|
112
|
+
false
|
113
|
+
end
|
114
|
+
|
115
|
+
# Notify systemd with the provided state, via the notification socket, if
|
116
|
+
# any.
|
117
|
+
#
|
118
|
+
# Generally this method will be used indirectly through the other methods
|
119
|
+
# of the library.
|
120
|
+
#
|
121
|
+
# @param state [String]
|
122
|
+
# @param unset_env [Boolean]
|
123
|
+
#
|
124
|
+
# @return [Fixnum, nil] the number of bytes written to the notification
|
125
|
+
# socket or nil if there was no socket to report to (eg. the program wasn't
|
126
|
+
# started by systemd)
|
127
|
+
#
|
128
|
+
# @raise [NotifyError] if there was an error communicating with the systemd
|
129
|
+
# socket
|
130
|
+
#
|
131
|
+
# @see https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
132
|
+
def self.notify(state, unset_env=false)
|
133
|
+
sock = ENV["NOTIFY_SOCKET"]
|
134
|
+
|
135
|
+
return nil if !sock
|
136
|
+
|
137
|
+
ENV.delete("NOTIFY_SOCKET") if unset_env
|
138
|
+
|
139
|
+
begin
|
140
|
+
Addrinfo.unix(sock, :DGRAM).connect do |s|
|
141
|
+
s.close_on_exec = true
|
142
|
+
s.write(state)
|
143
|
+
end
|
144
|
+
rescue StandardError => e
|
145
|
+
raise NotifyError, "#{e.class}: #{e.message}", e.backtrace
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
data/lib/puma/server.rb
CHANGED
@@ -2,19 +2,19 @@
|
|
2
2
|
|
3
3
|
require 'stringio'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
require_relative 'thread_pool'
|
6
|
+
require_relative 'const'
|
7
|
+
require_relative 'log_writer'
|
8
|
+
require_relative 'events'
|
9
|
+
require_relative 'null_io'
|
10
|
+
require_relative 'reactor'
|
11
|
+
require_relative 'client'
|
12
|
+
require_relative 'binder'
|
13
|
+
require_relative 'util'
|
14
|
+
require_relative 'request'
|
15
15
|
|
16
16
|
require 'socket'
|
17
|
-
require 'io/wait'
|
17
|
+
require 'io/wait' unless Puma::HAS_NATIVE_IO_WAIT
|
18
18
|
require 'forwardable'
|
19
19
|
|
20
20
|
module Puma
|
@@ -30,12 +30,12 @@ module Puma
|
|
30
30
|
#
|
31
31
|
# Each `Puma::Server` will have one reactor and one thread pool.
|
32
32
|
class Server
|
33
|
-
|
34
33
|
include Puma::Const
|
35
34
|
include Request
|
36
35
|
extend Forwardable
|
37
36
|
|
38
37
|
attr_reader :thread
|
38
|
+
attr_reader :log_writer
|
39
39
|
attr_reader :events
|
40
40
|
attr_reader :min_threads, :max_threads # for #stats
|
41
41
|
attr_reader :requests_count # @version 5.0.0
|
@@ -45,11 +45,6 @@ module Puma
|
|
45
45
|
:leak_stack_on_error,
|
46
46
|
:persistent_timeout, :reaping_time
|
47
47
|
|
48
|
-
# @deprecated v6.0.0
|
49
|
-
attr_writer :auto_trim_time, :early_hints, :first_data_timeout,
|
50
|
-
:leak_stack_on_error, :min_threads, :max_threads,
|
51
|
-
:persistent_timeout, :reaping_time
|
52
|
-
|
53
48
|
attr_accessor :app
|
54
49
|
attr_accessor :binder
|
55
50
|
|
@@ -60,8 +55,9 @@ module Puma
|
|
60
55
|
|
61
56
|
# Create a server for the rack app +app+.
|
62
57
|
#
|
63
|
-
# +
|
64
|
-
#
|
58
|
+
# +log_writer+ is a Puma::LogWriter object used to log info and error messages.
|
59
|
+
#
|
60
|
+
# +events+ is a Puma::Events object used to notify application status events.
|
65
61
|
#
|
66
62
|
# Server#run returns a thread that you can join on to wait for the server
|
67
63
|
# to do its work.
|
@@ -70,34 +66,41 @@ module Puma
|
|
70
66
|
# and have default values set via +fetch+. Normally the values are set via
|
71
67
|
# `::Puma::Configuration.puma_default_options`.
|
72
68
|
#
|
73
|
-
|
69
|
+
# @note The `events` parameter is set to nil, and set to `Events.new` in code.
|
70
|
+
# Often `options` needs to be passed, but `events` does not. Using nil allows
|
71
|
+
# calling code to not require events.rb.
|
72
|
+
#
|
73
|
+
def initialize(app, events = nil, options = {})
|
74
74
|
@app = app
|
75
|
-
@events = events
|
75
|
+
@events = events || Events.new
|
76
76
|
|
77
77
|
@check, @notify = nil
|
78
78
|
@status = :stop
|
79
79
|
|
80
|
-
@auto_trim_time = 30
|
81
|
-
@reaping_time = 1
|
82
|
-
|
83
80
|
@thread = nil
|
84
81
|
@thread_pool = nil
|
85
82
|
|
86
|
-
@options = options
|
83
|
+
@options = if options.is_a?(UserFileDefaultOptions)
|
84
|
+
options
|
85
|
+
else
|
86
|
+
UserFileDefaultOptions.new(options, Configuration::DEFAULTS)
|
87
|
+
end
|
87
88
|
|
88
|
-
@
|
89
|
-
@
|
90
|
-
@
|
91
|
-
@
|
92
|
-
@
|
93
|
-
@
|
94
|
-
@
|
95
|
-
@
|
89
|
+
@log_writer = @options.fetch :log_writer, LogWriter.stdio
|
90
|
+
@early_hints = @options[:early_hints]
|
91
|
+
@first_data_timeout = @options[:first_data_timeout]
|
92
|
+
@min_threads = @options[:min_threads]
|
93
|
+
@max_threads = @options[:max_threads]
|
94
|
+
@persistent_timeout = @options[:persistent_timeout]
|
95
|
+
@queue_requests = @options[:queue_requests]
|
96
|
+
@max_fast_inline = @options[:max_fast_inline]
|
97
|
+
@io_selector_backend = @options[:io_selector_backend]
|
98
|
+
@http_content_length_limit = @options[:http_content_length_limit]
|
96
99
|
|
97
100
|
temp = !!(@options[:environment] =~ /\A(development|test)\z/)
|
98
101
|
@leak_stack_on_error = @options[:environment] ? temp : true
|
99
102
|
|
100
|
-
@binder = Binder.new(
|
103
|
+
@binder = Binder.new(log_writer)
|
101
104
|
|
102
105
|
ENV['RACK_ENV'] ||= "development"
|
103
106
|
|
@@ -193,12 +196,12 @@ module Puma
|
|
193
196
|
|
194
197
|
# @!attribute [r] backlog
|
195
198
|
def backlog
|
196
|
-
@thread_pool
|
199
|
+
@thread_pool&.backlog
|
197
200
|
end
|
198
201
|
|
199
202
|
# @!attribute [r] running
|
200
203
|
def running
|
201
|
-
@thread_pool
|
204
|
+
@thread_pool&.spawned
|
202
205
|
end
|
203
206
|
|
204
207
|
|
@@ -211,7 +214,7 @@ module Puma
|
|
211
214
|
# value would be 4 until it finishes processing.
|
212
215
|
# @!attribute [r] pool_capacity
|
213
216
|
def pool_capacity
|
214
|
-
@thread_pool
|
217
|
+
@thread_pool&.pool_capacity
|
215
218
|
end
|
216
219
|
|
217
220
|
# Runs the server.
|
@@ -227,29 +230,16 @@ module Puma
|
|
227
230
|
|
228
231
|
@status = :run
|
229
232
|
|
230
|
-
@thread_pool = ThreadPool.new(
|
231
|
-
thread_name,
|
232
|
-
@min_threads,
|
233
|
-
@max_threads,
|
234
|
-
::Puma::IOBuffer,
|
235
|
-
&method(:process_client)
|
236
|
-
)
|
237
|
-
|
238
|
-
@thread_pool.out_of_band_hook = @options[:out_of_band]
|
239
|
-
@thread_pool.clean_thread_locals = @options[:clean_thread_locals]
|
233
|
+
@thread_pool = ThreadPool.new(thread_name, @options) { |client| process_client client }
|
240
234
|
|
241
235
|
if @queue_requests
|
242
|
-
@reactor = Reactor.new(@io_selector_backend
|
236
|
+
@reactor = Reactor.new(@io_selector_backend) { |c| reactor_wakeup c }
|
243
237
|
@reactor.run
|
244
238
|
end
|
245
239
|
|
246
|
-
if @reaping_time
|
247
|
-
@thread_pool.auto_reap!(@reaping_time)
|
248
|
-
end
|
249
240
|
|
250
|
-
if @
|
251
|
-
|
252
|
-
end
|
241
|
+
@thread_pool.auto_reap! if @options[:reaping_time]
|
242
|
+
@thread_pool.auto_trim! if @options[:auto_trim_time]
|
253
243
|
|
254
244
|
@check, @notify = Puma::Util.pipe unless @notify
|
255
245
|
|
@@ -345,6 +335,7 @@ module Puma
|
|
345
335
|
drain += 1 if shutting_down?
|
346
336
|
pool << Client.new(io, @binder.env(sock)).tap { |c|
|
347
337
|
c.listener = sock
|
338
|
+
c.http_content_length_limit = @http_content_length_limit
|
348
339
|
c.send(addr_send_name, addr_value) if addr_value
|
349
340
|
}
|
350
341
|
end
|
@@ -353,11 +344,11 @@ module Puma
|
|
353
344
|
# In the case that any of the sockets are unexpectedly close.
|
354
345
|
raise
|
355
346
|
rescue StandardError => e
|
356
|
-
@
|
347
|
+
@log_writer.unknown_error e, nil, "Listen loop"
|
357
348
|
end
|
358
349
|
end
|
359
350
|
|
360
|
-
@
|
351
|
+
@log_writer.debug "Drained #{drain} additional connections." if drain
|
361
352
|
@events.fire :state, @status
|
362
353
|
|
363
354
|
if queue_requests
|
@@ -366,14 +357,13 @@ module Puma
|
|
366
357
|
end
|
367
358
|
graceful_shutdown if @status == :stop || @status == :restart
|
368
359
|
rescue Exception => e
|
369
|
-
@
|
360
|
+
@log_writer.unknown_error e, nil, "Exception handling servers"
|
370
361
|
ensure
|
371
|
-
# RuntimeError is Ruby 2.2 issue, can't modify frozen IOError
|
372
362
|
# Errno::EBADF is infrequently raised
|
373
363
|
[@check, @notify].each do |io|
|
374
364
|
begin
|
375
365
|
io.close unless io.closed?
|
376
|
-
rescue Errno::EBADF
|
366
|
+
rescue Errno::EBADF
|
377
367
|
end
|
378
368
|
end
|
379
369
|
@notify = nil
|
@@ -412,7 +402,7 @@ module Puma
|
|
412
402
|
# returning.
|
413
403
|
#
|
414
404
|
# Return true if one or more requests were processed.
|
415
|
-
def process_client(client
|
405
|
+
def process_client(client)
|
416
406
|
# Advertise this server into the thread
|
417
407
|
Thread.current[ThreadLocalKey] = self
|
418
408
|
|
@@ -438,15 +428,13 @@ module Puma
|
|
438
428
|
|
439
429
|
while true
|
440
430
|
@requests_count += 1
|
441
|
-
case handle_request(client,
|
431
|
+
case handle_request(client, requests + 1)
|
442
432
|
when false
|
443
433
|
break
|
444
434
|
when :async
|
445
435
|
close_socket = false
|
446
436
|
break
|
447
437
|
when true
|
448
|
-
buffer.reset
|
449
|
-
|
450
438
|
ThreadPool.clean_thread_locals if clean_thread_locals
|
451
439
|
|
452
440
|
requests += 1
|
@@ -480,7 +468,7 @@ module Puma
|
|
480
468
|
# The ensure tries to close +client+ down
|
481
469
|
requests > 0
|
482
470
|
ensure
|
483
|
-
|
471
|
+
client.io_buffer.reset
|
484
472
|
|
485
473
|
begin
|
486
474
|
client.close if close_socket
|
@@ -488,7 +476,7 @@ module Puma
|
|
488
476
|
Puma::Util.purge_interrupt_queue
|
489
477
|
# Already closed
|
490
478
|
rescue StandardError => e
|
491
|
-
@
|
479
|
+
@log_writer.unknown_error e, nil, "Client"
|
492
480
|
end
|
493
481
|
end
|
494
482
|
end
|
@@ -511,16 +499,16 @@ module Puma
|
|
511
499
|
lowlevel_error(e, client.env)
|
512
500
|
case e
|
513
501
|
when MiniSSL::SSLError
|
514
|
-
@
|
502
|
+
@log_writer.ssl_error e, client.io
|
515
503
|
when HttpParserError
|
516
504
|
client.write_error(400)
|
517
|
-
@
|
505
|
+
@log_writer.parse_error e, client
|
518
506
|
when HttpParserError501
|
519
507
|
client.write_error(501)
|
520
|
-
@
|
508
|
+
@log_writer.parse_error e, client
|
521
509
|
else
|
522
510
|
client.write_error(500)
|
523
|
-
@
|
511
|
+
@log_writer.unknown_error e, nil, "Read"
|
524
512
|
end
|
525
513
|
end
|
526
514
|
|
data/lib/puma/single.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
require_relative 'runner'
|
4
|
+
require_relative 'detect'
|
5
|
+
require_relative 'plugin'
|
6
6
|
|
7
7
|
module Puma
|
8
8
|
# This class is instantiated by the `Puma::Launcher` and used
|
@@ -16,26 +16,26 @@ module Puma
|
|
16
16
|
# @!attribute [r] stats
|
17
17
|
def stats
|
18
18
|
{
|
19
|
-
started_at: @started_at
|
20
|
-
}.merge(@server.stats)
|
19
|
+
started_at: utc_iso8601(@started_at)
|
20
|
+
}.merge(@server.stats).merge(super)
|
21
21
|
end
|
22
22
|
|
23
23
|
def restart
|
24
|
-
@server
|
24
|
+
@server&.begin_restart
|
25
25
|
end
|
26
26
|
|
27
27
|
def stop
|
28
|
-
@server
|
28
|
+
@server&.stop false
|
29
29
|
end
|
30
30
|
|
31
31
|
def halt
|
32
|
-
@server
|
32
|
+
@server&.halt
|
33
33
|
end
|
34
34
|
|
35
35
|
def stop_blocked
|
36
36
|
log "- Gracefully stopping, waiting for requests to finish"
|
37
|
-
@control
|
38
|
-
@server
|
37
|
+
@control&.stop true
|
38
|
+
@server&.stop true
|
39
39
|
end
|
40
40
|
|
41
41
|
def run
|
@@ -55,7 +55,9 @@ module Puma
|
|
55
55
|
log "Use Ctrl-C to stop"
|
56
56
|
redirect_io
|
57
57
|
|
58
|
-
@
|
58
|
+
@events.fire_on_booted!
|
59
|
+
|
60
|
+
debug_loaded_extensions("Loaded Extensions:") if @log_writer.debug?
|
59
61
|
|
60
62
|
begin
|
61
63
|
server_thread.join
|
data/lib/puma/state_file.rb
CHANGED
@@ -15,15 +15,12 @@ module Puma
|
|
15
15
|
|
16
16
|
ALLOWED_FIELDS = %w!control_url control_auth_token pid running_from!
|
17
17
|
|
18
|
-
# @deprecated 6.0.0
|
19
|
-
FIELDS = ALLOWED_FIELDS
|
20
|
-
|
21
18
|
def initialize
|
22
19
|
@options = {}
|
23
20
|
end
|
24
21
|
|
25
22
|
def save(path, permission = nil)
|
26
|
-
contents = "---\n"
|
23
|
+
contents = +"---\n"
|
27
24
|
@options.each do |k,v|
|
28
25
|
next unless ALLOWED_FIELDS.include? k
|
29
26
|
case v
|
@@ -50,6 +47,7 @@ module Puma
|
|
50
47
|
v = v.strip
|
51
48
|
@options[k] =
|
52
49
|
case v
|
50
|
+
when '' then nil
|
53
51
|
when /\A\d+\z/ then v.to_i
|
54
52
|
when /\A\d+\.\d+\z/ then v.to_f
|
55
53
|
else v.gsub(/\A"|"\z/, '')
|