puma 6.0.2 → 6.4.2

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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +213 -7
  3. data/LICENSE +0 -0
  4. data/README.md +59 -13
  5. data/bin/puma-wild +0 -0
  6. data/docs/architecture.md +0 -0
  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 +12 -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 +1 -0
  21. data/docs/signals.md +0 -0
  22. data/docs/stats.md +0 -0
  23. data/docs/systemd.md +3 -6
  24. data/docs/testing_benchmarks_local_files.md +0 -0
  25. data/docs/testing_test_rackup_ci_files.md +0 -0
  26. data/ext/puma_http11/PumaHttp11Service.java +0 -0
  27. data/ext/puma_http11/ext_help.h +0 -0
  28. data/ext/puma_http11/extconf.rb +5 -1
  29. data/ext/puma_http11/http11_parser.c +0 -0
  30. data/ext/puma_http11/http11_parser.h +0 -0
  31. data/ext/puma_http11/http11_parser.java.rl +0 -0
  32. data/ext/puma_http11/http11_parser.rl +0 -0
  33. data/ext/puma_http11/http11_parser_common.rl +0 -0
  34. data/ext/puma_http11/mini_ssl.c +96 -9
  35. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
  36. data/ext/puma_http11/org/jruby/puma/Http11.java +0 -0
  37. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +0 -0
  38. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +2 -1
  39. data/ext/puma_http11/puma_http11.c +0 -0
  40. data/lib/puma/app/status.rb +1 -1
  41. data/lib/puma/binder.rb +14 -11
  42. data/lib/puma/cli.rb +5 -1
  43. data/lib/puma/client.rb +77 -16
  44. data/lib/puma/cluster/worker.rb +5 -0
  45. data/lib/puma/cluster/worker_handle.rb +0 -0
  46. data/lib/puma/cluster.rb +71 -10
  47. data/lib/puma/commonlogger.rb +21 -14
  48. data/lib/puma/configuration.rb +6 -4
  49. data/lib/puma/const.rb +58 -9
  50. data/lib/puma/control_cli.rb +12 -5
  51. data/lib/puma/detect.rb +5 -4
  52. data/lib/puma/dsl.rb +157 -7
  53. data/lib/puma/error_logger.rb +2 -1
  54. data/lib/puma/events.rb +0 -0
  55. data/lib/puma/io_buffer.rb +0 -0
  56. data/lib/puma/jruby_restart.rb +0 -0
  57. data/lib/puma/json_serialization.rb +0 -0
  58. data/lib/puma/launcher/bundle_pruner.rb +0 -0
  59. data/lib/puma/launcher.rb +9 -22
  60. data/lib/puma/log_writer.rb +14 -4
  61. data/lib/puma/minissl/context_builder.rb +3 -0
  62. data/lib/puma/minissl.rb +22 -0
  63. data/lib/puma/null_io.rb +16 -2
  64. data/lib/puma/plugin/systemd.rb +90 -0
  65. data/lib/puma/plugin/tmp_restart.rb +0 -0
  66. data/lib/puma/plugin.rb +0 -0
  67. data/lib/puma/rack/builder.rb +2 -2
  68. data/lib/puma/rack/urlmap.rb +1 -1
  69. data/lib/puma/rack_default.rb +18 -3
  70. data/lib/puma/reactor.rb +16 -7
  71. data/lib/puma/request.rb +91 -64
  72. data/lib/puma/runner.rb +13 -2
  73. data/lib/puma/sd_notify.rb +149 -0
  74. data/lib/puma/server.rb +91 -27
  75. data/lib/puma/single.rb +2 -0
  76. data/lib/puma/state_file.rb +2 -2
  77. data/lib/puma/thread_pool.rb +41 -3
  78. data/lib/puma/util.rb +0 -0
  79. data/lib/puma.rb +0 -0
  80. data/lib/rack/handler/puma.rb +113 -86
  81. data/tools/Dockerfile +2 -2
  82. data/tools/trickletest.rb +0 -0
  83. metadata +5 -4
  84. data/lib/puma/systemd.rb +0 -47
data/lib/puma/cluster.rb CHANGED
@@ -85,9 +85,7 @@ module Puma
85
85
  @workers << WorkerHandle.new(idx, pid, @phase, @options)
86
86
  end
87
87
 
88
- if @options[:fork_worker] &&
89
- @workers.all? {|x| x.phase == @phase}
90
-
88
+ if @options[:fork_worker] && all_workers_in_phase?
91
89
  @fork_writer << "0\n"
92
90
  end
93
91
  end
@@ -148,10 +146,22 @@ module Puma
148
146
  idx
149
147
  end
150
148
 
149
+ def worker_at(idx)
150
+ @workers.find { |w| w.index == idx }
151
+ end
152
+
151
153
  def all_workers_booted?
152
154
  @workers.count { |w| !w.booted? } == 0
153
155
  end
154
156
 
157
+ def all_workers_in_phase?
158
+ @workers.all? { |w| w.phase == @phase }
159
+ end
160
+
161
+ def all_workers_idle_timed_out?
162
+ (@workers.map(&:pid) - idle_timed_out_worker_pids).empty?
163
+ end
164
+
155
165
  def check_workers
156
166
  return if @next_check >= Time.now
157
167
 
@@ -276,7 +286,7 @@ module Puma
276
286
 
277
287
  # @version 5.0.0
278
288
  def fork_worker!
279
- if (worker = @workers.find { |w| w.index == 0 })
289
+ if (worker = worker_at 0)
280
290
  worker.phase += 1
281
291
  end
282
292
  phased_restart(true)
@@ -338,6 +348,8 @@ module Puma
338
348
  def run
339
349
  @status = :run
340
350
 
351
+ @idle_workers = {}
352
+
341
353
  output_header "cluster"
342
354
 
343
355
  # This is aligned with the output from Runner, see Runner#output_header
@@ -411,6 +423,8 @@ module Puma
411
423
 
412
424
  @master_read, @worker_write = read, @wakeup
413
425
 
426
+ @options[:worker_write] = @worker_write
427
+
414
428
  @config.run_hooks(:before_fork, nil, @log_writer)
415
429
 
416
430
  spawn_workers
@@ -426,6 +440,11 @@ module Puma
426
440
 
427
441
  while @status == :run
428
442
  begin
443
+ if all_workers_idle_timed_out?
444
+ log "- All workers reached idle timeout"
445
+ break
446
+ end
447
+
429
448
  if @phased_restart
430
449
  start_phased_restart
431
450
  @phased_restart = false
@@ -446,7 +465,7 @@ module Puma
446
465
 
447
466
  if req == "b" || req == "f"
448
467
  pid, idx = result.split(':').map(&:to_i)
449
- w = @workers.find {|x| x.index == idx}
468
+ w = worker_at idx
450
469
  w.pid = pid if w.pid.nil?
451
470
  end
452
471
 
@@ -463,22 +482,37 @@ module Puma
463
482
  when "t"
464
483
  w.term unless w.term?
465
484
  when "p"
466
- w.ping!(result.sub(/^\d+/,'').chomp)
485
+ status = result.sub(/^\d+/,'').chomp
486
+ w.ping!(status)
467
487
  @events.fire(:ping!, w)
488
+
489
+ if in_phased_restart && workers_not_booted.positive? && w0 = worker_at(0)
490
+ w0.ping!(status)
491
+ @events.fire(:ping!, w0)
492
+ end
493
+
468
494
  if !booted && @workers.none? {|worker| worker.last_status.empty?}
469
495
  @events.fire_on_booted!
496
+ debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
470
497
  booted = true
471
498
  end
499
+ when "i"
500
+ if @idle_workers[pid]
501
+ @idle_workers.delete pid
502
+ else
503
+ @idle_workers[pid] = true
504
+ end
472
505
  end
473
506
  else
474
507
  log "! Out-of-sync worker list, no #{pid} worker"
475
508
  end
476
509
  end
510
+
477
511
  if in_phased_restart && workers_not_booted.zero?
478
512
  @events.fire_on_booted!
513
+ debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
479
514
  in_phased_restart = false
480
515
  end
481
-
482
516
  rescue Interrupt
483
517
  @status = :stop
484
518
  end
@@ -507,10 +541,28 @@ module Puma
507
541
  # loops thru @workers, removing workers that exited, and calling
508
542
  # `#term` if needed
509
543
  def wait_workers
544
+ # Reap all children, known workers or otherwise.
545
+ # If puma has PID 1, as it's common in containerized environments,
546
+ # then it's responsible for reaping orphaned processes, so we must reap
547
+ # all our dead children, regardless of whether they are workers we spawned
548
+ # or some reattached processes.
549
+ reaped_children = {}
550
+ loop do
551
+ begin
552
+ pid, status = Process.wait2(-1, Process::WNOHANG)
553
+ break unless pid
554
+ reaped_children[pid] = status
555
+ rescue Errno::ECHILD
556
+ break
557
+ end
558
+ end
559
+
510
560
  @workers.reject! do |w|
511
561
  next false if w.pid.nil?
512
562
  begin
513
- if Process.wait(w.pid, Process::WNOHANG)
563
+ # When `fork_worker` is enabled, some worker may not be direct children, but grand children.
564
+ # Because of this they won't be reaped by `Process.wait2(-1)`, so we need to check them individually)
565
+ if reaped_children.delete(w.pid) || (@options[:fork_worker] && Process.wait(w.pid, Process::WNOHANG))
514
566
  true
515
567
  else
516
568
  w.term if w.term?
@@ -527,6 +579,11 @@ module Puma
527
579
  end
528
580
  end
529
581
  end
582
+
583
+ # Log unknown children
584
+ reaped_children.each do |pid, status|
585
+ log "! reaped unknown child process pid=#{pid} status=#{status}"
586
+ end
530
587
  end
531
588
 
532
589
  # @version 5.0.0
@@ -534,14 +591,18 @@ module Puma
534
591
  @workers.each do |w|
535
592
  if !w.term? && w.ping_timeout <= Time.now
536
593
  details = if w.booted?
537
- "(worker failed to check in within #{@options[:worker_timeout]} seconds)"
594
+ "(Worker #{w.index} failed to check in within #{@options[:worker_timeout]} seconds)"
538
595
  else
539
- "(worker failed to boot within #{@options[:worker_boot_timeout]} seconds)"
596
+ "(Worker #{w.index} failed to boot within #{@options[:worker_boot_timeout]} seconds)"
540
597
  end
541
598
  log "! Terminating timed out worker #{details}: #{w.pid}"
542
599
  w.kill
543
600
  end
544
601
  end
545
602
  end
603
+
604
+ def idle_timed_out_worker_pids
605
+ @idle_workers.keys
606
+ end
546
607
  end
547
608
  end
@@ -3,7 +3,7 @@
3
3
  module Puma
4
4
  # Rack::CommonLogger forwards every request to the given +app+, and
5
5
  # logs a line in the
6
- # {Apache common log format}[https://httpd.apache.org/docs/1.3/logs.html#common]
6
+ # {Apache common log format}[https://httpd.apache.org/docs/2.4/logs.html#common]
7
7
  # to the +logger+.
8
8
  #
9
9
  # If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
@@ -16,7 +16,7 @@ module Puma
16
16
  # (which is called without arguments in order to make the error appear for
17
17
  # sure)
18
18
  class CommonLogger
19
- # Common Log Format: https://httpd.apache.org/docs/1.3/logs.html#common
19
+ # Common Log Format: https://httpd.apache.org/docs/2.4/logs.html#common
20
20
  #
21
21
  # lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
22
22
  #
@@ -25,10 +25,17 @@ module Puma
25
25
 
26
26
  HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
27
27
 
28
- CONTENT_LENGTH = 'Content-Length'.freeze
29
- PATH_INFO = 'PATH_INFO'.freeze
30
- QUERY_STRING = 'QUERY_STRING'.freeze
31
- REQUEST_METHOD = 'REQUEST_METHOD'.freeze
28
+ LOG_TIME_FORMAT = '%d/%b/%Y:%H:%M:%S %z'
29
+
30
+ CONTENT_LENGTH = 'Content-Length' # should be lower case from app,
31
+ # Util::HeaderHash allows mixed
32
+ HTTP_VERSION = Const::HTTP_VERSION
33
+ HTTP_X_FORWARDED_FOR = Const::HTTP_X_FORWARDED_FOR
34
+ PATH_INFO = Const::PATH_INFO
35
+ QUERY_STRING = Const::QUERY_STRING
36
+ REMOTE_ADDR = Const::REMOTE_ADDR
37
+ REMOTE_USER = 'REMOTE_USER'
38
+ REQUEST_METHOD = Const::REQUEST_METHOD
32
39
 
33
40
  def initialize(app, logger=nil)
34
41
  @app = app
@@ -57,13 +64,13 @@ module Puma
57
64
  now = Time.now
58
65
 
59
66
  msg = HIJACK_FORMAT % [
60
- env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
61
- env["REMOTE_USER"] || "-",
62
- now.strftime("%d/%b/%Y %H:%M:%S"),
67
+ env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-",
68
+ env[REMOTE_USER] || "-",
69
+ now.strftime(LOG_TIME_FORMAT),
63
70
  env[REQUEST_METHOD],
64
71
  env[PATH_INFO],
65
72
  env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
66
- env["HTTP_VERSION"],
73
+ env[HTTP_VERSION],
67
74
  now - began_at ]
68
75
 
69
76
  write(msg)
@@ -74,13 +81,13 @@ module Puma
74
81
  length = extract_content_length(header)
75
82
 
76
83
  msg = FORMAT % [
77
- env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
78
- env["REMOTE_USER"] || "-",
79
- now.strftime("%d/%b/%Y:%H:%M:%S %z"),
84
+ env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-",
85
+ env[REMOTE_USER] || "-",
86
+ now.strftime(LOG_TIME_FORMAT),
80
87
  env[REQUEST_METHOD],
81
88
  env[PATH_INFO],
82
89
  env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
83
- env["HTTP_VERSION"],
90
+ env[HTTP_VERSION],
84
91
  status.to_s[0..3],
85
92
  length,
86
93
  now - began_at ]
@@ -3,7 +3,7 @@
3
3
  require_relative 'rack/builder'
4
4
  require_relative 'plugin'
5
5
  require_relative 'const'
6
- # note that dsl is loaded at end of file, requires ConfigDefault constants
6
+ require_relative 'dsl'
7
7
 
8
8
  module Puma
9
9
  # A class used for storing "leveled" configuration options.
@@ -133,8 +133,10 @@ module Puma
133
133
  debug: false,
134
134
  early_hints: nil,
135
135
  environment: 'development'.freeze,
136
- # Number of seconds to wait until we get the first data for the request
136
+ # Number of seconds to wait until we get the first data for the request.
137
137
  first_data_timeout: 30,
138
+ # Number of seconds to wait until the next request before shutting down.
139
+ idle_timeout: nil,
138
140
  io_selector_backend: :auto,
139
141
  log_requests: false,
140
142
  logger: STDOUT,
@@ -157,6 +159,7 @@ module Puma
157
159
  reaping_time: 1,
158
160
  remote_address: :socket,
159
161
  silence_single_worker_warning: false,
162
+ silence_fork_callback_warning: false,
160
163
  tag: File.basename(Dir.getwd),
161
164
  tcp_host: '0.0.0.0'.freeze,
162
165
  tcp_port: 9292,
@@ -167,6 +170,7 @@ module Puma
167
170
  worker_shutdown_timeout: 30,
168
171
  worker_timeout: 60,
169
172
  workers: 0,
173
+ http_content_length_limit: nil
170
174
  }
171
175
 
172
176
  def initialize(user_options={}, default_options = {}, &block)
@@ -383,5 +387,3 @@ module Puma
383
387
  end
384
388
  end
385
389
  end
386
-
387
- require_relative 'dsl'
data/lib/puma/const.rb CHANGED
@@ -18,6 +18,7 @@ module Puma
18
18
  100 => 'Continue',
19
19
  101 => 'Switching Protocols',
20
20
  102 => 'Processing',
21
+ 103 => 'Early Hints',
21
22
  200 => 'OK',
22
23
  201 => 'Created',
23
24
  202 => 'Accepted',
@@ -49,16 +50,16 @@ module Puma
49
50
  410 => 'Gone',
50
51
  411 => 'Length Required',
51
52
  412 => 'Precondition Failed',
52
- 413 => 'Payload Too Large',
53
+ 413 => 'Content Too Large',
53
54
  414 => 'URI Too Long',
54
55
  415 => 'Unsupported Media Type',
55
56
  416 => 'Range Not Satisfiable',
56
57
  417 => 'Expectation Failed',
57
- 418 => 'I\'m A Teapot',
58
58
  421 => 'Misdirected Request',
59
- 422 => 'Unprocessable Entity',
59
+ 422 => 'Unprocessable Content',
60
60
  423 => 'Locked',
61
61
  424 => 'Failed Dependency',
62
+ 425 => 'Too Early',
62
63
  426 => 'Upgrade Required',
63
64
  428 => 'Precondition Required',
64
65
  429 => 'Too Many Requests',
@@ -73,7 +74,7 @@ module Puma
73
74
  506 => 'Variant Also Negotiates',
74
75
  507 => 'Insufficient Storage',
75
76
  508 => 'Loop Detected',
76
- 510 => 'Not Extended',
77
+ 510 => 'Not Extended (OBSOLETED)',
77
78
  511 => 'Network Authentication Required'
78
79
  }.freeze
79
80
 
@@ -99,8 +100,8 @@ module Puma
99
100
  # too taxing on performance.
100
101
  module Const
101
102
 
102
- PUMA_VERSION = VERSION = "6.0.2"
103
- CODE_NAME = "Sunflower"
103
+ PUMA_VERSION = VERSION = "6.4.2"
104
+ CODE_NAME = "The Eagle of Durango"
104
105
 
105
106
  PUMA_SERVER_STRING = ["puma", PUMA_VERSION, CODE_NAME].join(" ").freeze
106
107
 
@@ -124,15 +125,15 @@ module Puma
124
125
  # Indicate that we couldn't parse the request
125
126
  400 => "HTTP/1.1 400 Bad Request\r\n\r\n",
126
127
  # The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
127
- 404 => "HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\nNOT FOUND",
128
+ 404 => "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n",
128
129
  # The standard empty 408 response for requests that timed out.
129
- 408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\n",
130
+ 408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\n\r\n",
130
131
  # Indicate that there was an internal error, obviously.
131
132
  500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n",
132
133
  # Incorrect or invalid header value
133
134
  501 => "HTTP/1.1 501 Not Implemented\r\n\r\n",
134
135
  # A common header for indicating the server is too busy. Not used yet.
135
- 503 => "HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY"
136
+ 503 => "HTTP/1.1 503 Service Unavailable\r\n\r\n"
136
137
  }.freeze
137
138
 
138
139
  # The basic max request size we'll try to read.
@@ -147,7 +148,55 @@ module Puma
147
148
 
148
149
  REQUEST_METHOD = "REQUEST_METHOD"
149
150
  HEAD = "HEAD"
151
+
152
+ # based on https://www.rfc-editor.org/rfc/rfc9110.html#name-overview,
153
+ # with CONNECT removed, and PATCH added
150
154
  SUPPORTED_HTTP_METHODS = %w[HEAD GET POST PUT DELETE OPTIONS TRACE PATCH].freeze
155
+
156
+ # list from https://www.iana.org/assignments/http-methods/http-methods.xhtml
157
+ # as of 04-May-23
158
+ IANA_HTTP_METHODS = %w[
159
+ ACL
160
+ BASELINE-CONTROL
161
+ BIND
162
+ CHECKIN
163
+ CHECKOUT
164
+ CONNECT
165
+ COPY
166
+ DELETE
167
+ GET
168
+ HEAD
169
+ LABEL
170
+ LINK
171
+ LOCK
172
+ MERGE
173
+ MKACTIVITY
174
+ MKCALENDAR
175
+ MKCOL
176
+ MKREDIRECTREF
177
+ MKWORKSPACE
178
+ MOVE
179
+ OPTIONS
180
+ ORDERPATCH
181
+ PATCH
182
+ POST
183
+ PRI
184
+ PROPFIND
185
+ PROPPATCH
186
+ PUT
187
+ REBIND
188
+ REPORT
189
+ SEARCH
190
+ TRACE
191
+ UNBIND
192
+ UNCHECKOUT
193
+ UNLINK
194
+ UNLOCK
195
+ UPDATE
196
+ UPDATEREDIRECTREF
197
+ VERSION-CONTROL
198
+ ].freeze
199
+
151
200
  # ETag is based on the apache standard of hex mtime-size-inode (inode is 0 on win32)
152
201
  LINE_END = "\r\n"
153
202
  REMOTE_ADDR = "REMOTE_ADDR"
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'optparse'
4
- require_relative 'state_file'
5
4
  require_relative 'const'
6
5
  require_relative 'detect'
7
- require_relative 'configuration'
8
6
  require 'uri'
9
7
  require 'socket'
10
8
 
@@ -126,6 +124,9 @@ module Puma
126
124
  end
127
125
 
128
126
  if @config_file
127
+ require_relative 'configuration'
128
+ require_relative 'log_writer'
129
+
129
130
  config = Puma::Configuration.new({ config_files: [@config_file] }, {})
130
131
  config.load
131
132
  @state ||= config.options[:state]
@@ -149,6 +150,8 @@ module Puma
149
150
  raise "State file not found: #{@state}"
150
151
  end
151
152
 
153
+ require_relative 'state_file'
154
+
152
155
  sf = Puma::StateFile.new
153
156
  sf.load @state
154
157
 
@@ -164,22 +167,26 @@ module Puma
164
167
  def send_request
165
168
  uri = URI.parse @control_url
166
169
 
170
+ host = uri.host
171
+
167
172
  # create server object by scheme
168
173
  server =
169
174
  case uri.scheme
170
175
  when 'ssl'
171
176
  require 'openssl'
177
+ host = host[1..-2] if host&.start_with? '['
172
178
  OpenSSL::SSL::SSLSocket.new(
173
- TCPSocket.new(uri.host, uri.port),
179
+ TCPSocket.new(host, uri.port),
174
180
  OpenSSL::SSL::SSLContext.new)
175
181
  .tap { |ssl| ssl.sync_close = true } # default is false
176
182
  .tap(&:connect)
177
183
  when 'tcp'
178
- TCPSocket.new uri.host, uri.port
184
+ host = host[1..-2] if host&.start_with? '['
185
+ TCPSocket.new host, uri.port
179
186
  when 'unix'
180
187
  # check for abstract UNIXSocket
181
188
  UNIXSocket.new(@control_url.start_with?('unix://@') ?
182
- "\0#{uri.host}#{uri.path}" : "#{uri.host}#{uri.path}")
189
+ "\0#{host}#{uri.path}" : "#{host}#{uri.path}")
183
190
  else
184
191
  raise "Invalid scheme: #{uri.scheme}"
185
192
  end
data/lib/puma/detect.rb CHANGED
@@ -12,13 +12,14 @@ module Puma
12
12
 
13
13
  IS_JRUBY = Object.const_defined? :JRUBY_VERSION
14
14
 
15
- IS_OSX = RUBY_PLATFORM.include? 'darwin'
15
+ IS_OSX = RUBY_DESCRIPTION.include? 'darwin'
16
16
 
17
- IS_WINDOWS = !!(RUBY_PLATFORM =~ /mswin|ming|cygwin/) ||
18
- IS_JRUBY && RUBY_DESCRIPTION.include?('mswin')
17
+ IS_WINDOWS = RUBY_DESCRIPTION.match?(/mswin|ming|cygwin/)
18
+
19
+ IS_LINUX = !(IS_OSX || IS_WINDOWS)
19
20
 
20
21
  # @version 5.2.0
21
- IS_MRI = (RUBY_ENGINE == 'ruby' || RUBY_ENGINE.nil?)
22
+ IS_MRI = RUBY_ENGINE == 'ruby'
22
23
 
23
24
  def self.jruby?
24
25
  IS_JRUBY