puma 2.12.3 → 2.16.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/DEPLOYMENT.md +3 -3
- data/History.txt +164 -0
- data/README.md +21 -2
- data/docs/nginx.md +1 -1
- data/ext/puma_http11/extconf.rb +8 -4
- data/ext/puma_http11/mini_ssl.c +36 -3
- data/ext/puma_http11/org/jruby/puma/Http11.java +12 -3
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +21 -74
- data/ext/puma_http11/puma_http11.c +12 -4
- data/lib/puma/binder.rb +9 -2
- data/lib/puma/capistrano.rb +2 -0
- data/lib/puma/cli.rb +57 -52
- data/lib/puma/client.rb +19 -0
- data/lib/puma/cluster.rb +24 -3
- data/lib/puma/configuration.rb +63 -12
- data/lib/puma/const.rb +6 -5
- data/lib/puma/control_cli.rb +24 -14
- data/lib/puma/dsl.rb +71 -3
- data/lib/puma/events.rb +1 -1
- data/lib/puma/minissl.rb +2 -0
- data/lib/puma/runner.rb +2 -1
- data/lib/puma/server.rb +23 -7
- data/lib/puma/single.rb +1 -1
- data/lib/puma/thread_pool.rb +5 -7
- data/lib/rack/handler/puma.rb +13 -9
- data/tools/jungle/init.d/puma +50 -3
- metadata +5 -5
data/lib/puma/dsl.rb
CHANGED
@@ -42,6 +42,7 @@ module Puma
|
|
42
42
|
@options[:control_auth_token] = auth_token if auth_token
|
43
43
|
|
44
44
|
@options[:control_auth_token] = :none if opts[:no_token]
|
45
|
+
@options[:control_url_umask] = opts[:umask] if opts[:umask]
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
@@ -132,7 +133,7 @@ module Puma
|
|
132
133
|
min = Integer(min)
|
133
134
|
max = Integer(max)
|
134
135
|
if min > max
|
135
|
-
raise "The minimum (#{min}) number of threads must be less than the max (#{max})"
|
136
|
+
raise "The minimum (#{min}) number of threads must be less than or equal to the max (#{max})"
|
136
137
|
end
|
137
138
|
|
138
139
|
@options[:min_threads] = min
|
@@ -140,7 +141,12 @@ module Puma
|
|
140
141
|
end
|
141
142
|
|
142
143
|
def ssl_bind(host, port, opts)
|
143
|
-
|
144
|
+
if defined?(JRUBY_VERSION)
|
145
|
+
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
146
|
+
@options[:binds] << "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}"
|
147
|
+
else
|
148
|
+
@options[:binds] << "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}"
|
149
|
+
end
|
144
150
|
end
|
145
151
|
|
146
152
|
# Use +path+ as the file to store the server info state. This is
|
@@ -156,6 +162,19 @@ module Puma
|
|
156
162
|
@options[:workers] = count.to_i
|
157
163
|
end
|
158
164
|
|
165
|
+
# *Cluster mode only* Code to run immediately before master process
|
166
|
+
# forks workers (once on boot). These hooks can block if necessary
|
167
|
+
# to wait for background operations unknown to puma to finish before
|
168
|
+
# the process terminates.
|
169
|
+
# This can be used to close any connections to remote servers (database, redis, ...)
|
170
|
+
# that were opened when preloading the code
|
171
|
+
#
|
172
|
+
# This can be called multiple times to add hooks.
|
173
|
+
#
|
174
|
+
def before_fork(&block)
|
175
|
+
@options[:before_fork] << block
|
176
|
+
end
|
177
|
+
|
159
178
|
# *Cluster mode only* Code to run immediately before a worker shuts
|
160
179
|
# down (after it has finished processing HTTP requests). These hooks
|
161
180
|
# can block if necessary to wait for background operations unknown
|
@@ -243,11 +262,19 @@ module Puma
|
|
243
262
|
@options[:tag] = string
|
244
263
|
end
|
245
264
|
|
246
|
-
# *Cluster mode only* Set the timeout for workers
|
265
|
+
# *Cluster mode only* Set the timeout for workers in seconds
|
266
|
+
# When set the master process will terminate any workers
|
267
|
+
# that have not checked in within the given +timeout+.
|
268
|
+
# This mitigates hung processes. Default value is 60 seconds.
|
247
269
|
def worker_timeout(timeout)
|
248
270
|
@options[:worker_timeout] = timeout
|
249
271
|
end
|
250
272
|
|
273
|
+
# *Cluster mode only* Set the timeout for workers to boot
|
274
|
+
def worker_boot_timeout(timeout)
|
275
|
+
@options[:worker_boot_timeout] = timeout
|
276
|
+
end
|
277
|
+
|
251
278
|
# *Cluster mode only* Set the timeout for worker shutdown
|
252
279
|
def worker_shutdown_timeout(timeout)
|
253
280
|
@options[:worker_shutdown_timeout] = timeout
|
@@ -276,5 +303,46 @@ module Puma
|
|
276
303
|
def shutdown_debug(val=true)
|
277
304
|
@options[:shutdown_debug] = val
|
278
305
|
end
|
306
|
+
|
307
|
+
# Control how the remote address of the connection is set. This
|
308
|
+
# is configurable because to calculate the true socket peer address
|
309
|
+
# a kernel syscall is required which for very fast rack handlers
|
310
|
+
# slows down the handling significantly.
|
311
|
+
#
|
312
|
+
# There are 4 possible values:
|
313
|
+
#
|
314
|
+
# * :socket (the default) - read the peername from the socket using the
|
315
|
+
# syscall. This is the normal behavior.
|
316
|
+
# * :localhost - set the remote address to "127.0.0.1"
|
317
|
+
# * header: http_header - set the remote address to the value of the
|
318
|
+
# provided http header. For instance:
|
319
|
+
# `set_remote_address header: "X-Real-IP"`.
|
320
|
+
# Only the first word (as separated by spaces or comma)
|
321
|
+
# is used, allowing headers such as X-Forwarded-For
|
322
|
+
# to be used as well.
|
323
|
+
# * Any string - this allows you to hardcode remote address to any value
|
324
|
+
# you wish. Because puma never uses this field anyway, it's
|
325
|
+
# format is entirely in your hands.
|
326
|
+
def set_remote_address(val=:socket)
|
327
|
+
case val
|
328
|
+
when :socket
|
329
|
+
@options[:remote_address] = val
|
330
|
+
when :localhost
|
331
|
+
@options[:remote_address] = :value
|
332
|
+
@options[:remote_address_value] = "127.0.0.1".freeze
|
333
|
+
when String
|
334
|
+
@options[:remote_address] = :value
|
335
|
+
@options[:remote_address_value] = val
|
336
|
+
when Hash
|
337
|
+
if hdr = val[:header]
|
338
|
+
@options[:remote_address] = :header
|
339
|
+
@options[:remote_address_header] = "HTTP_" + hdr.upcase.gsub("-", "_")
|
340
|
+
else
|
341
|
+
raise "Invalid value for set_remote_address - #{val.inspect}"
|
342
|
+
end
|
343
|
+
else
|
344
|
+
raise "Invalid value for set_remote_address - #{val}"
|
345
|
+
end
|
346
|
+
end
|
279
347
|
end
|
280
348
|
end
|
data/lib/puma/events.rb
CHANGED
data/lib/puma/minissl.rb
CHANGED
data/lib/puma/runner.rb
CHANGED
@@ -52,8 +52,9 @@ module Puma
|
|
52
52
|
when "unix"
|
53
53
|
log "* Starting control server on #{str}"
|
54
54
|
path = "#{uri.host}#{uri.path}"
|
55
|
+
mask = @options[:control_url_umask]
|
55
56
|
|
56
|
-
control.add_unix_listener path
|
57
|
+
control.add_unix_listener path, mask
|
57
58
|
else
|
58
59
|
error "Invalid control URI: #{str}"
|
59
60
|
end
|
data/lib/puma/server.rb
CHANGED
@@ -45,7 +45,7 @@ module Puma
|
|
45
45
|
# to be handled. See Puma::Events for the list of current methods to implement.
|
46
46
|
#
|
47
47
|
# Server#run returns a thread that you can join on to wait for the server
|
48
|
-
# to do
|
48
|
+
# to do its work.
|
49
49
|
#
|
50
50
|
def initialize(app, events=Events.stdio, options={})
|
51
51
|
@app = app
|
@@ -307,6 +307,16 @@ module Puma
|
|
307
307
|
pool = @thread_pool
|
308
308
|
queue_requests = @queue_requests
|
309
309
|
|
310
|
+
remote_addr_value = nil
|
311
|
+
remote_addr_header = nil
|
312
|
+
|
313
|
+
case @options[:remote_address]
|
314
|
+
when :value
|
315
|
+
remote_addr_value = @options[:remote_address_value]
|
316
|
+
when :header
|
317
|
+
remote_addr_header = @options[:remote_address_header]
|
318
|
+
end
|
319
|
+
|
310
320
|
while @status == :run
|
311
321
|
begin
|
312
322
|
ios = IO.select sockets
|
@@ -317,6 +327,12 @@ module Puma
|
|
317
327
|
begin
|
318
328
|
if io = sock.accept_nonblock
|
319
329
|
client = Client.new io, @binder.env(sock)
|
330
|
+
if remote_addr_value
|
331
|
+
client.peerip = remote_addr_value
|
332
|
+
elsif remote_addr_header
|
333
|
+
client.remote_addr_header = remote_addr_header
|
334
|
+
end
|
335
|
+
|
320
336
|
pool << client
|
321
337
|
pool.wait_until_not_full unless queue_requests
|
322
338
|
end
|
@@ -481,7 +497,7 @@ module Puma
|
|
481
497
|
|
482
498
|
unless env.key?(REMOTE_ADDR)
|
483
499
|
begin
|
484
|
-
addr = client.
|
500
|
+
addr = client.peerip
|
485
501
|
rescue Errno::ENOTCONN
|
486
502
|
# Client disconnects can result in an inability to get the
|
487
503
|
# peeraddr from the socket; default to localhost.
|
@@ -513,7 +529,7 @@ module Puma
|
|
513
529
|
env = req.env
|
514
530
|
client = req.io
|
515
531
|
|
516
|
-
normalize_env env,
|
532
|
+
normalize_env env, req
|
517
533
|
|
518
534
|
env[PUMA_SOCKET] = client
|
519
535
|
|
@@ -571,7 +587,7 @@ module Puma
|
|
571
587
|
|
572
588
|
http_11 = if env[HTTP_VERSION] == HTTP_11
|
573
589
|
allow_chunked = true
|
574
|
-
keep_alive = env
|
590
|
+
keep_alive = env.fetch(HTTP_CONNECTION, "").downcase != CLOSE
|
575
591
|
include_keepalive_header = false
|
576
592
|
|
577
593
|
# An optimization. The most common response is 200, so we can
|
@@ -589,7 +605,7 @@ module Puma
|
|
589
605
|
true
|
590
606
|
else
|
591
607
|
allow_chunked = false
|
592
|
-
keep_alive = env
|
608
|
+
keep_alive = env.fetch(HTTP_CONNECTION, "").downcase == KEEP_ALIVE
|
593
609
|
include_keepalive_header = keep_alive
|
594
610
|
|
595
611
|
# Same optimization as above for HTTP/1.1
|
@@ -608,7 +624,7 @@ module Puma
|
|
608
624
|
response_hijack = nil
|
609
625
|
|
610
626
|
headers.each do |k, vs|
|
611
|
-
case k
|
627
|
+
case k.downcase
|
612
628
|
when CONTENT_LENGTH2
|
613
629
|
content_length = vs
|
614
630
|
next
|
@@ -644,7 +660,7 @@ module Puma
|
|
644
660
|
fast_write client, lines.to_s
|
645
661
|
return keep_alive
|
646
662
|
end
|
647
|
-
|
663
|
+
|
648
664
|
if content_length
|
649
665
|
lines.append CONTENT_LENGTH_S, content_length.to_s, line_ending
|
650
666
|
chunked = false
|
data/lib/puma/single.rb
CHANGED
data/lib/puma/thread_pool.rb
CHANGED
@@ -160,7 +160,7 @@ module Puma
|
|
160
160
|
end
|
161
161
|
|
162
162
|
# If there are dead threads in the pool make them go away while decreasing
|
163
|
-
#
|
163
|
+
# spawned counter so that new healthy threads could be created again.
|
164
164
|
def reap
|
165
165
|
@mutex.synchronize do
|
166
166
|
dead_workers = @workers.reject(&:alive?)
|
@@ -235,20 +235,18 @@ module Puma
|
|
235
235
|
# Tell all threads in the pool to exit and wait for them to finish.
|
236
236
|
#
|
237
237
|
def shutdown
|
238
|
-
@mutex.synchronize do
|
238
|
+
threads = @mutex.synchronize do
|
239
239
|
@shutdown = true
|
240
240
|
@not_empty.broadcast
|
241
241
|
@not_full.broadcast
|
242
242
|
|
243
243
|
@auto_trim.stop if @auto_trim
|
244
244
|
@reaper.stop if @reaper
|
245
|
+
# dup workers so that we join them all safely
|
246
|
+
@workers.dup
|
245
247
|
end
|
246
248
|
|
247
|
-
|
248
|
-
# of each and see a mutated object mid #each
|
249
|
-
if !@workers.empty?
|
250
|
-
@workers.first.join until @workers.empty?
|
251
|
-
end
|
249
|
+
threads.each(&:join)
|
252
250
|
|
253
251
|
@spawned = 0
|
254
252
|
@workers = []
|
data/lib/rack/handler/puma.rb
CHANGED
@@ -8,7 +8,8 @@ module Rack
|
|
8
8
|
:Host => '0.0.0.0',
|
9
9
|
:Port => 8080,
|
10
10
|
:Threads => '0:16',
|
11
|
-
:Verbose => false
|
11
|
+
:Verbose => false,
|
12
|
+
:Silent => false
|
12
13
|
}
|
13
14
|
|
14
15
|
def self.run(app, options = {})
|
@@ -22,13 +23,16 @@ module Rack
|
|
22
23
|
ENV['RACK_ENV'] = options[:environment].to_s
|
23
24
|
end
|
24
25
|
|
25
|
-
|
26
|
+
events_hander = options[:Silent] ? ::Puma::Events.strings : ::Puma::Events.stdio
|
27
|
+
server = ::Puma::Server.new(app, events_hander)
|
26
28
|
min, max = options[:Threads].split(':', 2)
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
puts "
|
31
|
-
puts "*
|
30
|
+
log = events_hander.stdout
|
31
|
+
|
32
|
+
log.puts "Puma #{::Puma::Const::PUMA_VERSION} starting..."
|
33
|
+
log.puts "* Min threads: #{min}, max threads: #{max}"
|
34
|
+
log.puts "* Environment: #{ENV['RACK_ENV']}"
|
35
|
+
log.puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}"
|
32
36
|
|
33
37
|
server.add_tcp_listener options[:Host], options[:Port]
|
34
38
|
server.min_threads = min
|
@@ -38,9 +42,9 @@ module Rack
|
|
38
42
|
begin
|
39
43
|
server.run.join
|
40
44
|
rescue Interrupt
|
41
|
-
puts "* Gracefully stopping, waiting for requests to finish"
|
45
|
+
log.puts "* Gracefully stopping, waiting for requests to finish"
|
42
46
|
server.stop(true)
|
43
|
-
puts "* Goodbye!"
|
47
|
+
log.puts "* Goodbye!"
|
44
48
|
end
|
45
49
|
|
46
50
|
end
|
@@ -50,7 +54,7 @@ module Rack
|
|
50
54
|
"Host=HOST" => "Hostname to listen on (default: localhost)",
|
51
55
|
"Port=PORT" => "Port to listen on (default: 8080)",
|
52
56
|
"Threads=MIN:MAX" => "min:max threads to use (default 0:16)",
|
53
|
-
"
|
57
|
+
"Verbose" => "Don't report each request (default: false)"
|
54
58
|
}
|
55
59
|
end
|
56
60
|
end
|
data/tools/jungle/init.d/puma
CHANGED
@@ -23,6 +23,7 @@ SCRIPTNAME=/etc/init.d/$NAME
|
|
23
23
|
CONFIG=/etc/puma.conf
|
24
24
|
JUNGLE=`cat $CONFIG`
|
25
25
|
RUNPUMA=/usr/local/bin/run-puma
|
26
|
+
USE_LOCAL_BUNDLE=0
|
26
27
|
|
27
28
|
# Load the VERBOSE setting and other rcS variables
|
28
29
|
. /lib/init/vars.sh
|
@@ -105,7 +106,11 @@ do_stop_one() {
|
|
105
106
|
log_daemon_msg "---> Puma $1 isn't running."
|
106
107
|
else
|
107
108
|
log_daemon_msg "---> About to kill PID `cat $PIDFILE`"
|
108
|
-
|
109
|
+
if [ "$USE_LOCAL_BUNDLE" -eq 1 ]; then
|
110
|
+
cd $1 && bundle exec pumactl --state $STATEFILE stop
|
111
|
+
else
|
112
|
+
pumactl --state $STATEFILE stop
|
113
|
+
fi
|
109
114
|
# Many daemons don't delete their pidfiles when they exit.
|
110
115
|
rm -f $PIDFILE $STATEFILE
|
111
116
|
fi
|
@@ -135,7 +140,11 @@ do_restart_one() {
|
|
135
140
|
|
136
141
|
if [ -e $PIDFILE ]; then
|
137
142
|
log_daemon_msg "--> About to restart puma $1"
|
138
|
-
|
143
|
+
if [ "$USE_LOCAL_BUNDLE" -eq 1 ]; then
|
144
|
+
cd $1 && bundle exec pumactl --state $dir/tmp/puma/state restart
|
145
|
+
else
|
146
|
+
pumactl --state $dir/tmp/puma/state restart
|
147
|
+
fi
|
139
148
|
# kill -s USR2 `cat $PIDFILE`
|
140
149
|
# TODO Check if process exist
|
141
150
|
else
|
@@ -175,7 +184,11 @@ do_status_one() {
|
|
175
184
|
|
176
185
|
if [ -e $PIDFILE ]; then
|
177
186
|
log_daemon_msg "--> About to status puma $1"
|
178
|
-
|
187
|
+
if [ "$USE_LOCAL_BUNDLE" -eq 1 ]; then
|
188
|
+
cd $1 && bundle exec pumactl --state $dir/tmp/puma/state stats
|
189
|
+
else
|
190
|
+
pumactl --state $dir/tmp/puma/state stats
|
191
|
+
fi
|
179
192
|
# kill -s USR2 `cat $PIDFILE`
|
180
193
|
# TODO Check if process exist
|
181
194
|
else
|
@@ -241,6 +254,40 @@ do_remove() {
|
|
241
254
|
fi
|
242
255
|
}
|
243
256
|
|
257
|
+
config_bundler() {
|
258
|
+
HOME="$(eval echo ~$(id -un))"
|
259
|
+
if [ -d "/usr/local/rbenv/bin" ]; then
|
260
|
+
PATH="/usr/local/rbenv/bin:/usr/local/rbenv/shims:$PATH"
|
261
|
+
eval "$(rbenv init -)"
|
262
|
+
USE_LOCAL_BUNDLE=1
|
263
|
+
return 0
|
264
|
+
elif [ -d "$HOME/.rbenv/bin" ]; then
|
265
|
+
PATH="$HOME/.rbenv/bin:$HOME/.rbenv/shims:$PATH"
|
266
|
+
eval "$(rbenv init -)"
|
267
|
+
USE_LOCAL_BUNDLE=1
|
268
|
+
return 0
|
269
|
+
# TODO: test rvm
|
270
|
+
# elif [ -f /etc/profile.d/rvm.sh ]; then
|
271
|
+
# source /etc/profile.d/rvm.sh
|
272
|
+
# elif [ -f /usr/local/rvm/scripts/rvm ]; then
|
273
|
+
# source /etc/profile.d/rvm.sh
|
274
|
+
# elif [ -f "$HOME/.rvm/scripts/rvm" ]; then
|
275
|
+
# source "$HOME/.rvm/scripts/rvm"
|
276
|
+
# TODO: don't know what to do with chruby
|
277
|
+
# elif [ -f /usr/local/share/chruby/chruby.sh ]; then
|
278
|
+
# source /usr/local/share/chruby/chruby.sh
|
279
|
+
# if [ -f /usr/local/share/chruby/auto.sh ]; then
|
280
|
+
# source /usr/local/share/chruby/auto.sh
|
281
|
+
# fi
|
282
|
+
# if you aren't using auto, set your version here
|
283
|
+
# chruby 2.0.0
|
284
|
+
fi
|
285
|
+
|
286
|
+
return 1
|
287
|
+
}
|
288
|
+
|
289
|
+
config_bundler
|
290
|
+
|
244
291
|
case "$1" in
|
245
292
|
start)
|
246
293
|
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Phoenix
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rdoc
|
@@ -64,14 +64,14 @@ dependencies:
|
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: '3.
|
67
|
+
version: '3.14'
|
68
68
|
type: :development
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: '3.
|
74
|
+
version: '3.14'
|
75
75
|
description: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server
|
76
76
|
for Ruby/Rack applications. Puma is intended for use in both development and production
|
77
77
|
environments. In order to get the best throughput, it is highly recommended that
|
@@ -191,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
191
191
|
version: '0'
|
192
192
|
requirements: []
|
193
193
|
rubyforge_project:
|
194
|
-
rubygems_version: 2.
|
194
|
+
rubygems_version: 2.5.1
|
195
195
|
signing_key:
|
196
196
|
specification_version: 4
|
197
197
|
summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
|