puma 5.5.2-java → 5.6.0-java

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 +51 -0
  3. data/LICENSE +0 -0
  4. data/README.md +5 -0
  5. data/bin/puma-wild +0 -0
  6. data/docs/architecture.md +4 -4
  7. data/docs/compile_options.md +0 -0
  8. data/docs/deployment.md +0 -0
  9. data/docs/fork_worker.md +0 -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/jungle/README.md +0 -0
  14. data/docs/jungle/rc.d/README.md +0 -0
  15. data/docs/jungle/rc.d/puma.conf +0 -0
  16. data/docs/kubernetes.md +0 -0
  17. data/docs/nginx.md +0 -0
  18. data/docs/plugins.md +0 -0
  19. data/docs/rails_dev_mode.md +0 -0
  20. data/docs/restart.md +0 -0
  21. data/docs/signals.md +1 -0
  22. data/docs/stats.md +0 -0
  23. data/docs/systemd.md +0 -0
  24. data/ext/puma_http11/PumaHttp11Service.java +0 -0
  25. data/ext/puma_http11/ext_help.h +0 -0
  26. data/ext/puma_http11/extconf.rb +12 -6
  27. data/ext/puma_http11/http11_parser.c +0 -0
  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 +0 -0
  31. data/ext/puma_http11/http11_parser_common.rl +0 -0
  32. data/ext/puma_http11/mini_ssl.c +54 -9
  33. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
  34. data/ext/puma_http11/org/jruby/puma/Http11.java +0 -0
  35. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +0 -0
  36. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +28 -43
  37. data/ext/puma_http11/puma_http11.c +1 -1
  38. data/lib/puma/app/status.rb +0 -0
  39. data/lib/puma/binder.rb +19 -5
  40. data/lib/puma/cli.rb +9 -4
  41. data/lib/puma/client.rb +1 -1
  42. data/lib/puma/cluster/worker.rb +5 -5
  43. data/lib/puma/cluster/worker_handle.rb +4 -0
  44. data/lib/puma/cluster.rb +29 -11
  45. data/lib/puma/commonlogger.rb +0 -0
  46. data/lib/puma/configuration.rb +3 -0
  47. data/lib/puma/const.rb +2 -5
  48. data/lib/puma/control_cli.rb +0 -0
  49. data/lib/puma/detect.rb +8 -2
  50. data/lib/puma/dsl.rb +85 -8
  51. data/lib/puma/error_logger.rb +0 -0
  52. data/lib/puma/events.rb +0 -0
  53. data/lib/puma/io_buffer.rb +0 -0
  54. data/lib/puma/jruby_restart.rb +0 -0
  55. data/lib/puma/json_serialization.rb +0 -0
  56. data/lib/puma/launcher.rb +2 -1
  57. data/lib/puma/minissl/context_builder.rb +8 -6
  58. data/lib/puma/minissl.rb +18 -2
  59. data/lib/puma/null_io.rb +0 -0
  60. data/lib/puma/plugin/tmp_restart.rb +0 -0
  61. data/lib/puma/plugin.rb +1 -1
  62. data/lib/puma/puma_http11.jar +0 -0
  63. data/lib/puma/queue_close.rb +0 -0
  64. data/lib/puma/rack/builder.rb +0 -0
  65. data/lib/puma/rack/urlmap.rb +0 -0
  66. data/lib/puma/rack_default.rb +0 -0
  67. data/lib/puma/reactor.rb +0 -0
  68. data/lib/puma/request.rb +47 -29
  69. data/lib/puma/runner.rb +3 -2
  70. data/lib/puma/server.rb +29 -33
  71. data/lib/puma/single.rb +0 -0
  72. data/lib/puma/state_file.rb +41 -7
  73. data/lib/puma/systemd.rb +0 -0
  74. data/lib/puma/thread_pool.rb +2 -2
  75. data/lib/puma/util.rb +0 -0
  76. data/lib/puma.rb +0 -0
  77. data/lib/rack/handler/puma.rb +0 -0
  78. data/tools/Dockerfile +1 -1
  79. data/tools/trickletest.rb +0 -0
  80. metadata +3 -3
@@ -33,8 +33,8 @@ module Puma
33
33
  Signal.trap "SIGINT", "IGNORE"
34
34
  Signal.trap "SIGCHLD", "DEFAULT"
35
35
 
36
- Thread.new do
37
- Puma.set_thread_name "worker check pipe"
36
+ Thread.new do
37
+ Puma.set_thread_name "wrkr check"
38
38
  @check_pipe.wait_readable
39
39
  log "! Detected parent died, dying"
40
40
  exit! 1
@@ -76,7 +76,7 @@ module Puma
76
76
  end
77
77
 
78
78
  Thread.new do
79
- Puma.set_thread_name "worker fork pipe"
79
+ Puma.set_thread_name "wrkr fork"
80
80
  while (idx = @fork_pipe.gets)
81
81
  idx = idx.to_i
82
82
  if idx == -1 # stop server
@@ -114,7 +114,7 @@ module Puma
114
114
  while restart_server.pop
115
115
  server_thread = server.run
116
116
  stat_thread ||= Thread.new(@worker_write) do |io|
117
- Puma.set_thread_name "stat payload"
117
+ Puma.set_thread_name "stat pld"
118
118
  base_payload = "p#{Process.pid}"
119
119
 
120
120
  while true
@@ -130,7 +130,7 @@ module Puma
130
130
  Puma::Util.purge_interrupt_queue
131
131
  break
132
132
  end
133
- sleep Const::WORKER_CHECK_INTERVAL
133
+ sleep @options[:worker_check_interval]
134
134
  end
135
135
  end
136
136
  server_thread.join
@@ -40,6 +40,10 @@ module Puma
40
40
  @stage = :booted
41
41
  end
42
42
 
43
+ def term!
44
+ @term = true
45
+ end
46
+
43
47
  def term?
44
48
  @term
45
49
  end
data/lib/puma/cluster.rb CHANGED
@@ -108,24 +108,42 @@ module Puma
108
108
  def cull_workers
109
109
  diff = @workers.size - @options[:workers]
110
110
  return if diff < 1
111
+ debug "Culling #{diff} workers"
111
112
 
112
- debug "Culling #{diff.inspect} workers"
113
+ workers = workers_to_cull(diff)
114
+ debug "Workers to cull: #{workers.inspect}"
113
115
 
114
- workers_to_cull = @workers[-diff,diff]
115
- debug "Workers to cull: #{workers_to_cull.inspect}"
116
-
117
- workers_to_cull.each do |worker|
116
+ workers.each do |worker|
118
117
  log "- Worker #{worker.index} (PID: #{worker.pid}) terminating"
119
118
  worker.term
120
119
  end
121
120
  end
122
121
 
122
+ def workers_to_cull(diff)
123
+ workers = @workers.sort_by(&:started_at)
124
+
125
+ # In fork_worker mode, worker 0 acts as our master process.
126
+ # We should avoid culling it to preserve copy-on-write memory gains.
127
+ workers.reject! { |w| w.index == 0 } if @options[:fork_worker]
128
+
129
+ workers[cull_start_index(diff), diff]
130
+ end
131
+
132
+ def cull_start_index(diff)
133
+ case @options[:worker_culling_strategy]
134
+ when :oldest
135
+ 0
136
+ else # :youngest
137
+ -diff
138
+ end
139
+ end
140
+
123
141
  # @!attribute [r] next_worker_index
124
142
  def next_worker_index
125
- all_positions = 0...@options[:workers]
126
- occupied_positions = @workers.map { |w| w.index }
127
- available_positions = all_positions.to_a - occupied_positions
128
- available_positions.first
143
+ occupied_positions = @workers.map(&:index)
144
+ idx = 0
145
+ idx += 1 until !occupied_positions.include?(idx)
146
+ idx
129
147
  end
130
148
 
131
149
  def all_workers_booted?
@@ -135,7 +153,7 @@ module Puma
135
153
  def check_workers
136
154
  return if @next_check >= Time.now
137
155
 
138
- @next_check = Time.now + Const::WORKER_CHECK_INTERVAL
156
+ @next_check = Time.now + @options[:worker_check_interval]
139
157
 
140
158
  timeout_workers
141
159
  wait_workers
@@ -440,7 +458,7 @@ module Puma
440
458
  workers_not_booted -= 1
441
459
  when "e"
442
460
  # external term, see worker method, Signal.trap "SIGTERM"
443
- w.instance_variable_set :@term, true
461
+ w.term!
444
462
  when "t"
445
463
  w.term unless w.term?
446
464
  when "p"
File without changes
@@ -11,6 +11,7 @@ module Puma
11
11
 
12
12
  DefaultTCPHost = "0.0.0.0"
13
13
  DefaultTCPPort = 9292
14
+ DefaultWorkerCheckInterval = 5
14
15
  DefaultWorkerTimeout = 60
15
16
  DefaultWorkerShutdownTimeout = 30
16
17
  end
@@ -195,9 +196,11 @@ module Puma
195
196
  :workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
196
197
  :silence_single_worker_warning => false,
197
198
  :mode => :http,
199
+ :worker_check_interval => DefaultWorkerCheckInterval,
198
200
  :worker_timeout => DefaultWorkerTimeout,
199
201
  :worker_boot_timeout => DefaultWorkerTimeout,
200
202
  :worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
203
+ :worker_culling_strategy => :youngest,
201
204
  :remote_address => :socket,
202
205
  :tag => method(:infer_tag),
203
206
  :environment => -> { ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development' },
data/lib/puma/const.rb CHANGED
@@ -100,8 +100,8 @@ module Puma
100
100
  # too taxing on performance.
101
101
  module Const
102
102
 
103
- PUMA_VERSION = VERSION = "5.5.2".freeze
104
- CODE_NAME = "Zawgyi".freeze
103
+ PUMA_VERSION = VERSION = "5.6.0".freeze
104
+ CODE_NAME = "Birdie's Version".freeze
105
105
 
106
106
  PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
107
107
 
@@ -235,9 +235,6 @@ module Puma
235
235
 
236
236
  EARLY_HINTS = "rack.early_hints".freeze
237
237
 
238
- # Minimum interval to checks worker health
239
- WORKER_CHECK_INTERVAL = 5
240
-
241
238
  # Illegal character in the key or value of response header
242
239
  DQUOTE = "\"".freeze
243
240
  HTTP_HEADER_DELIMITER = Regexp.escape("(),/:;<=>?@[]{}\\").freeze
File without changes
data/lib/puma/detect.rb CHANGED
@@ -10,8 +10,10 @@ module Puma
10
10
 
11
11
  IS_JRUBY = Object.const_defined? :JRUBY_VERSION
12
12
 
13
- IS_WINDOWS = !!(RUBY_PLATFORM =~ /mswin|ming|cygwin/ ||
14
- IS_JRUBY && RUBY_DESCRIPTION =~ /mswin/)
13
+ IS_OSX = RUBY_PLATFORM.include? 'darwin'
14
+
15
+ IS_WINDOWS = !!(RUBY_PLATFORM =~ /mswin|ming|cygwin/) ||
16
+ IS_JRUBY && RUBY_DESCRIPTION.include?('mswin')
15
17
 
16
18
  # @version 5.2.0
17
19
  IS_MRI = (RUBY_ENGINE == 'ruby' || RUBY_ENGINE.nil?)
@@ -20,6 +22,10 @@ module Puma
20
22
  IS_JRUBY
21
23
  end
22
24
 
25
+ def self.osx?
26
+ IS_OSX
27
+ end
28
+
23
29
  def self.windows?
24
30
  IS_WINDOWS
25
31
  end
data/lib/puma/dsl.rb CHANGED
@@ -48,6 +48,8 @@ module Puma
48
48
 
49
49
  ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
50
50
 
51
+ backlog_str = opts[:backlog] ? "&backlog=#{Integer(opts[:backlog])}" : ''
52
+
51
53
  if defined?(JRUBY_VERSION)
52
54
  ssl_cipher_list = opts[:ssl_cipher_list] ?
53
55
  "&ssl_cipher_list=#{opts[:ssl_cipher_list]}" : nil
@@ -55,7 +57,7 @@ module Puma
55
57
  keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
56
58
 
57
59
  "ssl://#{host}:#{port}?#{keystore_additions}#{ssl_cipher_list}" \
58
- "&verify_mode=#{verify}#{tls_str}#{ca_additions}"
60
+ "&verify_mode=#{verify}#{tls_str}#{ca_additions}#{backlog_str}"
59
61
  else
60
62
  ssl_cipher_filter = opts[:ssl_cipher_filter] ?
61
63
  "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" : nil
@@ -64,7 +66,7 @@ module Puma
64
66
  "&verification_flags=#{Array(ary).join ','}" : nil
65
67
 
66
68
  "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}" \
67
- "#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}"
69
+ "#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}#{backlog_str}"
68
70
  end
69
71
  end
70
72
 
@@ -191,7 +193,7 @@ module Puma
191
193
  end
192
194
 
193
195
  # Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
194
- # accepted protocols. Multiple urls can be bound to, calling `bind` does
196
+ # accepted protocols. Multiple urls can be bound to, calling +bind+ does
195
197
  # not overwrite previous bindings.
196
198
  #
197
199
  # The default is "tcp://0.0.0.0:9292".
@@ -436,8 +438,15 @@ module Puma
436
438
  @options[:max_threads] = max
437
439
  end
438
440
 
439
- # Instead of `bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'` you
440
- # can also use the this method.
441
+ # Instead of using +bind+ and manually constructing a URI like:
442
+ #
443
+ # bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'
444
+ #
445
+ # you can use the this method.
446
+ #
447
+ # When binding on localhost you don't need to specify +cert+ and +key+,
448
+ # Puma will assume you are using the +localhost+ gem and try to load the
449
+ # appropriate files.
441
450
  #
442
451
  # @example
443
452
  # ssl_bind '127.0.0.1', '9292', {
@@ -447,14 +456,25 @@ module Puma
447
456
  # verify_mode: verify_mode, # default 'none'
448
457
  # verification_flags: flags, # optional, not supported by JRuby
449
458
  # }
450
- # @example For JRuby, two keys are required: keystore & keystore_pass.
459
+ #
460
+ # @example Using self-signed certificate with the +localhost+ gem:
461
+ # ssl_bind '127.0.0.1', '9292'
462
+ #
463
+ # @example Alternatively, you can provide +cert_pem+ and +key_pem+:
464
+ # ssl_bind '127.0.0.1', '9292', {
465
+ # cert_pem: File.read(path_to_cert),
466
+ # key_pem: File.read(path_to_key),
467
+ # }
468
+ #
469
+ # @example For JRuby, two keys are required: +keystore+ & +keystore_pass+
451
470
  # ssl_bind '127.0.0.1', '9292', {
452
471
  # keystore: path_to_keystore,
453
472
  # keystore_pass: password,
454
473
  # ssl_cipher_list: cipher_list, # optional
455
474
  # verify_mode: verify_mode # default 'none'
456
475
  # }
457
- def ssl_bind(host, port, opts)
476
+ def ssl_bind(host, port, opts = {})
477
+ add_pem_values_to_options_store(opts)
458
478
  bind self.class.ssl_bind_str(host, port, opts)
459
479
  end
460
480
 
@@ -727,6 +747,19 @@ module Puma
727
747
  @options[:tag] = string.to_s
728
748
  end
729
749
 
750
+ # Change the default interval for checking workers.
751
+ #
752
+ # The default value is 5 seconds.
753
+ #
754
+ # @note Cluster mode only.
755
+ # @example
756
+ # worker_check_interval 5
757
+ # @see Puma::Cluster#check_workers
758
+ #
759
+ def worker_check_interval(interval)
760
+ @options[:worker_check_interval] = Integer(interval)
761
+ end
762
+
730
763
  # Verifies that all workers have checked in to the master process within
731
764
  # the given timeout. If not the worker process will be restarted. This is
732
765
  # not a request timeout, it is to protect against a hung or dead process.
@@ -741,7 +774,7 @@ module Puma
741
774
  #
742
775
  def worker_timeout(timeout)
743
776
  timeout = Integer(timeout)
744
- min = Const::WORKER_CHECK_INTERVAL
777
+ min = @options.fetch(:worker_check_interval, Puma::ConfigDefault::DefaultWorkerCheckInterval)
745
778
 
746
779
  if timeout <= min
747
780
  raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
@@ -773,6 +806,30 @@ module Puma
773
806
  @options[:worker_shutdown_timeout] = Integer(timeout)
774
807
  end
775
808
 
809
+ # Set the strategy for worker culling.
810
+ #
811
+ # There are two possible values:
812
+ #
813
+ # 1. **:youngest** - the youngest workers (i.e. the workers that were
814
+ # the most recently started) will be culled.
815
+ # 2. **:oldest** - the oldest workers (i.e. the workers that were started
816
+ # the longest time ago) will be culled.
817
+ #
818
+ # @note Cluster mode only.
819
+ # @example
820
+ # worker_culling_strategy :oldest
821
+ # @see Puma::Cluster#cull_workers
822
+ #
823
+ def worker_culling_strategy(strategy)
824
+ stategy = strategy.to_sym
825
+
826
+ if ![:youngest, :oldest].include?(strategy)
827
+ raise "Invalid value for worker_culling_strategy - #{stategy}"
828
+ end
829
+
830
+ @options[:worker_culling_strategy] = strategy
831
+ end
832
+
776
833
  # When set to true (the default), workers accept all requests
777
834
  # and queue them before passing them to the handlers.
778
835
  # When set to false, each worker process accepts exactly as
@@ -927,5 +984,25 @@ module Puma
927
984
  def mutate_stdout_and_stderr_to_sync_on_write(enabled=true)
928
985
  @options[:mutate_stdout_and_stderr_to_sync_on_write] = enabled
929
986
  end
987
+
988
+ private
989
+
990
+ # To avoid adding cert_pem and key_pem as URI params, we store them on the
991
+ # options[:store] from where Puma binder knows how to find and extract them.
992
+ def add_pem_values_to_options_store(opts)
993
+ return if defined?(JRUBY_VERSION)
994
+
995
+ @options[:store] ||= []
996
+
997
+ # Store cert_pem and key_pem to options[:store] if present
998
+ [:cert, :key].each do |v|
999
+ opt_key = :"#{v}_pem"
1000
+ if opts[opt_key]
1001
+ index = @options[:store].length
1002
+ @options[:store] << opts[opt_key]
1003
+ opts[v] = "store:#{index}"
1004
+ end
1005
+ end
1006
+ end
930
1007
  end
931
1008
  end
File without changes
data/lib/puma/events.rb CHANGED
File without changes
File without changes
File without changes
File without changes
data/lib/puma/launcher.rb CHANGED
@@ -15,6 +15,7 @@ module Puma
15
15
  # It is responsible for either launching a cluster of Puma workers or a single
16
16
  # puma server.
17
17
  class Launcher
18
+ # @deprecated 6.0.0
18
19
  KEYS_NOT_TO_PERSIST_IN_STATE = [
19
20
  :logger, :lowlevel_error_handler,
20
21
  :before_worker_shutdown, :before_worker_boot, :before_worker_fork,
@@ -73,7 +74,7 @@ module Puma
73
74
 
74
75
  generate_restart_data
75
76
 
76
- if clustered? && !Process.respond_to?(:fork)
77
+ if clustered? && !Puma.forkable?
77
78
  unsupported "worker mode not supported on #{RUBY_ENGINE} on this platform"
78
79
  end
79
80
 
@@ -23,17 +23,19 @@ module Puma
23
23
  ctx.keystore_pass = params['keystore-pass']
24
24
  ctx.ssl_cipher_list = params['ssl_cipher_list'] if params['ssl_cipher_list']
25
25
  else
26
- unless params['key']
27
- events.error "Please specify the SSL key via 'key='"
26
+ if params['key'].nil? && params['key_pem'].nil?
27
+ events.error "Please specify the SSL key via 'key=' or 'key_pem='"
28
28
  end
29
29
 
30
- ctx.key = params['key']
30
+ ctx.key = params['key'] if params['key']
31
+ ctx.key_pem = params['key_pem'] if params['key_pem']
31
32
 
32
- unless params['cert']
33
- events.error "Please specify the SSL cert via 'cert='"
33
+ if params['cert'].nil? && params['cert_pem'].nil?
34
+ events.error "Please specify the SSL cert via 'cert=' or 'cert_pem='"
34
35
  end
35
36
 
36
- ctx.cert = params['cert']
37
+ ctx.cert = params['cert'] if params['cert']
38
+ ctx.cert_pem = params['cert_pem'] if params['cert_pem']
37
39
 
38
40
  if ['peer', 'force_peer'].include?(params['verify_mode'])
39
41
  unless params['ca']
data/lib/puma/minissl.rb CHANGED
@@ -208,6 +208,10 @@ module Puma
208
208
  def initialize
209
209
  @no_tlsv1 = false
210
210
  @no_tlsv1_1 = false
211
+ @key = nil
212
+ @cert = nil
213
+ @key_pem = nil
214
+ @cert_pem = nil
211
215
  end
212
216
 
213
217
  if IS_JRUBY
@@ -230,6 +234,8 @@ module Puma
230
234
  attr_reader :key
231
235
  attr_reader :cert
232
236
  attr_reader :ca
237
+ attr_reader :cert_pem
238
+ attr_reader :key_pem
233
239
  attr_accessor :ssl_cipher_filter
234
240
  attr_accessor :verification_flags
235
241
 
@@ -248,9 +254,19 @@ module Puma
248
254
  @ca = ca
249
255
  end
250
256
 
257
+ def cert_pem=(cert_pem)
258
+ raise ArgumentError, "'cert_pem' is not a String" unless cert_pem.is_a? String
259
+ @cert_pem = cert_pem
260
+ end
261
+
262
+ def key_pem=(key_pem)
263
+ raise ArgumentError, "'key_pem' is not a String" unless key_pem.is_a? String
264
+ @key_pem = key_pem
265
+ end
266
+
251
267
  def check
252
- raise "Key not configured" unless @key
253
- raise "Cert not configured" unless @cert
268
+ raise "Key not configured" if @key.nil? && @key_pem.nil?
269
+ raise "Cert not configured" if @cert.nil? && @cert_pem.nil?
254
270
  end
255
271
  end
256
272
 
data/lib/puma/null_io.rb CHANGED
File without changes
File without changes
data/lib/puma/plugin.rb CHANGED
@@ -64,7 +64,7 @@ module Puma
64
64
  def fire_background
65
65
  @background.each_with_index do |b, i|
66
66
  Thread.new do
67
- Puma.set_thread_name "plugin background #{i}"
67
+ Puma.set_thread_name "plgn bg #{i}"
68
68
  b.call
69
69
  end
70
70
  end
Binary file
File without changes
File without changes
File without changes
File without changes
data/lib/puma/reactor.rb CHANGED
File without changes
data/lib/puma/request.rb CHANGED
@@ -46,11 +46,7 @@ module Puma
46
46
  env[HIJACK_P] = true
47
47
  env[HIJACK] = client
48
48
 
49
- body = client.body
50
-
51
- head = env[REQUEST_METHOD] == HEAD
52
-
53
- env[RACK_INPUT] = body
49
+ env[RACK_INPUT] = client.body
54
50
  env[RACK_URL_SCHEME] ||= default_server_port(env) == PORT_443 ? HTTPS : HTTP
55
51
 
56
52
  if @early_hints
@@ -69,36 +65,58 @@ module Puma
69
65
  # A rack extension. If the app writes #call'ables to this
70
66
  # array, we will invoke them when the request is done.
71
67
  #
72
- after_reply = env[RACK_AFTER_REPLY] = []
68
+ env[RACK_AFTER_REPLY] = []
73
69
 
74
70
  begin
75
- begin
76
- status, headers, res_body = @thread_pool.with_force_shutdown do
77
- @app.call(env)
71
+ status, headers, res_body = @thread_pool.with_force_shutdown do
72
+ @app.call(env)
73
+ end
74
+
75
+ return :async if client.hijacked
76
+
77
+ status = status.to_i
78
+
79
+ if status == -1
80
+ unless headers.empty? and res_body == []
81
+ raise "async response must have empty headers and body"
78
82
  end
79
83
 
80
- return :async if client.hijacked
84
+ return :async
85
+ end
86
+ rescue ThreadPool::ForceShutdown => e
87
+ @events.unknown_error e, client, "Rack app"
88
+ @events.log "Detected force shutdown of a thread"
81
89
 
82
- status = status.to_i
90
+ status, headers, res_body = lowlevel_error(e, env, 503)
91
+ rescue Exception => e
92
+ @events.unknown_error e, client, "Rack app"
83
93
 
84
- if status == -1
85
- unless headers.empty? and res_body == []
86
- raise "async response must have empty headers and body"
87
- end
94
+ status, headers, res_body = lowlevel_error(e, env, 500)
95
+ end
88
96
 
89
- return :async
90
- end
91
- rescue ThreadPool::ForceShutdown => e
92
- @events.unknown_error e, client, "Rack app"
93
- @events.log "Detected force shutdown of a thread"
97
+ write_response(status, headers, res_body, lines, requests, client)
98
+ end
94
99
 
95
- status, headers, res_body = lowlevel_error(e, env, 503)
96
- rescue Exception => e
97
- @events.unknown_error e, client, "Rack app"
100
+ # Does the actual response writing for Request#handle_request and Server#client_error
101
+ #
102
+ # @param status [Integer] the status returned by the Rack application
103
+ # @param headers [Hash] the headers returned by the Rack application
104
+ # @param res_body [Array] the body returned by the Rack application
105
+ # @param lines [Puma::IOBuffer] modified in place
106
+ # @param requests [Integer] number of inline requests handled
107
+ # @param client [Puma::Client]
108
+ # @return [Boolean,:async]
109
+ def write_response(status, headers, res_body, lines, requests, client)
110
+ env = client.env
111
+ io = client.io
98
112
 
99
- status, headers, res_body = lowlevel_error(e, env, 500)
100
- end
113
+ return false if closed_socket?(io)
114
+ lines.clear
101
115
 
116
+ head = env[REQUEST_METHOD] == HEAD
117
+ after_reply = env[RACK_AFTER_REPLY] || []
118
+
119
+ begin
102
120
  res_info = {}
103
121
  res_info[:content_length] = nil
104
122
  res_info[:no_body] = head
@@ -149,9 +167,9 @@ module Puma
149
167
  res_body.each do |part|
150
168
  next if part.bytesize.zero?
151
169
  if chunked
152
- fast_write io, (part.bytesize.to_s(16) << line_ending)
153
- fast_write io, part # part may have different encoding
154
- fast_write io, line_ending
170
+ fast_write io, (part.bytesize.to_s(16) << line_ending)
171
+ fast_write io, part # part may have different encoding
172
+ fast_write io, line_ending
155
173
  else
156
174
  fast_write io, part
157
175
  end
@@ -169,7 +187,7 @@ module Puma
169
187
  ensure
170
188
  uncork_socket io
171
189
 
172
- body.close
190
+ client.body.close if client.body
173
191
  client.tempfile.unlink if client.tempfile
174
192
  res_body.close if res_body.respond_to? :close
175
193
 
data/lib/puma/runner.rb CHANGED
@@ -69,7 +69,7 @@ module Puma
69
69
 
70
70
  control.binder.parse [str], self, 'Starting control server'
71
71
 
72
- control.run thread_name: 'control'
72
+ control.run thread_name: 'ctl'
73
73
  @control = control
74
74
  end
75
75
 
@@ -94,12 +94,13 @@ module Puma
94
94
  def output_header(mode)
95
95
  min_t = @options[:min_threads]
96
96
  max_t = @options[:max_threads]
97
+ environment = @options[:environment]
97
98
 
98
99
  log "Puma starting in #{mode} mode..."
99
100
  log "* Puma version: #{Puma::Const::PUMA_VERSION} (#{ruby_engine}) (\"#{Puma::Const::CODE_NAME}\")"
100
101
  log "* Min threads: #{min_t}"
101
102
  log "* Max threads: #{max_t}"
102
- log "* Environment: #{ENV['RACK_ENV']}"
103
+ log "* Environment: #{environment}"
103
104
 
104
105
  if mode == "cluster"
105
106
  log "* Master PID: #{Process.pid}"