piesync-puma 3.12.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/History.md +1429 -0
  3. data/LICENSE +26 -0
  4. data/README.md +280 -0
  5. data/bin/puma +10 -0
  6. data/bin/puma-wild +31 -0
  7. data/bin/pumactl +12 -0
  8. data/docs/architecture.md +36 -0
  9. data/docs/deployment.md +91 -0
  10. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  11. data/docs/images/puma-connection-flow.png +0 -0
  12. data/docs/images/puma-general-arch.png +0 -0
  13. data/docs/nginx.md +80 -0
  14. data/docs/plugins.md +28 -0
  15. data/docs/restart.md +39 -0
  16. data/docs/signals.md +96 -0
  17. data/docs/systemd.md +272 -0
  18. data/ext/puma_http11/PumaHttp11Service.java +17 -0
  19. data/ext/puma_http11/ext_help.h +15 -0
  20. data/ext/puma_http11/extconf.rb +15 -0
  21. data/ext/puma_http11/http11_parser.c +1071 -0
  22. data/ext/puma_http11/http11_parser.h +65 -0
  23. data/ext/puma_http11/http11_parser.java.rl +161 -0
  24. data/ext/puma_http11/http11_parser.rl +149 -0
  25. data/ext/puma_http11/http11_parser_common.rl +54 -0
  26. data/ext/puma_http11/io_buffer.c +155 -0
  27. data/ext/puma_http11/mini_ssl.c +494 -0
  28. data/ext/puma_http11/org/jruby/puma/Http11.java +234 -0
  29. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +470 -0
  30. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +352 -0
  31. data/ext/puma_http11/puma_http11.c +500 -0
  32. data/lib/puma.rb +23 -0
  33. data/lib/puma/accept_nonblock.rb +23 -0
  34. data/lib/puma/app/status.rb +74 -0
  35. data/lib/puma/binder.rb +413 -0
  36. data/lib/puma/cli.rb +235 -0
  37. data/lib/puma/client.rb +480 -0
  38. data/lib/puma/cluster.rb +531 -0
  39. data/lib/puma/commonlogger.rb +108 -0
  40. data/lib/puma/compat.rb +14 -0
  41. data/lib/puma/configuration.rb +361 -0
  42. data/lib/puma/const.rb +239 -0
  43. data/lib/puma/control_cli.rb +264 -0
  44. data/lib/puma/convenient.rb +25 -0
  45. data/lib/puma/daemon_ext.rb +33 -0
  46. data/lib/puma/delegation.rb +13 -0
  47. data/lib/puma/detect.rb +15 -0
  48. data/lib/puma/dsl.rb +518 -0
  49. data/lib/puma/events.rb +153 -0
  50. data/lib/puma/io_buffer.rb +9 -0
  51. data/lib/puma/java_io_buffer.rb +47 -0
  52. data/lib/puma/jruby_restart.rb +84 -0
  53. data/lib/puma/launcher.rb +433 -0
  54. data/lib/puma/minissl.rb +285 -0
  55. data/lib/puma/null_io.rb +44 -0
  56. data/lib/puma/plugin.rb +117 -0
  57. data/lib/puma/plugin/tmp_restart.rb +34 -0
  58. data/lib/puma/rack/backports/uri/common_193.rb +33 -0
  59. data/lib/puma/rack/builder.rb +299 -0
  60. data/lib/puma/rack/urlmap.rb +91 -0
  61. data/lib/puma/rack_default.rb +7 -0
  62. data/lib/puma/reactor.rb +347 -0
  63. data/lib/puma/runner.rb +184 -0
  64. data/lib/puma/server.rb +1072 -0
  65. data/lib/puma/single.rb +123 -0
  66. data/lib/puma/state_file.rb +31 -0
  67. data/lib/puma/tcp_logger.rb +41 -0
  68. data/lib/puma/thread_pool.rb +346 -0
  69. data/lib/puma/util.rb +129 -0
  70. data/lib/rack/handler/puma.rb +115 -0
  71. data/tools/jungle/README.md +19 -0
  72. data/tools/jungle/init.d/README.md +61 -0
  73. data/tools/jungle/init.d/puma +421 -0
  74. data/tools/jungle/init.d/run-puma +18 -0
  75. data/tools/jungle/rc.d/README.md +74 -0
  76. data/tools/jungle/rc.d/puma +61 -0
  77. data/tools/jungle/rc.d/puma.conf +10 -0
  78. data/tools/jungle/upstart/README.md +61 -0
  79. data/tools/jungle/upstart/puma-manager.conf +31 -0
  80. data/tools/jungle/upstart/puma.conf +69 -0
  81. data/tools/trickletest.rb +45 -0
  82. metadata +131 -0
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Puma
4
+ # Rack::CommonLogger forwards every request to the given +app+, and
5
+ # logs a line in the
6
+ # {Apache common log format}[http://httpd.apache.org/docs/1.3/logs.html#common]
7
+ # to the +logger+.
8
+ #
9
+ # If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
10
+ # an instance of Rack::NullLogger.
11
+ #
12
+ # +logger+ can be any class, including the standard library Logger, and is
13
+ # expected to have either +write+ or +<<+ method, which accepts the CommonLogger::FORMAT.
14
+ # According to the SPEC, the error stream must also respond to +puts+
15
+ # (which takes a single argument that responds to +to_s+), and +flush+
16
+ # (which is called without arguments in order to make the error appear for
17
+ # sure)
18
+ class CommonLogger
19
+ # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
20
+ #
21
+ # lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
22
+ #
23
+ # %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
24
+ FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n}
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
+
33
+ def initialize(app, logger=nil)
34
+ @app = app
35
+ @logger = logger
36
+ end
37
+
38
+ def call(env)
39
+ began_at = Time.now
40
+ status, header, body = @app.call(env)
41
+ header = Util::HeaderHash.new(header)
42
+
43
+ # If we've been hijacked, then output a special line
44
+ if env['rack.hijack_io']
45
+ log_hijacking(env, 'HIJACK', header, began_at)
46
+ else
47
+ ary = env['rack.after_reply']
48
+ ary << lambda { log(env, status, header, began_at) }
49
+ end
50
+
51
+ [status, header, body]
52
+ end
53
+
54
+ private
55
+
56
+ def log_hijacking(env, status, header, began_at)
57
+ now = Time.now
58
+
59
+ msg = HIJACK_FORMAT % [
60
+ env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
61
+ env["REMOTE_USER"] || "-",
62
+ now.strftime("%d/%b/%Y %H:%M:%S"),
63
+ env[REQUEST_METHOD],
64
+ env[PATH_INFO],
65
+ env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
66
+ env["HTTP_VERSION"],
67
+ now - began_at ]
68
+
69
+ write(msg)
70
+ end
71
+
72
+ def log(env, status, header, began_at)
73
+ now = Time.now
74
+ length = extract_content_length(header)
75
+
76
+ msg = FORMAT % [
77
+ env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
78
+ env["REMOTE_USER"] || "-",
79
+ now.strftime("%d/%b/%Y:%H:%M:%S %z"),
80
+ env[REQUEST_METHOD],
81
+ env[PATH_INFO],
82
+ env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
83
+ env["HTTP_VERSION"],
84
+ status.to_s[0..3],
85
+ length,
86
+ now - began_at ]
87
+
88
+ write(msg)
89
+ end
90
+
91
+ def write(msg)
92
+ logger = @logger || env['rack.errors']
93
+
94
+ # Standard library logger doesn't support write but it supports << which actually
95
+ # calls to write on the log device without formatting
96
+ if logger.respond_to?(:write)
97
+ logger.write(msg)
98
+ else
99
+ logger << msg
100
+ end
101
+ end
102
+
103
+ def extract_content_length(headers)
104
+ value = headers[CONTENT_LENGTH] or return '-'
105
+ value.to_s == '0' ? '-' : value
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,14 @@
1
+ # Provides code to work properly on 1.8 and 1.9
2
+
3
+ class String
4
+ unless method_defined? :bytesize
5
+ alias_method :bytesize, :size
6
+ end
7
+
8
+ unless method_defined? :byteslice
9
+ def byteslice(*arg)
10
+ enc = self.encoding
11
+ self.dup.force_encoding(Encoding::ASCII_8BIT).slice(*arg).force_encoding(enc)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,361 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'puma/rack/builder'
4
+ require 'puma/plugin'
5
+ require 'puma/const'
6
+
7
+ module Puma
8
+
9
+ module ConfigDefault
10
+ DefaultRackup = "config.ru"
11
+
12
+ DefaultTCPHost = "0.0.0.0"
13
+ DefaultTCPPort = 9292
14
+ DefaultWorkerTimeout = 60
15
+ DefaultWorkerShutdownTimeout = 30
16
+ end
17
+
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 prefered 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 prefered 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
55
+
56
+ def [](key)
57
+ return user_options[key] if user_options.key?(key)
58
+ return file_options[key] if file_options.key?(key)
59
+ return default_options[key] if default_options.key?(key)
60
+ end
61
+
62
+ def []=(key, value)
63
+ user_options[key] = value
64
+ end
65
+
66
+ def fetch(key, default_value = nil)
67
+ self[key] || default_value
68
+ end
69
+
70
+ def all_of(key)
71
+ user = user_options[key]
72
+ file = file_options[key]
73
+ default = default_options[key]
74
+
75
+ user = [user] unless user.is_a?(Array)
76
+ file = [file] unless file.is_a?(Array)
77
+ default = [default] unless default.is_a?(Array)
78
+
79
+ user.compact!
80
+ file.compact!
81
+ default.compact!
82
+
83
+ user + file + default
84
+ end
85
+
86
+ def finalize_values
87
+ @default_options.each do |k,v|
88
+ if v.respond_to? :call
89
+ @default_options[k] = v.call
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ # The main configuration class of Puma.
96
+ #
97
+ # It can be initialized with a set of "user" options and "default" options.
98
+ # Defaults will be merged with `Configuration.puma_default_options`.
99
+ #
100
+ # This class works together with 2 main other classes the `UserFileDefaultOptions`
101
+ # which stores configuration options in order so the precedence is that user
102
+ # set configuration wins over "file" based configuration wins over "default"
103
+ # configuration. These configurations are set via the `DSL` class. This
104
+ # class powers the Puma config file syntax and does double duty as a configuration
105
+ # DSL used by the `Puma::CLI` and Puma rack handler.
106
+ #
107
+ # It also handles loading plugins.
108
+ #
109
+ # > Note: `:port` and `:host` are not valid keys. By they time they make it to the
110
+ # configuration options they are expected to be incorporated into a `:binds` key.
111
+ # Under the hood the DSL maps `port` and `host` calls to `:binds`
112
+ #
113
+ # config = Configuration.new({}) do |user_config, file_config, default_config|
114
+ # user_config.port 3003
115
+ # end
116
+ # config.load
117
+ # puts config.options[:port]
118
+ # # => 3003
119
+ #
120
+ # It is expected that `load` is called on the configuration instance after setting
121
+ # config. This method expands any values in `config_file` and puts them into the
122
+ # correct configuration option hash.
123
+ #
124
+ # Once all configuration is complete it is expected that `clamp` will be called
125
+ # on the instance. This will expand any procs stored under "default" values. This
126
+ # is done because an environment variable may have been modified while loading
127
+ # configuration files.
128
+ class Configuration
129
+ include ConfigDefault
130
+
131
+ def initialize(user_options={}, default_options = {}, &block)
132
+ default_options = self.puma_default_options.merge(default_options)
133
+
134
+ @options = UserFileDefaultOptions.new(user_options, default_options)
135
+ @plugins = PluginLoader.new
136
+ @user_dsl = DSL.new(@options.user_options, self)
137
+ @file_dsl = DSL.new(@options.file_options, self)
138
+ @default_dsl = DSL.new(@options.default_options, self)
139
+
140
+ if block
141
+ configure(&block)
142
+ end
143
+ end
144
+
145
+ attr_reader :options, :plugins
146
+
147
+ def configure
148
+ yield @user_dsl, @file_dsl, @default_dsl
149
+ ensure
150
+ @user_dsl._offer_plugins
151
+ @file_dsl._offer_plugins
152
+ @default_dsl._offer_plugins
153
+ end
154
+
155
+ def initialize_copy(other)
156
+ @conf = nil
157
+ @cli_options = nil
158
+ @options = @options.dup
159
+ end
160
+
161
+ def flatten
162
+ dup.flatten!
163
+ end
164
+
165
+ def flatten!
166
+ @options = @options.flatten
167
+ self
168
+ end
169
+
170
+ def puma_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 => -> { ENV['RACK_ENV'] || "development" },
186
+ :rackup => DefaultRackup,
187
+ :logger => STDOUT,
188
+ :persistent_timeout => Const::PERSISTENT_TIMEOUT,
189
+ :first_data_timeout => Const::FIRST_DATA_TIMEOUT
190
+ }
191
+ end
192
+
193
+ def load
194
+ config_files.each { |config_file| @file_dsl._load_from(config_file) }
195
+
196
+ @options
197
+ end
198
+
199
+ def config_files
200
+ files = @options.all_of(:config_files)
201
+
202
+ return [] if files == ['-']
203
+ return files if files.any?
204
+
205
+ first_default_file = %W(config/puma/#{environment_str}.rb config/puma.rb).find do |f|
206
+ File.exist?(f)
207
+ end
208
+
209
+ [first_default_file]
210
+ end
211
+
212
+ # Call once all configuration (included from rackup files)
213
+ # is loaded to flesh out any defaults
214
+ def clamp
215
+ @options.finalize_values
216
+ end
217
+
218
+ # Injects the Configuration object into the env
219
+ class ConfigMiddleware
220
+ def initialize(config, app)
221
+ @config = config
222
+ @app = app
223
+ end
224
+
225
+ def call(env)
226
+ env[Const::PUMA_CONFIG] = @config
227
+ @app.call(env)
228
+ end
229
+ end
230
+
231
+ # Indicate if there is a properly configured app
232
+ #
233
+ def app_configured?
234
+ @options[:app] || File.exist?(rackup)
235
+ end
236
+
237
+ def rackup
238
+ @options[:rackup]
239
+ end
240
+
241
+ # Load the specified rackup file, pull options from
242
+ # the rackup file, and set @app.
243
+ #
244
+ def app
245
+ found = options[:app] || load_rackup
246
+
247
+ if @options[:mode] == :tcp
248
+ require 'puma/tcp_logger'
249
+
250
+ logger = @options[:logger]
251
+ quiet = !@options[:log_requests]
252
+ return TCPLogger.new(logger, found, quiet)
253
+ end
254
+
255
+ if @options[:log_requests]
256
+ require 'puma/commonlogger'
257
+ logger = @options[:logger]
258
+ found = CommonLogger.new(found, logger)
259
+ end
260
+
261
+ ConfigMiddleware.new(self, found)
262
+ end
263
+
264
+ # Return which environment we're running in
265
+ def environment
266
+ @options[:environment]
267
+ end
268
+
269
+ def environment_str
270
+ environment.respond_to?(:call) ? environment.call : environment
271
+ end
272
+
273
+ def load_plugin(name)
274
+ @plugins.create name
275
+ end
276
+
277
+ def run_hooks(key, arg)
278
+ @options.all_of(key).each { |b| b.call arg }
279
+ end
280
+
281
+ def self.temp_path
282
+ require 'tmpdir'
283
+
284
+ t = (Time.now.to_f * 1000).to_i
285
+ "#{Dir.tmpdir}/puma-status-#{t}-#{$$}"
286
+ end
287
+
288
+ private
289
+
290
+ def infer_tag
291
+ File.basename(Dir.getwd)
292
+ end
293
+
294
+ # Load and use the normal Rack builder if we can, otherwise
295
+ # fallback to our minimal version.
296
+ def rack_builder
297
+ # Load bundler now if we can so that we can pickup rack from
298
+ # a Gemfile
299
+ if ENV.key? 'PUMA_BUNDLER_PRUNED'
300
+ begin
301
+ require 'bundler/setup'
302
+ rescue LoadError
303
+ end
304
+ end
305
+
306
+ begin
307
+ require 'rack'
308
+ require 'rack/builder'
309
+ rescue LoadError
310
+ # ok, use builtin version
311
+ return Puma::Rack::Builder
312
+ else
313
+ return ::Rack::Builder
314
+ end
315
+ end
316
+
317
+ def load_rackup
318
+ raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
319
+
320
+ rack_app, rack_options = rack_builder.parse_file(rackup)
321
+ @options.file_options.merge!(rack_options)
322
+
323
+ config_ru_binds = []
324
+ rack_options.each do |k, v|
325
+ config_ru_binds << v if k.to_s.start_with?("bind")
326
+ end
327
+
328
+ @options.file_options[:binds] = config_ru_binds unless config_ru_binds.empty?
329
+
330
+ rack_app
331
+ end
332
+
333
+ def self.random_token
334
+ begin
335
+ require 'openssl'
336
+ rescue LoadError
337
+ end
338
+
339
+ count = 16
340
+
341
+ bytes = nil
342
+
343
+ if defined? OpenSSL::Random
344
+ bytes = OpenSSL::Random.random_bytes(count)
345
+ elsif File.exist?("/dev/urandom")
346
+ File.open('/dev/urandom') { |f| bytes = f.read(count) }
347
+ end
348
+
349
+ if bytes
350
+ token = "".dup
351
+ bytes.each_byte { |b| token << b.to_s(16) }
352
+ else
353
+ token = (0..count).to_a.map { rand(255).to_s(16) }.join
354
+ end
355
+
356
+ return token
357
+ end
358
+ end
359
+ end
360
+
361
+ require 'puma/dsl'