puma 5.0.0 → 5.0.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 +1126 -574
- data/lib/puma.rb +5 -2
- data/lib/puma/binder.rb +2 -0
- data/lib/puma/client.rb +5 -1
- data/lib/puma/cluster.rb +2 -0
- data/lib/puma/const.rb +1 -1
- data/lib/puma/error_logger.rb +2 -2
- data/lib/puma/events.rb +5 -3
- data/lib/puma/launcher.rb +8 -0
- data/lib/puma/minissl.rb +8 -0
- data/lib/puma/reactor.rb +2 -13
- data/lib/puma/runner.rb +4 -17
- data/lib/puma/server.rb +92 -64
- data/lib/puma/single.rb +1 -0
- data/lib/puma/thread_pool.rb +22 -2
- data/lib/puma/util.rb +1 -0
- metadata +6 -6
data/lib/puma.rb
CHANGED
@@ -10,23 +10,26 @@ require 'stringio'
|
|
10
10
|
|
11
11
|
require 'thread'
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
require 'puma/puma_http11'
|
14
|
+
require 'puma/detect'
|
15
15
|
|
16
16
|
module Puma
|
17
17
|
autoload :Const, 'puma/const'
|
18
18
|
autoload :Server, 'puma/server'
|
19
19
|
autoload :Launcher, 'puma/launcher'
|
20
20
|
|
21
|
+
# @!attribute [rw] stats_object=
|
21
22
|
def self.stats_object=(val)
|
22
23
|
@get_stats = val
|
23
24
|
end
|
24
25
|
|
26
|
+
# @!attribute [rw] stats_object
|
25
27
|
def self.stats
|
26
28
|
require 'json'
|
27
29
|
@get_stats.stats.to_json
|
28
30
|
end
|
29
31
|
|
32
|
+
# @!attribute [r] stats_hash
|
30
33
|
# @version 5.0.0
|
31
34
|
def self.stats_hash
|
32
35
|
@get_stats.stats
|
data/lib/puma/binder.rb
CHANGED
@@ -66,6 +66,7 @@ module Puma
|
|
66
66
|
@ios.each { |i| i.close }
|
67
67
|
end
|
68
68
|
|
69
|
+
# @!attribute [r] connected_ports
|
69
70
|
# @version 5.0.0
|
70
71
|
def connected_ports
|
71
72
|
ios.map { |io| io.addr[1] }.uniq
|
@@ -391,6 +392,7 @@ module Puma
|
|
391
392
|
|
392
393
|
private
|
393
394
|
|
395
|
+
# @!attribute [r] loopback_addresses
|
394
396
|
def loopback_addresses
|
395
397
|
Socket.ip_address_list.select do |addrinfo|
|
396
398
|
addrinfo.ipv6_loopback? || addrinfo.ipv4_loopback?
|
data/lib/puma/client.rb
CHANGED
@@ -85,6 +85,7 @@ module Puma
|
|
85
85
|
|
86
86
|
def_delegators :@io, :closed?
|
87
87
|
|
88
|
+
# @!attribute [r] inspect
|
88
89
|
def inspect
|
89
90
|
"#<Puma::Client:0x#{object_id.to_s(16)} @ready=#{@ready.inspect}>"
|
90
91
|
end
|
@@ -96,6 +97,7 @@ module Puma
|
|
96
97
|
env[HIJACK_IO] ||= @io
|
97
98
|
end
|
98
99
|
|
100
|
+
# @!attribute [r] in_data_phase
|
99
101
|
def in_data_phase
|
100
102
|
!@read_header
|
101
103
|
end
|
@@ -155,7 +157,9 @@ module Puma
|
|
155
157
|
data = @io.read_nonblock(CHUNK_SIZE)
|
156
158
|
rescue IO::WaitReadable
|
157
159
|
return false
|
158
|
-
rescue
|
160
|
+
rescue EOFError
|
161
|
+
# Swallow error, don't log
|
162
|
+
rescue SystemCallError, IOError
|
159
163
|
raise ConnectionError, "Connection error detected during read"
|
160
164
|
end
|
161
165
|
|
data/lib/puma/cluster.rb
CHANGED
@@ -194,6 +194,7 @@ module Puma
|
|
194
194
|
end
|
195
195
|
end
|
196
196
|
|
197
|
+
# @!attribute [r] next_worker_index
|
197
198
|
def next_worker_index
|
198
199
|
all_positions = 0...@options[:workers]
|
199
200
|
occupied_positions = @workers.map { |w| w.index }
|
@@ -396,6 +397,7 @@ module Puma
|
|
396
397
|
|
397
398
|
# Inside of a child process, this will return all zeroes, as @workers is only populated in
|
398
399
|
# the master process.
|
400
|
+
# @!attribute [r] stats
|
399
401
|
def stats
|
400
402
|
old_worker_count = @workers.count { |w| w.phase != @phase }
|
401
403
|
worker_status = @workers.map do |w|
|
data/lib/puma/const.rb
CHANGED
@@ -100,7 +100,7 @@ module Puma
|
|
100
100
|
# too taxing on performance.
|
101
101
|
module Const
|
102
102
|
|
103
|
-
PUMA_VERSION = VERSION = "5.0.
|
103
|
+
PUMA_VERSION = VERSION = "5.0.1".freeze
|
104
104
|
CODE_NAME = "Spoony Bard".freeze
|
105
105
|
|
106
106
|
PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
|
data/lib/puma/error_logger.rb
CHANGED
@@ -51,8 +51,8 @@ module Puma
|
|
51
51
|
|
52
52
|
string_block = []
|
53
53
|
string_block << title(options)
|
54
|
-
string_block << request_dump(req) if req
|
55
|
-
string_block <<
|
54
|
+
string_block << request_dump(req) if request_parsed?(req)
|
55
|
+
string_block << error.backtrace if error
|
56
56
|
|
57
57
|
ioerr.puts string_block.join("\n")
|
58
58
|
end
|
data/lib/puma/events.rb
CHANGED
@@ -106,10 +106,12 @@ module Puma
|
|
106
106
|
end
|
107
107
|
|
108
108
|
# An SSL error has occurred.
|
109
|
-
#
|
110
|
-
#
|
109
|
+
# @param error <Puma::MiniSSL::SSLError>
|
110
|
+
# @param ssl_socket <Puma::MiniSSL::Socket>
|
111
111
|
#
|
112
|
-
def ssl_error(error,
|
112
|
+
def ssl_error(error, ssl_socket)
|
113
|
+
peeraddr = ssl_socket.peeraddr.last rescue "<unknown>"
|
114
|
+
peercert = ssl_socket.peercert
|
113
115
|
subject = peercert ? peercert.subject : nil
|
114
116
|
@error_logger.info(error: error, text: "SSL error, peer: #{peeraddr}, peer cert: #{subject}")
|
115
117
|
end
|
data/lib/puma/launcher.rb
CHANGED
@@ -188,11 +188,13 @@ module Puma
|
|
188
188
|
end
|
189
189
|
|
190
190
|
# Return all tcp ports the launcher may be using, TCP or SSL
|
191
|
+
# @!attribute [r] connected_ports
|
191
192
|
# @version 5.0.0
|
192
193
|
def connected_ports
|
193
194
|
@binder.connected_ports
|
194
195
|
end
|
195
196
|
|
197
|
+
# @!attribute [r] restart_args
|
196
198
|
def restart_args
|
197
199
|
cmd = @options[:restart_cmd]
|
198
200
|
if cmd
|
@@ -207,6 +209,7 @@ module Puma
|
|
207
209
|
@binder.close_listeners
|
208
210
|
end
|
209
211
|
|
212
|
+
# @!attribute [r] thread_status
|
210
213
|
# @version 5.0.0
|
211
214
|
def thread_status
|
212
215
|
Thread.list.each do |thread|
|
@@ -261,6 +264,7 @@ module Puma
|
|
261
264
|
end
|
262
265
|
end
|
263
266
|
|
267
|
+
# @!attribute [r] dependencies_and_files_to_require_after_prune
|
264
268
|
def dependencies_and_files_to_require_after_prune
|
265
269
|
puma = spec_for_gem("puma")
|
266
270
|
|
@@ -271,6 +275,7 @@ module Puma
|
|
271
275
|
[deps, require_paths_for_gem(puma) + extra_runtime_deps_directories]
|
272
276
|
end
|
273
277
|
|
278
|
+
# @!attribute [r] extra_runtime_deps_directories
|
274
279
|
def extra_runtime_deps_directories
|
275
280
|
Array(@options[:extra_runtime_dependencies]).map do |d_name|
|
276
281
|
if (spec = spec_for_gem(d_name))
|
@@ -282,6 +287,7 @@ module Puma
|
|
282
287
|
end.flatten.compact
|
283
288
|
end
|
284
289
|
|
290
|
+
# @!attribute [r] puma_wild_location
|
285
291
|
def puma_wild_location
|
286
292
|
puma = spec_for_gem("puma")
|
287
293
|
dirs = require_paths_for_gem(puma)
|
@@ -345,6 +351,7 @@ module Puma
|
|
345
351
|
Process.respond_to?(:setproctitle) ? Process.setproctitle(title) : $0 = title
|
346
352
|
end
|
347
353
|
|
354
|
+
# @!attribute [r] title
|
348
355
|
def title
|
349
356
|
buffer = "puma #{Puma::Const::VERSION} (#{@options[:binds].join(',')})"
|
350
357
|
buffer += " [#{@options[:tag]}]" if @options[:tag] && !@options[:tag].empty?
|
@@ -356,6 +363,7 @@ module Puma
|
|
356
363
|
ENV['RACK_ENV'] = environment
|
357
364
|
end
|
358
365
|
|
366
|
+
# @!attribute [r] environment
|
359
367
|
def environment
|
360
368
|
@environment
|
361
369
|
end
|
data/lib/puma/minissl.rb
CHANGED
@@ -24,6 +24,7 @@ module Puma
|
|
24
24
|
@peercert = nil
|
25
25
|
end
|
26
26
|
|
27
|
+
# @!attribute [r] to_io
|
27
28
|
def to_io
|
28
29
|
@socket
|
29
30
|
end
|
@@ -38,6 +39,7 @@ module Puma
|
|
38
39
|
#
|
39
40
|
# Used for dropping tcp connections to ssl.
|
40
41
|
# See OpenSSL ssl/ssl_stat.c SSL_state_string for info
|
42
|
+
# @!attribute [r] ssl_version_state
|
41
43
|
# @version 5.0.0
|
42
44
|
#
|
43
45
|
def ssl_version_state
|
@@ -188,10 +190,12 @@ module Puma
|
|
188
190
|
end
|
189
191
|
end
|
190
192
|
|
193
|
+
# @!attribute [r] peeraddr
|
191
194
|
def peeraddr
|
192
195
|
@socket.peeraddr
|
193
196
|
end
|
194
197
|
|
198
|
+
# @!attribute [r] peercert
|
195
199
|
def peercert
|
196
200
|
return @peercert if @peercert
|
197
201
|
|
@@ -264,12 +268,14 @@ module Puma
|
|
264
268
|
end
|
265
269
|
|
266
270
|
# disables TLSv1
|
271
|
+
# @!attribute [w] no_tlsv1=
|
267
272
|
def no_tlsv1=(tlsv1)
|
268
273
|
raise ArgumentError, "Invalid value of no_tlsv1=" unless ['true', 'false', true, false].include?(tlsv1)
|
269
274
|
@no_tlsv1 = tlsv1
|
270
275
|
end
|
271
276
|
|
272
277
|
# disables TLSv1 and TLSv1.1. Overrides `#no_tlsv1=`
|
278
|
+
# @!attribute [w] no_tlsv1_1=
|
273
279
|
def no_tlsv1_1=(tlsv1_1)
|
274
280
|
raise ArgumentError, "Invalid value of no_tlsv1_1=" unless ['true', 'false', true, false].include?(tlsv1_1)
|
275
281
|
@no_tlsv1_1 = tlsv1_1
|
@@ -287,6 +293,7 @@ module Puma
|
|
287
293
|
@ctx = ctx
|
288
294
|
end
|
289
295
|
|
296
|
+
# @!attribute [r] to_io
|
290
297
|
def to_io
|
291
298
|
@socket
|
292
299
|
end
|
@@ -307,6 +314,7 @@ module Puma
|
|
307
314
|
Socket.new io, engine
|
308
315
|
end
|
309
316
|
|
317
|
+
# @!attribute [r] addr
|
310
318
|
# @version 5.0.0
|
311
319
|
def addr
|
312
320
|
@socket.addr
|
data/lib/puma/reactor.rb
CHANGED
@@ -237,23 +237,12 @@ module Puma
|
|
237
237
|
|
238
238
|
# SSL handshake failure
|
239
239
|
rescue MiniSSL::SSLError => e
|
240
|
-
@server.lowlevel_error
|
241
|
-
|
242
|
-
ssl_socket = c.io
|
243
|
-
begin
|
244
|
-
addr = ssl_socket.peeraddr.last
|
245
|
-
# EINVAL can happen when browser closes socket w/security exception
|
246
|
-
rescue IOError, Errno::EINVAL
|
247
|
-
addr = "<unknown>"
|
248
|
-
end
|
249
|
-
|
250
|
-
cert = ssl_socket.peercert
|
240
|
+
@server.lowlevel_error e, c.env
|
241
|
+
@events.ssl_error e, c.io
|
251
242
|
|
252
243
|
c.close
|
253
244
|
clear_monitor mon
|
254
245
|
|
255
|
-
@events.ssl_error e, addr, cert
|
256
|
-
|
257
246
|
# The client doesn't know HTTP well
|
258
247
|
rescue HttpParserError => e
|
259
248
|
@server.lowlevel_error(e, c.env)
|
data/lib/puma/runner.rb
CHANGED
@@ -54,9 +54,8 @@ module Puma
|
|
54
54
|
|
55
55
|
app = Puma::App::Status.new @launcher, token
|
56
56
|
|
57
|
-
control = Puma::Server.new app, @launcher.events
|
58
|
-
|
59
|
-
control.max_threads = 1
|
57
|
+
control = Puma::Server.new app, @launcher.events,
|
58
|
+
{ min_threads: 0, max_threads: 1 }
|
60
59
|
|
61
60
|
control.binder.parse [str], self, 'Starting control server'
|
62
61
|
|
@@ -69,6 +68,7 @@ module Puma
|
|
69
68
|
@control.binder.close_listeners if @control
|
70
69
|
end
|
71
70
|
|
71
|
+
# @!attribute [r] ruby_engine
|
72
72
|
def ruby_engine
|
73
73
|
if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
|
74
74
|
"ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
|
@@ -137,27 +137,14 @@ module Puma
|
|
137
137
|
@launcher.binder.parse @options[:binds], self
|
138
138
|
end
|
139
139
|
|
140
|
+
# @!attribute [r] app
|
140
141
|
def app
|
141
142
|
@app ||= @launcher.config.app
|
142
143
|
end
|
143
144
|
|
144
145
|
def start_server
|
145
|
-
min_t = @options[:min_threads]
|
146
|
-
max_t = @options[:max_threads]
|
147
|
-
|
148
146
|
server = Puma::Server.new app, @launcher.events, @options
|
149
|
-
server.min_threads = min_t
|
150
|
-
server.max_threads = max_t
|
151
147
|
server.inherit_binder @launcher.binder
|
152
|
-
|
153
|
-
if @options[:early_hints]
|
154
|
-
server.early_hints = true
|
155
|
-
end
|
156
|
-
|
157
|
-
unless development? || test?
|
158
|
-
server.leak_stack_on_error = false
|
159
|
-
end
|
160
|
-
|
161
148
|
server
|
162
149
|
end
|
163
150
|
end
|
data/lib/puma/server.rb
CHANGED
@@ -34,15 +34,21 @@ module Puma
|
|
34
34
|
|
35
35
|
attr_reader :thread
|
36
36
|
attr_reader :events
|
37
|
-
attr_reader :
|
37
|
+
attr_reader :min_threads, :max_threads # for #stats
|
38
|
+
attr_reader :requests_count # @version 5.0.0
|
39
|
+
|
40
|
+
# the following may be deprecated in the future
|
41
|
+
attr_reader :auto_trim_time
|
42
|
+
attr_reader :first_data_timeout
|
43
|
+
attr_reader :persistent_timeout
|
44
|
+
attr_reader :reaping_time
|
45
|
+
|
38
46
|
attr_accessor :app
|
47
|
+
attr_accessor :binder
|
39
48
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
attr_accessor :auto_trim_time
|
44
|
-
attr_accessor :reaping_time
|
45
|
-
attr_accessor :first_data_timeout
|
49
|
+
def_delegators :@binder, :add_tcp_listener, :add_ssl_listener, :add_unix_listener, :connected_ports
|
50
|
+
|
51
|
+
ThreadLocalKey = :puma_server
|
46
52
|
|
47
53
|
# Create a server for the rack app +app+.
|
48
54
|
#
|
@@ -52,6 +58,10 @@ module Puma
|
|
52
58
|
# Server#run returns a thread that you can join on to wait for the server
|
53
59
|
# to do its work.
|
54
60
|
#
|
61
|
+
# @note Several instance variables exist so they are available for testing,
|
62
|
+
# and have default values set via +fetch+. Normally the values are set via
|
63
|
+
# `::Puma::Configuration.puma_default_options`.
|
64
|
+
#
|
55
65
|
def initialize(app, events=Events.stdio, options={})
|
56
66
|
@app = app
|
57
67
|
@events = events
|
@@ -59,24 +69,24 @@ module Puma
|
|
59
69
|
@check, @notify = nil
|
60
70
|
@status = :stop
|
61
71
|
|
62
|
-
@min_threads = 0
|
63
|
-
@max_threads = 16
|
64
72
|
@auto_trim_time = 30
|
65
73
|
@reaping_time = 1
|
66
74
|
|
67
75
|
@thread = nil
|
68
76
|
@thread_pool = nil
|
69
|
-
@early_hints = nil
|
70
77
|
|
71
|
-
@
|
72
|
-
@first_data_timeout = options.fetch(:first_data_timeout, FIRST_DATA_TIMEOUT)
|
78
|
+
@options = options
|
73
79
|
|
74
|
-
@
|
80
|
+
@early_hints = options.fetch :early_hints, nil
|
81
|
+
@first_data_timeout = options.fetch :first_data_timeout, FIRST_DATA_TIMEOUT
|
82
|
+
@min_threads = options.fetch :min_threads, 0
|
83
|
+
@max_threads = options.fetch :max_threads , (Puma.mri? ? 5 : 16)
|
84
|
+
@persistent_timeout = options.fetch :persistent_timeout, PERSISTENT_TIMEOUT
|
85
|
+
@queue_requests = options.fetch :queue_requests, true
|
75
86
|
|
76
|
-
@leak_stack_on_error =
|
87
|
+
@leak_stack_on_error = !!(@options[:environment] =~ /\A(development|test)\z/)
|
77
88
|
|
78
|
-
@
|
79
|
-
@queue_requests = options[:queue_requests].nil? ? true : options[:queue_requests]
|
89
|
+
@binder = Binder.new(events)
|
80
90
|
|
81
91
|
ENV['RACK_ENV'] ||= "development"
|
82
92
|
|
@@ -85,26 +95,37 @@ module Puma
|
|
85
95
|
@precheck_closing = true
|
86
96
|
|
87
97
|
@requests_count = 0
|
88
|
-
end
|
89
98
|
|
90
|
-
|
91
|
-
|
92
|
-
def_delegators :@binder, :add_tcp_listener, :add_ssl_listener, :add_unix_listener, :connected_ports
|
99
|
+
@shutdown_mutex = Mutex.new
|
100
|
+
end
|
93
101
|
|
94
102
|
def inherit_binder(bind)
|
95
103
|
@binder = bind
|
96
104
|
end
|
97
105
|
|
98
106
|
class << self
|
107
|
+
# @!attribute [r] current
|
108
|
+
def current
|
109
|
+
Thread.current[ThreadLocalKey]
|
110
|
+
end
|
111
|
+
|
99
112
|
# :nodoc:
|
100
113
|
# @version 5.0.0
|
101
114
|
def tcp_cork_supported?
|
102
115
|
RbConfig::CONFIG['host_os'] =~ /linux/ &&
|
103
116
|
Socket.const_defined?(:IPPROTO_TCP) &&
|
104
|
-
Socket.const_defined?(:TCP_CORK)
|
117
|
+
Socket.const_defined?(:TCP_CORK)
|
118
|
+
end
|
119
|
+
|
120
|
+
# :nodoc:
|
121
|
+
# @version 5.0.0
|
122
|
+
def closed_socket_supported?
|
123
|
+
RbConfig::CONFIG['host_os'] =~ /linux/ &&
|
124
|
+
Socket.const_defined?(:IPPROTO_TCP) &&
|
105
125
|
Socket.const_defined?(:TCP_INFO)
|
106
126
|
end
|
107
127
|
private :tcp_cork_supported?
|
128
|
+
private :closed_socket_supported?
|
108
129
|
end
|
109
130
|
|
110
131
|
# On Linux, use TCP_CORK to better control how the TCP stack
|
@@ -131,7 +152,15 @@ module Puma
|
|
131
152
|
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
132
153
|
end
|
133
154
|
end
|
155
|
+
else
|
156
|
+
def cork_socket(socket)
|
157
|
+
end
|
158
|
+
|
159
|
+
def uncork_socket(socket)
|
160
|
+
end
|
161
|
+
end
|
134
162
|
|
163
|
+
if closed_socket_supported?
|
135
164
|
def closed_socket?(socket)
|
136
165
|
return false unless socket.kind_of? TCPSocket
|
137
166
|
return false unless @precheck_closing
|
@@ -149,21 +178,17 @@ module Puma
|
|
149
178
|
end
|
150
179
|
end
|
151
180
|
else
|
152
|
-
def cork_socket(socket)
|
153
|
-
end
|
154
|
-
|
155
|
-
def uncork_socket(socket)
|
156
|
-
end
|
157
|
-
|
158
181
|
def closed_socket?(socket)
|
159
182
|
false
|
160
183
|
end
|
161
184
|
end
|
162
185
|
|
186
|
+
# @!attribute [r] backlog
|
163
187
|
def backlog
|
164
188
|
@thread_pool and @thread_pool.backlog
|
165
189
|
end
|
166
190
|
|
191
|
+
# @!attribute [r] running
|
167
192
|
def running
|
168
193
|
@thread_pool and @thread_pool.spawned
|
169
194
|
end
|
@@ -176,6 +201,7 @@ module Puma
|
|
176
201
|
# there are 5 threads sitting idle ready to take
|
177
202
|
# a request. If one request comes in, then the
|
178
203
|
# value would be 4 until it finishes processing.
|
204
|
+
# @!attribute [r] pool_capacity
|
179
205
|
def pool_capacity
|
180
206
|
@thread_pool and @thread_pool.pool_capacity
|
181
207
|
end
|
@@ -206,33 +232,36 @@ module Puma
|
|
206
232
|
if @queue_requests
|
207
233
|
process_now = client.eagerly_finish
|
208
234
|
else
|
209
|
-
|
235
|
+
@thread_pool.with_force_shutdown do
|
236
|
+
client.finish(@first_data_timeout)
|
237
|
+
end
|
210
238
|
process_now = true
|
211
239
|
end
|
212
240
|
rescue MiniSSL::SSLError => e
|
213
|
-
|
214
|
-
addr = ssl_socket.peeraddr.last
|
215
|
-
cert = ssl_socket.peercert
|
216
|
-
|
241
|
+
@events.ssl_error e, client.io
|
217
242
|
client.close
|
218
243
|
|
219
|
-
@events.ssl_error e, addr, cert
|
220
244
|
rescue HttpParserError => e
|
221
245
|
client.write_error(400)
|
222
246
|
client.close
|
223
247
|
|
224
248
|
@events.parse_error e, client
|
225
|
-
rescue
|
249
|
+
rescue EOFError => e
|
250
|
+
client.close
|
251
|
+
|
252
|
+
# Swallow, do not log
|
253
|
+
rescue ConnectionError, ThreadPool::ForceShutdown => e
|
226
254
|
client.close
|
227
255
|
|
228
256
|
@events.connection_error e, client
|
229
257
|
else
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
258
|
+
process_now ||= @shutdown_mutex.synchronize do
|
259
|
+
next true unless @queue_requests
|
260
|
+
client.set_timeout @first_data_timeout
|
261
|
+
@reactor.add client
|
262
|
+
false
|
263
|
+
end
|
264
|
+
process_client client, buffer if process_now
|
236
265
|
end
|
237
266
|
|
238
267
|
process_now
|
@@ -318,7 +347,9 @@ module Puma
|
|
318
347
|
@events.fire :state, @status
|
319
348
|
|
320
349
|
if queue_requests
|
321
|
-
@
|
350
|
+
@shutdown_mutex.synchronize do
|
351
|
+
@queue_requests = false
|
352
|
+
end
|
322
353
|
@reactor.clear!
|
323
354
|
@reactor.shutdown
|
324
355
|
end
|
@@ -397,32 +428,32 @@ module Puma
|
|
397
428
|
check_for_more_data = false
|
398
429
|
end
|
399
430
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
431
|
+
next_request_ready = @thread_pool.with_force_shutdown do
|
432
|
+
client.reset(check_for_more_data)
|
433
|
+
end
|
434
|
+
|
435
|
+
unless next_request_ready
|
436
|
+
@shutdown_mutex.synchronize do
|
437
|
+
return unless @queue_requests
|
438
|
+
close_socket = false
|
439
|
+
client.set_timeout @persistent_timeout
|
440
|
+
@reactor.add client
|
441
|
+
return
|
442
|
+
end
|
406
443
|
end
|
407
444
|
end
|
408
445
|
end
|
409
446
|
|
410
447
|
# The client disconnected while we were reading data
|
411
|
-
rescue ConnectionError
|
448
|
+
rescue ConnectionError, ThreadPool::ForceShutdown
|
412
449
|
# Swallow them. The ensure tries to close +client+ down
|
413
450
|
|
414
451
|
# SSL handshake error
|
415
452
|
rescue MiniSSL::SSLError => e
|
416
|
-
lowlevel_error
|
417
|
-
|
418
|
-
ssl_socket = client.io
|
419
|
-
addr = ssl_socket.peeraddr.last
|
420
|
-
cert = ssl_socket.peercert
|
421
|
-
|
453
|
+
lowlevel_error e, client.env
|
454
|
+
@events.ssl_error e, client.io
|
422
455
|
close_socket = true
|
423
456
|
|
424
|
-
@events.ssl_error e, addr, cert
|
425
|
-
|
426
457
|
# The client doesn't know HTTP well
|
427
458
|
rescue HttpParserError => e
|
428
459
|
lowlevel_error(e, client.env)
|
@@ -617,7 +648,9 @@ module Puma
|
|
617
648
|
|
618
649
|
begin
|
619
650
|
begin
|
620
|
-
status, headers, res_body = @
|
651
|
+
status, headers, res_body = @thread_pool.with_force_shutdown do
|
652
|
+
@app.call(env)
|
653
|
+
end
|
621
654
|
|
622
655
|
return :async if req.hijacked
|
623
656
|
|
@@ -915,7 +948,7 @@ module Puma
|
|
915
948
|
|
916
949
|
if @thread_pool
|
917
950
|
if timeout = @options[:force_shutdown_after]
|
918
|
-
@thread_pool.shutdown timeout.
|
951
|
+
@thread_pool.shutdown timeout.to_f
|
919
952
|
else
|
920
953
|
@thread_pool.shutdown
|
921
954
|
end
|
@@ -979,12 +1012,6 @@ module Puma
|
|
979
1012
|
end
|
980
1013
|
private :fast_write
|
981
1014
|
|
982
|
-
ThreadLocalKey = :puma_server
|
983
|
-
|
984
|
-
def self.current
|
985
|
-
Thread.current[ThreadLocalKey]
|
986
|
-
end
|
987
|
-
|
988
1015
|
def shutting_down?
|
989
1016
|
@status == :stop || @status == :restart
|
990
1017
|
end
|
@@ -1000,6 +1027,7 @@ module Puma
|
|
1000
1027
|
|
1001
1028
|
# Returns a hash of stats about the running server for reporting purposes.
|
1002
1029
|
# @version 5.0.0
|
1030
|
+
# @!attribute [r] stats
|
1003
1031
|
def stats
|
1004
1032
|
STAT_METHODS.map {|name| [name, send(name) || 0]}.to_h
|
1005
1033
|
end
|