puma 5.4.0-java → 5.6.0-java

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +96 -2
  3. data/LICENSE +0 -0
  4. data/README.md +47 -6
  5. data/bin/puma-wild +0 -0
  6. data/docs/architecture.md +49 -16
  7. data/docs/compile_options.md +4 -2
  8. data/docs/deployment.md +53 -52
  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 +15 -15
  19. data/docs/rails_dev_mode.md +2 -3
  20. data/docs/restart.md +6 -6
  21. data/docs/signals.md +11 -10
  22. data/docs/stats.md +8 -8
  23. data/docs/systemd.md +64 -67
  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 +23 -10
  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 +1 -1
  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 +49 -47
  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 +46 -4
  40. data/lib/puma/cli.rb +14 -4
  41. data/lib/puma/client.rb +46 -4
  42. data/lib/puma/cluster/worker.rb +7 -17
  43. data/lib/puma/cluster/worker_handle.rb +4 -0
  44. data/lib/puma/cluster.rb +29 -21
  45. data/lib/puma/commonlogger.rb +0 -0
  46. data/lib/puma/configuration.rb +4 -1
  47. data/lib/puma/const.rb +4 -5
  48. data/lib/puma/control_cli.rb +1 -1
  49. data/lib/puma/detect.rb +8 -2
  50. data/lib/puma/dsl.rb +98 -11
  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 +4 -1
  57. data/lib/puma/minissl/context_builder.rb +8 -6
  58. data/lib/puma/minissl.rb +24 -23
  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 +22 -8
  70. data/lib/puma/server.rb +40 -37
  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 +7 -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 +6 -6
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
@@ -164,16 +182,6 @@ module Puma
164
182
  ].compact.min
165
183
  end
166
184
 
167
- def wakeup!
168
- return unless @wakeup
169
-
170
- begin
171
- @wakeup.write "!" unless @wakeup.closed?
172
- rescue SystemCallError, IOError
173
- Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
174
- end
175
- end
176
-
177
185
  def worker(index, master)
178
186
  @workers = []
179
187
 
@@ -450,7 +458,7 @@ module Puma
450
458
  workers_not_booted -= 1
451
459
  when "e"
452
460
  # external term, see worker method, Signal.trap "SIGTERM"
453
- w.instance_variable_set :@term, true
461
+ w.term!
454
462
  when "t"
455
463
  w.term unless w.term?
456
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,12 +196,14 @@ 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
- :environment => -> { ENV['RACK_ENV'] || ENV['RAILS_ENV'] || "development" },
206
+ :environment => -> { ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development' },
204
207
  :rackup => DefaultRackup,
205
208
  :logger => STDOUT,
206
209
  :persistent_timeout => Const::PERSISTENT_TIMEOUT,
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.4.0".freeze
104
- CODE_NAME = "Super Flight".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
@@ -247,5 +244,7 @@ module Puma
247
244
 
248
245
  # Banned keys of response header
249
246
  BANNED_HEADER_KEY = /\A(rack\.|status\z)/.freeze
247
+
248
+ PROXY_PROTOCOL_V1_REGEX = /^PROXY (?:TCP4|TCP6|UNKNOWN) ([^\r]+)\r\n/.freeze
250
249
  end
251
250
  end
@@ -47,7 +47,7 @@ module Puma
47
47
  @control_auth_token = nil
48
48
  @config_file = nil
49
49
  @command = nil
50
- @environment = ENV['RACK_ENV'] || ENV['RAILS_ENV']
50
+ @environment = ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV']
51
51
 
52
52
  @argv = argv.dup
53
53
  @stdout = stdout
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
 
@@ -585,7 +605,7 @@ module Puma
585
605
  # end
586
606
  def after_worker_fork(&block)
587
607
  @options[:after_worker_fork] ||= []
588
- @options[:after_worker_fork] = block
608
+ @options[:after_worker_fork] << block
589
609
  end
590
610
 
591
611
  alias_method :after_worker_boot, :after_worker_fork
@@ -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
@@ -818,7 +875,7 @@ module Puma
818
875
  # a kernel syscall is required which for very fast rack handlers
819
876
  # slows down the handling significantly.
820
877
  #
821
- # There are 4 possible values:
878
+ # There are 5 possible values:
822
879
  #
823
880
  # 1. **:socket** (the default) - read the peername from the socket using the
824
881
  # syscall. This is the normal behavior.
@@ -828,7 +885,10 @@ module Puma
828
885
  # `set_remote_address header: "X-Real-IP"`.
829
886
  # Only the first word (as separated by spaces or comma) is used, allowing
830
887
  # headers such as X-Forwarded-For to be used as well.
831
- # 4. **\<Any string\>** - this allows you to hardcode remote address to any value
888
+ # 4. **proxy_protocol: :v1**- set the remote address to the value read from the
889
+ # HAproxy PROXY protocol, version 1. If the request does not have the PROXY
890
+ # protocol attached to it, will fall back to :socket
891
+ # 5. **\<Any string\>** - this allows you to hardcode remote address to any value
832
892
  # you wish. Because Puma never uses this field anyway, it's format is
833
893
  # entirely in your hands.
834
894
  #
@@ -846,6 +906,13 @@ module Puma
846
906
  if hdr = val[:header]
847
907
  @options[:remote_address] = :header
848
908
  @options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
909
+ elsif protocol_version = val[:proxy_protocol]
910
+ @options[:remote_address] = :proxy_protocol
911
+ protocol_version = protocol_version.downcase.to_sym
912
+ unless [:v1].include?(protocol_version)
913
+ raise "Invalid value for proxy_protocol - #{protocol_version.inspect}"
914
+ end
915
+ @options[:remote_address_proxy_protocol] = protocol_version
849
916
  else
850
917
  raise "Invalid value for set_remote_address - #{val.inspect}"
851
918
  end
@@ -917,5 +984,25 @@ module Puma
917
984
  def mutate_stdout_and_stderr_to_sync_on_write(enabled=true)
918
985
  @options[:mutate_stdout_and_stderr_to_sync_on_write] = enabled
919
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
920
1007
  end
921
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
 
@@ -319,10 +320,12 @@ module Puma
319
320
  log '* Pruning Bundler environment'
320
321
  home = ENV['GEM_HOME']
321
322
  bundle_gemfile = Bundler.original_env['BUNDLE_GEMFILE']
323
+ bundle_app_config = Bundler.original_env['BUNDLE_APP_CONFIG']
322
324
  with_unbundled_env do
323
325
  ENV['GEM_HOME'] = home
324
326
  ENV['BUNDLE_GEMFILE'] = bundle_gemfile
325
327
  ENV['PUMA_BUNDLER_PRUNED'] = '1'
328
+ ENV["BUNDLE_APP_CONFIG"] = bundle_app_config
326
329
  args = [Gem.ruby, puma_wild_location, '-I', dirs.join(':')] + @original_argv
327
330
  # Ruby 2.0+ defaults to true which breaks socket activation
328
331
  args += [{:close_others => false}]
@@ -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
@@ -161,30 +161,15 @@ module Puma
161
161
  @socket.flush
162
162
  end
163
163
 
164
- def read_and_drop(timeout = 1)
165
- return :timeout unless @socket.wait_readable(timeout)
166
- case @socket.read_nonblock(1024, exception: false)
167
- when nil
168
- :eof
169
- when :wait_readable
170
- :eagain
171
- else
172
- :drop
173
- end
174
- end
175
-
176
- def should_drop_bytes?
177
- @engine.init? || !@engine.shutdown
178
- end
179
-
180
164
  def close
181
165
  begin
182
- # Read any drop any partially initialized sockets and any received bytes during shutdown.
183
- # Don't let this socket hold this loop forever.
184
- # If it can't send more packets within 1s, then give up.
185
- return if [:timeout, :eof].include?(read_and_drop(1)) while should_drop_bytes?
166
+ unless @engine.shutdown
167
+ while alert_data = @engine.extract
168
+ @socket.write alert_data
169
+ end
170
+ end
186
171
  rescue IOError, SystemCallError
187
- Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
172
+ Puma::Util.purge_interrupt_queue
188
173
  # nothing
189
174
  ensure
190
175
  @socket.close
@@ -223,6 +208,10 @@ module Puma
223
208
  def initialize
224
209
  @no_tlsv1 = false
225
210
  @no_tlsv1_1 = false
211
+ @key = nil
212
+ @cert = nil
213
+ @key_pem = nil
214
+ @cert_pem = nil
226
215
  end
227
216
 
228
217
  if IS_JRUBY
@@ -245,6 +234,8 @@ module Puma
245
234
  attr_reader :key
246
235
  attr_reader :cert
247
236
  attr_reader :ca
237
+ attr_reader :cert_pem
238
+ attr_reader :key_pem
248
239
  attr_accessor :ssl_cipher_filter
249
240
  attr_accessor :verification_flags
250
241
 
@@ -263,9 +254,19 @@ module Puma
263
254
  @ca = ca
264
255
  end
265
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
+
266
267
  def check
267
- raise "Key not configured" unless @key
268
- 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?
269
270
  end
270
271
  end
271
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