puma-simon 3.7.1

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 (157) hide show
  1. checksums.yaml +7 -0
  2. data/.github/issue_template.md +20 -0
  3. data/.gitignore +18 -0
  4. data/.hoeignore +12 -0
  5. data/.travis.yml +29 -0
  6. data/DEPLOYMENT.md +91 -0
  7. data/Gemfile +12 -0
  8. data/History.md +1254 -0
  9. data/LICENSE +26 -0
  10. data/Manifest.txt +78 -0
  11. data/README.md +353 -0
  12. data/Rakefile +158 -0
  13. data/Release.md +9 -0
  14. data/bin/puma +10 -0
  15. data/bin/puma-wild +31 -0
  16. data/bin/pumactl +12 -0
  17. data/docs/nginx.md +80 -0
  18. data/docs/signals.md +43 -0
  19. data/docs/systemd.md +197 -0
  20. data/examples/CA/cacert.pem +23 -0
  21. data/examples/CA/newcerts/cert_1.pem +19 -0
  22. data/examples/CA/newcerts/cert_2.pem +19 -0
  23. data/examples/CA/private/cakeypair.pem +30 -0
  24. data/examples/CA/serial +1 -0
  25. data/examples/config.rb +200 -0
  26. data/examples/plugins/redis_stop_puma.rb +46 -0
  27. data/examples/puma/cert_puma.pem +19 -0
  28. data/examples/puma/client-certs/ca.crt +19 -0
  29. data/examples/puma/client-certs/ca.key +27 -0
  30. data/examples/puma/client-certs/client.crt +19 -0
  31. data/examples/puma/client-certs/client.key +27 -0
  32. data/examples/puma/client-certs/client_expired.crt +19 -0
  33. data/examples/puma/client-certs/client_expired.key +27 -0
  34. data/examples/puma/client-certs/client_unknown.crt +19 -0
  35. data/examples/puma/client-certs/client_unknown.key +27 -0
  36. data/examples/puma/client-certs/generate.rb +78 -0
  37. data/examples/puma/client-certs/keystore.jks +0 -0
  38. data/examples/puma/client-certs/server.crt +19 -0
  39. data/examples/puma/client-certs/server.key +27 -0
  40. data/examples/puma/client-certs/server.p12 +0 -0
  41. data/examples/puma/client-certs/unknown_ca.crt +19 -0
  42. data/examples/puma/client-certs/unknown_ca.key +27 -0
  43. data/examples/puma/csr_puma.pem +11 -0
  44. data/examples/puma/keystore.jks +0 -0
  45. data/examples/puma/puma_keypair.pem +15 -0
  46. data/examples/qc_config.rb +13 -0
  47. data/ext/puma_http11/PumaHttp11Service.java +17 -0
  48. data/ext/puma_http11/ext_help.h +15 -0
  49. data/ext/puma_http11/extconf.rb +15 -0
  50. data/ext/puma_http11/http11_parser.c +1069 -0
  51. data/ext/puma_http11/http11_parser.h +65 -0
  52. data/ext/puma_http11/http11_parser.java.rl +161 -0
  53. data/ext/puma_http11/http11_parser.rl +147 -0
  54. data/ext/puma_http11/http11_parser_common.rl +54 -0
  55. data/ext/puma_http11/io_buffer.c +155 -0
  56. data/ext/puma_http11/mini_ssl.c +457 -0
  57. data/ext/puma_http11/org/jruby/puma/Http11.java +234 -0
  58. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +473 -0
  59. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +339 -0
  60. data/ext/puma_http11/puma_http11.c +500 -0
  61. data/gemfiles/2.1-Gemfile +12 -0
  62. data/lib/puma.rb +15 -0
  63. data/lib/puma/accept_nonblock.rb +23 -0
  64. data/lib/puma/app/status.rb +66 -0
  65. data/lib/puma/binder.rb +402 -0
  66. data/lib/puma/cli.rb +220 -0
  67. data/lib/puma/client.rb +434 -0
  68. data/lib/puma/cluster.rb +510 -0
  69. data/lib/puma/commonlogger.rb +106 -0
  70. data/lib/puma/compat.rb +14 -0
  71. data/lib/puma/configuration.rb +364 -0
  72. data/lib/puma/const.rb +224 -0
  73. data/lib/puma/control_cli.rb +259 -0
  74. data/lib/puma/convenient.rb +23 -0
  75. data/lib/puma/daemon_ext.rb +31 -0
  76. data/lib/puma/delegation.rb +11 -0
  77. data/lib/puma/detect.rb +13 -0
  78. data/lib/puma/dsl.rb +486 -0
  79. data/lib/puma/events.rb +152 -0
  80. data/lib/puma/io_buffer.rb +7 -0
  81. data/lib/puma/java_io_buffer.rb +45 -0
  82. data/lib/puma/jruby_restart.rb +83 -0
  83. data/lib/puma/launcher.rb +410 -0
  84. data/lib/puma/minissl.rb +221 -0
  85. data/lib/puma/null_io.rb +42 -0
  86. data/lib/puma/plugin.rb +115 -0
  87. data/lib/puma/plugin/tmp_restart.rb +35 -0
  88. data/lib/puma/rack/backports/uri/common_193.rb +33 -0
  89. data/lib/puma/rack/builder.rb +298 -0
  90. data/lib/puma/rack/urlmap.rb +91 -0
  91. data/lib/puma/rack_default.rb +7 -0
  92. data/lib/puma/reactor.rb +210 -0
  93. data/lib/puma/runner.rb +171 -0
  94. data/lib/puma/server.rb +949 -0
  95. data/lib/puma/single.rb +112 -0
  96. data/lib/puma/state_file.rb +29 -0
  97. data/lib/puma/tcp_logger.rb +39 -0
  98. data/lib/puma/thread_pool.rb +297 -0
  99. data/lib/puma/util.rb +128 -0
  100. data/lib/rack/handler/puma.rb +78 -0
  101. data/puma.gemspec +52 -0
  102. data/test/ab_rs.rb +22 -0
  103. data/test/config.rb +2 -0
  104. data/test/config/app.rb +9 -0
  105. data/test/config/plugin.rb +1 -0
  106. data/test/config/settings.rb +2 -0
  107. data/test/config/state_file_testing_config.rb +14 -0
  108. data/test/hello-bind.ru +2 -0
  109. data/test/hello-delay.ru +3 -0
  110. data/test/hello-map.ru +3 -0
  111. data/test/hello-post.ru +4 -0
  112. data/test/hello-stuck.ru +1 -0
  113. data/test/hello-tcp.ru +5 -0
  114. data/test/hello.ru +1 -0
  115. data/test/hijack.ru +6 -0
  116. data/test/hijack2.ru +5 -0
  117. data/test/lobster.ru +4 -0
  118. data/test/shell/run.sh +24 -0
  119. data/test/shell/t1.rb +19 -0
  120. data/test/shell/t1_conf.rb +3 -0
  121. data/test/shell/t2.rb +17 -0
  122. data/test/shell/t2_conf.rb +6 -0
  123. data/test/shell/t3.rb +25 -0
  124. data/test/shell/t3_conf.rb +5 -0
  125. data/test/slow.ru +4 -0
  126. data/test/ssl_config.rb +4 -0
  127. data/test/test_app_status.rb +93 -0
  128. data/test/test_binder.rb +31 -0
  129. data/test/test_cli.rb +209 -0
  130. data/test/test_config.rb +95 -0
  131. data/test/test_events.rb +161 -0
  132. data/test/test_helper.rb +50 -0
  133. data/test/test_http10.rb +27 -0
  134. data/test/test_http11.rb +186 -0
  135. data/test/test_integration.rb +247 -0
  136. data/test/test_iobuffer.rb +39 -0
  137. data/test/test_minissl.rb +29 -0
  138. data/test/test_null_io.rb +49 -0
  139. data/test/test_persistent.rb +245 -0
  140. data/test/test_puma_server.rb +626 -0
  141. data/test/test_puma_server_ssl.rb +222 -0
  142. data/test/test_rack_handler.rb +57 -0
  143. data/test/test_rack_server.rb +138 -0
  144. data/test/test_tcp_logger.rb +39 -0
  145. data/test/test_tcp_rack.rb +36 -0
  146. data/test/test_thread_pool.rb +250 -0
  147. data/test/test_unix_socket.rb +35 -0
  148. data/test/test_web_server.rb +88 -0
  149. data/tools/jungle/README.md +9 -0
  150. data/tools/jungle/init.d/README.md +59 -0
  151. data/tools/jungle/init.d/puma +421 -0
  152. data/tools/jungle/init.d/run-puma +18 -0
  153. data/tools/jungle/upstart/README.md +61 -0
  154. data/tools/jungle/upstart/puma-manager.conf +31 -0
  155. data/tools/jungle/upstart/puma.conf +69 -0
  156. data/tools/trickletest.rb +45 -0
  157. metadata +297 -0
@@ -0,0 +1,106 @@
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
+ HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
25
+
26
+ CONTENT_LENGTH = 'Content-Length'.freeze
27
+ PATH_INFO = 'PATH_INFO'.freeze
28
+ QUERY_STRING = 'QUERY_STRING'.freeze
29
+ REQUEST_METHOD = 'REQUEST_METHOD'.freeze
30
+
31
+ def initialize(app, logger=nil)
32
+ @app = app
33
+ @logger = logger
34
+ end
35
+
36
+ def call(env)
37
+ began_at = Time.now
38
+ status, header, body = @app.call(env)
39
+ header = Util::HeaderHash.new(header)
40
+
41
+ # If we've been hijacked, then output a special line
42
+ if env['rack.hijack_io']
43
+ log_hijacking(env, 'HIJACK', header, began_at)
44
+ else
45
+ ary = env['rack.after_reply']
46
+ ary << lambda { log(env, status, header, began_at) }
47
+ end
48
+
49
+ [status, header, body]
50
+ end
51
+
52
+ private
53
+
54
+ def log_hijacking(env, status, header, began_at)
55
+ now = Time.now
56
+
57
+ msg = HIJACK_FORMAT % [
58
+ env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
59
+ env["REMOTE_USER"] || "-",
60
+ now.strftime("%d/%b/%Y %H:%M:%S"),
61
+ env[REQUEST_METHOD],
62
+ env[PATH_INFO],
63
+ env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
64
+ env["HTTP_VERSION"],
65
+ now - began_at ]
66
+
67
+ write(msg)
68
+ end
69
+
70
+ def log(env, status, header, began_at)
71
+ now = Time.now
72
+ length = extract_content_length(header)
73
+
74
+ msg = FORMAT % [
75
+ env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
76
+ env["REMOTE_USER"] || "-",
77
+ now.strftime("%d/%b/%Y:%H:%M:%S %z"),
78
+ env[REQUEST_METHOD],
79
+ env[PATH_INFO],
80
+ env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
81
+ env["HTTP_VERSION"],
82
+ status.to_s[0..3],
83
+ length,
84
+ now - began_at ]
85
+
86
+ write(msg)
87
+ end
88
+
89
+ def write(msg)
90
+ logger = @logger || env['rack.errors']
91
+
92
+ # Standard library logger doesn't support write but it supports << which actually
93
+ # calls to write on the log device without formatting
94
+ if logger.respond_to?(:write)
95
+ logger.write(msg)
96
+ else
97
+ logger << msg
98
+ end
99
+ end
100
+
101
+ def extract_content_length(headers)
102
+ value = headers[CONTENT_LENGTH] or return '-'
103
+ value.to_s == '0' ? '-' : value
104
+ end
105
+ end
106
+ 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,364 @@
1
+ require 'puma/rack/builder'
2
+ require 'puma/plugin'
3
+ require 'puma/const'
4
+
5
+ module Puma
6
+
7
+ module ConfigDefault
8
+ DefaultRackup = "config.ru"
9
+
10
+ DefaultTCPHost = "0.0.0.0"
11
+ DefaultTCPPort = 9292
12
+ DefaultWorkerTimeout = 60
13
+ DefaultWorkerShutdownTimeout = 30
14
+ end
15
+
16
+ class LeveledOptions
17
+ def initialize(default_options, user_options)
18
+ @cur = user_options
19
+ @set = [@cur]
20
+ @defaults = default_options.dup
21
+ end
22
+
23
+ def initialize_copy(other)
24
+ @set = @set.map { |o| o.dup }
25
+ @cur = @set.last
26
+ end
27
+
28
+ def shift
29
+ @cur = {}
30
+ @set << @cur
31
+ end
32
+
33
+ def reverse_shift
34
+ @cur = {}
35
+ @set.unshift(@cur)
36
+ end
37
+
38
+ def [](key)
39
+ @set.reverse_each do |o|
40
+ if o.key? key
41
+ return o[key]
42
+ end
43
+ end
44
+
45
+ v = @defaults[key]
46
+ if v.respond_to? :call
47
+ v.call
48
+ else
49
+ v
50
+ end
51
+ end
52
+
53
+ def fetch(key, default=nil)
54
+ val = self[key]
55
+ return val if val
56
+ default
57
+ end
58
+
59
+ attr_reader :cur
60
+
61
+ def all_of(key)
62
+ all = []
63
+
64
+ @set.each do |o|
65
+ if v = o[key]
66
+ if v.kind_of? Array
67
+ all += v
68
+ else
69
+ all << v
70
+ end
71
+ end
72
+ end
73
+
74
+ all
75
+ end
76
+
77
+ def []=(key, val)
78
+ @cur[key] = val
79
+ end
80
+
81
+ def key?(key)
82
+ @set.each do |o|
83
+ if o.key? key
84
+ return true
85
+ end
86
+ end
87
+
88
+ @default.key? key
89
+ end
90
+
91
+ def merge!(o)
92
+ o.each do |k,v|
93
+ @cur[k]= v
94
+ end
95
+ end
96
+
97
+ def flatten
98
+ options = {}
99
+
100
+ @set.each do |o|
101
+ o.each do |k,v|
102
+ options[k] ||= v
103
+ end
104
+ end
105
+
106
+ options
107
+ end
108
+
109
+ def explain
110
+ indent = ""
111
+
112
+ @set.each do |o|
113
+ o.keys.sort.each do |k|
114
+ puts "#{indent}#{k}: #{o[k].inspect}"
115
+ end
116
+
117
+ indent = " #{indent}"
118
+ end
119
+ end
120
+
121
+ def force_defaults
122
+ @defaults.each do |k,v|
123
+ if v.respond_to? :call
124
+ @defaults[k] = v.call
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ class Configuration
131
+ include ConfigDefault
132
+
133
+ def self.from_file(path)
134
+ cfg = new
135
+
136
+ DSL.new(cfg.options, cfg)._load_from path
137
+
138
+ return cfg
139
+ end
140
+
141
+ def initialize(options={}, &blk)
142
+ @options = LeveledOptions.new(default_options, options)
143
+
144
+ @plugins = PluginLoader.new
145
+
146
+ if blk
147
+ configure(&blk)
148
+ end
149
+ end
150
+
151
+ attr_reader :options, :plugins
152
+
153
+ def configure(&blk)
154
+ @options.shift
155
+ DSL.new(@options, self)._run(&blk)
156
+ end
157
+
158
+ def initialize_copy(other)
159
+ @conf = nil
160
+ @cli_options = nil
161
+ @options = @options.dup
162
+ end
163
+
164
+ def flatten
165
+ dup.flatten!
166
+ end
167
+
168
+ def flatten!
169
+ @options = @options.flatten
170
+ self
171
+ end
172
+
173
+ def default_options
174
+ {
175
+ :min_threads => 0,
176
+ :max_threads => 16,
177
+ :log_requests => false,
178
+ :debug => false,
179
+ :binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
180
+ :workers => 0,
181
+ :daemon => false,
182
+ :mode => :http,
183
+ :worker_timeout => DefaultWorkerTimeout,
184
+ :worker_boot_timeout => DefaultWorkerTimeout,
185
+ :worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
186
+ :remote_address => :socket,
187
+ :tag => method(:infer_tag),
188
+ :environment => lambda { ENV['RACK_ENV'] || "development" },
189
+ :rackup => DefaultRackup,
190
+ :logger => STDOUT,
191
+ :persistent_timeout => Const::PERSISTENT_TIMEOUT
192
+ }
193
+ end
194
+
195
+ def load
196
+ files = @options.all_of(:config_files)
197
+
198
+ if files.empty?
199
+ imp = %W(config/puma/#{@options[:environment]}.rb config/puma.rb).find { |f|
200
+ File.exist?(f)
201
+ }
202
+
203
+ files << imp
204
+ elsif files == ["-"]
205
+ files = []
206
+ end
207
+
208
+ files.each do |f|
209
+ @options.reverse_shift
210
+
211
+ DSL.load @options, self, f
212
+ end
213
+ @options.shift
214
+ end
215
+
216
+ # Call once all configuration (included from rackup files)
217
+ # is loaded to flesh out any defaults
218
+ def clamp
219
+ @options.shift
220
+ @options.force_defaults
221
+ end
222
+
223
+ # Injects the Configuration object into the env
224
+ class ConfigMiddleware
225
+ def initialize(config, app)
226
+ @config = config
227
+ @app = app
228
+ end
229
+
230
+ def call(env)
231
+ env[Const::PUMA_CONFIG] = @config
232
+ @app.call(env)
233
+ end
234
+ end
235
+
236
+ # Indicate if there is a properly configured app
237
+ #
238
+ def app_configured?
239
+ @options[:app] || File.exist?(rackup)
240
+ end
241
+
242
+ def rackup
243
+ @options[:rackup]
244
+ end
245
+
246
+ # Load the specified rackup file, pull options from
247
+ # the rackup file, and set @app.
248
+ #
249
+ def app
250
+ found = options[:app] || load_rackup
251
+
252
+ if @options[:mode] == :tcp
253
+ require 'puma/tcp_logger'
254
+
255
+ logger = @options[:logger]
256
+ quiet = !@options[:log_requests]
257
+ return TCPLogger.new(logger, found, quiet)
258
+ end
259
+
260
+ if @options[:log_requests]
261
+ require 'puma/commonlogger'
262
+ logger = @options[:logger]
263
+ found = CommonLogger.new(found, logger)
264
+ end
265
+
266
+ ConfigMiddleware.new(self, found)
267
+ end
268
+
269
+ # Return which environment we're running in
270
+ def environment
271
+ @options[:environment]
272
+ end
273
+
274
+ def load_plugin(name)
275
+ @plugins.create name
276
+ end
277
+
278
+ def run_hooks(key, arg)
279
+ @options.all_of(key).each { |b| b.call arg }
280
+ end
281
+
282
+ def self.temp_path
283
+ require 'tmpdir'
284
+
285
+ t = (Time.now.to_f * 1000).to_i
286
+ "#{Dir.tmpdir}/puma-status-#{t}-#{$$}"
287
+ end
288
+
289
+ private
290
+
291
+ def infer_tag
292
+ File.basename(Dir.getwd)
293
+ end
294
+
295
+ # Load and use the normal Rack builder if we can, otherwise
296
+ # fallback to our minimal version.
297
+ def rack_builder
298
+ # Load bundler now if we can so that we can pickup rack from
299
+ # a Gemfile
300
+ if ENV.key? 'PUMA_BUNDLER_PRUNED'
301
+ begin
302
+ require 'bundler/setup'
303
+ rescue LoadError
304
+ end
305
+ end
306
+
307
+ begin
308
+ require 'rack'
309
+ require 'rack/builder'
310
+ rescue LoadError
311
+ # ok, use builtin version
312
+ return Puma::Rack::Builder
313
+ else
314
+ return ::Rack::Builder
315
+ end
316
+ end
317
+
318
+ def load_rackup
319
+ raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
320
+
321
+ @options.shift
322
+
323
+ rack_app, rack_options = rack_builder.parse_file(rackup)
324
+ @options.merge!(rack_options)
325
+
326
+ config_ru_binds = []
327
+ rack_options.each do |k, v|
328
+ config_ru_binds << v if k.to_s.start_with?("bind")
329
+ end
330
+
331
+ @options[:binds] = config_ru_binds unless config_ru_binds.empty?
332
+
333
+ rack_app
334
+ end
335
+
336
+ def self.random_token
337
+ begin
338
+ require 'openssl'
339
+ rescue LoadError
340
+ end
341
+
342
+ count = 16
343
+
344
+ bytes = nil
345
+
346
+ if defined? OpenSSL::Random
347
+ bytes = OpenSSL::Random.random_bytes(count)
348
+ elsif File.exist?("/dev/urandom")
349
+ File.open('/dev/urandom') { |f| bytes = f.read(count) }
350
+ end
351
+
352
+ if bytes
353
+ token = ""
354
+ bytes.each_byte { |b| token << b.to_s(16) }
355
+ else
356
+ token = (0..count).to_a.map { rand(255).to_s(16) }.join
357
+ end
358
+
359
+ return token
360
+ end
361
+ end
362
+ end
363
+
364
+ require 'puma/dsl'