puma 3.6.2 → 3.7.0
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/Gemfile +3 -4
- data/{History.txt → History.md} +121 -82
- data/Manifest.txt +1 -3
- data/README.md +7 -1
- data/Rakefile +4 -4
- data/docs/systemd.md +27 -0
- data/ext/puma_http11/http11_parser.c +1 -0
- data/ext/puma_http11/http11_parser.h +1 -0
- data/ext/puma_http11/http11_parser.rl +1 -0
- data/ext/puma_http11/io_buffer.c +7 -7
- data/ext/puma_http11/mini_ssl.c +17 -6
- data/ext/puma_http11/puma_http11.c +1 -0
- data/lib/puma.rb +5 -5
- data/lib/puma/binder.rb +6 -3
- data/lib/puma/cli.rb +3 -0
- data/lib/puma/client.rb +4 -4
- data/lib/puma/cluster.rb +25 -4
- data/lib/puma/commonlogger.rb +19 -20
- data/lib/puma/compat.rb +3 -7
- data/lib/puma/configuration.rb +3 -1
- data/lib/puma/const.rb +7 -36
- data/lib/puma/control_cli.rb +27 -27
- data/lib/puma/detect.rb +3 -1
- data/lib/puma/events.rb +5 -6
- data/lib/puma/io_buffer.rb +1 -1
- data/lib/puma/launcher.rb +10 -9
- data/lib/puma/null_io.rb +6 -13
- data/lib/puma/rack/builder.rb +3 -0
- data/lib/puma/rack/urlmap.rb +9 -8
- data/lib/puma/runner.rb +11 -0
- data/lib/puma/single.rb +2 -0
- data/lib/puma/thread_pool.rb +13 -13
- data/lib/puma/util.rb +1 -5
- data/lib/rack/handler/puma.rb +9 -2
- data/puma.gemspec +1 -1
- data/tools/jungle/init.d/README.md +7 -2
- data/tools/jungle/init.d/puma +1 -1
- metadata +7 -9
- data/lib/puma/rack/backports/uri/common_18.rb +0 -59
- data/lib/puma/rack/backports/uri/common_192.rb +0 -55
data/lib/puma/compat.rb
CHANGED
@@ -6,13 +6,9 @@ class String
|
|
6
6
|
end
|
7
7
|
|
8
8
|
unless method_defined? :byteslice
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def byteslice(*arg)
|
13
|
-
enc = self.encoding
|
14
|
-
self.dup.force_encoding(Encoding::ASCII_8BIT).slice(*arg).force_encoding(enc)
|
15
|
-
end
|
9
|
+
def byteslice(*arg)
|
10
|
+
enc = self.encoding
|
11
|
+
self.dup.force_encoding(Encoding::ASCII_8BIT).slice(*arg).force_encoding(enc)
|
16
12
|
end
|
17
13
|
end
|
18
14
|
end
|
data/lib/puma/configuration.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'puma/rack/builder'
|
2
2
|
require 'puma/plugin'
|
3
|
+
require 'puma/const'
|
3
4
|
|
4
5
|
module Puma
|
5
6
|
|
@@ -30,7 +31,7 @@ module Puma
|
|
30
31
|
end
|
31
32
|
|
32
33
|
def [](key)
|
33
|
-
@set.
|
34
|
+
@set.reverse_each do |o|
|
34
35
|
if o.key? key
|
35
36
|
return o[key]
|
36
37
|
end
|
@@ -251,6 +252,7 @@ module Puma
|
|
251
252
|
end
|
252
253
|
|
253
254
|
if @options[:log_requests]
|
255
|
+
require 'puma/commonlogger'
|
254
256
|
logger = @options[:logger]
|
255
257
|
found = CommonLogger.new(found, logger)
|
256
258
|
end
|
data/lib/puma/const.rb
CHANGED
@@ -73,19 +73,14 @@ module Puma
|
|
73
73
|
511 => 'Network Authentication Required'
|
74
74
|
}
|
75
75
|
|
76
|
-
SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
|
77
|
-
[message.downcase.gsub(/\s|-|'/, '_').to_sym, code]
|
78
|
-
}.flatten]
|
79
|
-
|
80
76
|
# For some HTTP status codes the client only expects headers.
|
81
77
|
#
|
82
78
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
STATUS_WITH_NO_ENTITY_BODY = no_body
|
79
|
+
STATUS_WITH_NO_ENTITY_BODY = {
|
80
|
+
204 => true,
|
81
|
+
205 => true,
|
82
|
+
304 => true
|
83
|
+
}
|
89
84
|
|
90
85
|
# Frequently used constants when constructing requests or responses. Many times
|
91
86
|
# the constant just refers to a string with the same contents. Using these constants
|
@@ -100,8 +95,8 @@ module Puma
|
|
100
95
|
# too taxing on performance.
|
101
96
|
module Const
|
102
97
|
|
103
|
-
PUMA_VERSION = VERSION = "3.
|
104
|
-
CODE_NAME = "
|
98
|
+
PUMA_VERSION = VERSION = "3.7.0".freeze
|
99
|
+
CODE_NAME = "Snowy Sagebrush".freeze
|
105
100
|
PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
|
106
101
|
|
107
102
|
FAST_TRACK_KA_TIMEOUT = 0.2
|
@@ -118,15 +113,6 @@ module Puma
|
|
118
113
|
# sending data back
|
119
114
|
WRITE_TIMEOUT = 10
|
120
115
|
|
121
|
-
# How long, after raising the ForceShutdown of a thread during
|
122
|
-
# forced shutdown mode, to wait for the thread to try and finish
|
123
|
-
# up it's work before leaving the thread to die on the vine.
|
124
|
-
SHUTDOWN_GRACE_TIME = 5 # seconds
|
125
|
-
|
126
|
-
DATE = "Date".freeze
|
127
|
-
|
128
|
-
SCRIPT_NAME = "SCRIPT_NAME".freeze
|
129
|
-
|
130
116
|
# The original URI requested by the client.
|
131
117
|
REQUEST_URI= 'REQUEST_URI'.freeze
|
132
118
|
REQUEST_PATH = 'REQUEST_PATH'.freeze
|
@@ -163,26 +149,12 @@ module Puma
|
|
163
149
|
# Maximum request body size before it is moved out of memory and into a tempfile for reading.
|
164
150
|
MAX_BODY = MAX_HEADER
|
165
151
|
|
166
|
-
# A frozen format for this is about 15% faster
|
167
|
-
STATUS_FORMAT = "HTTP/1.1 %d %s\r\nConnection: close\r\n".freeze
|
168
|
-
|
169
|
-
CONTENT_TYPE = "Content-Type".freeze
|
170
|
-
|
171
|
-
LAST_MODIFIED = "Last-Modified".freeze
|
172
|
-
ETAG = "ETag".freeze
|
173
|
-
SLASH = "/".freeze
|
174
152
|
REQUEST_METHOD = "REQUEST_METHOD".freeze
|
175
|
-
GET = "GET".freeze
|
176
153
|
HEAD = "HEAD".freeze
|
177
154
|
# ETag is based on the apache standard of hex mtime-size-inode (inode is 0 on win32)
|
178
|
-
ETAG_FORMAT = "\"%x-%x-%x\"".freeze
|
179
155
|
LINE_END = "\r\n".freeze
|
180
156
|
REMOTE_ADDR = "REMOTE_ADDR".freeze
|
181
157
|
HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze
|
182
|
-
HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE".freeze
|
183
|
-
HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH".freeze
|
184
|
-
REDIRECT = "HTTP/1.1 302 Found\r\nLocation: %s\r\nConnection: close\r\n\r\n".freeze
|
185
|
-
HOST = "HOST".freeze
|
186
158
|
|
187
159
|
SERVER_NAME = "SERVER_NAME".freeze
|
188
160
|
SERVER_PORT = "SERVER_PORT".freeze
|
@@ -195,7 +167,6 @@ module Puma
|
|
195
167
|
|
196
168
|
SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
|
197
169
|
HTTP_11 = "HTTP/1.1".freeze
|
198
|
-
HTTP_10 = "HTTP/1.0".freeze
|
199
170
|
|
200
171
|
SERVER_SOFTWARE = "SERVER_SOFTWARE".freeze
|
201
172
|
GATEWAY_INTERFACE = "GATEWAY_INTERFACE".freeze
|
data/lib/puma/control_cli.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'optparse'
|
2
|
-
require 'puma'
|
2
|
+
require 'puma/state_file'
|
3
3
|
require 'puma/const'
|
4
4
|
require 'puma/detect'
|
5
5
|
require 'puma/configuration'
|
@@ -179,39 +179,39 @@ module Puma
|
|
179
179
|
end
|
180
180
|
|
181
181
|
begin
|
182
|
-
Process.getpgid @pid
|
183
|
-
rescue SystemCallError
|
184
|
-
if @command == "restart"
|
185
|
-
start
|
186
|
-
else
|
187
|
-
raise "No pid '#{@pid}' found"
|
188
|
-
end
|
189
|
-
end
|
190
182
|
|
191
|
-
|
192
|
-
|
193
|
-
|
183
|
+
case @command
|
184
|
+
when "restart"
|
185
|
+
Process.kill "SIGUSR2", @pid
|
194
186
|
|
195
|
-
|
196
|
-
|
187
|
+
when "halt"
|
188
|
+
Process.kill "QUIT", @pid
|
197
189
|
|
198
|
-
|
199
|
-
|
190
|
+
when "stop"
|
191
|
+
Process.kill "SIGTERM", @pid
|
200
192
|
|
201
|
-
|
202
|
-
|
203
|
-
|
193
|
+
when "stats"
|
194
|
+
puts "Stats not available via pid only"
|
195
|
+
return
|
204
196
|
|
205
|
-
|
206
|
-
|
207
|
-
|
197
|
+
when "reload-worker-directory"
|
198
|
+
puts "reload-worker-directory not available via pid only"
|
199
|
+
return
|
208
200
|
|
209
|
-
|
210
|
-
|
201
|
+
when "phased-restart"
|
202
|
+
Process.kill "SIGUSR1", @pid
|
211
203
|
|
212
|
-
|
213
|
-
|
214
|
-
|
204
|
+
else
|
205
|
+
message "Puma is started"
|
206
|
+
return
|
207
|
+
end
|
208
|
+
|
209
|
+
rescue SystemCallError
|
210
|
+
if @command == "restart"
|
211
|
+
start
|
212
|
+
else
|
213
|
+
raise "No pid '#{@pid}' found"
|
214
|
+
end
|
215
215
|
end
|
216
216
|
|
217
217
|
message "Command #{@command} sent success"
|
data/lib/puma/detect.rb
CHANGED
data/lib/puma/events.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'puma/const'
|
2
|
+
require "puma/null_io"
|
2
3
|
require 'stringio'
|
3
4
|
|
4
5
|
module Puma
|
@@ -34,8 +35,6 @@ module Puma
|
|
34
35
|
|
35
36
|
@debug = ENV.key? 'PUMA_DEBUG'
|
36
37
|
|
37
|
-
@on_booted = []
|
38
|
-
|
39
38
|
@hooks = Hash.new { |h,k| h[k] = [] }
|
40
39
|
end
|
41
40
|
|
@@ -48,7 +47,7 @@ module Puma
|
|
48
47
|
@hooks[hook].each { |t| t.call(*args) }
|
49
48
|
end
|
50
49
|
|
51
|
-
# Register a
|
50
|
+
# Register a callback for a given hook
|
52
51
|
#
|
53
52
|
def register(hook, obj=nil, &blk)
|
54
53
|
if obj and blk
|
@@ -124,12 +123,12 @@ module Puma
|
|
124
123
|
end
|
125
124
|
end
|
126
125
|
|
127
|
-
def on_booted(&
|
128
|
-
|
126
|
+
def on_booted(&block)
|
127
|
+
register(:on_booted, &block)
|
129
128
|
end
|
130
129
|
|
131
130
|
def fire_on_booted!
|
132
|
-
|
131
|
+
fire(:on_booted)
|
133
132
|
end
|
134
133
|
|
135
134
|
DEFAULT = new(STDOUT, STDERR)
|
data/lib/puma/io_buffer.rb
CHANGED
data/lib/puma/launcher.rb
CHANGED
@@ -1,15 +1,12 @@
|
|
1
|
-
require 'puma/
|
2
|
-
require 'puma/const'
|
3
|
-
require 'puma/configuration'
|
4
|
-
require 'puma/binder'
|
1
|
+
require 'puma/events'
|
5
2
|
require 'puma/detect'
|
6
|
-
|
7
|
-
require 'puma/util'
|
8
|
-
require 'puma/single'
|
3
|
+
|
9
4
|
require 'puma/cluster'
|
10
|
-
require 'puma/
|
5
|
+
require 'puma/single'
|
11
6
|
|
12
|
-
require 'puma/
|
7
|
+
require 'puma/const'
|
8
|
+
|
9
|
+
require 'puma/binder'
|
13
10
|
|
14
11
|
module Puma
|
15
12
|
# Puma::Launcher is the single entry point for starting a Puma server based on user
|
@@ -107,6 +104,8 @@ module Puma
|
|
107
104
|
path = @options[:state]
|
108
105
|
return unless path
|
109
106
|
|
107
|
+
require 'puma/state_file'
|
108
|
+
|
110
109
|
sf = StateFile.new
|
111
110
|
sf.pid = Process.pid
|
112
111
|
sf.control_url = @options[:control_url]
|
@@ -256,6 +255,8 @@ module Puma
|
|
256
255
|
ENV['PUMA_BUNDLER_PRUNED'] = '1'
|
257
256
|
wild = File.expand_path(File.join(puma_lib_dir, "../bin/puma-wild"))
|
258
257
|
args = [Gem.ruby, wild, '-I', dirs.join(':'), deps.join(',')] + @original_argv
|
258
|
+
# Ruby 2.0+ defaults to true which breaks socket activation
|
259
|
+
args += [{:close_others => false}] if RUBY_VERSION >= '2.0'
|
259
260
|
Kernel.exec(*args)
|
260
261
|
end
|
261
262
|
end
|
data/lib/puma/null_io.rb
CHANGED
@@ -1,42 +1,35 @@
|
|
1
1
|
module Puma
|
2
|
-
|
3
2
|
# Provides an IO-like object that always appears to contain no data.
|
4
3
|
# Used as the value for rack.input when the request has no body.
|
5
4
|
#
|
6
5
|
class NullIO
|
7
|
-
# Always returns nil
|
8
|
-
#
|
9
6
|
def gets
|
10
7
|
nil
|
11
8
|
end
|
12
9
|
|
13
|
-
# Never yields
|
14
|
-
#
|
15
10
|
def each
|
16
11
|
end
|
17
12
|
|
18
|
-
# Mimics IO#read with no data
|
13
|
+
# Mimics IO#read with no data.
|
19
14
|
#
|
20
|
-
def read(count=nil,
|
15
|
+
def read(count = nil, _buffer = nil)
|
21
16
|
(count && count > 0) ? nil : ""
|
22
17
|
end
|
23
18
|
|
24
|
-
# Does nothing
|
25
|
-
#
|
26
19
|
def rewind
|
27
20
|
end
|
28
21
|
|
29
|
-
# Does nothing
|
30
|
-
#
|
31
22
|
def close
|
32
23
|
end
|
33
24
|
|
34
|
-
# Always zero
|
35
|
-
#
|
36
25
|
def size
|
37
26
|
0
|
38
27
|
end
|
39
28
|
|
29
|
+
def eof?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
40
33
|
def sync=(v)
|
41
34
|
end
|
42
35
|
|
data/lib/puma/rack/builder.rb
CHANGED
data/lib/puma/rack/urlmap.rb
CHANGED
@@ -43,15 +43,17 @@ module Puma::Rack
|
|
43
43
|
def call(env)
|
44
44
|
path = env['PATH_INFO']
|
45
45
|
script_name = env['SCRIPT_NAME']
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
http_host = env['HTTP_HOST']
|
47
|
+
server_name = env['SERVER_NAME']
|
48
|
+
server_port = env['SERVER_PORT']
|
49
|
+
|
50
|
+
is_same_server = casecmp?(http_host, server_name) ||
|
51
|
+
casecmp?(http_host, "#{server_name}:#{server_port}")
|
49
52
|
|
50
53
|
@mapping.each do |host, location, match, app|
|
51
|
-
unless casecmp?(
|
52
|
-
|| casecmp?(
|
53
|
-
|| (!host &&
|
54
|
-
casecmp?(hHost, sName+':'+sPort)))
|
54
|
+
unless casecmp?(http_host, host) \
|
55
|
+
|| casecmp?(server_name, host) \
|
56
|
+
|| (!host && is_same_server)
|
55
57
|
next
|
56
58
|
end
|
57
59
|
|
@@ -87,4 +89,3 @@ module Puma::Rack
|
|
87
89
|
end
|
88
90
|
end
|
89
91
|
end
|
90
|
-
|
data/lib/puma/runner.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'puma/server'
|
2
|
+
require 'puma/const'
|
3
|
+
|
1
4
|
module Puma
|
2
5
|
class Runner
|
3
6
|
def initialize(cli, events)
|
@@ -104,12 +107,20 @@ module Puma
|
|
104
107
|
append = @options[:redirect_append]
|
105
108
|
|
106
109
|
if stdout
|
110
|
+
unless Dir.exists?(File.dirname(stdout))
|
111
|
+
raise "Cannot redirect STDOUT to #{stdout}"
|
112
|
+
end
|
113
|
+
|
107
114
|
STDOUT.reopen stdout, (append ? "a" : "w")
|
108
115
|
STDOUT.sync = true
|
109
116
|
STDOUT.puts "=== puma startup: #{Time.now} ==="
|
110
117
|
end
|
111
118
|
|
112
119
|
if stderr
|
120
|
+
unless Dir.exists?(File.dirname(stderr))
|
121
|
+
raise "Cannot redirect STDERR to #{stderr}"
|
122
|
+
end
|
123
|
+
|
113
124
|
STDERR.reopen stderr, (append ? "a" : "w")
|
114
125
|
STDERR.sync = true
|
115
126
|
STDERR.puts "=== puma startup: #{Time.now} ==="
|
data/lib/puma/single.rb
CHANGED
data/lib/puma/thread_pool.rb
CHANGED
@@ -4,10 +4,14 @@ module Puma
|
|
4
4
|
# A simple thread pool management object.
|
5
5
|
#
|
6
6
|
class ThreadPool
|
7
|
-
|
8
7
|
class ForceShutdown < RuntimeError
|
9
8
|
end
|
10
9
|
|
10
|
+
# How long, after raising the ForceShutdown of a thread during
|
11
|
+
# forced shutdown mode, to wait for the thread to try and finish
|
12
|
+
# up its work before leaving the thread to die on the vine.
|
13
|
+
SHUTDOWN_GRACE_TIME = 5 # seconds
|
14
|
+
|
11
15
|
# Maintain a minimum of +min+ and maximum of +max+ threads
|
12
16
|
# in the pool.
|
13
17
|
#
|
@@ -181,7 +185,9 @@ module Puma
|
|
181
185
|
@spawned -= 1
|
182
186
|
end
|
183
187
|
|
184
|
-
@workers
|
188
|
+
@workers.delete_if do |w|
|
189
|
+
dead_workers.include?(w)
|
190
|
+
end
|
185
191
|
end
|
186
192
|
end
|
187
193
|
|
@@ -257,18 +263,12 @@ module Puma
|
|
257
263
|
@workers.dup
|
258
264
|
end
|
259
265
|
|
260
|
-
|
261
|
-
|
266
|
+
if timeout == -1
|
267
|
+
# Wait for threads to finish without force shutdown.
|
262
268
|
threads.each(&:join)
|
263
|
-
when 0
|
264
|
-
threads.each do |t|
|
265
|
-
t.raise ForceShutdown
|
266
|
-
end
|
267
|
-
|
268
|
-
threads.each do |t|
|
269
|
-
t.join Const::SHUTDOWN_GRACE_TIME
|
270
|
-
end
|
271
269
|
else
|
270
|
+
# Wait for threads to finish after n attempts (+timeout+).
|
271
|
+
# If threads are still running, it will forcefully kill them.
|
272
272
|
timeout.times do
|
273
273
|
threads.delete_if do |t|
|
274
274
|
t.join 1
|
@@ -286,7 +286,7 @@ module Puma
|
|
286
286
|
end
|
287
287
|
|
288
288
|
threads.each do |t|
|
289
|
-
t.join
|
289
|
+
t.join SHUTDOWN_GRACE_TIME
|
290
290
|
end
|
291
291
|
end
|
292
292
|
|