puma 2.7.0 → 3.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 +5 -13
- data/DEPLOYMENT.md +91 -0
- data/Gemfile +3 -2
- data/History.txt +624 -1
- data/Manifest.txt +15 -3
- data/README.md +129 -14
- data/Rakefile +3 -3
- data/bin/puma-wild +31 -0
- data/bin/pumactl +1 -1
- data/docs/nginx.md +1 -1
- data/docs/signals.md +43 -0
- data/ext/puma_http11/extconf.rb +7 -2
- data/ext/puma_http11/http11_parser.java.rl +5 -5
- data/ext/puma_http11/io_buffer.c +1 -1
- data/ext/puma_http11/mini_ssl.c +233 -18
- data/ext/puma_http11/org/jruby/puma/Http11.java +12 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +39 -39
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +245 -195
- data/ext/puma_http11/puma_http11.c +12 -4
- data/lib/puma.rb +1 -0
- data/lib/puma/app/status.rb +7 -0
- data/lib/puma/binder.rb +108 -39
- data/lib/puma/capistrano.rb +23 -6
- data/lib/puma/cli.rb +141 -446
- data/lib/puma/client.rb +48 -1
- data/lib/puma/cluster.rb +207 -58
- data/lib/puma/commonlogger.rb +107 -0
- data/lib/puma/configuration.rb +262 -235
- data/lib/puma/const.rb +97 -14
- data/lib/puma/control_cli.rb +85 -77
- data/lib/puma/convenient.rb +23 -0
- data/lib/puma/daemon_ext.rb +11 -4
- data/lib/puma/detect.rb +8 -1
- data/lib/puma/dsl.rb +456 -0
- data/lib/puma/events.rb +35 -18
- data/lib/puma/jruby_restart.rb +1 -1
- data/lib/puma/launcher.rb +399 -0
- data/lib/puma/minissl.rb +49 -20
- data/lib/puma/null_io.rb +15 -0
- data/lib/puma/plugin.rb +104 -0
- data/lib/puma/plugin/tmp_restart.rb +35 -0
- data/lib/puma/rack/backports/uri/common_18.rb +56 -0
- data/lib/puma/rack/backports/uri/common_192.rb +52 -0
- data/lib/puma/rack/backports/uri/common_193.rb +29 -0
- data/lib/puma/rack/builder.rb +295 -0
- data/lib/puma/rack/urlmap.rb +90 -0
- data/lib/puma/reactor.rb +14 -1
- data/lib/puma/runner.rb +35 -17
- data/lib/puma/server.rb +161 -58
- data/lib/puma/single.rb +15 -10
- data/lib/puma/state_file.rb +29 -0
- data/lib/puma/thread_pool.rb +88 -13
- data/lib/puma/util.rb +123 -0
- data/lib/rack/handler/puma.rb +35 -29
- data/puma.gemspec +2 -4
- data/tools/jungle/init.d/README.md +2 -2
- data/tools/jungle/init.d/puma +69 -7
- data/tools/jungle/upstart/puma.conf +8 -2
- metadata +51 -71
- data/COPYING +0 -55
- data/TODO +0 -5
- data/lib/puma/rack_patch.rb +0 -45
- data/test/test_app_status.rb +0 -92
- data/test/test_cli.rb +0 -173
- data/test/test_config.rb +0 -16
- data/test/test_http10.rb +0 -27
- data/test/test_http11.rb +0 -145
- data/test/test_integration.rb +0 -165
- data/test/test_iobuffer.rb +0 -38
- data/test/test_minissl.rb +0 -25
- data/test/test_null_io.rb +0 -31
- data/test/test_persistent.rb +0 -238
- data/test/test_puma_server.rb +0 -292
- data/test/test_rack_handler.rb +0 -10
- data/test/test_rack_server.rb +0 -141
- data/test/test_tcp_rack.rb +0 -42
- data/test/test_thread_pool.rb +0 -156
- data/test/test_unix_socket.rb +0 -39
- data/test/test_ws.rb +0 -89
@@ -0,0 +1,107 @@
|
|
1
|
+
module Puma
|
2
|
+
# Rack::CommonLogger forwards every request to the given +app+, and
|
3
|
+
# logs a line in the
|
4
|
+
# {Apache common log format}[http://httpd.apache.org/docs/1.3/logs.html#common]
|
5
|
+
# to the +logger+.
|
6
|
+
#
|
7
|
+
# If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
|
8
|
+
# an instance of Rack::NullLogger.
|
9
|
+
#
|
10
|
+
# +logger+ can be any class, including the standard library Logger, and is
|
11
|
+
# expected to have either +write+ or +<<+ method, which accepts the CommonLogger::FORMAT.
|
12
|
+
# According to the SPEC, the error stream must also respond to +puts+
|
13
|
+
# (which takes a single argument that responds to +to_s+), and +flush+
|
14
|
+
# (which is called without arguments in order to make the error appear for
|
15
|
+
# sure)
|
16
|
+
class CommonLogger
|
17
|
+
# Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
|
18
|
+
#
|
19
|
+
# lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
|
20
|
+
#
|
21
|
+
# %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
|
22
|
+
FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n}
|
23
|
+
|
24
|
+
def initialize(app, logger=nil)
|
25
|
+
@app = app
|
26
|
+
@logger = logger
|
27
|
+
end
|
28
|
+
|
29
|
+
def call(env)
|
30
|
+
began_at = Time.now
|
31
|
+
status, header, body = @app.call(env)
|
32
|
+
header = Util::HeaderHash.new(header)
|
33
|
+
|
34
|
+
# If we've been hijacked, then output a special line
|
35
|
+
if env['rack.hijack_io']
|
36
|
+
log_hijacking(env, 'HIJACK', header, began_at)
|
37
|
+
else
|
38
|
+
ary = env['rack.after_reply']
|
39
|
+
ary << lambda { log(env, status, header, began_at) }
|
40
|
+
end
|
41
|
+
|
42
|
+
[status, header, body]
|
43
|
+
end
|
44
|
+
|
45
|
+
HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def log_hijacking(env, status, header, began_at)
|
50
|
+
now = Time.now
|
51
|
+
|
52
|
+
logger = @logger || env['rack.errors']
|
53
|
+
logger.write HIJACK_FORMAT % [
|
54
|
+
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
|
55
|
+
env["REMOTE_USER"] || "-",
|
56
|
+
now.strftime("%d/%b/%Y %H:%M:%S"),
|
57
|
+
env["REQUEST_METHOD"],
|
58
|
+
env["PATH_INFO"],
|
59
|
+
env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
|
60
|
+
env["HTTP_VERSION"],
|
61
|
+
now - began_at ]
|
62
|
+
end
|
63
|
+
|
64
|
+
PATH_INFO = 'PATH_INFO'.freeze
|
65
|
+
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
|
66
|
+
SCRIPT_NAME = 'SCRIPT_NAME'.freeze
|
67
|
+
QUERY_STRING = 'QUERY_STRING'.freeze
|
68
|
+
CACHE_CONTROL = 'Cache-Control'.freeze
|
69
|
+
CONTENT_LENGTH = 'Content-Length'.freeze
|
70
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
71
|
+
|
72
|
+
GET = 'GET'.freeze
|
73
|
+
HEAD = 'HEAD'.freeze
|
74
|
+
|
75
|
+
|
76
|
+
def log(env, status, header, began_at)
|
77
|
+
now = Time.now
|
78
|
+
length = extract_content_length(header)
|
79
|
+
|
80
|
+
msg = FORMAT % [
|
81
|
+
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
|
82
|
+
env["REMOTE_USER"] || "-",
|
83
|
+
now.strftime("%d/%b/%Y:%H:%M:%S %z"),
|
84
|
+
env[REQUEST_METHOD],
|
85
|
+
env[PATH_INFO],
|
86
|
+
env[QUERY_STRING].empty? ? "" : "?"+env[QUERY_STRING],
|
87
|
+
env["HTTP_VERSION"],
|
88
|
+
status.to_s[0..3],
|
89
|
+
length,
|
90
|
+
now - began_at ]
|
91
|
+
|
92
|
+
logger = @logger || env['rack.errors']
|
93
|
+
# Standard library logger doesn't support write but it supports << which actually
|
94
|
+
# calls to write on the log device without formatting
|
95
|
+
if logger.respond_to?(:write)
|
96
|
+
logger.write(msg)
|
97
|
+
else
|
98
|
+
logger << msg
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def extract_content_length(headers)
|
103
|
+
value = headers[CONTENT_LENGTH] or return '-'
|
104
|
+
value.to_s == '0' ? '-' : value
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/lib/puma/configuration.rb
CHANGED
@@ -1,59 +1,218 @@
|
|
1
|
+
require 'puma/rack/builder'
|
2
|
+
require 'puma/plugin'
|
3
|
+
|
1
4
|
module Puma
|
2
5
|
|
3
|
-
|
4
|
-
|
5
|
-
# since it is not set if the app is launched via another
|
6
|
-
# mechanism than the CLI class.
|
6
|
+
module ConfigDefault
|
7
|
+
DefaultRackup = "config.ru"
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
DefaultTCPHost = "0.0.0.0"
|
10
|
+
DefaultTCPPort = 9292
|
11
|
+
DefaultWorkerTimeout = 60
|
12
|
+
DefaultWorkerShutdownTimeout = 30
|
13
|
+
end
|
14
|
+
|
15
|
+
class LeveledOptions
|
16
|
+
def initialize(default={})
|
17
|
+
@cur = {}
|
18
|
+
@set = [@cur]
|
19
|
+
@defaults = default.dup
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize_copy(other)
|
23
|
+
@set = @set.map { |o| o.dup }
|
24
|
+
@cur = @set.last
|
25
|
+
end
|
26
|
+
|
27
|
+
def shift
|
28
|
+
@cur = {}
|
29
|
+
@set << @cur
|
30
|
+
end
|
31
|
+
|
32
|
+
def [](key)
|
33
|
+
@set.each do |o|
|
34
|
+
if o.key? key
|
35
|
+
return o[key]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
v = @defaults[key]
|
40
|
+
if v.respond_to? :call
|
41
|
+
v.call
|
42
|
+
else
|
43
|
+
v
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def fetch(key, default=nil)
|
48
|
+
val = self[key]
|
49
|
+
return val if val
|
50
|
+
default
|
51
|
+
end
|
52
|
+
|
53
|
+
attr_reader :cur
|
54
|
+
|
55
|
+
def all_of(key)
|
56
|
+
all = []
|
57
|
+
|
58
|
+
@set.each do |o|
|
59
|
+
if v = o[key]
|
60
|
+
if v.kind_of? Array
|
61
|
+
all += v
|
62
|
+
else
|
63
|
+
all << v
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
all
|
69
|
+
end
|
70
|
+
|
71
|
+
def []=(key, val)
|
72
|
+
@cur[key] = val
|
73
|
+
end
|
74
|
+
|
75
|
+
def key?(key)
|
76
|
+
@set.each do |o|
|
77
|
+
if o.key? key
|
78
|
+
return true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
@default.key? key
|
83
|
+
end
|
84
|
+
|
85
|
+
def merge!(o)
|
86
|
+
o.each do |k,v|
|
87
|
+
@cur[k]= v
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def flatten
|
92
|
+
options = {}
|
93
|
+
|
94
|
+
@set.each do |o|
|
95
|
+
o.each do |k,v|
|
96
|
+
options[k] ||= v
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
options
|
101
|
+
end
|
102
|
+
|
103
|
+
def explain
|
104
|
+
indent = ""
|
105
|
+
|
106
|
+
@set.each do |o|
|
107
|
+
o.keys.sort.each do |k|
|
108
|
+
puts "#{indent}#{k}: #{o[k].inspect}"
|
109
|
+
end
|
110
|
+
|
111
|
+
indent = " #{indent}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def force_defaults
|
116
|
+
@defaults.each do |k,v|
|
117
|
+
if v.respond_to? :call
|
118
|
+
@defaults[k] = v.call
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
10
122
|
end
|
11
123
|
|
12
124
|
class Configuration
|
13
|
-
|
125
|
+
include ConfigDefault
|
14
126
|
|
15
|
-
|
16
|
-
|
127
|
+
def self.from_file(path)
|
128
|
+
cfg = new
|
17
129
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@options[:binds] ||= []
|
22
|
-
@options[:on_restart] ||= []
|
23
|
-
@options[:worker_boot] ||= []
|
130
|
+
DSL.new(cfg.options, cfg)._load_from path
|
131
|
+
|
132
|
+
return cfg
|
24
133
|
end
|
25
134
|
|
26
|
-
|
135
|
+
def initialize(options={}, &blk)
|
136
|
+
@options = LeveledOptions.new(default_options)
|
137
|
+
@plugins = PluginLoader.new
|
138
|
+
|
139
|
+
# options.each do |k,v|
|
140
|
+
# @options[k] = v
|
141
|
+
# end
|
142
|
+
|
143
|
+
if blk
|
144
|
+
configure(&blk)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
attr_reader :options, :plugins
|
149
|
+
|
150
|
+
def configure(&blk)
|
151
|
+
@options.shift
|
152
|
+
DSL.new(@options, self)._run(&blk)
|
153
|
+
end
|
27
154
|
|
28
155
|
def initialize_copy(other)
|
156
|
+
@conf = nil
|
157
|
+
@cli_options = nil
|
29
158
|
@options = @options.dup
|
30
159
|
end
|
31
160
|
|
161
|
+
def flatten
|
162
|
+
dup.flatten!
|
163
|
+
end
|
164
|
+
|
165
|
+
def flatten!
|
166
|
+
@options = @options.flatten
|
167
|
+
self
|
168
|
+
end
|
169
|
+
|
170
|
+
def default_options
|
171
|
+
{
|
172
|
+
:min_threads => 0,
|
173
|
+
:max_threads => 16,
|
174
|
+
:log_requests => false,
|
175
|
+
:debug => false,
|
176
|
+
:binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
|
177
|
+
:workers => 0,
|
178
|
+
:daemon => false,
|
179
|
+
:mode => :http,
|
180
|
+
:worker_timeout => DefaultWorkerTimeout,
|
181
|
+
:worker_boot_timeout => DefaultWorkerTimeout,
|
182
|
+
:worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
|
183
|
+
:remote_address => :socket,
|
184
|
+
:tag => method(:infer_tag),
|
185
|
+
:environment => lambda { ENV['RACK_ENV'] || "development" },
|
186
|
+
:rackup => DefaultRackup,
|
187
|
+
:logger => STDOUT
|
188
|
+
}
|
189
|
+
end
|
190
|
+
|
32
191
|
def load
|
33
|
-
|
34
|
-
DSL.new(@options)._load_from path
|
35
|
-
end
|
192
|
+
files = @options.all_of(:config_files)
|
36
193
|
|
37
|
-
|
38
|
-
|
39
|
-
|
194
|
+
if files.empty?
|
195
|
+
imp = %W(config/puma/#{@options[:environment]}.rb config/puma.rb).find { |f|
|
196
|
+
File.exist?(f)
|
197
|
+
}
|
40
198
|
|
41
|
-
|
199
|
+
files << imp
|
200
|
+
elsif files == ["-"]
|
201
|
+
files = []
|
42
202
|
end
|
43
203
|
|
44
|
-
|
45
|
-
@options
|
46
|
-
end
|
204
|
+
files.each do |f|
|
205
|
+
@options.shift
|
47
206
|
|
48
|
-
|
49
|
-
path = Configuration.temp_path
|
50
|
-
@options[:control_url] = "unix://#{path}"
|
51
|
-
@options[:control_url_temp] = path
|
207
|
+
DSL.load @options, self, f
|
52
208
|
end
|
209
|
+
end
|
53
210
|
|
54
|
-
|
55
|
-
|
56
|
-
|
211
|
+
# Call once all configuration (included from rackup files)
|
212
|
+
# is loaded to flesh out any defaults
|
213
|
+
def clamp
|
214
|
+
@options.shift
|
215
|
+
@options.force_defaults
|
57
216
|
end
|
58
217
|
|
59
218
|
# Injects the Configuration object into the env
|
@@ -72,75 +231,45 @@ module Puma
|
|
72
231
|
# Indicate if there is a properly configured app
|
73
232
|
#
|
74
233
|
def app_configured?
|
75
|
-
@options[:app] || File.
|
234
|
+
@options[:app] || File.exist?(rackup)
|
76
235
|
end
|
77
236
|
|
78
237
|
def rackup
|
79
|
-
@options[:rackup]
|
238
|
+
@options[:rackup]
|
80
239
|
end
|
81
240
|
|
82
|
-
# Load the specified rackup file, pull
|
241
|
+
# Load the specified rackup file, pull options from
|
83
242
|
# the rackup file, and set @app.
|
84
243
|
#
|
85
244
|
def app
|
86
|
-
|
87
|
-
|
88
|
-
unless app
|
89
|
-
unless File.exists?(rackup)
|
90
|
-
raise "Missing rackup file '#{rackup}'"
|
91
|
-
end
|
92
|
-
|
93
|
-
app, options = Rack::Builder.parse_file rackup
|
94
|
-
@options.merge! options
|
95
|
-
|
96
|
-
options.each do |key,val|
|
97
|
-
if key.to_s[0,4] == "bind"
|
98
|
-
@options[:binds] << val
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
245
|
+
found = options[:app] || load_rackup
|
102
246
|
|
103
247
|
if @options[:mode] == :tcp
|
104
248
|
require 'puma/tcp_logger'
|
105
249
|
|
106
|
-
logger = @options[:logger]
|
107
|
-
return TCPLogger.new(logger,
|
250
|
+
logger = @options[:logger]
|
251
|
+
return TCPLogger.new(logger, found, @options[:log_requests])
|
108
252
|
end
|
109
253
|
|
110
|
-
if
|
111
|
-
logger = @options[:logger]
|
112
|
-
|
254
|
+
if @options[:log_requests]
|
255
|
+
logger = @options[:logger]
|
256
|
+
found = CommonLogger.new(found, logger)
|
113
257
|
end
|
114
258
|
|
115
|
-
|
259
|
+
ConfigMiddleware.new(self, found)
|
116
260
|
end
|
117
261
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
count = 16
|
125
|
-
|
126
|
-
bytes = nil
|
127
|
-
|
128
|
-
if defined? OpenSSL::Random
|
129
|
-
bytes = OpenSSL::Random.random_bytes(count)
|
130
|
-
elsif File.exists?("/dev/urandom")
|
131
|
-
File.open("/dev/urandom") do |f|
|
132
|
-
bytes = f.read(count)
|
133
|
-
end
|
134
|
-
end
|
262
|
+
# Return which environment we're running in
|
263
|
+
def environment
|
264
|
+
@options[:environment]
|
265
|
+
end
|
135
266
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
else
|
140
|
-
token = (0..count).to_a.map { rand(255).to_s(16) }.join
|
141
|
-
end
|
267
|
+
def load_plugin(name)
|
268
|
+
@plugins.create name
|
269
|
+
end
|
142
270
|
|
143
|
-
|
271
|
+
def run_hooks(key, arg)
|
272
|
+
@options.all_of(key).each { |b| b.call arg }
|
144
273
|
end
|
145
274
|
|
146
275
|
def self.temp_path
|
@@ -150,181 +279,79 @@ module Puma
|
|
150
279
|
"#{Dir.tmpdir}/puma-status-#{t}-#{$$}"
|
151
280
|
end
|
152
281
|
|
153
|
-
|
154
|
-
#
|
155
|
-
class DSL
|
156
|
-
def initialize(options)
|
157
|
-
@options = options
|
158
|
-
end
|
159
|
-
|
160
|
-
def _load_from(path)
|
161
|
-
instance_eval File.read(path), path, 1
|
162
|
-
end
|
163
|
-
|
164
|
-
# Use +obj+ or +block+ as the Rack app. This allows a config file to
|
165
|
-
# be the app itself.
|
166
|
-
#
|
167
|
-
def app(obj=nil, &block)
|
168
|
-
obj ||= block
|
282
|
+
private
|
169
283
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
end
|
174
|
-
|
175
|
-
# Start the Puma control rack app on +url+. This app can be communicated
|
176
|
-
# with to control the main server.
|
177
|
-
#
|
178
|
-
def activate_control_app(url="auto", opts=nil)
|
179
|
-
@options[:control_url] = url
|
180
|
-
|
181
|
-
if opts
|
182
|
-
if tok = opts[:auth_token]
|
183
|
-
@options[:control_auth_token] = tok
|
184
|
-
end
|
284
|
+
def infer_tag
|
285
|
+
File.basename(Dir.getwd)
|
286
|
+
end
|
185
287
|
|
186
|
-
|
187
|
-
|
188
|
-
|
288
|
+
# Load and use the normal Rack builder if we can, otherwise
|
289
|
+
# fallback to our minimal version.
|
290
|
+
def rack_builder
|
291
|
+
# Load bundler now if we can so that we can pickup rack from
|
292
|
+
# a Gemfile
|
293
|
+
if ENV.key? 'PUMA_BUNDLER_PRUNED'
|
294
|
+
begin
|
295
|
+
require 'bundler/setup'
|
296
|
+
rescue LoadError
|
189
297
|
end
|
190
298
|
end
|
191
299
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
#
|
201
|
-
def port(port)
|
202
|
-
@options[:binds] << "tcp://#{Configuration::DefaultTCPHost}:#{port}"
|
203
|
-
end
|
204
|
-
|
205
|
-
# Daemonize the server into the background. Highly suggest that
|
206
|
-
# this be combined with +pidfile+ and +stdout_redirect+.
|
207
|
-
def daemonize(which=true)
|
208
|
-
@options[:daemon] = which
|
209
|
-
end
|
210
|
-
|
211
|
-
# When shutting down, drain the accept socket of pending
|
212
|
-
# connections and proces them. This loops over the accept
|
213
|
-
# socket until there are no more read events and then stops
|
214
|
-
# looking and waits for the requests to finish.
|
215
|
-
def drain_on_shutdown(which=true)
|
216
|
-
@options[:drain_on_shutdown] = which
|
217
|
-
end
|
218
|
-
|
219
|
-
# Set the environment in which the Rack's app will run.
|
220
|
-
def environment(environment)
|
221
|
-
@options[:environment] = environment
|
222
|
-
end
|
223
|
-
|
224
|
-
# Code to run before doing a restart. This code should
|
225
|
-
# close logfiles, database connections, etc.
|
226
|
-
#
|
227
|
-
# This can be called multiple times to add code each time.
|
228
|
-
#
|
229
|
-
def on_restart(&block)
|
230
|
-
@options[:on_restart] << block
|
231
|
-
end
|
232
|
-
|
233
|
-
# Command to use to restart puma. This should be just how to
|
234
|
-
# load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
|
235
|
-
# to puma, as those are the same as the original process.
|
236
|
-
#
|
237
|
-
def restart_command(cmd)
|
238
|
-
@options[:restart_cmd] = cmd
|
300
|
+
begin
|
301
|
+
require 'rack'
|
302
|
+
require 'rack/builder'
|
303
|
+
rescue LoadError
|
304
|
+
# ok, use builtin version
|
305
|
+
return Puma::Rack::Builder
|
306
|
+
else
|
307
|
+
return ::Rack::Builder
|
239
308
|
end
|
309
|
+
end
|
240
310
|
|
241
|
-
|
242
|
-
|
243
|
-
@options[:pidfile] = path
|
244
|
-
end
|
311
|
+
def load_rackup
|
312
|
+
raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
|
245
313
|
|
246
|
-
|
247
|
-
#
|
248
|
-
def quiet
|
249
|
-
@options[:quiet] = true
|
250
|
-
end
|
314
|
+
@options.shift
|
251
315
|
|
252
|
-
|
253
|
-
|
254
|
-
def rackup(path)
|
255
|
-
@options[:rackup] = path.to_s
|
256
|
-
end
|
316
|
+
rack_app, rack_options = rack_builder.parse_file(rackup)
|
317
|
+
@options.merge!(rack_options)
|
257
318
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
@options[:redirect_stderr] = stderr
|
262
|
-
@options[:redirect_append] = append
|
319
|
+
config_ru_binds = []
|
320
|
+
rack_options.each do |k, v|
|
321
|
+
config_ru_binds << v if k.to_s.start_with?("bind")
|
263
322
|
end
|
264
323
|
|
265
|
-
|
266
|
-
# requests and +max+ the maximum.
|
267
|
-
#
|
268
|
-
def threads(min, max)
|
269
|
-
min = Integer(min)
|
270
|
-
max = Integer(max)
|
271
|
-
if min > max
|
272
|
-
raise "The minimum (#{min}) number of threads must be less than the max (#{max})"
|
273
|
-
end
|
274
|
-
|
275
|
-
@options[:min_threads] = min
|
276
|
-
@options[:max_threads] = max
|
277
|
-
end
|
324
|
+
@options[:binds] = config_ru_binds unless config_ru_binds.empty?
|
278
325
|
|
279
|
-
|
280
|
-
|
281
|
-
"cert=#{opts[:cert]}",
|
282
|
-
"key=#{opts[:key]}"
|
283
|
-
]
|
284
|
-
|
285
|
-
@options[:binds] << "ssl://#{host}:#{port}?#{o.join('&')}"
|
286
|
-
end
|
326
|
+
rack_app
|
327
|
+
end
|
287
328
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
@options[:state] = path.to_s
|
329
|
+
def self.random_token
|
330
|
+
begin
|
331
|
+
require 'openssl'
|
332
|
+
rescue LoadError
|
293
333
|
end
|
294
334
|
|
295
|
-
|
296
|
-
#
|
297
|
-
def workers(count)
|
298
|
-
@options[:workers] = count.to_i
|
299
|
-
end
|
335
|
+
count = 16
|
300
336
|
|
301
|
-
|
302
|
-
# the process before booting the app.
|
303
|
-
#
|
304
|
-
# This can be called multiple times to add hooks.
|
305
|
-
#
|
306
|
-
def on_worker_boot(&block)
|
307
|
-
@options[:worker_boot] << block
|
308
|
-
end
|
337
|
+
bytes = nil
|
309
338
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
339
|
+
if defined? OpenSSL::Random
|
340
|
+
bytes = OpenSSL::Random.random_bytes(count)
|
341
|
+
elsif File.exist?("/dev/urandom")
|
342
|
+
File.open('/dev/urandom') { |f| bytes = f.read(count) }
|
314
343
|
end
|
315
344
|
|
316
|
-
|
317
|
-
|
318
|
-
|
345
|
+
if bytes
|
346
|
+
token = ""
|
347
|
+
bytes.each_byte { |b| token << b.to_s(16) }
|
348
|
+
else
|
349
|
+
token = (0..count).to_a.map { rand(255).to_s(16) }.join
|
319
350
|
end
|
320
351
|
|
321
|
-
|
322
|
-
# the workers and setting up the listen ports. This conflicts
|
323
|
-
# with using the phased restart feature, you can't use both.
|
324
|
-
#
|
325
|
-
def preload_app!(answer=true)
|
326
|
-
@options[:preload_app] = answer
|
327
|
-
end
|
352
|
+
return token
|
328
353
|
end
|
329
354
|
end
|
330
355
|
end
|
356
|
+
|
357
|
+
require 'puma/dsl'
|