puma 4.3.12 → 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.

Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +58 -41
  3. data/LICENSE +23 -20
  4. data/README.md +17 -11
  5. data/bin/puma-wild +0 -0
  6. data/docs/architecture.md +0 -0
  7. data/docs/deployment.md +3 -1
  8. data/docs/fork_worker.md +31 -0
  9. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  10. data/docs/images/puma-connection-flow.png +0 -0
  11. data/docs/images/puma-general-arch.png +0 -0
  12. data/docs/jungle/README.md +13 -0
  13. data/{tools → docs}/jungle/rc.d/README.md +0 -0
  14. data/{tools → docs}/jungle/rc.d/puma +0 -0
  15. data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  16. data/{tools → docs}/jungle/upstart/README.md +0 -0
  17. data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
  18. data/{tools → docs}/jungle/upstart/puma.conf +0 -0
  19. data/docs/nginx.md +0 -0
  20. data/docs/plugins.md +0 -0
  21. data/docs/restart.md +0 -0
  22. data/docs/signals.md +1 -0
  23. data/docs/systemd.md +1 -63
  24. data/ext/puma_http11/PumaHttp11Service.java +2 -4
  25. data/ext/puma_http11/ext_help.h +0 -0
  26. data/ext/puma_http11/extconf.rb +3 -10
  27. data/ext/puma_http11/http11_parser.c +11 -26
  28. data/ext/puma_http11/http11_parser.h +0 -0
  29. data/ext/puma_http11/http11_parser.java.rl +0 -0
  30. data/ext/puma_http11/http11_parser.rl +1 -3
  31. data/ext/puma_http11/http11_parser_common.rl +1 -1
  32. data/ext/puma_http11/mini_ssl.c +47 -82
  33. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  34. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +46 -48
  35. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +0 -0
  36. data/ext/puma_http11/puma_http11.c +2 -38
  37. data/lib/puma/accept_nonblock.rb +0 -0
  38. data/lib/puma/app/status.rb +16 -5
  39. data/lib/puma/binder.rb +62 -60
  40. data/lib/puma/cli.rb +7 -15
  41. data/lib/puma/client.rb +38 -78
  42. data/lib/puma/cluster.rb +179 -74
  43. data/lib/puma/commonlogger.rb +0 -0
  44. data/lib/puma/configuration.rb +30 -42
  45. data/lib/puma/const.rb +5 -8
  46. data/lib/puma/control_cli.rb +27 -17
  47. data/lib/puma/detect.rb +8 -0
  48. data/lib/puma/dsl.rb +70 -34
  49. data/lib/puma/events.rb +0 -0
  50. data/lib/puma/io_buffer.rb +9 -2
  51. data/lib/puma/jruby_restart.rb +0 -58
  52. data/lib/puma/launcher.rb +41 -29
  53. data/lib/puma/minissl/context_builder.rb +0 -0
  54. data/lib/puma/minissl.rb +13 -8
  55. data/lib/puma/null_io.rb +1 -1
  56. data/lib/puma/plugin/tmp_restart.rb +0 -0
  57. data/lib/puma/plugin.rb +1 -10
  58. data/lib/puma/rack/builder.rb +0 -4
  59. data/lib/puma/rack/urlmap.rb +0 -0
  60. data/lib/puma/rack_default.rb +0 -0
  61. data/lib/puma/reactor.rb +6 -1
  62. data/lib/puma/runner.rb +5 -34
  63. data/lib/puma/server.rb +74 -206
  64. data/lib/puma/single.rb +7 -64
  65. data/lib/puma/state_file.rb +5 -2
  66. data/lib/puma/thread_pool.rb +85 -47
  67. data/lib/puma/util.rb +0 -0
  68. data/lib/puma.rb +4 -0
  69. data/lib/rack/handler/puma.rb +1 -3
  70. data/tools/{docker/Dockerfile → Dockerfile} +0 -0
  71. data/tools/trickletest.rb +0 -0
  72. metadata +20 -24
  73. data/docs/tcp_mode.md +0 -96
  74. data/ext/puma_http11/io_buffer.c +0 -155
  75. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  76. data/lib/puma/tcp_logger.rb +0 -41
  77. data/tools/jungle/README.md +0 -19
  78. data/tools/jungle/init.d/README.md +0 -61
  79. data/tools/jungle/init.d/puma +0 -421
  80. data/tools/jungle/init.d/run-puma +0 -18
data/lib/puma/cluster.rb CHANGED
@@ -5,6 +5,7 @@ require 'puma/util'
5
5
  require 'puma/plugin'
6
6
 
7
7
  require 'time'
8
+ require 'json'
8
9
 
9
10
  module Puma
10
11
  # This class is instantiated by the `Puma::Launcher` and used
@@ -24,9 +25,8 @@ module Puma
24
25
 
25
26
  @phase = 0
26
27
  @workers = []
27
- @next_check = nil
28
+ @next_check = Time.now
28
29
 
29
- @phased_state = :idle
30
30
  @phased_restart = false
31
31
  end
32
32
 
@@ -37,7 +37,7 @@ module Puma
37
37
  begin
38
38
  loop do
39
39
  wait_workers
40
- break if @workers.empty?
40
+ break if @workers.reject {|w| w.pid.nil?}.empty?
41
41
  sleep 0.2
42
42
  end
43
43
  rescue Interrupt
@@ -73,11 +73,12 @@ module Puma
73
73
  @first_term_sent = nil
74
74
  @started_at = Time.now
75
75
  @last_checkin = Time.now
76
- @last_status = '{}'
76
+ @last_status = {}
77
77
  @term = false
78
78
  end
79
79
 
80
80
  attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status, :started_at
81
+ attr_writer :pid, :phase
81
82
 
82
83
  def booted?
83
84
  @stage == :booted
@@ -94,11 +95,15 @@ module Puma
94
95
 
95
96
  def ping!(status)
96
97
  @last_checkin = Time.now
97
- @last_status = status
98
+ @last_status = JSON.parse(status, symbolize_names: true)
98
99
  end
99
100
 
100
- def ping_timeout?(which)
101
- Time.now - @last_checkin > which
101
+ def ping_timeout
102
+ @last_checkin +
103
+ (booted? ?
104
+ @options[:worker_timeout] :
105
+ @options[:worker_boot_timeout]
106
+ )
102
107
  end
103
108
 
104
109
  def term
@@ -109,14 +114,14 @@ module Puma
109
114
  @term ||= true
110
115
  @first_term_sent ||= Time.now
111
116
  end
112
- Process.kill @signal, @pid
117
+ Process.kill @signal, @pid if @pid
113
118
  rescue Errno::ESRCH
114
119
  end
115
120
  end
116
121
 
117
122
  def kill
118
- Process.kill "KILL", @pid
119
- rescue Errno::ESRCH
123
+ @signal = 'KILL'
124
+ term
120
125
  end
121
126
 
122
127
  def hup
@@ -130,27 +135,43 @@ module Puma
130
135
  return if diff < 1
131
136
 
132
137
  master = Process.pid
138
+ if @options[:fork_worker]
139
+ @fork_writer << "-1\n"
140
+ end
133
141
 
134
142
  diff.times do
135
143
  idx = next_worker_index
136
- @launcher.config.run_hooks :before_worker_fork, idx
137
144
 
138
- pid = fork { worker(idx, master) }
139
- if !pid
140
- log "! Complete inability to spawn new workers detected"
141
- log "! Seppuku is the only choice."
142
- exit! 1
145
+ if @options[:fork_worker] && idx != 0
146
+ @fork_writer << "#{idx}\n"
147
+ pid = nil
148
+ else
149
+ pid = spawn_worker(idx, master)
143
150
  end
144
151
 
145
152
  debug "Spawned worker: #{pid}"
146
153
  @workers << Worker.new(idx, pid, @phase, @options)
154
+ end
147
155
 
148
- @launcher.config.run_hooks :after_worker_fork, idx
156
+ if @options[:fork_worker] &&
157
+ @workers.all? {|x| x.phase == @phase}
158
+
159
+ @fork_writer << "0\n"
149
160
  end
161
+ end
150
162
 
151
- if diff > 0
152
- @phased_state = :idle
163
+ def spawn_worker(idx, master)
164
+ @launcher.config.run_hooks :before_worker_fork, idx, @launcher.events
165
+
166
+ pid = fork { worker(idx, master) }
167
+ if !pid
168
+ log "! Complete inability to spawn new workers detected"
169
+ log "! Seppuku is the only choice."
170
+ exit! 1
153
171
  end
172
+
173
+ @launcher.config.run_hooks :after_worker_fork, idx, @launcher.events
174
+ pid
154
175
  end
155
176
 
156
177
  def cull_workers
@@ -179,26 +200,12 @@ module Puma
179
200
  @workers.count { |w| !w.booted? } == 0
180
201
  end
181
202
 
182
- def check_workers(force=false)
183
- return if !force && @next_check && @next_check >= Time.now
203
+ def check_workers
204
+ return if @next_check >= Time.now
184
205
 
185
206
  @next_check = Time.now + Const::WORKER_CHECK_INTERVAL
186
207
 
187
- any = false
188
-
189
- @workers.each do |w|
190
- next if !w.booted? && !w.ping_timeout?(@options[:worker_boot_timeout])
191
- if w.ping_timeout?(@options[:worker_timeout])
192
- log "! Terminating timed out worker: #{w.pid}"
193
- w.kill
194
- any = true
195
- end
196
- end
197
-
198
- # If we killed any timed out workers, try to catch them
199
- # during this loop by giving the kernel time to kill them.
200
- sleep 1 if any
201
-
208
+ timeout_workers
202
209
  wait_workers
203
210
  cull_workers
204
211
  spawn_workers
@@ -211,17 +218,18 @@ module Puma
211
218
  w = @workers.find { |x| x.phase != @phase }
212
219
 
213
220
  if w
214
- if @phased_state == :idle
215
- @phased_state = :waiting
216
- log "- Stopping #{w.pid} for phased upgrade..."
217
- end
218
-
221
+ log "- Stopping #{w.pid} for phased upgrade..."
219
222
  unless w.term?
220
223
  w.term
221
224
  log "- #{w.signal} sent to #{w.pid}..."
222
225
  end
223
226
  end
224
227
  end
228
+
229
+ @next_check = [
230
+ @workers.reject(&:term?).map(&:ping_timeout).min,
231
+ @next_check
232
+ ].compact.min
225
233
  end
226
234
 
227
235
  def wakeup!
@@ -241,9 +249,14 @@ module Puma
241
249
 
242
250
  Signal.trap "SIGINT", "IGNORE"
243
251
 
252
+ fork_worker = @options[:fork_worker] && index == 0
253
+
244
254
  @workers = []
245
- @master_read.close
246
- @suicide_pipe.close
255
+ if !@options[:fork_worker] || fork_worker
256
+ @master_read.close
257
+ @suicide_pipe.close
258
+ @fork_writer.close
259
+ end
247
260
 
248
261
  Thread.new do
249
262
  Puma.set_thread_name "worker check pipe"
@@ -264,17 +277,47 @@ module Puma
264
277
 
265
278
  # Invoke any worker boot hooks so they can get
266
279
  # things in shape before booting the app.
267
- @launcher.config.run_hooks :before_worker_boot, index
280
+ @launcher.config.run_hooks :before_worker_boot, index, @launcher.events
281
+
282
+ server = @server ||= start_server
283
+ restart_server = Queue.new << true << false
268
284
 
269
- server = start_server
285
+ if fork_worker
286
+ restart_server.clear
287
+ Signal.trap "SIGCHLD" do
288
+ Process.wait(-1, Process::WNOHANG) rescue nil
289
+ wakeup!
290
+ end
291
+
292
+ Thread.new do
293
+ Puma.set_thread_name "worker fork pipe"
294
+ while (idx = @fork_pipe.gets)
295
+ idx = idx.to_i
296
+ if idx == -1 # stop server
297
+ if restart_server.length > 0
298
+ restart_server.clear
299
+ server.begin_restart(true)
300
+ @launcher.config.run_hooks :before_refork, nil, @launcher.events
301
+ nakayoshi_gc
302
+ end
303
+ elsif idx == 0 # restart server
304
+ restart_server << true << false
305
+ else # fork worker
306
+ pid = spawn_worker(idx, master)
307
+ @worker_write << "f#{pid}:#{idx}\n" rescue nil
308
+ end
309
+ end
310
+ end
311
+ end
270
312
 
271
313
  Signal.trap "SIGTERM" do
272
314
  @worker_write << "e#{Process.pid}\n" rescue nil
273
315
  server.stop
316
+ restart_server << false
274
317
  end
275
318
 
276
319
  begin
277
- @worker_write << "b#{Process.pid}\n"
320
+ @worker_write << "b#{Process.pid}:#{index}\n"
278
321
  rescue SystemCallError, IOError
279
322
  Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
280
323
  STDERR.puts "Master seems to have exited, exiting."
@@ -283,17 +326,11 @@ module Puma
283
326
 
284
327
  Thread.new(@worker_write) do |io|
285
328
  Puma.set_thread_name "stat payload"
286
- base_payload = "p#{Process.pid}"
287
329
 
288
330
  while true
289
331
  sleep Const::WORKER_CHECK_INTERVAL
290
332
  begin
291
- b = server.backlog || 0
292
- r = server.running || 0
293
- t = server.pool_capacity || 0
294
- m = server.max_threads || 0
295
- payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r}, "pool_capacity":#{t}, "max_threads": #{m} }\n!
296
- io << payload
333
+ io << "p#{Process.pid}#{server.stats.to_json}\n"
297
334
  rescue IOError
298
335
  Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
299
336
  break
@@ -301,11 +338,11 @@ module Puma
301
338
  end
302
339
  end
303
340
 
304
- server.run.join
341
+ server.run.join while restart_server.pop
305
342
 
306
343
  # Invoke any worker shutdown hooks so they can prevent the worker
307
344
  # exiting until any background operations are completed
308
- @launcher.config.run_hooks :before_worker_shutdown, index
345
+ @launcher.config.run_hooks :before_worker_shutdown, index, @launcher.events
309
346
  ensure
310
347
  @worker_write << "t#{Process.pid}\n" rescue nil
311
348
  @worker_write.close
@@ -352,18 +389,57 @@ module Puma
352
389
  # the master process.
353
390
  def stats
354
391
  old_worker_count = @workers.count { |w| w.phase != @phase }
355
- booted_worker_count = @workers.count { |w| w.booted? }
356
- worker_status = '[' + @workers.map { |w| %Q!{ "started_at": "#{w.started_at.utc.iso8601}", "pid": #{w.pid}, "index": #{w.index}, "phase": #{w.phase}, "booted": #{w.booted?}, "last_checkin": "#{w.last_checkin.utc.iso8601}", "last_status": #{w.last_status} }!}.join(",") + ']'
357
- %Q!{ "started_at": "#{@started_at.utc.iso8601}", "workers": #{@workers.size}, "phase": #{@phase}, "booted_workers": #{booted_worker_count}, "old_workers": #{old_worker_count}, "worker_status": #{worker_status} }!
392
+ worker_status = @workers.map do |w|
393
+ {
394
+ started_at: w.started_at.utc.iso8601,
395
+ pid: w.pid,
396
+ index: w.index,
397
+ phase: w.phase,
398
+ booted: w.booted?,
399
+ last_checkin: w.last_checkin.utc.iso8601,
400
+ last_status: w.last_status,
401
+ }
402
+ end
403
+
404
+ {
405
+ started_at: @started_at.utc.iso8601,
406
+ workers: @workers.size,
407
+ phase: @phase,
408
+ booted_workers: worker_status.count { |w| w[:booted] },
409
+ old_workers: old_worker_count,
410
+ worker_status: worker_status,
411
+ }
358
412
  end
359
413
 
360
414
  def preload?
361
415
  @options[:preload_app]
362
416
  end
363
417
 
418
+ def fork_worker!
419
+ if (worker = @workers.find { |w| w.index == 0 })
420
+ worker.phase += 1
421
+ end
422
+ phased_restart
423
+ end
424
+
364
425
  # We do this in a separate method to keep the lambda scope
365
426
  # of the signals handlers as small as possible.
366
427
  def setup_signals
428
+ if @options[:fork_worker]
429
+ Signal.trap "SIGURG" do
430
+ fork_worker!
431
+ end
432
+
433
+ # Auto-fork after the specified number of requests.
434
+ if (fork_requests = @options[:fork_worker].to_i) > 0
435
+ @launcher.events.register(:ping!) do |w|
436
+ fork_worker! if w.index == 0 &&
437
+ w.phase == 0 &&
438
+ w.last_status[:requests_count] >= fork_requests
439
+ end
440
+ end
441
+ end
442
+
367
443
  Signal.trap "SIGCHLD" do
368
444
  wakeup!
369
445
  end
@@ -447,12 +523,11 @@ module Puma
447
523
  #
448
524
  @check_pipe, @suicide_pipe = Puma::Util.pipe
449
525
 
450
- if daemon?
451
- log "* Daemonizing..."
452
- Process.daemon(true)
453
- else
454
- log "Use Ctrl-C to stop"
455
- end
526
+ # Separate pipe used by worker 0 to receive commands to
527
+ # fork new worker processes.
528
+ @fork_pipe, @fork_writer = Puma::Util.pipe
529
+
530
+ log "Use Ctrl-C to stop"
456
531
 
457
532
  redirect_io
458
533
 
@@ -464,7 +539,8 @@ module Puma
464
539
 
465
540
  @master_read, @worker_write = read, @wakeup
466
541
 
467
- @launcher.config.run_hooks :before_fork, nil
542
+ @launcher.config.run_hooks :before_fork, nil, @launcher.events
543
+ nakayoshi_gc
468
544
 
469
545
  spawn_workers
470
546
 
@@ -475,8 +551,6 @@ module Puma
475
551
  @launcher.events.fire_on_booted!
476
552
 
477
553
  begin
478
- force_check = false
479
-
480
554
  while @status == :run
481
555
  begin
482
556
  if @phased_restart
@@ -484,34 +558,39 @@ module Puma
484
558
  @phased_restart = false
485
559
  end
486
560
 
487
- check_workers force_check
561
+ check_workers
488
562
 
489
- force_check = false
490
-
491
- res = IO.select([read], nil, nil, Const::WORKER_CHECK_INTERVAL)
563
+ res = IO.select([read], nil, nil, [0, @next_check - Time.now].max)
492
564
 
493
565
  if res
494
566
  req = read.read_nonblock(1)
495
567
 
568
+ @next_check = Time.now if req == "!"
496
569
  next if !req || req == "!"
497
570
 
498
571
  result = read.gets
499
572
  pid = result.to_i
500
573
 
574
+ if req == "b" || req == "f"
575
+ pid, idx = result.split(':').map(&:to_i)
576
+ w = @workers.find {|x| x.index == idx}
577
+ w.pid = pid if w.pid.nil?
578
+ end
579
+
501
580
  if w = @workers.find { |x| x.pid == pid }
502
581
  case req
503
582
  when "b"
504
583
  w.boot!
505
584
  log "- Worker #{w.index} (pid: #{pid}) booted, phase: #{w.phase}"
506
- force_check = true
585
+ @next_check = Time.now
507
586
  when "e"
508
587
  # external term, see worker method, Signal.trap "SIGTERM"
509
588
  w.instance_variable_set :@term, true
510
589
  when "t"
511
590
  w.term unless w.term?
512
- force_check = true
513
591
  when "p"
514
592
  w.ping!(result.sub(/^\d+/,'').chomp)
593
+ @launcher.events.fire(:ping!, w)
515
594
  end
516
595
  else
517
596
  log "! Out-of-sync worker list, no #{pid} worker"
@@ -538,6 +617,7 @@ module Puma
538
617
  # `#term` if needed
539
618
  def wait_workers
540
619
  @workers.reject! do |w|
620
+ next false if w.pid.nil?
541
621
  begin
542
622
  if Process.wait(w.pid, Process::WNOHANG)
543
623
  true
@@ -546,9 +626,34 @@ module Puma
546
626
  nil
547
627
  end
548
628
  rescue Errno::ECHILD
549
- true # child is already terminated
629
+ begin
630
+ Process.kill(0, w.pid)
631
+ false # child still alive, but has another parent
632
+ rescue Errno::ESRCH, Errno::EPERM
633
+ true # child is already terminated
634
+ end
550
635
  end
551
636
  end
552
637
  end
638
+
639
+ def timeout_workers
640
+ @workers.each do |w|
641
+ if !w.term? && w.ping_timeout <= Time.now
642
+ log "! Terminating timed out worker: #{w.pid}"
643
+ w.kill
644
+ end
645
+ end
646
+ end
647
+
648
+ def nakayoshi_gc
649
+ return unless @options[:nakayoshi_fork]
650
+ log "! Promoting existing objects to old generation..."
651
+ 4.times { GC.start(full_mark: false) }
652
+ if GC.respond_to?(:compact)
653
+ log "! Compacting..."
654
+ GC.compact
655
+ end
656
+ log "! Friendly fork preparation complete."
657
+ end
553
658
  end
554
659
  end
File without changes
@@ -54,9 +54,7 @@ module Puma
54
54
  attr_reader :user_options, :file_options, :default_options
55
55
 
56
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)
57
+ fetch(key)
60
58
  end
61
59
 
62
60
  def []=(key, value)
@@ -64,7 +62,11 @@ module Puma
64
62
  end
65
63
 
66
64
  def fetch(key, default_value = nil)
67
- self[key] || default_value
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)
68
+
69
+ default_value
68
70
  end
69
71
 
70
72
  def all_of(key)
@@ -106,7 +108,7 @@ module Puma
106
108
  #
107
109
  # It also handles loading plugins.
108
110
  #
109
- # > Note: `:port` and `:host` are not valid keys. By they time they make it to the
111
+ # > Note: `:port` and `:host` are not valid keys. By the time they make it to the
110
112
  # configuration options they are expected to be incorporated into a `:binds` key.
111
113
  # Under the hood the DSL maps `port` and `host` calls to `:binds`
112
114
  #
@@ -137,6 +139,10 @@ module Puma
137
139
  @file_dsl = DSL.new(@options.file_options, self)
138
140
  @default_dsl = DSL.new(@options.default_options, self)
139
141
 
142
+ if !@options[:prune_bundler]
143
+ default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
144
+ end
145
+
140
146
  if block
141
147
  configure(&block)
142
148
  end
@@ -167,22 +173,25 @@ module Puma
167
173
  self
168
174
  end
169
175
 
176
+ def default_max_threads
177
+ Puma.mri? ? 5 : 16
178
+ end
179
+
170
180
  def puma_default_options
171
181
  {
172
- :min_threads => 0,
173
- :max_threads => 16,
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),
174
184
  :log_requests => false,
175
185
  :debug => false,
176
186
  :binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
177
- :workers => 0,
178
- :daemon => false,
187
+ :workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
179
188
  :mode => :http,
180
189
  :worker_timeout => DefaultWorkerTimeout,
181
190
  :worker_boot_timeout => DefaultWorkerTimeout,
182
191
  :worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
183
192
  :remote_address => :socket,
184
193
  :tag => method(:infer_tag),
185
- :environment => -> { ENV['RACK_ENV'] || "development" },
194
+ :environment => -> { ENV['RACK_ENV'] || ENV['RAILS_ENV'] || "development" },
186
195
  :rackup => DefaultRackup,
187
196
  :logger => STDOUT,
188
197
  :persistent_timeout => Const::PERSISTENT_TIMEOUT,
@@ -245,14 +254,6 @@ module Puma
245
254
  def app
246
255
  found = options[:app] || load_rackup
247
256
 
248
- if @options[:mode] == :tcp
249
- require 'puma/tcp_logger'
250
-
251
- logger = @options[:logger]
252
- quiet = !@options[:log_requests]
253
- return TCPLogger.new(logger, found, quiet)
254
- end
255
-
256
257
  if @options[:log_requests]
257
258
  require 'puma/commonlogger'
258
259
  logger = @options[:logger]
@@ -275,8 +276,15 @@ module Puma
275
276
  @plugins.create name
276
277
  end
277
278
 
278
- def run_hooks(key, arg)
279
- @options.all_of(key).each { |b| b.call arg }
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
280
288
  end
281
289
 
282
290
  def self.temp_path
@@ -332,29 +340,9 @@ module Puma
332
340
  end
333
341
 
334
342
  def self.random_token
335
- begin
336
- require 'openssl'
337
- rescue LoadError
338
- end
339
-
340
- count = 16
341
-
342
- bytes = nil
343
-
344
- if defined? OpenSSL::Random
345
- bytes = OpenSSL::Random.random_bytes(count)
346
- elsif File.exist?("/dev/urandom")
347
- File.open('/dev/urandom') { |f| bytes = f.read(count) }
348
- end
349
-
350
- if bytes
351
- token = "".dup
352
- bytes.each_byte { |b| token << b.to_s(16) }
353
- else
354
- token = (0..count).to_a.map { rand(255).to_s(16) }.join
355
- end
343
+ require 'securerandom' unless defined?(SecureRandom)
356
344
 
357
- return token
345
+ SecureRandom.hex(16)
358
346
  end
359
347
  end
360
348
  end
data/lib/puma/const.rb CHANGED
@@ -76,7 +76,7 @@ module Puma
76
76
  508 => 'Loop Detected',
77
77
  510 => 'Not Extended',
78
78
  511 => 'Network Authentication Required'
79
- }.freeze
79
+ }
80
80
 
81
81
  # For some HTTP status codes the client only expects headers.
82
82
  #
@@ -85,7 +85,7 @@ module Puma
85
85
  204 => true,
86
86
  205 => true,
87
87
  304 => true
88
- }.freeze
88
+ }
89
89
 
90
90
  # Frequently used constants when constructing requests or responses. Many times
91
91
  # the constant just refers to a string with the same contents. Using these constants
@@ -100,8 +100,8 @@ module Puma
100
100
  # too taxing on performance.
101
101
  module Const
102
102
 
103
- PUMA_VERSION = VERSION = "4.3.12".freeze
104
- CODE_NAME = "Mysterious Traveller".freeze
103
+ PUMA_VERSION = VERSION = "5.0.0.beta1".freeze
104
+ CODE_NAME = "Spoony Bard".freeze
105
105
  PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
106
106
 
107
107
  FAST_TRACK_KA_TIMEOUT = 0.2
@@ -144,11 +144,9 @@ module Puma
144
144
  408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\n".freeze,
145
145
  # Indicate that there was an internal error, obviously.
146
146
  500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n".freeze,
147
- # Incorrect or invalid header value
148
- 501 => "HTTP/1.1 501 Not Implemented\r\n\r\n".freeze,
149
147
  # A common header for indicating the server is too busy. Not used yet.
150
148
  503 => "HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY".freeze
151
- }.freeze
149
+ }
152
150
 
153
151
  # The basic max request size we'll try to read.
154
152
  CHUNK_SIZE = 16 * 1024
@@ -177,7 +175,6 @@ module Puma
177
175
  PORT_443 = "443".freeze
178
176
  LOCALHOST = "localhost".freeze
179
177
  LOCALHOST_IP = "127.0.0.1".freeze
180
- LOCALHOST_ADDR = "127.0.0.1:0".freeze
181
178
 
182
179
  SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
183
180
  HTTP_11 = "HTTP/1.1".freeze