puma 3.0.0.rc1 → 5.0.0.beta1
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 -5
- data/{History.txt → History.md} +703 -70
- data/LICENSE +23 -20
- data/README.md +173 -163
- data/docs/architecture.md +37 -0
- data/{DEPLOYMENT.md → docs/deployment.md} +28 -6
- data/docs/fork_worker.md +31 -0
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/jungle/README.md +13 -0
- data/docs/jungle/rc.d/README.md +74 -0
- data/docs/jungle/rc.d/puma +61 -0
- data/docs/jungle/rc.d/puma.conf +10 -0
- data/{tools → docs}/jungle/upstart/README.md +0 -0
- data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
- data/{tools → docs}/jungle/upstart/puma.conf +1 -1
- data/docs/nginx.md +2 -2
- data/docs/plugins.md +38 -0
- data/docs/restart.md +41 -0
- data/docs/signals.md +57 -3
- data/docs/systemd.md +228 -0
- data/ext/puma_http11/PumaHttp11Service.java +2 -2
- data/ext/puma_http11/extconf.rb +16 -0
- data/ext/puma_http11/http11_parser.c +287 -468
- data/ext/puma_http11/http11_parser.h +1 -0
- data/ext/puma_http11/http11_parser.java.rl +21 -37
- data/ext/puma_http11/http11_parser.rl +10 -9
- data/ext/puma_http11/http11_parser_common.rl +4 -4
- data/ext/puma_http11/mini_ssl.c +159 -10
- data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +99 -132
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +30 -6
- data/ext/puma_http11/puma_http11.c +6 -38
- data/lib/puma.rb +25 -5
- data/lib/puma/accept_nonblock.rb +7 -1
- data/lib/puma/app/status.rb +53 -26
- data/lib/puma/binder.rb +150 -119
- data/lib/puma/cli.rb +56 -38
- data/lib/puma/client.rb +277 -80
- data/lib/puma/cluster.rb +326 -130
- data/lib/puma/commonlogger.rb +21 -20
- data/lib/puma/configuration.rb +160 -161
- data/lib/puma/const.rb +50 -47
- data/lib/puma/control_cli.rb +104 -63
- data/lib/puma/detect.rb +13 -1
- data/lib/puma/dsl.rb +463 -114
- data/lib/puma/events.rb +22 -13
- data/lib/puma/io_buffer.rb +9 -5
- data/lib/puma/jruby_restart.rb +2 -59
- data/lib/puma/launcher.rb +195 -105
- data/lib/puma/minissl.rb +110 -4
- data/lib/puma/minissl/context_builder.rb +76 -0
- data/lib/puma/null_io.rb +9 -14
- data/lib/puma/plugin.rb +32 -12
- data/lib/puma/plugin/tmp_restart.rb +19 -6
- data/lib/puma/rack/builder.rb +7 -5
- data/lib/puma/rack/urlmap.rb +11 -8
- data/lib/puma/rack_default.rb +2 -0
- data/lib/puma/reactor.rb +242 -32
- data/lib/puma/runner.rb +41 -30
- data/lib/puma/server.rb +265 -183
- data/lib/puma/single.rb +22 -63
- data/lib/puma/state_file.rb +9 -2
- data/lib/puma/thread_pool.rb +179 -68
- data/lib/puma/util.rb +3 -11
- data/lib/rack/handler/puma.rb +60 -11
- data/tools/Dockerfile +16 -0
- data/tools/trickletest.rb +1 -2
- metadata +35 -99
- data/COPYING +0 -55
- data/Gemfile +0 -13
- data/Manifest.txt +0 -79
- data/Rakefile +0 -158
- data/docs/config.md +0 -0
- data/ext/puma_http11/io_buffer.c +0 -155
- data/lib/puma/capistrano.rb +0 -94
- data/lib/puma/compat.rb +0 -18
- data/lib/puma/convenient.rb +0 -23
- data/lib/puma/daemon_ext.rb +0 -31
- data/lib/puma/delegation.rb +0 -11
- data/lib/puma/java_io_buffer.rb +0 -45
- data/lib/puma/rack/backports/uri/common_18.rb +0 -56
- data/lib/puma/rack/backports/uri/common_192.rb +0 -52
- data/lib/puma/rack/backports/uri/common_193.rb +0 -29
- data/lib/puma/tcp_logger.rb +0 -32
- data/puma.gemspec +0 -52
- data/tools/jungle/README.md +0 -9
- data/tools/jungle/init.d/README.md +0 -54
- data/tools/jungle/init.d/puma +0 -394
- data/tools/jungle/init.d/run-puma +0 -3
data/lib/puma/commonlogger.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Puma
|
2
4
|
# Rack::CommonLogger forwards every request to the given +app+, and
|
3
5
|
# logs a line in the
|
@@ -21,6 +23,13 @@ module Puma
|
|
21
23
|
# %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
|
22
24
|
FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n}
|
23
25
|
|
26
|
+
HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
|
27
|
+
|
28
|
+
CONTENT_LENGTH = 'Content-Length'.freeze
|
29
|
+
PATH_INFO = 'PATH_INFO'.freeze
|
30
|
+
QUERY_STRING = 'QUERY_STRING'.freeze
|
31
|
+
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
|
32
|
+
|
24
33
|
def initialize(app, logger=nil)
|
25
34
|
@app = app
|
26
35
|
@logger = logger
|
@@ -42,36 +51,23 @@ module Puma
|
|
42
51
|
[status, header, body]
|
43
52
|
end
|
44
53
|
|
45
|
-
HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
|
46
|
-
|
47
54
|
private
|
48
55
|
|
49
56
|
def log_hijacking(env, status, header, began_at)
|
50
57
|
now = Time.now
|
51
58
|
|
52
|
-
|
53
|
-
logger.write HIJACK_FORMAT % [
|
59
|
+
msg = HIJACK_FORMAT % [
|
54
60
|
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
|
55
61
|
env["REMOTE_USER"] || "-",
|
56
62
|
now.strftime("%d/%b/%Y %H:%M:%S"),
|
57
|
-
env[
|
58
|
-
env[
|
59
|
-
env[
|
63
|
+
env[REQUEST_METHOD],
|
64
|
+
env[PATH_INFO],
|
65
|
+
env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
|
60
66
|
env["HTTP_VERSION"],
|
61
67
|
now - began_at ]
|
62
|
-
end
|
63
68
|
|
64
|
-
|
65
|
-
|
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
|
-
|
69
|
+
write(msg)
|
70
|
+
end
|
75
71
|
|
76
72
|
def log(env, status, header, began_at)
|
77
73
|
now = Time.now
|
@@ -83,13 +79,18 @@ module Puma
|
|
83
79
|
now.strftime("%d/%b/%Y:%H:%M:%S %z"),
|
84
80
|
env[REQUEST_METHOD],
|
85
81
|
env[PATH_INFO],
|
86
|
-
env[QUERY_STRING].empty? ? "" : "
|
82
|
+
env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
|
87
83
|
env["HTTP_VERSION"],
|
88
84
|
status.to_s[0..3],
|
89
85
|
length,
|
90
86
|
now - began_at ]
|
91
87
|
|
88
|
+
write(msg)
|
89
|
+
end
|
90
|
+
|
91
|
+
def write(msg)
|
92
92
|
logger = @logger || env['rack.errors']
|
93
|
+
|
93
94
|
# Standard library logger doesn't support write but it supports << which actually
|
94
95
|
# calls to write on the log device without formatting
|
95
96
|
if logger.respond_to?(:write)
|
data/lib/puma/configuration.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'puma/rack/builder'
|
2
4
|
require 'puma/plugin'
|
5
|
+
require 'puma/const'
|
3
6
|
|
4
7
|
module Puma
|
5
8
|
|
@@ -12,144 +15,153 @@ module Puma
|
|
12
15
|
DefaultWorkerShutdownTimeout = 30
|
13
16
|
end
|
14
17
|
|
15
|
-
class
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
18
|
+
# A class used for storing "leveled" configuration options.
|
19
|
+
#
|
20
|
+
# In this class any "user" specified options take precedence over any
|
21
|
+
# "file" specified options, take precedence over any "default" options.
|
22
|
+
#
|
23
|
+
# User input is preferred over "defaults":
|
24
|
+
# user_options = { foo: "bar" }
|
25
|
+
# default_options = { foo: "zoo" }
|
26
|
+
# options = UserFileDefaultOptions.new(user_options, default_options)
|
27
|
+
# puts options[:foo]
|
28
|
+
# # => "bar"
|
29
|
+
#
|
30
|
+
# All values can be accessed via `all_of`
|
31
|
+
#
|
32
|
+
# puts options.all_of(:foo)
|
33
|
+
# # => ["bar", "zoo"]
|
34
|
+
#
|
35
|
+
# A "file" option can be set. This config will be preferred over "default" options
|
36
|
+
# but will defer to any available "user" specified options.
|
37
|
+
#
|
38
|
+
# user_options = { foo: "bar" }
|
39
|
+
# default_options = { rackup: "zoo.rb" }
|
40
|
+
# options = UserFileDefaultOptions.new(user_options, default_options)
|
41
|
+
# options.file_options[:rackup] = "sup.rb"
|
42
|
+
# puts options[:rackup]
|
43
|
+
# # => "sup.rb"
|
44
|
+
#
|
45
|
+
# The "default" options can be set via procs. These are resolved during runtime
|
46
|
+
# via calls to `finalize_values`
|
47
|
+
class UserFileDefaultOptions
|
48
|
+
def initialize(user_options, default_options)
|
49
|
+
@user_options = user_options
|
50
|
+
@file_options = {}
|
51
|
+
@default_options = default_options
|
52
|
+
end
|
53
|
+
|
54
|
+
attr_reader :user_options, :file_options, :default_options
|
31
55
|
|
32
56
|
def [](key)
|
33
|
-
|
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
|
-
attr_reader :cur
|
48
|
-
|
49
|
-
def all_of(key)
|
50
|
-
all = []
|
51
|
-
|
52
|
-
@set.each do |o|
|
53
|
-
if v = o[key]
|
54
|
-
if v.kind_of? Array
|
55
|
-
all += v
|
56
|
-
else
|
57
|
-
all << v
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
all
|
57
|
+
fetch(key)
|
63
58
|
end
|
64
59
|
|
65
|
-
def []=(key,
|
66
|
-
|
60
|
+
def []=(key, value)
|
61
|
+
user_options[key] = value
|
67
62
|
end
|
68
63
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
@default.key? key
|
77
|
-
end
|
64
|
+
def fetch(key, default_value = nil)
|
65
|
+
return user_options[key] if user_options.key?(key)
|
66
|
+
return file_options[key] if file_options.key?(key)
|
67
|
+
return default_options[key] if default_options.key?(key)
|
78
68
|
|
79
|
-
|
80
|
-
o.each do |k,v|
|
81
|
-
@cur[k]= v
|
82
|
-
end
|
69
|
+
default_value
|
83
70
|
end
|
84
71
|
|
85
|
-
def
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
o.each do |k,v|
|
90
|
-
options[k] ||= v
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
options
|
95
|
-
end
|
72
|
+
def all_of(key)
|
73
|
+
user = user_options[key]
|
74
|
+
file = file_options[key]
|
75
|
+
default = default_options[key]
|
96
76
|
|
97
|
-
|
98
|
-
|
77
|
+
user = [user] unless user.is_a?(Array)
|
78
|
+
file = [file] unless file.is_a?(Array)
|
79
|
+
default = [default] unless default.is_a?(Array)
|
99
80
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
81
|
+
user.compact!
|
82
|
+
file.compact!
|
83
|
+
default.compact!
|
104
84
|
|
105
|
-
|
106
|
-
end
|
85
|
+
user + file + default
|
107
86
|
end
|
108
87
|
|
109
|
-
def
|
110
|
-
@
|
88
|
+
def finalize_values
|
89
|
+
@default_options.each do |k,v|
|
111
90
|
if v.respond_to? :call
|
112
|
-
@
|
91
|
+
@default_options[k] = v.call
|
113
92
|
end
|
114
93
|
end
|
115
94
|
end
|
116
95
|
end
|
117
96
|
|
97
|
+
# The main configuration class of Puma.
|
98
|
+
#
|
99
|
+
# It can be initialized with a set of "user" options and "default" options.
|
100
|
+
# Defaults will be merged with `Configuration.puma_default_options`.
|
101
|
+
#
|
102
|
+
# This class works together with 2 main other classes the `UserFileDefaultOptions`
|
103
|
+
# which stores configuration options in order so the precedence is that user
|
104
|
+
# set configuration wins over "file" based configuration wins over "default"
|
105
|
+
# configuration. These configurations are set via the `DSL` class. This
|
106
|
+
# class powers the Puma config file syntax and does double duty as a configuration
|
107
|
+
# DSL used by the `Puma::CLI` and Puma rack handler.
|
108
|
+
#
|
109
|
+
# It also handles loading plugins.
|
110
|
+
#
|
111
|
+
# > Note: `:port` and `:host` are not valid keys. By the time they make it to the
|
112
|
+
# configuration options they are expected to be incorporated into a `:binds` key.
|
113
|
+
# Under the hood the DSL maps `port` and `host` calls to `:binds`
|
114
|
+
#
|
115
|
+
# config = Configuration.new({}) do |user_config, file_config, default_config|
|
116
|
+
# user_config.port 3003
|
117
|
+
# end
|
118
|
+
# config.load
|
119
|
+
# puts config.options[:port]
|
120
|
+
# # => 3003
|
121
|
+
#
|
122
|
+
# It is expected that `load` is called on the configuration instance after setting
|
123
|
+
# config. This method expands any values in `config_file` and puts them into the
|
124
|
+
# correct configuration option hash.
|
125
|
+
#
|
126
|
+
# Once all configuration is complete it is expected that `clamp` will be called
|
127
|
+
# on the instance. This will expand any procs stored under "default" values. This
|
128
|
+
# is done because an environment variable may have been modified while loading
|
129
|
+
# configuration files.
|
118
130
|
class Configuration
|
119
131
|
include ConfigDefault
|
120
132
|
|
121
|
-
def
|
122
|
-
|
123
|
-
|
124
|
-
DSL.new(cfg.options, cfg)._load_from path
|
125
|
-
|
126
|
-
return cfg
|
127
|
-
end
|
133
|
+
def initialize(user_options={}, default_options = {}, &block)
|
134
|
+
default_options = self.puma_default_options.merge(default_options)
|
128
135
|
|
129
|
-
|
130
|
-
@
|
131
|
-
@
|
136
|
+
@options = UserFileDefaultOptions.new(user_options, default_options)
|
137
|
+
@plugins = PluginLoader.new
|
138
|
+
@user_dsl = DSL.new(@options.user_options, self)
|
139
|
+
@file_dsl = DSL.new(@options.file_options, self)
|
140
|
+
@default_dsl = DSL.new(@options.default_options, self)
|
132
141
|
|
133
|
-
|
134
|
-
|
135
|
-
|
142
|
+
if !@options[:prune_bundler]
|
143
|
+
default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
|
144
|
+
end
|
136
145
|
|
137
|
-
if
|
138
|
-
configure(&
|
146
|
+
if block
|
147
|
+
configure(&block)
|
139
148
|
end
|
140
149
|
end
|
141
150
|
|
142
151
|
attr_reader :options, :plugins
|
143
152
|
|
144
|
-
def configure
|
145
|
-
@
|
146
|
-
|
153
|
+
def configure
|
154
|
+
yield @user_dsl, @file_dsl, @default_dsl
|
155
|
+
ensure
|
156
|
+
@user_dsl._offer_plugins
|
157
|
+
@file_dsl._offer_plugins
|
158
|
+
@default_dsl._offer_plugins
|
147
159
|
end
|
148
160
|
|
149
161
|
def initialize_copy(other)
|
150
|
-
@conf
|
162
|
+
@conf = nil
|
151
163
|
@cli_options = nil
|
152
|
-
@options
|
164
|
+
@options = @options.dup
|
153
165
|
end
|
154
166
|
|
155
167
|
def flatten
|
@@ -161,52 +173,56 @@ module Puma
|
|
161
173
|
self
|
162
174
|
end
|
163
175
|
|
164
|
-
def
|
176
|
+
def default_max_threads
|
177
|
+
Puma.mri? ? 5 : 16
|
178
|
+
end
|
179
|
+
|
180
|
+
def puma_default_options
|
165
181
|
{
|
166
|
-
:min_threads => 0,
|
167
|
-
:max_threads =>
|
168
|
-
:
|
182
|
+
:min_threads => Integer(ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS'] || 0),
|
183
|
+
:max_threads => Integer(ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS'] || default_max_threads),
|
184
|
+
:log_requests => false,
|
169
185
|
:debug => false,
|
170
186
|
:binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
|
171
|
-
:workers => 0,
|
172
|
-
:daemon => false,
|
187
|
+
:workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
|
173
188
|
:mode => :http,
|
174
189
|
:worker_timeout => DefaultWorkerTimeout,
|
175
190
|
:worker_boot_timeout => DefaultWorkerTimeout,
|
176
191
|
:worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
|
177
192
|
:remote_address => :socket,
|
178
193
|
:tag => method(:infer_tag),
|
179
|
-
:environment =>
|
194
|
+
:environment => -> { ENV['RACK_ENV'] || ENV['RAILS_ENV'] || "development" },
|
180
195
|
:rackup => DefaultRackup,
|
181
|
-
:logger => STDOUT
|
196
|
+
:logger => STDOUT,
|
197
|
+
:persistent_timeout => Const::PERSISTENT_TIMEOUT,
|
198
|
+
:first_data_timeout => Const::FIRST_DATA_TIMEOUT,
|
199
|
+
:raise_exception_on_sigterm => true
|
182
200
|
}
|
183
201
|
end
|
184
202
|
|
185
203
|
def load
|
186
|
-
|
204
|
+
config_files.each { |config_file| @file_dsl._load_from(config_file) }
|
187
205
|
|
188
|
-
|
189
|
-
|
190
|
-
File.exist?(f)
|
191
|
-
}
|
206
|
+
@options
|
207
|
+
end
|
192
208
|
|
193
|
-
|
194
|
-
|
195
|
-
files = []
|
196
|
-
end
|
209
|
+
def config_files
|
210
|
+
files = @options.all_of(:config_files)
|
197
211
|
|
198
|
-
files
|
199
|
-
|
212
|
+
return [] if files == ['-']
|
213
|
+
return files if files.any?
|
200
214
|
|
201
|
-
|
215
|
+
first_default_file = %W(config/puma/#{environment_str}.rb config/puma.rb).find do |f|
|
216
|
+
File.exist?(f)
|
202
217
|
end
|
218
|
+
|
219
|
+
[first_default_file]
|
203
220
|
end
|
204
221
|
|
205
222
|
# Call once all configuration (included from rackup files)
|
206
223
|
# is loaded to flesh out any defaults
|
207
224
|
def clamp
|
208
|
-
@options.
|
209
|
-
@options.force_defaults
|
225
|
+
@options.finalize_values
|
210
226
|
end
|
211
227
|
|
212
228
|
# Injects the Configuration object into the env
|
@@ -238,14 +254,8 @@ module Puma
|
|
238
254
|
def app
|
239
255
|
found = options[:app] || load_rackup
|
240
256
|
|
241
|
-
if @options[:
|
242
|
-
require 'puma/
|
243
|
-
|
244
|
-
logger = @options[:logger]
|
245
|
-
return TCPLogger.new(logger, found, @options[:quiet])
|
246
|
-
end
|
247
|
-
|
248
|
-
if !@options[:quiet] and @options[:environment] == "development"
|
257
|
+
if @options[:log_requests]
|
258
|
+
require 'puma/commonlogger'
|
249
259
|
logger = @options[:logger]
|
250
260
|
found = CommonLogger.new(found, logger)
|
251
261
|
end
|
@@ -258,12 +268,23 @@ module Puma
|
|
258
268
|
@options[:environment]
|
259
269
|
end
|
260
270
|
|
271
|
+
def environment_str
|
272
|
+
environment.respond_to?(:call) ? environment.call : environment
|
273
|
+
end
|
274
|
+
|
261
275
|
def load_plugin(name)
|
262
276
|
@plugins.create name
|
263
277
|
end
|
264
278
|
|
265
|
-
def run_hooks(key, arg)
|
266
|
-
@options.all_of(key).each
|
279
|
+
def run_hooks(key, arg, events)
|
280
|
+
@options.all_of(key).each do |b|
|
281
|
+
begin
|
282
|
+
b.call arg
|
283
|
+
rescue => e
|
284
|
+
events.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
|
285
|
+
events.debug e.backtrace.join("\n")
|
286
|
+
end
|
287
|
+
end
|
267
288
|
end
|
268
289
|
|
269
290
|
def self.temp_path
|
@@ -305,45 +326,23 @@ module Puma
|
|
305
326
|
def load_rackup
|
306
327
|
raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
|
307
328
|
|
308
|
-
@options.shift
|
309
|
-
|
310
329
|
rack_app, rack_options = rack_builder.parse_file(rackup)
|
311
|
-
@options.merge!(rack_options)
|
330
|
+
@options.file_options.merge!(rack_options)
|
312
331
|
|
313
332
|
config_ru_binds = []
|
314
333
|
rack_options.each do |k, v|
|
315
334
|
config_ru_binds << v if k.to_s.start_with?("bind")
|
316
335
|
end
|
317
336
|
|
318
|
-
@options[:binds] = config_ru_binds unless config_ru_binds.empty?
|
337
|
+
@options.file_options[:binds] = config_ru_binds unless config_ru_binds.empty?
|
319
338
|
|
320
339
|
rack_app
|
321
340
|
end
|
322
341
|
|
323
342
|
def self.random_token
|
324
|
-
|
325
|
-
require 'openssl'
|
326
|
-
rescue LoadError
|
327
|
-
end
|
328
|
-
|
329
|
-
count = 16
|
330
|
-
|
331
|
-
bytes = nil
|
332
|
-
|
333
|
-
if defined? OpenSSL::Random
|
334
|
-
bytes = OpenSSL::Random.random_bytes(count)
|
335
|
-
elsif File.exist?("/dev/urandom")
|
336
|
-
File.open('/dev/urandom') { |f| bytes = f.read(count) }
|
337
|
-
end
|
338
|
-
|
339
|
-
if bytes
|
340
|
-
token = ""
|
341
|
-
bytes.each_byte { |b| token << b.to_s(16) }
|
342
|
-
else
|
343
|
-
token = (0..count).to_a.map { rand(255).to_s(16) }.join
|
344
|
-
end
|
343
|
+
require 'securerandom' unless defined?(SecureRandom)
|
345
344
|
|
346
|
-
|
345
|
+
SecureRandom.hex(16)
|
347
346
|
end
|
348
347
|
end
|
349
348
|
end
|