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.

Files changed (79) hide show
  1. checksums.yaml +5 -13
  2. data/DEPLOYMENT.md +91 -0
  3. data/Gemfile +3 -2
  4. data/History.txt +624 -1
  5. data/Manifest.txt +15 -3
  6. data/README.md +129 -14
  7. data/Rakefile +3 -3
  8. data/bin/puma-wild +31 -0
  9. data/bin/pumactl +1 -1
  10. data/docs/nginx.md +1 -1
  11. data/docs/signals.md +43 -0
  12. data/ext/puma_http11/extconf.rb +7 -2
  13. data/ext/puma_http11/http11_parser.java.rl +5 -5
  14. data/ext/puma_http11/io_buffer.c +1 -1
  15. data/ext/puma_http11/mini_ssl.c +233 -18
  16. data/ext/puma_http11/org/jruby/puma/Http11.java +12 -3
  17. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +39 -39
  18. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +245 -195
  19. data/ext/puma_http11/puma_http11.c +12 -4
  20. data/lib/puma.rb +1 -0
  21. data/lib/puma/app/status.rb +7 -0
  22. data/lib/puma/binder.rb +108 -39
  23. data/lib/puma/capistrano.rb +23 -6
  24. data/lib/puma/cli.rb +141 -446
  25. data/lib/puma/client.rb +48 -1
  26. data/lib/puma/cluster.rb +207 -58
  27. data/lib/puma/commonlogger.rb +107 -0
  28. data/lib/puma/configuration.rb +262 -235
  29. data/lib/puma/const.rb +97 -14
  30. data/lib/puma/control_cli.rb +85 -77
  31. data/lib/puma/convenient.rb +23 -0
  32. data/lib/puma/daemon_ext.rb +11 -4
  33. data/lib/puma/detect.rb +8 -1
  34. data/lib/puma/dsl.rb +456 -0
  35. data/lib/puma/events.rb +35 -18
  36. data/lib/puma/jruby_restart.rb +1 -1
  37. data/lib/puma/launcher.rb +399 -0
  38. data/lib/puma/minissl.rb +49 -20
  39. data/lib/puma/null_io.rb +15 -0
  40. data/lib/puma/plugin.rb +104 -0
  41. data/lib/puma/plugin/tmp_restart.rb +35 -0
  42. data/lib/puma/rack/backports/uri/common_18.rb +56 -0
  43. data/lib/puma/rack/backports/uri/common_192.rb +52 -0
  44. data/lib/puma/rack/backports/uri/common_193.rb +29 -0
  45. data/lib/puma/rack/builder.rb +295 -0
  46. data/lib/puma/rack/urlmap.rb +90 -0
  47. data/lib/puma/reactor.rb +14 -1
  48. data/lib/puma/runner.rb +35 -17
  49. data/lib/puma/server.rb +161 -58
  50. data/lib/puma/single.rb +15 -10
  51. data/lib/puma/state_file.rb +29 -0
  52. data/lib/puma/thread_pool.rb +88 -13
  53. data/lib/puma/util.rb +123 -0
  54. data/lib/rack/handler/puma.rb +35 -29
  55. data/puma.gemspec +2 -4
  56. data/tools/jungle/init.d/README.md +2 -2
  57. data/tools/jungle/init.d/puma +69 -7
  58. data/tools/jungle/upstart/puma.conf +8 -2
  59. metadata +51 -71
  60. data/COPYING +0 -55
  61. data/TODO +0 -5
  62. data/lib/puma/rack_patch.rb +0 -45
  63. data/test/test_app_status.rb +0 -92
  64. data/test/test_cli.rb +0 -173
  65. data/test/test_config.rb +0 -16
  66. data/test/test_http10.rb +0 -27
  67. data/test/test_http11.rb +0 -145
  68. data/test/test_integration.rb +0 -165
  69. data/test/test_iobuffer.rb +0 -38
  70. data/test/test_minissl.rb +0 -25
  71. data/test/test_null_io.rb +0 -31
  72. data/test/test_persistent.rb +0 -238
  73. data/test/test_puma_server.rb +0 -292
  74. data/test/test_rack_handler.rb +0 -10
  75. data/test/test_rack_server.rb +0 -141
  76. data/test/test_tcp_rack.rb +0 -42
  77. data/test/test_thread_pool.rb +0 -156
  78. data/test/test_unix_socket.rb +0 -39
  79. data/test/test_ws.rb +0 -89
@@ -0,0 +1,23 @@
1
+ require 'puma/launcher'
2
+ require 'puma/configuration'
3
+
4
+ module Puma
5
+ def self.run(opts={})
6
+ cfg = Puma::Configuration.new do |c|
7
+ if port = opts[:port]
8
+ c.port port
9
+ end
10
+
11
+ c.quiet
12
+
13
+ yield c
14
+ end
15
+
16
+ cfg.clamp
17
+
18
+ events = Puma::Events.null
19
+
20
+ launcher = Puma::Launcher.new cfg, :events => events
21
+ launcher.run
22
+ end
23
+ end
@@ -3,6 +3,12 @@ module Process
3
3
  # This overrides the default version because it is broken if it
4
4
  # exists.
5
5
 
6
+ if respond_to? :daemon
7
+ class << self
8
+ remove_method :daemon
9
+ end
10
+ end
11
+
6
12
  def self.daemon(nochdir=false, noclose=false)
7
13
  exit if fork # Parent exits, child continues.
8
14
 
@@ -13,10 +19,11 @@ module Process
13
19
  Dir.chdir "/" unless nochdir # Release old working directory.
14
20
 
15
21
  if !noclose
16
- null = File.open "/dev/null", "w+"
17
- STDIN.reopen null
18
- STDOUT.reopen null
19
- STDERR.reopen null
22
+ STDIN.reopen File.open("/dev/null", "r")
23
+
24
+ null_out = File.open "/dev/null", "w"
25
+ STDOUT.reopen null_out
26
+ STDERR.reopen null_out
20
27
  end
21
28
 
22
29
  0
data/lib/puma/detect.rb CHANGED
@@ -1,4 +1,11 @@
1
1
  module Puma
2
2
  IS_JRUBY = defined?(JRUBY_VERSION)
3
- end
4
3
 
4
+ def self.jruby?
5
+ IS_JRUBY
6
+ end
7
+
8
+ def self.windows?
9
+ RUBY_PLATFORM =~ /mswin32|ming32/
10
+ end
11
+ end
data/lib/puma/dsl.rb ADDED
@@ -0,0 +1,456 @@
1
+ module Puma
2
+ # The methods that are available for use inside the config file.
3
+ #
4
+ class DSL
5
+ include ConfigDefault
6
+
7
+ def self.load(options, cfg, path)
8
+ d = new(options, cfg)
9
+ d._load_from(path)
10
+
11
+ options
12
+ ensure
13
+ d._offer_plugins
14
+ end
15
+
16
+ def initialize(options, config)
17
+ @config = config
18
+ @options = options
19
+
20
+ @plugins = []
21
+ end
22
+
23
+ def _load_from(path)
24
+ if path
25
+ @path = path
26
+ instance_eval(File.read(path), path, 1)
27
+ end
28
+ ensure
29
+ _offer_plugins
30
+ end
31
+
32
+ def _offer_plugins
33
+ @plugins.each do |o|
34
+ if o.respond_to? :config
35
+ @options.shift
36
+ o.config self
37
+ end
38
+ end
39
+
40
+ @plugins.clear
41
+ end
42
+
43
+ def _run(&blk)
44
+ blk.call self
45
+ ensure
46
+ _offer_plugins
47
+ end
48
+
49
+ def inject(&blk)
50
+ instance_eval(&blk)
51
+ end
52
+
53
+ # Load configuration from another named file. If the file name is absolute,
54
+ # load the file as an absolute path. Otherwise load it relative to the
55
+ # current config file.
56
+ #
57
+ def import(file)
58
+ if File.extname(file) == ""
59
+ file += ".rb"
60
+ end
61
+
62
+ if file[0,1] == "/"
63
+ path = file
64
+ elsif @path
65
+ path = File.join File.dirname(@path), file
66
+ else
67
+ raise "No original configuration path to import relative to"
68
+ end
69
+
70
+ DSL.new(@options, @config)._load_from(path)
71
+ end
72
+
73
+ def get(key,default=nil)
74
+ @options[key.to_sym] || default
75
+ end
76
+
77
+ # Load the named plugin for use by this configuration
78
+ #
79
+ def plugin(name)
80
+ @plugins << @config.load_plugin(name)
81
+ end
82
+
83
+ # Use +obj+ or +block+ as the Rack app. This allows a config file to
84
+ # be the app itself.
85
+ #
86
+ def app(obj=nil, &block)
87
+ obj ||= block
88
+
89
+ raise "Provide either a #call'able or a block" unless obj
90
+
91
+ @options[:app] = obj
92
+ end
93
+
94
+ # Start the Puma control rack app on +url+. This app can be communicated
95
+ # with to control the main server.
96
+ #
97
+ def activate_control_app(url="auto", opts={})
98
+ if url == "auto"
99
+ path = Configuration.temp_path
100
+ @options[:control_url] = "unix://#{path}"
101
+ @options[:control_url_temp] = path
102
+ else
103
+ @options[:control_url] = url
104
+ end
105
+
106
+ if opts[:no_token]
107
+ auth_token = :none
108
+ else
109
+ auth_token = opts[:auth_token]
110
+ auth_token ||= Configuration.random_token
111
+ end
112
+
113
+ @options[:control_auth_token] = auth_token
114
+ @options[:control_url_umask] = opts[:umask] if opts[:umask]
115
+ end
116
+
117
+ # Load additional configuration from a file
118
+ def load(file)
119
+ _ary(:config_files) << file
120
+ end
121
+
122
+ # Bind the server to +url+. tcp:// and unix:// are the only accepted
123
+ # protocols.
124
+ #
125
+ def bind(url)
126
+ _ary(:binds) << url
127
+ end
128
+
129
+ # Define the TCP port to bind to. Use +bind+ for more advanced options.
130
+ #
131
+ def port(port, host=nil)
132
+ host ||= Configuration::DefaultTCPHost
133
+ bind "tcp://#{host}:#{port}"
134
+ end
135
+
136
+ # Work around leaky apps that leave garbage in Thread locals
137
+ # across requests
138
+ #
139
+ def clean_thread_locals(which=true)
140
+ @options[:clean_thread_locals] = which
141
+ end
142
+
143
+ # Daemonize the server into the background. Highly suggest that
144
+ # this be combined with +pidfile+ and +stdout_redirect+.
145
+ def daemonize(which=true)
146
+ @options[:daemon] = which
147
+ end
148
+
149
+ # When shutting down, drain the accept socket of pending
150
+ # connections and proces them. This loops over the accept
151
+ # socket until there are no more read events and then stops
152
+ # looking and waits for the requests to finish.
153
+ def drain_on_shutdown(which=true)
154
+ @options[:drain_on_shutdown] = which
155
+ end
156
+
157
+ # Set the environment in which the Rack's app will run.
158
+ def environment(environment)
159
+ @options[:environment] = environment
160
+ end
161
+
162
+ # Code to run before doing a restart. This code should
163
+ # close logfiles, database connections, etc.
164
+ #
165
+ # This can be called multiple times to add code each time.
166
+ #
167
+ def on_restart(&block)
168
+ _ary(:on_restart) << block
169
+ end
170
+
171
+ # Command to use to restart puma. This should be just how to
172
+ # load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
173
+ # to puma, as those are the same as the original process.
174
+ #
175
+ def restart_command(cmd)
176
+ @options[:restart_cmd] = cmd.to_s
177
+ end
178
+
179
+ # Store the pid of the server in the file at +path+.
180
+ def pidfile(path)
181
+ @options[:pidfile] = path.to_s
182
+ end
183
+
184
+ # Disable request logging.
185
+ #
186
+ def quiet(which=true)
187
+ @options[:log_requests] = !which
188
+ end
189
+
190
+ # Enable request logging
191
+ #
192
+ def log_requests(which=true)
193
+ @options[:log_requests] = which
194
+ end
195
+
196
+ # Show debugging info
197
+ #
198
+ def debug
199
+ @options[:debug] = true
200
+ end
201
+
202
+ # Load +path+ as a rackup file.
203
+ #
204
+ def rackup(path)
205
+ @options[:rackup] = path.to_s
206
+ end
207
+
208
+ # Run Puma in TCP mode
209
+ #
210
+ def tcp_mode!
211
+ @options[:mode] = :tcp
212
+ end
213
+
214
+ # Redirect STDOUT and STDERR to files specified.
215
+ def stdout_redirect(stdout=nil, stderr=nil, append=false)
216
+ @options[:redirect_stdout] = stdout
217
+ @options[:redirect_stderr] = stderr
218
+ @options[:redirect_append] = append
219
+ end
220
+
221
+ # Configure +min+ to be the minimum number of threads to use to answer
222
+ # requests and +max+ the maximum.
223
+ #
224
+ def threads(min, max)
225
+ min = Integer(min)
226
+ max = Integer(max)
227
+ if min > max
228
+ raise "The minimum (#{min}) number of threads must be less than or equal to the max (#{max})"
229
+ end
230
+
231
+ if max < 1
232
+ raise "The maximum number of threads (#{max}) must be greater than 0"
233
+ end
234
+
235
+ @options[:min_threads] = min
236
+ @options[:max_threads] = max
237
+ end
238
+
239
+ def ssl_bind(host, port, opts)
240
+ if defined?(JRUBY_VERSION)
241
+ keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
242
+ bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}"
243
+ else
244
+ bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}"
245
+ end
246
+ end
247
+
248
+ # Use +path+ as the file to store the server info state. This is
249
+ # used by pumactl to query and control the server.
250
+ #
251
+ def state_path(path)
252
+ @options[:state] = path.to_s
253
+ end
254
+
255
+ # *Cluster mode only* How many worker processes to run.
256
+ #
257
+ def workers(count)
258
+ @options[:workers] = count.to_i
259
+ end
260
+
261
+ # *Cluster mode only* Code to run immediately before master process
262
+ # forks workers (once on boot). These hooks can block if necessary
263
+ # to wait for background operations unknown to puma to finish before
264
+ # the process terminates.
265
+ # This can be used to close any connections to remote servers (database, redis, ...)
266
+ # that were opened when preloading the code
267
+ #
268
+ # This can be called multiple times to add hooks.
269
+ #
270
+ def before_fork(&block)
271
+ _ary(:before_fork) << block
272
+ end
273
+
274
+ # *Cluster mode only* Code to run immediately before a worker shuts
275
+ # down (after it has finished processing HTTP requests). These hooks
276
+ # can block if necessary to wait for background operations unknown
277
+ # to puma to finish before the process terminates.
278
+ #
279
+ # This can be called multiple times to add hooks.
280
+ #
281
+ def on_worker_shutdown(&block)
282
+ _ary(:before_worker_shutdown) << block
283
+ end
284
+
285
+ # *Cluster mode only* Code to run when a worker boots to setup
286
+ # the process before booting the app.
287
+ #
288
+ # This can be called multiple times to add hooks.
289
+ #
290
+ def on_worker_boot(&block)
291
+ _ary(:before_worker_boot) << block
292
+ end
293
+
294
+ # *Cluster mode only* Code to run when a master process is
295
+ # about to create the worker by forking itself.
296
+ #
297
+ # This can be called multiple times to add hooks.
298
+ #
299
+ def on_worker_fork(&block)
300
+ _ary(:before_worker_fork) << block
301
+ end
302
+
303
+ # *Cluster mode only* Code to run when a worker boots to setup
304
+ # the process after booting the app.
305
+ #
306
+ # This can be called multiple times to add hooks.
307
+ #
308
+ def after_worker_boot(&block)
309
+ _ary(:after_worker_fork) << block
310
+ end
311
+
312
+ # The directory to operate out of.
313
+ def directory(dir)
314
+ @options[:directory] = dir.to_s
315
+
316
+ worker_directory dir
317
+ end
318
+
319
+ # Set the directory for workers to start in
320
+ def worker_directory(dir)
321
+ @options[:worker_directory] = dir.to_s
322
+ end
323
+
324
+ # Run the app as a raw TCP app instead of an HTTP rack app
325
+ def tcp_mode
326
+ @options[:mode] = :tcp
327
+ end
328
+
329
+ # *Cluster mode only* Preload the application before starting
330
+ # the workers and setting up the listen ports. This conflicts
331
+ # with using the phased restart feature, you can't use both.
332
+ #
333
+ def preload_app!(answer=true)
334
+ @options[:preload_app] = answer
335
+ end
336
+
337
+ # Use +obj+ or +block+ as the low level error handler. This allows a config file to
338
+ # change the default error on the server.
339
+ #
340
+ def lowlevel_error_handler(obj=nil, &block)
341
+ obj ||= block
342
+ raise "Provide either a #call'able or a block" unless obj
343
+ @options[:lowlevel_error_handler] = obj
344
+ end
345
+
346
+ # This option is used to allow your app and its gems to be
347
+ # properly reloaded when not using preload.
348
+ #
349
+ # When set, if puma detects that it's been invoked in the
350
+ # context of Bundler, it will cleanup the environment and
351
+ # re-run itself outside the Bundler environment, but directly
352
+ # using the files that Bundler has setup.
353
+ #
354
+ # This means that puma is now decoupled from your Bundler
355
+ # context and when each worker loads, it will be loading a
356
+ # new Bundler context and thus can float around as the release
357
+ # dictates.
358
+ def prune_bundler(answer=true)
359
+ @options[:prune_bundler] = answer
360
+ end
361
+
362
+ # Additional text to display in process listing
363
+ def tag(string)
364
+ @options[:tag] = string.to_s
365
+ end
366
+
367
+ # *Cluster mode only* Set the timeout for workers in seconds
368
+ # When set the master process will terminate any workers
369
+ # that have not checked in within the given +timeout+.
370
+ # This mitigates hung processes. Default value is 60 seconds.
371
+ def worker_timeout(timeout)
372
+ @options[:worker_timeout] = timeout
373
+ end
374
+
375
+ # *Cluster mode only* Set the timeout for workers to boot
376
+ def worker_boot_timeout(timeout)
377
+ @options[:worker_boot_timeout] = timeout
378
+ end
379
+
380
+ # *Cluster mode only* Set the timeout for worker shutdown
381
+ def worker_shutdown_timeout(timeout)
382
+ @options[:worker_shutdown_timeout] = timeout
383
+ end
384
+
385
+ # When set to true (the default), workers accept all requests
386
+ # and queue them before passing them to the handlers.
387
+ # When set to false, each worker process accepts exactly as
388
+ # many requests as it is configured to simultaneously handle.
389
+ #
390
+ # Queueing requests generally improves performance. In some
391
+ # cases, such as a single threaded application, it may be
392
+ # better to ensure requests get balanced across workers.
393
+ #
394
+ # Note that setting this to false disables HTTP keepalive and
395
+ # slow clients will occupy a handler thread while the request
396
+ # is being sent. A reverse proxy, such as nginx, can handle
397
+ # slow clients and queue requests before they reach puma.
398
+ def queue_requests(answer=true)
399
+ @options[:queue_requests] = answer
400
+ end
401
+
402
+ # When a shutdown is requested, the backtraces of all the
403
+ # threads will be written to $stdout. This can help figure
404
+ # out why shutdown is hanging.
405
+ def shutdown_debug(val=true)
406
+ @options[:shutdown_debug] = val
407
+ end
408
+
409
+ # Control how the remote address of the connection is set. This
410
+ # is configurable because to calculate the true socket peer address
411
+ # a kernel syscall is required which for very fast rack handlers
412
+ # slows down the handling significantly.
413
+ #
414
+ # There are 4 possible values:
415
+ #
416
+ # * :socket (the default) - read the peername from the socket using the
417
+ # syscall. This is the normal behavior.
418
+ # * :localhost - set the remote address to "127.0.0.1"
419
+ # * header: http_header - set the remote address to the value of the
420
+ # provided http header. For instance:
421
+ # `set_remote_address header: "X-Real-IP"`.
422
+ # Only the first word (as separated by spaces or comma)
423
+ # is used, allowing headers such as X-Forwarded-For
424
+ # to be used as well.
425
+ # * Any string - this allows you to hardcode remote address to any value
426
+ # you wish. Because puma never uses this field anyway, it's
427
+ # format is entirely in your hands.
428
+ def set_remote_address(val=:socket)
429
+ case val
430
+ when :socket
431
+ @options[:remote_address] = val
432
+ when :localhost
433
+ @options[:remote_address] = :value
434
+ @options[:remote_address_value] = "127.0.0.1".freeze
435
+ when String
436
+ @options[:remote_address] = :value
437
+ @options[:remote_address_value] = val
438
+ when Hash
439
+ if hdr = val[:header]
440
+ @options[:remote_address] = :header
441
+ @options[:remote_address_header] = "HTTP_" + hdr.upcase.gsub("-", "_")
442
+ else
443
+ raise "Invalid value for set_remote_address - #{val.inspect}"
444
+ end
445
+ else
446
+ raise "Invalid value for set_remote_address - #{val}"
447
+ end
448
+ end
449
+
450
+ private
451
+
452
+ def _ary(key)
453
+ (@options.cur[key] ||= [])
454
+ end
455
+ end
456
+ end