puma 6.0.2 → 6.4.2

Sign up to get free protection for your applications and to get access to all the features.
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