piesync-puma 3.12.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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'