puma 5.6.5 → 6.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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +165 -11
  3. data/README.md +22 -17
  4. data/bin/puma-wild +1 -1
  5. data/docs/compile_options.md +34 -0
  6. data/docs/fork_worker.md +1 -3
  7. data/docs/nginx.md +1 -1
  8. data/docs/systemd.md +1 -2
  9. data/docs/testing_benchmarks_local_files.md +150 -0
  10. data/docs/testing_test_rackup_ci_files.md +36 -0
  11. data/ext/puma_http11/extconf.rb +11 -8
  12. data/ext/puma_http11/http11_parser.c +1 -1
  13. data/ext/puma_http11/http11_parser.h +1 -1
  14. data/ext/puma_http11/http11_parser.java.rl +2 -2
  15. data/ext/puma_http11/http11_parser.rl +2 -2
  16. data/ext/puma_http11/http11_parser_common.rl +2 -2
  17. data/ext/puma_http11/mini_ssl.c +36 -15
  18. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  19. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
  20. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +156 -53
  21. data/ext/puma_http11/puma_http11.c +17 -9
  22. data/lib/puma/app/status.rb +3 -3
  23. data/lib/puma/binder.rb +40 -45
  24. data/lib/puma/cli.rb +11 -17
  25. data/lib/puma/client.rb +54 -16
  26. data/lib/puma/cluster/worker.rb +18 -11
  27. data/lib/puma/cluster/worker_handle.rb +4 -1
  28. data/lib/puma/cluster.rb +33 -30
  29. data/lib/puma/configuration.rb +75 -58
  30. data/lib/puma/const.rb +76 -88
  31. data/lib/puma/control_cli.rb +3 -6
  32. data/lib/puma/detect.rb +4 -0
  33. data/lib/puma/dsl.rb +110 -52
  34. data/lib/puma/error_logger.rb +17 -9
  35. data/lib/puma/events.rb +6 -126
  36. data/lib/puma/io_buffer.rb +39 -4
  37. data/lib/puma/jruby_restart.rb +2 -1
  38. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  39. data/lib/puma/launcher.rb +100 -175
  40. data/lib/puma/log_writer.rb +141 -0
  41. data/lib/puma/minissl/context_builder.rb +23 -12
  42. data/lib/puma/minissl.rb +82 -11
  43. data/lib/puma/plugin/systemd.rb +90 -0
  44. data/lib/puma/plugin/tmp_restart.rb +1 -1
  45. data/lib/puma/rack/builder.rb +4 -4
  46. data/lib/puma/rack_default.rb +19 -4
  47. data/lib/puma/reactor.rb +4 -4
  48. data/lib/puma/request.rb +344 -165
  49. data/lib/puma/runner.rb +52 -20
  50. data/lib/puma/sd_notify.rb +149 -0
  51. data/lib/puma/server.rb +57 -71
  52. data/lib/puma/single.rb +13 -11
  53. data/lib/puma/state_file.rb +1 -4
  54. data/lib/puma/thread_pool.rb +16 -16
  55. data/lib/puma/util.rb +0 -11
  56. data/lib/puma.rb +12 -11
  57. data/lib/rack/handler/puma.rb +115 -94
  58. metadata +10 -5
  59. data/lib/puma/queue_close.rb +0 -26
  60. data/lib/puma/systemd.rb +0 -46
data/lib/puma/cluster.rb CHANGED
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/runner'
4
- require 'puma/util'
5
- require 'puma/plugin'
6
- require 'puma/cluster/worker_handle'
7
- require 'puma/cluster/worker'
8
-
9
- require 'time'
3
+ require_relative 'runner'
4
+ require_relative 'util'
5
+ require_relative 'plugin'
6
+ require_relative 'cluster/worker_handle'
7
+ require_relative 'cluster/worker'
10
8
 
11
9
  module Puma
12
10
  # This class is instantiated by the `Puma::Launcher` and used
@@ -17,8 +15,8 @@ module Puma
17
15
  # via the `spawn_workers` method call. Each worker will have it's own
18
16
  # instance of a `Puma::Server`.
19
17
  class Cluster < Runner
20
- def initialize(cli, events)
21
- super cli, events
18
+ def initialize(launcher)
19
+ super(launcher)
22
20
 
23
21
  @phase = 0
24
22
  @workers = []
@@ -27,6 +25,10 @@ module Puma
27
25
  @phased_restart = false
28
26
  end
29
27
 
28
+ # Returns the list of cluster worker handles.
29
+ # @return [Array<Puma::Cluster::WorkerHandle>]
30
+ attr_reader :workers
31
+
30
32
  def stop_workers
31
33
  log "- Gracefully shutting down workers..."
32
34
  @workers.each { |x| x.term }
@@ -92,7 +94,7 @@ module Puma
92
94
 
93
95
  # @version 5.0.0
94
96
  def spawn_worker(idx, master)
95
- @launcher.config.run_hooks :before_worker_fork, idx, @launcher.events
97
+ @config.run_hooks(:before_worker_fork, idx, @log_writer)
96
98
 
97
99
  pid = fork { worker(idx, master) }
98
100
  if !pid
@@ -101,7 +103,7 @@ module Puma
101
103
  exit! 1
102
104
  end
103
105
 
104
- @launcher.config.run_hooks :after_worker_fork, idx, @launcher.events
106
+ @config.run_hooks(:after_worker_fork, idx, @log_writer)
105
107
  pid
106
108
  end
107
109
 
@@ -176,10 +178,10 @@ module Puma
176
178
  end
177
179
  end
178
180
 
179
- @next_check = [
180
- @workers.reject(&:term?).map(&:ping_timeout).min,
181
- @next_check
182
- ].compact.min
181
+ t = @workers.reject(&:term?)
182
+ t.map!(&:ping_timeout)
183
+
184
+ @next_check = [t.min, @next_check].compact.min
183
185
  end
184
186
 
185
187
  def worker(index, master)
@@ -209,8 +211,8 @@ module Puma
209
211
  stop
210
212
  end
211
213
 
212
- def phased_restart
213
- return false if @options[:preload_app]
214
+ def phased_restart(refork = false)
215
+ return false if @options[:preload_app] && !refork
214
216
 
215
217
  @phased_restart = true
216
218
  wakeup!
@@ -226,7 +228,7 @@ module Puma
226
228
  def stop_blocked
227
229
  @status = :stop if @status == :run
228
230
  wakeup!
229
- @control.stop(true) if @control
231
+ @control&.stop true
230
232
  Process.waitall
231
233
  end
232
234
 
@@ -248,24 +250,24 @@ module Puma
248
250
  old_worker_count = @workers.count { |w| w.phase != @phase }
249
251
  worker_status = @workers.map do |w|
250
252
  {
251
- started_at: w.started_at.utc.iso8601,
253
+ started_at: utc_iso8601(w.started_at),
252
254
  pid: w.pid,
253
255
  index: w.index,
254
256
  phase: w.phase,
255
257
  booted: w.booted?,
256
- last_checkin: w.last_checkin.utc.iso8601,
258
+ last_checkin: utc_iso8601(w.last_checkin),
257
259
  last_status: w.last_status,
258
260
  }
259
261
  end
260
262
 
261
263
  {
262
- started_at: @started_at.utc.iso8601,
264
+ started_at: utc_iso8601(@started_at),
263
265
  workers: @workers.size,
264
266
  phase: @phase,
265
267
  booted_workers: worker_status.count { |w| w[:booted] },
266
268
  old_workers: old_worker_count,
267
269
  worker_status: worker_status,
268
- }
270
+ }.merge(super)
269
271
  end
270
272
 
271
273
  def preload?
@@ -277,7 +279,7 @@ module Puma
277
279
  if (worker = @workers.find { |w| w.index == 0 })
278
280
  worker.phase += 1
279
281
  end
280
- phased_restart
282
+ phased_restart(true)
281
283
  end
282
284
 
283
285
  # We do this in a separate method to keep the lambda scope
@@ -290,7 +292,7 @@ module Puma
290
292
 
291
293
  # Auto-fork after the specified number of requests.
292
294
  if (fork_requests = @options[:fork_worker].to_i) > 0
293
- @launcher.events.register(:ping!) do |w|
295
+ @events.register(:ping!) do |w|
294
296
  fork_worker! if w.index == 0 &&
295
297
  w.phase == 0 &&
296
298
  w.last_status[:requests_count] >= fork_requests
@@ -372,12 +374,12 @@ module Puma
372
374
  else
373
375
  log "* Restarts: (\u2714) hot (\u2714) phased"
374
376
 
375
- unless @launcher.config.app_configured?
377
+ unless @config.app_configured?
376
378
  error "No application configured, nothing to run"
377
379
  exit 1
378
380
  end
379
381
 
380
- @launcher.binder.parse @options[:binds], self
382
+ @launcher.binder.parse @options[:binds]
381
383
  end
382
384
 
383
385
  read, @wakeup = Puma::Util.pipe
@@ -409,8 +411,7 @@ module Puma
409
411
 
410
412
  @master_read, @worker_write = read, @wakeup
411
413
 
412
- @launcher.config.run_hooks :before_fork, nil, @launcher.events
413
- Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
414
+ @config.run_hooks(:before_fork, nil, @log_writer)
414
415
 
415
416
  spawn_workers
416
417
 
@@ -463,9 +464,10 @@ module Puma
463
464
  w.term unless w.term?
464
465
  when "p"
465
466
  w.ping!(result.sub(/^\d+/,'').chomp)
466
- @launcher.events.fire(:ping!, w)
467
+ @events.fire(:ping!, w)
467
468
  if !booted && @workers.none? {|worker| worker.last_status.empty?}
468
- @launcher.events.fire_on_booted!
469
+ @events.fire_on_booted!
470
+ debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
469
471
  booted = true
470
472
  end
471
473
  end
@@ -475,6 +477,7 @@ module Puma
475
477
  end
476
478
  if in_phased_restart && workers_not_booted.zero?
477
479
  @events.fire_on_booted!
480
+ debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
478
481
  in_phased_restart = false
479
482
  end
480
483
 
@@ -1,21 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/rack/builder'
4
- require 'puma/plugin'
5
- require 'puma/const'
3
+ require_relative 'rack/builder'
4
+ require_relative 'plugin'
5
+ require_relative 'const'
6
+ # note that dsl is loaded at end of file, requires ConfigDefault constants
6
7
 
7
8
  module Puma
8
-
9
- module ConfigDefault
10
- DefaultRackup = "config.ru"
11
-
12
- DefaultTCPHost = "0.0.0.0"
13
- DefaultTCPPort = 9292
14
- DefaultWorkerCheckInterval = 5
15
- DefaultWorkerTimeout = 60
16
- DefaultWorkerShutdownTimeout = 30
17
- end
18
-
19
9
  # A class used for storing "leveled" configuration options.
20
10
  #
21
11
  # In this class any "user" specified options take precedence over any
@@ -136,7 +126,49 @@ module Puma
136
126
  # is done because an environment variable may have been modified while loading
137
127
  # configuration files.
138
128
  class Configuration
139
- include ConfigDefault
129
+ DEFAULTS = {
130
+ auto_trim_time: 30,
131
+ binds: ['tcp://0.0.0.0:9292'.freeze],
132
+ clean_thread_locals: false,
133
+ debug: false,
134
+ early_hints: nil,
135
+ environment: 'development'.freeze,
136
+ # Number of seconds to wait until we get the first data for the request
137
+ first_data_timeout: 30,
138
+ io_selector_backend: :auto,
139
+ log_requests: false,
140
+ logger: STDOUT,
141
+ # How many requests to attempt inline before sending a client back to
142
+ # the reactor to be subject to normal ordering. The idea here is that
143
+ # we amortize the cost of going back to the reactor for a well behaved
144
+ # but very "greedy" client across 10 requests. This prevents a not
145
+ # well behaved client from monopolizing the thread forever.
146
+ max_fast_inline: 10,
147
+ max_threads: Puma.mri? ? 5 : 16,
148
+ min_threads: 0,
149
+ mode: :http,
150
+ mutate_stdout_and_stderr_to_sync_on_write: true,
151
+ out_of_band: [],
152
+ # Number of seconds for another request within a persistent session.
153
+ persistent_timeout: 20,
154
+ queue_requests: true,
155
+ rackup: 'config.ru'.freeze,
156
+ raise_exception_on_sigterm: true,
157
+ reaping_time: 1,
158
+ remote_address: :socket,
159
+ silence_single_worker_warning: false,
160
+ tag: File.basename(Dir.getwd),
161
+ tcp_host: '0.0.0.0'.freeze,
162
+ tcp_port: 9292,
163
+ wait_for_less_busy_worker: 0.005,
164
+ worker_boot_timeout: 60,
165
+ worker_check_interval: 5,
166
+ worker_culling_strategy: :youngest,
167
+ worker_shutdown_timeout: 30,
168
+ worker_timeout: 60,
169
+ workers: 0,
170
+ http_content_length_limit: nil
171
+ }
140
172
 
141
173
  def initialize(user_options={}, default_options = {}, &block)
142
174
  default_options = self.puma_default_options.merge(default_options)
@@ -181,37 +213,22 @@ module Puma
181
213
  self
182
214
  end
183
215
 
184
- # @version 5.0.0
185
- def default_max_threads
186
- Puma.mri? ? 5 : 16
216
+ def puma_default_options
217
+ defaults = DEFAULTS.dup
218
+ puma_options_from_env.each { |k,v| defaults[k] = v if v }
219
+ defaults
187
220
  end
188
221
 
189
- def puma_default_options
222
+ def puma_options_from_env
223
+ min = ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS']
224
+ max = ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS']
225
+ workers = ENV['WEB_CONCURRENCY']
226
+
190
227
  {
191
- :min_threads => Integer(ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS'] || 0),
192
- :max_threads => Integer(ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS'] || default_max_threads),
193
- :log_requests => false,
194
- :debug => false,
195
- :binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
196
- :workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
197
- :silence_single_worker_warning => false,
198
- :mode => :http,
199
- :worker_check_interval => DefaultWorkerCheckInterval,
200
- :worker_timeout => DefaultWorkerTimeout,
201
- :worker_boot_timeout => DefaultWorkerTimeout,
202
- :worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
203
- :worker_culling_strategy => :youngest,
204
- :remote_address => :socket,
205
- :tag => method(:infer_tag),
206
- :environment => -> { ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development' },
207
- :rackup => DefaultRackup,
208
- :logger => STDOUT,
209
- :persistent_timeout => Const::PERSISTENT_TIMEOUT,
210
- :first_data_timeout => Const::FIRST_DATA_TIMEOUT,
211
- :raise_exception_on_sigterm => true,
212
- :max_fast_inline => Const::MAX_FAST_INLINE,
213
- :io_selector_backend => :auto,
214
- :mutate_stdout_and_stderr_to_sync_on_write => true,
228
+ min_threads: min && Integer(min),
229
+ max_threads: max && Integer(max),
230
+ workers: workers && Integer(workers),
231
+ environment: ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'],
215
232
  }
216
233
  end
217
234
 
@@ -227,7 +244,7 @@ module Puma
227
244
  return [] if files == ['-']
228
245
  return files if files.any?
229
246
 
230
- first_default_file = %W(config/puma/#{environment_str}.rb config/puma.rb).find do |f|
247
+ first_default_file = %W(config/puma/#{@options[:environment]}.rb config/puma.rb).find do |f|
231
248
  File.exist?(f)
232
249
  end
233
250
 
@@ -270,7 +287,7 @@ module Puma
270
287
  found = options[:app] || load_rackup
271
288
 
272
289
  if @options[:log_requests]
273
- require 'puma/commonlogger'
290
+ require_relative 'commonlogger'
274
291
  logger = @options[:logger]
275
292
  found = CommonLogger.new(found, logger)
276
293
  end
@@ -283,21 +300,25 @@ module Puma
283
300
  @options[:environment]
284
301
  end
285
302
 
286
- def environment_str
287
- environment.respond_to?(:call) ? environment.call : environment
288
- end
289
-
290
303
  def load_plugin(name)
291
304
  @plugins.create name
292
305
  end
293
306
 
294
- def run_hooks(key, arg, events)
307
+ # @param key [:Symbol] hook to run
308
+ # @param arg [Launcher, Int] `:on_restart` passes Launcher
309
+ #
310
+ def run_hooks(key, arg, log_writer, hook_data = nil)
295
311
  @options.all_of(key).each do |b|
296
312
  begin
297
- b.call arg
313
+ if Array === b
314
+ hook_data[b[1]] ||= Hash.new
315
+ b[0].call arg, hook_data[b[1]]
316
+ else
317
+ b.call arg
318
+ end
298
319
  rescue => e
299
- events.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
300
- events.debug e.backtrace.join("\n")
320
+ log_writer.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
321
+ log_writer.debug e.backtrace.join("\n")
301
322
  end
302
323
  end
303
324
  end
@@ -315,10 +336,6 @@ module Puma
315
336
 
316
337
  private
317
338
 
318
- def infer_tag
319
- File.basename(Dir.getwd)
320
- end
321
-
322
339
  # Load and use the normal Rack builder if we can, otherwise
323
340
  # fallback to our minimal version.
324
341
  def rack_builder
@@ -368,4 +385,4 @@ module Puma
368
385
  end
369
386
  end
370
387
 
371
- require 'puma/dsl'
388
+ require_relative 'dsl'
data/lib/puma/const.rb CHANGED
@@ -5,7 +5,6 @@ module Puma
5
5
  class UnsupportedOption < RuntimeError
6
6
  end
7
7
 
8
-
9
8
  # Every standard HTTP code mapped to the appropriate message. These are
10
9
  # used so frequently that they are placed directly in Puma for easy
11
10
  # access rather than Puma::Const itself.
@@ -100,55 +99,40 @@ module Puma
100
99
  # too taxing on performance.
101
100
  module Const
102
101
 
103
- PUMA_VERSION = VERSION = "5.6.5".freeze
104
- CODE_NAME = "Birdie's Version".freeze
102
+ PUMA_VERSION = VERSION = "6.1.1"
103
+ CODE_NAME = "The Way Up"
105
104
 
106
- PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
105
+ PUMA_SERVER_STRING = ["puma", PUMA_VERSION, CODE_NAME].join(" ").freeze
107
106
 
108
107
  FAST_TRACK_KA_TIMEOUT = 0.2
109
108
 
110
- # The default number of seconds for another request within a persistent
111
- # session.
112
- PERSISTENT_TIMEOUT = 20
113
-
114
- # The default number of seconds to wait until we get the first data
115
- # for the request
116
- FIRST_DATA_TIMEOUT = 30
117
-
118
109
  # How long to wait when getting some write blocking on the socket when
119
110
  # sending data back
120
111
  WRITE_TIMEOUT = 10
121
112
 
122
- # How many requests to attempt inline before sending a client back to
123
- # the reactor to be subject to normal ordering. The idea here is that
124
- # we amortize the cost of going back to the reactor for a well behaved
125
- # but very "greedy" client across 10 requests. This prevents a not
126
- # well behaved client from monopolizing the thread forever.
127
- MAX_FAST_INLINE = 10
128
-
129
113
  # The original URI requested by the client.
130
- REQUEST_URI= 'REQUEST_URI'.freeze
131
- REQUEST_PATH = 'REQUEST_PATH'.freeze
132
- QUERY_STRING = 'QUERY_STRING'.freeze
133
- CONTENT_LENGTH = "CONTENT_LENGTH".freeze
114
+ REQUEST_URI= "REQUEST_URI"
115
+ REQUEST_PATH = "REQUEST_PATH"
116
+ QUERY_STRING = "QUERY_STRING"
117
+ CONTENT_LENGTH = "CONTENT_LENGTH"
134
118
 
135
- PATH_INFO = 'PATH_INFO'.freeze
119
+ PATH_INFO = "PATH_INFO"
136
120
 
137
- PUMA_TMP_BASE = "puma".freeze
121
+ PUMA_TMP_BASE = "puma"
138
122
 
139
123
  ERROR_RESPONSE = {
140
124
  # Indicate that we couldn't parse the request
141
- 400 => "HTTP/1.1 400 Bad Request\r\n\r\n".freeze,
125
+ 400 => "HTTP/1.1 400 Bad Request\r\n\r\n",
142
126
  # The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
143
- 404 => "HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\nNOT FOUND".freeze,
127
+ 404 => "HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\nNOT FOUND",
144
128
  # The standard empty 408 response for requests that timed out.
145
- 408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\n".freeze,
129
+ 408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\n",
146
130
  # Indicate that there was an internal error, obviously.
147
- 500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n".freeze,
131
+ 500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n",
148
132
  # Incorrect or invalid header value
149
- 501 => "HTTP/1.1 501 Not Implemented\r\n\r\n".freeze,
133
+ 501 => "HTTP/1.1 501 Not Implemented\r\n\r\n",
150
134
  # A common header for indicating the server is too busy. Not used yet.
151
- 503 => "HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY".freeze
135
+ 503 => "HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY"
152
136
  }.freeze
153
137
 
154
138
  # The basic max request size we'll try to read.
@@ -161,84 +145,88 @@ module Puma
161
145
  # Maximum request body size before it is moved out of memory and into a tempfile for reading.
162
146
  MAX_BODY = MAX_HEADER
163
147
 
164
- REQUEST_METHOD = "REQUEST_METHOD".freeze
165
- HEAD = "HEAD".freeze
148
+ REQUEST_METHOD = "REQUEST_METHOD"
149
+ HEAD = "HEAD"
150
+ SUPPORTED_HTTP_METHODS = %w[HEAD GET POST PUT DELETE OPTIONS TRACE PATCH].freeze
166
151
  # ETag is based on the apache standard of hex mtime-size-inode (inode is 0 on win32)
167
- LINE_END = "\r\n".freeze
168
- REMOTE_ADDR = "REMOTE_ADDR".freeze
169
- HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze
170
- HTTP_X_FORWARDED_SSL = "HTTP_X_FORWARDED_SSL".freeze
171
- HTTP_X_FORWARDED_SCHEME = "HTTP_X_FORWARDED_SCHEME".freeze
172
- HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO".freeze
152
+ LINE_END = "\r\n"
153
+ REMOTE_ADDR = "REMOTE_ADDR"
154
+ HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
155
+ HTTP_X_FORWARDED_SSL = "HTTP_X_FORWARDED_SSL"
156
+ HTTP_X_FORWARDED_SCHEME = "HTTP_X_FORWARDED_SCHEME"
157
+ HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO"
173
158
 
174
- SERVER_NAME = "SERVER_NAME".freeze
175
- SERVER_PORT = "SERVER_PORT".freeze
176
- HTTP_HOST = "HTTP_HOST".freeze
177
- PORT_80 = "80".freeze
178
- PORT_443 = "443".freeze
179
- LOCALHOST = "localhost".freeze
180
- LOCALHOST_IP = "127.0.0.1".freeze
159
+ SERVER_NAME = "SERVER_NAME"
160
+ SERVER_PORT = "SERVER_PORT"
161
+ HTTP_HOST = "HTTP_HOST"
162
+ PORT_80 = "80"
163
+ PORT_443 = "443"
164
+ LOCALHOST = "localhost"
165
+ LOCALHOST_IPV4 = "127.0.0.1"
166
+ LOCALHOST_IPV6 = "::1"
167
+ UNSPECIFIED_IPV4 = "0.0.0.0"
168
+ UNSPECIFIED_IPV6 = "::"
181
169
 
182
- SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
183
- HTTP_11 = "HTTP/1.1".freeze
170
+ SERVER_PROTOCOL = "SERVER_PROTOCOL"
171
+ HTTP_11 = "HTTP/1.1"
184
172
 
185
- SERVER_SOFTWARE = "SERVER_SOFTWARE".freeze
186
- GATEWAY_INTERFACE = "GATEWAY_INTERFACE".freeze
187
- CGI_VER = "CGI/1.2".freeze
173
+ SERVER_SOFTWARE = "SERVER_SOFTWARE"
174
+ GATEWAY_INTERFACE = "GATEWAY_INTERFACE"
175
+ CGI_VER = "CGI/1.2"
188
176
 
189
- STOP_COMMAND = "?".freeze
190
- HALT_COMMAND = "!".freeze
191
- RESTART_COMMAND = "R".freeze
177
+ STOP_COMMAND = "?"
178
+ HALT_COMMAND = "!"
179
+ RESTART_COMMAND = "R"
192
180
 
193
- RACK_INPUT = "rack.input".freeze
194
- RACK_URL_SCHEME = "rack.url_scheme".freeze
195
- RACK_AFTER_REPLY = "rack.after_reply".freeze
196
- PUMA_SOCKET = "puma.socket".freeze
197
- PUMA_CONFIG = "puma.config".freeze
198
- PUMA_PEERCERT = "puma.peercert".freeze
181
+ RACK_INPUT = "rack.input"
182
+ RACK_URL_SCHEME = "rack.url_scheme"
183
+ RACK_AFTER_REPLY = "rack.after_reply"
184
+ PUMA_SOCKET = "puma.socket"
185
+ PUMA_CONFIG = "puma.config"
186
+ PUMA_PEERCERT = "puma.peercert"
199
187
 
200
- HTTP = "http".freeze
201
- HTTPS = "https".freeze
188
+ HTTP = "http"
189
+ HTTPS = "https"
202
190
 
203
- HTTPS_KEY = "HTTPS".freeze
191
+ HTTPS_KEY = "HTTPS"
204
192
 
205
- HTTP_VERSION = "HTTP_VERSION".freeze
206
- HTTP_CONNECTION = "HTTP_CONNECTION".freeze
207
- HTTP_EXPECT = "HTTP_EXPECT".freeze
208
- CONTINUE = "100-continue".freeze
193
+ HTTP_VERSION = "HTTP_VERSION"
194
+ HTTP_CONNECTION = "HTTP_CONNECTION"
195
+ HTTP_EXPECT = "HTTP_EXPECT"
196
+ CONTINUE = "100-continue"
209
197
 
210
- HTTP_11_100 = "HTTP/1.1 100 Continue\r\n\r\n".freeze
211
- HTTP_11_200 = "HTTP/1.1 200 OK\r\n".freeze
212
- HTTP_10_200 = "HTTP/1.0 200 OK\r\n".freeze
198
+ HTTP_11_100 = "HTTP/1.1 100 Continue\r\n\r\n"
199
+ HTTP_11_200 = "HTTP/1.1 200 OK\r\n"
200
+ HTTP_10_200 = "HTTP/1.0 200 OK\r\n"
213
201
 
214
- CLOSE = "close".freeze
215
- KEEP_ALIVE = "keep-alive".freeze
202
+ CLOSE = "close"
203
+ KEEP_ALIVE = "keep-alive"
216
204
 
217
- CONTENT_LENGTH2 = "content-length".freeze
218
- CONTENT_LENGTH_S = "Content-Length: ".freeze
219
- TRANSFER_ENCODING = "transfer-encoding".freeze
220
- TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING".freeze
205
+ CONTENT_LENGTH2 = "content-length"
206
+ CONTENT_LENGTH_S = "Content-Length: "
207
+ TRANSFER_ENCODING = "transfer-encoding"
208
+ TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING"
221
209
 
222
- CONNECTION_CLOSE = "Connection: close\r\n".freeze
223
- CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n".freeze
210
+ CONNECTION_CLOSE = "Connection: close\r\n"
211
+ CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n"
224
212
 
225
- TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n".freeze
226
- CLOSE_CHUNKED = "0\r\n\r\n".freeze
213
+ TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n"
214
+ CLOSE_CHUNKED = "0\r\n\r\n"
227
215
 
228
- CHUNKED = "chunked".freeze
216
+ CHUNKED = "chunked"
229
217
 
230
- COLON = ": ".freeze
218
+ COLON = ": "
231
219
 
232
- NEWLINE = "\n".freeze
220
+ NEWLINE = "\n"
233
221
 
234
- HIJACK_P = "rack.hijack?".freeze
235
- HIJACK = "rack.hijack".freeze
236
- HIJACK_IO = "rack.hijack_io".freeze
222
+ HIJACK_P = "rack.hijack?"
223
+ HIJACK = "rack.hijack"
224
+ HIJACK_IO = "rack.hijack_io"
237
225
 
238
- EARLY_HINTS = "rack.early_hints".freeze
226
+ EARLY_HINTS = "rack.early_hints"
239
227
 
240
228
  # Illegal character in the key or value of response header
241
- DQUOTE = "\"".freeze
229
+ DQUOTE = "\""
242
230
  HTTP_HEADER_DELIMITER = Regexp.escape("(),/:;<=>?@[]{}\\").freeze
243
231
  ILLEGAL_HEADER_KEY_REGEX = /[\x00-\x20#{DQUOTE}#{HTTP_HEADER_DELIMITER}]/.freeze
244
232
  # header values can contain HTAB?
@@ -33,9 +33,6 @@ module Puma
33
33
  'worker-count-up' => 'SIGTTIN'
34
34
  }.freeze
35
35
 
36
- # @deprecated 6.0.0
37
- COMMANDS = CMD_PATH_SIG_MAP.keys.freeze
38
-
39
36
  # commands that cannot be used in a request
40
37
  NO_REQ_COMMANDS = %w[info reopen-log worker-count-down worker-count-up].freeze
41
38
 
@@ -287,7 +284,7 @@ module Puma
287
284
 
288
285
  private
289
286
  def start
290
- require 'puma/cli'
287
+ require_relative 'cli'
291
288
 
292
289
  run_args = []
293
290
 
@@ -299,13 +296,13 @@ module Puma
299
296
  run_args += ["-C", @config_file] if @config_file
300
297
  run_args += ["-e", @environment] if @environment
301
298
 
302
- events = Puma::Events.new @stdout, @stderr
299
+ log_writer = Puma::LogWriter.new(@stdout, @stderr)
303
300
 
304
301
  # replace $0 because puma use it to generate restart command
305
302
  puma_cmd = $0.gsub(/pumactl$/, 'puma')
306
303
  $0 = puma_cmd if File.exist?(puma_cmd)
307
304
 
308
- cli = Puma::CLI.new run_args, events
305
+ cli = Puma::CLI.new run_args, log_writer
309
306
  cli.run
310
307
  end
311
308
  end
data/lib/puma/detect.rb CHANGED
@@ -8,6 +8,8 @@ module Puma
8
8
  # @version 5.2.1
9
9
  HAS_FORK = ::Process.respond_to? :fork
10
10
 
11
+ HAS_NATIVE_IO_WAIT = ::IO.public_instance_methods(false).include? :wait_readable
12
+
11
13
  IS_JRUBY = Object.const_defined? :JRUBY_VERSION
12
14
 
13
15
  IS_OSX = RUBY_PLATFORM.include? 'darwin'
@@ -15,6 +17,8 @@ module Puma
15
17
  IS_WINDOWS = !!(RUBY_PLATFORM =~ /mswin|ming|cygwin/) ||
16
18
  IS_JRUBY && RUBY_DESCRIPTION.include?('mswin')
17
19
 
20
+ IS_LINUX = !(IS_OSX || IS_WINDOWS)
21
+
18
22
  # @version 5.2.0
19
23
  IS_MRI = (RUBY_ENGINE == 'ruby' || RUBY_ENGINE.nil?)
20
24