puma 3.12.0 → 3.12.6

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bff4687b24c136075e00b45d5314fd6326b6240733fff22c706096d10d8ec965
4
- data.tar.gz: db2020f983ba02f7403e50f9f9391bd2f20e811fa42121147d4cbaf619e1d8d3
3
+ metadata.gz: da843833fd17b4bb2283f4c5161a1aa9367a6613455b8fbf31bae49393db4f80
4
+ data.tar.gz: bd9259270bd27f8421827c66e7f515044f51a7672c3dc755836d2a6b1240e84d
5
5
  SHA512:
6
- metadata.gz: d6d7efcb9aeb437c07f49cb5a589ed016d888acab08f130bb382f2d470b301ec40ce3df90fbe4cf989bc84468633b180894c60daca377346d283210e6fedba98
7
- data.tar.gz: 2d45380434e8d88d534a27db1a1f843d70b925a64065d55ee637153669b3c78f1539bf4c84ee166ec90636ba3ee948a97540c0bdbac5cc3d68809c86874038f8
6
+ metadata.gz: 74d807145c97b7714c04ebf7858af57b1cdf00e87217b8a88428494718893f7670ffd27216c31164f57bd96984cd8e79f3c7f856d39c1b54c192965fe8ecdec8
7
+ data.tar.gz: e0616e41dceddc3b8aad69a5baab5b49007053d151bf2689de173495f3160900269bab94c539a47fe2bbdd2db1aab98a0df8177ece857a06bea6261c5d37a704
data/History.md CHANGED
@@ -1,3 +1,35 @@
1
+ ## Master
2
+
3
+ * x features
4
+
5
+ * x bugfixes
6
+
7
+
8
+ ## 4.3.3 and 3.12.4 / 2020-02-28
9
+ * Bugfixes
10
+ * Fix: Fixes a problem where we weren't splitting headers correctly on newlines (#2132)
11
+ * Security
12
+ * Fix: Prevent HTTP Response splitting via CR in early hints.
13
+
14
+ ## 4.3.2 and 3.12.3 / 2020-02-27
15
+
16
+ * Security
17
+ * Fix: Prevent HTTP Response splitting via CR/LF in header values. CVE-2020-5247.
18
+
19
+ ## 4.3.1 and 3.12.2 / 2019-12-05
20
+
21
+ * Security
22
+ * Fix: a poorly-behaved client could use keepalive requests to monopolize Puma's reactor and create a denial of service attack. CVE-2019-16770.
23
+
24
+ ## 3.12.1 / 2019-03-19
25
+
26
+ * 1 features
27
+ * Internal strings are frozen (#1649)
28
+ * 3 bugfixes
29
+ * Fix chunked ending check (#1607)
30
+ * Rack handler should use provided default host (#1700)
31
+ * Better support for detecting runtimes that support `fork` (#1630)
32
+
1
33
  ## 3.12.0 / 2018-07-13
2
34
 
3
35
  * 5 features:
Binary file
Binary file
@@ -14,12 +14,14 @@
14
14
 
15
15
  /*
16
16
  * capitalizes all lower-case ASCII characters,
17
- * converts dashes to underscores.
17
+ * converts dashes to underscores, and underscores to commas.
18
18
  */
19
19
  static void snake_upcase_char(char *c)
20
20
  {
21
21
  if (*c >= 'a' && *c <= 'z')
22
22
  *c &= ~0x20;
23
+ else if (*c == '_')
24
+ *c = ',';
23
25
  else if (*c == '-')
24
26
  *c = '_';
25
27
  }
@@ -12,12 +12,14 @@
12
12
 
13
13
  /*
14
14
  * capitalizes all lower-case ASCII characters,
15
- * converts dashes to underscores.
15
+ * converts dashes to underscores, and underscores to commas.
16
16
  */
17
17
  static void snake_upcase_char(char *c)
18
18
  {
19
19
  if (*c >= 'a' && *c <= 'z')
20
20
  *c &= ~0x20;
21
+ else if (*c == '_')
22
+ *c = ',';
21
23
  else if (*c == '-')
22
24
  *c = '_';
23
25
  }
@@ -433,6 +433,18 @@ void Init_mini_ssl(VALUE puma) {
433
433
  mod = rb_define_module_under(puma, "MiniSSL");
434
434
  eng = rb_define_class_under(mod, "Engine", rb_cObject);
435
435
 
436
+ // OpenSSL Build / Runtime/Load versions
437
+
438
+ /* Version of OpenSSL that Puma was compiled with */
439
+ rb_define_const(mod, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
440
+
441
+ #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
442
+ /* Version of OpenSSL that Puma loaded with */
443
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
444
+ #else
445
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
446
+ #endif
447
+
436
448
  rb_define_singleton_method(mod, "check", noop, 0);
437
449
 
438
450
  eError = rb_define_class_under(mod, "SSLError", rb_eStandardError);
data/lib/puma/binder.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
  require 'socket'
3
5
 
@@ -90,19 +92,19 @@ module Puma
90
92
  case uri.scheme
91
93
  when "tcp"
92
94
  if fd = @inherited_fds.delete(str)
93
- logger.log "* Inherited #{str}"
94
95
  io = inherit_tcp_listener uri.host, uri.port, fd
96
+ logger.log "* Inherited #{str}"
95
97
  elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
96
- logger.log "* Activated #{str}"
97
98
  io = inherit_tcp_listener uri.host, uri.port, sock
99
+ logger.log "* Activated #{str}"
98
100
  else
99
101
  params = Util.parse_query uri.query
100
102
 
101
103
  opt = params.key?('low_latency')
102
104
  bak = params.fetch('backlog', 1024).to_i
103
105
 
104
- logger.log "* Listening on #{str}"
105
106
  io = add_tcp_listener uri.host, uri.port, opt, bak
107
+ logger.log "* Listening on #{str}"
106
108
  end
107
109
 
108
110
  @listeners << [str, io] if io
@@ -110,14 +112,12 @@ module Puma
110
112
  path = "#{uri.host}#{uri.path}".gsub("%20", " ")
111
113
 
112
114
  if fd = @inherited_fds.delete(str)
113
- logger.log "* Inherited #{str}"
114
115
  io = inherit_unix_listener path, fd
116
+ logger.log "* Inherited #{str}"
115
117
  elsif sock = @activated_sockets.delete([ :unix, path ])
116
- logger.log "* Activated #{str}"
117
118
  io = inherit_unix_listener path, sock
119
+ logger.log "* Activated #{str}"
118
120
  else
119
- logger.log "* Listening on #{str}"
120
-
121
121
  umask = nil
122
122
  mode = nil
123
123
  backlog = 1024
@@ -139,6 +139,7 @@ module Puma
139
139
  end
140
140
 
141
141
  io = add_unix_listener path, umask, mode, backlog
142
+ logger.log "* Listening on #{str}"
142
143
  end
143
144
 
144
145
  @listeners << [str, io]
@@ -204,11 +205,11 @@ module Puma
204
205
  logger.log "* Inherited #{str}"
205
206
  io = inherit_ssl_listener fd, ctx
206
207
  elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
207
- logger.log "* Activated #{str}"
208
208
  io = inherit_ssl_listener sock, ctx
209
+ logger.log "* Activated #{str}"
209
210
  else
210
- logger.log "* Listening on #{str}"
211
211
  io = add_ssl_listener uri.host, uri.port, ctx
212
+ logger.log "* Listening on #{str}"
212
213
  end
213
214
 
214
215
  @listeners << [str, io] if io
data/lib/puma/cli.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'optparse'
2
4
  require 'uri'
3
5
 
data/lib/puma/client.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class IO
2
4
  # We need to use this for a jruby work around on both 1.8 and 1.9.
3
5
  # So this either creates the constant (on 1.8), or harmlessly
@@ -168,6 +170,7 @@ module Puma
168
170
  if len == 0
169
171
  @body.rewind
170
172
  rest = io.read
173
+ rest = rest[2..-1] if rest.start_with?("\r\n")
171
174
  @buffer = rest.empty? ? nil : rest
172
175
  @requests_served += 1
173
176
  @ready = true
@@ -241,8 +244,16 @@ module Puma
241
244
 
242
245
  te = @env[TRANSFER_ENCODING2]
243
246
 
244
- if te && CHUNKED.casecmp(te) == 0
245
- return setup_chunked_body(body)
247
+ if te
248
+ if te.include?(",")
249
+ te.split(",").each do |part|
250
+ if CHUNKED.casecmp(part.strip) == 0
251
+ return setup_chunked_body(body)
252
+ end
253
+ end
254
+ elsif CHUNKED.casecmp(te) == 0
255
+ return setup_chunked_body(body)
256
+ end
246
257
  end
247
258
 
248
259
  @chunked_body = false
data/lib/puma/cluster.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puma/runner'
2
4
  require 'puma/util'
3
5
  require 'puma/plugin'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puma
2
4
  # Rack::CommonLogger forwards every request to the given +app+, and
3
5
  # logs a line in the
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puma/rack/builder'
2
4
  require 'puma/plugin'
3
5
  require 'puma/const'
data/lib/puma/const.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  #encoding: utf-8
2
+ # frozen_string_literal: true
3
+
2
4
  module Puma
3
5
  class UnsupportedOption < RuntimeError
4
6
  end
@@ -98,7 +100,7 @@ module Puma
98
100
  # too taxing on performance.
99
101
  module Const
100
102
 
101
- PUMA_VERSION = VERSION = "3.12.0".freeze
103
+ PUMA_VERSION = VERSION = "3.12.6".freeze
102
104
  CODE_NAME = "Llamas in Pajamas".freeze
103
105
  PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
104
106
 
@@ -116,6 +118,13 @@ module Puma
116
118
  # sending data back
117
119
  WRITE_TIMEOUT = 10
118
120
 
121
+ # How many requests to attempt inline before sending a client back to
122
+ # the reactor to be subject to normal ordering. The idea here is that
123
+ # we amortize the cost of going back to the reactor for a well behaved
124
+ # but very "greedy" client across 10 requests. This prevents a not
125
+ # well behaved client from monopolizing the thread forever.
126
+ MAX_FAST_INLINE = 10
127
+
119
128
  # The original URI requested by the client.
120
129
  REQUEST_URI= 'REQUEST_URI'.freeze
121
130
  REQUEST_PATH = 'REQUEST_PATH'.freeze
@@ -219,6 +228,7 @@ module Puma
219
228
  COLON = ": ".freeze
220
229
 
221
230
  NEWLINE = "\n".freeze
231
+ HTTP_INJECTION_REGEX = /[\r\n]/.freeze
222
232
 
223
233
  HIJACK_P = "rack.hijack?".freeze
224
234
  HIJACK = "rack.hijack".freeze
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'optparse'
2
- require 'puma/state_file'
3
- require 'puma/const'
4
- require 'puma/detect'
5
- require 'puma/configuration'
4
+ require_relative 'state_file'
5
+ require_relative 'const'
6
+ require_relative 'detect'
7
+ require_relative 'configuration'
6
8
  require 'uri'
7
9
  require 'socket'
8
10
 
@@ -129,7 +131,7 @@ module Puma
129
131
  uri = URI.parse @control_url
130
132
 
131
133
  # create server object by scheme
132
- @server = case uri.scheme
134
+ server = case uri.scheme
133
135
  when "tcp"
134
136
  TCPSocket.new uri.host, uri.port
135
137
  when "unix"
@@ -147,9 +149,9 @@ module Puma
147
149
  url = url + "?token=#{@control_auth_token}"
148
150
  end
149
151
 
150
- @server << "GET #{url} HTTP/1.0\r\n\r\n"
152
+ server << "GET #{url} HTTP/1.0\r\n\r\n"
151
153
 
152
- unless data = @server.read
154
+ unless data = server.read
153
155
  raise "Server closed connection before responding"
154
156
  end
155
157
 
@@ -172,8 +174,8 @@ module Puma
172
174
  message "Command #{@command} sent success"
173
175
  message response.last if @command == "stats" || @command == "gc-stats"
174
176
  end
175
-
176
- @server.close
177
+ ensure
178
+ server.close if server && !server.closed?
177
179
  end
178
180
 
179
181
  def send_signal
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puma/launcher'
2
4
  require 'puma/configuration'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Process
2
4
 
3
5
  # This overrides the default version because it is broken if it
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puma
2
4
  module Delegation
3
5
  def forward(what, who)
data/lib/puma/detect.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puma
2
4
  IS_JRUBY = defined?(JRUBY_VERSION)
3
5
 
data/lib/puma/dsl.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puma
2
4
  # The methods that are available for use inside the config file.
3
5
  # These same methods are used in Puma cli and the rack handler
@@ -55,6 +57,14 @@ module Puma
55
57
  @plugins.clear
56
58
  end
57
59
 
60
+ def set_default_host(host)
61
+ @options[:default_host] = host
62
+ end
63
+
64
+ def default_host
65
+ @options[:default_host] || Configuration::DefaultTCPHost
66
+ end
67
+
58
68
  def inject(&blk)
59
69
  instance_eval(&blk)
60
70
  end
@@ -138,7 +148,7 @@ module Puma
138
148
  # Define the TCP port to bind to. Use +bind+ for more advanced options.
139
149
  #
140
150
  def port(port, host=nil)
141
- host ||= Configuration::DefaultTCPHost
151
+ host ||= default_host
142
152
  bind "tcp://#{host}:#{port}"
143
153
  end
144
154
 
@@ -493,7 +503,7 @@ module Puma
493
503
  when Hash
494
504
  if hdr = val[:header]
495
505
  @options[:remote_address] = :header
496
- @options[:remote_address_header] = "HTTP_" + hdr.upcase.gsub("-", "_")
506
+ @options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
497
507
  else
498
508
  raise "Invalid value for set_remote_address - #{val.inspect}"
499
509
  end
data/lib/puma/events.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puma/const'
2
4
  require "puma/null_io"
3
5
  require 'stringio'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puma/detect'
2
4
 
3
5
  if Puma.jruby?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'java'
2
4
 
3
5
  # Conservative native JRuby/Java implementation of IOBuffer
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ffi'
2
4
 
3
5
  module Puma
data/lib/puma/launcher.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puma/events'
2
4
  require 'puma/detect'
3
5
 
@@ -63,8 +65,8 @@ module Puma
63
65
 
64
66
  generate_restart_data
65
67
 
66
- if clustered? && (Puma.jruby? || Puma.windows?)
67
- unsupported 'worker mode not supported on JRuby or Windows'
68
+ if clustered? && !Process.respond_to?(:fork)
69
+ unsupported "worker mode not supported on #{RUBY_ENGINE} on this platform"
68
70
  end
69
71
 
70
72
  if @options[:daemon] && Puma.windows?
data/lib/puma/minissl.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'io/wait'
3
5
  rescue LoadError
data/lib/puma/null_io.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puma
2
4
  # Provides an IO-like object that always appears to contain no data.
3
5
  # Used as the value for rack.input when the request has no body.
data/lib/puma/plugin.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puma
2
4
  class UnknownPlugin < RuntimeError; end
3
5
 
@@ -110,7 +110,8 @@ module Puma::Rack
110
110
 
111
111
  has_options = false
112
112
  server.valid_options.each do |name, description|
113
- next if name.to_s.match(/^(Host|Port)[^a-zA-Z]/) # ignore handler's host and port options, we do our own.
113
+ next if name.to_s =~ /^(Host|Port)[^a-zA-Z]/ # ignore handler's host and port options, we do our own.
114
+
114
115
  info << " -O %-21s %s" % [name, description]
115
116
  has_options = true
116
117
  end
data/lib/puma/reactor.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puma/util'
2
4
  require 'puma/minissl'
3
5
 
data/lib/puma/runner.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puma/server'
2
4
  require 'puma/const'
3
5
 
data/lib/puma/server.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'stringio'
2
4
 
3
5
  require 'puma/thread_pool'
@@ -468,6 +470,8 @@ module Puma
468
470
  clean_thread_locals = @options[:clean_thread_locals]
469
471
  close_socket = true
470
472
 
473
+ requests = 0
474
+
471
475
  while true
472
476
  case handle_request(client, buffer)
473
477
  when false
@@ -481,7 +485,19 @@ module Puma
481
485
 
482
486
  ThreadPool.clean_thread_locals if clean_thread_locals
483
487
 
484
- unless client.reset(@status == :run)
488
+ requests += 1
489
+
490
+ check_for_more_data = @status == :run
491
+
492
+ if requests >= MAX_FAST_INLINE
493
+ # This will mean that reset will only try to use the data it already
494
+ # has buffered and won't try to read more data. What this means is that
495
+ # every client, independent of their request speed, gets treated like a slow
496
+ # one once every MAX_FAST_INLINE requests.
497
+ check_for_more_data = false
498
+ end
499
+
500
+ unless client.reset(check_for_more_data)
485
501
  close_socket = false
486
502
  client.set_timeout @persistent_timeout
487
503
  @reactor.add client
@@ -637,6 +653,7 @@ module Puma
637
653
  headers.each_pair do |k, vs|
638
654
  if vs.respond_to?(:to_s) && !vs.to_s.empty?
639
655
  vs.to_s.split(NEWLINE).each do |v|
656
+ next if possible_header_injection?(v)
640
657
  fast_write client, "#{k}: #{v}\r\n"
641
658
  end
642
659
  else
@@ -648,6 +665,37 @@ module Puma
648
665
  }
649
666
  end
650
667
 
668
+ # Fixup any headers with , in the name to have _ now. We emit
669
+ # headers with , in them during the parse phase to avoid ambiguity
670
+ # with the - to _ conversion for critical headers. But here for
671
+ # compatibility, we'll convert them back. This code is written to
672
+ # avoid allocation in the common case (ie there are no headers
673
+ # with , in their names), that's why it has the extra conditionals.
674
+
675
+ to_delete = nil
676
+ to_add = nil
677
+
678
+ env.each do |k,v|
679
+ if k.start_with?("HTTP_") and k.include?(",") and k != "HTTP_TRANSFER,ENCODING"
680
+ if to_delete
681
+ to_delete << k
682
+ else
683
+ to_delete = [k]
684
+ end
685
+
686
+ unless to_add
687
+ to_add = {}
688
+ end
689
+
690
+ to_add[k.gsub(",", "_")] = v
691
+ end
692
+ end
693
+
694
+ if to_delete
695
+ to_delete.each { |k| env.delete(k) }
696
+ env.merge! to_add
697
+ end
698
+
651
699
  # A rack extension. If the app writes #call'ables to this
652
700
  # array, we will invoke them when the request is done.
653
701
  #
@@ -735,6 +783,7 @@ module Puma
735
783
  headers.each do |k, vs|
736
784
  case k.downcase
737
785
  when CONTENT_LENGTH2
786
+ next if possible_header_injection?(vs)
738
787
  content_length = vs
739
788
  next
740
789
  when TRANSFER_ENCODING
@@ -747,6 +796,7 @@ module Puma
747
796
 
748
797
  if vs.respond_to?(:to_s) && !vs.to_s.empty?
749
798
  vs.to_s.split(NEWLINE).each do |v|
799
+ next if possible_header_injection?(v)
750
800
  lines.append k, colon, v, line_ending
751
801
  end
752
802
  else
@@ -1013,5 +1063,10 @@ module Puma
1013
1063
  def shutting_down?
1014
1064
  @status == :stop || @status == :restart
1015
1065
  end
1066
+
1067
+ def possible_header_injection?(header_value)
1068
+ HTTP_INJECTION_REGEX =~ header_value.to_s
1069
+ end
1070
+ private :possible_header_injection?
1016
1071
  end
1017
1072
  end
data/lib/puma/single.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puma/runner'
2
4
  require 'puma/detect'
3
5
  require 'puma/plugin'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
 
3
5
  module Puma
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puma
2
4
  class TCPLogger
3
5
  def initialize(logger, app, quiet=false)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thread'
2
4
 
3
5
  module Puma
data/lib/puma/util.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  major, minor, patch = RUBY_VERSION.split('.').map { |v| v.to_i }
2
3
 
3
4
  if major == 1 && minor == 9 && patch == 3 && RUBY_PATCHLEVEL < 125
@@ -49,6 +49,9 @@ module Rack
49
49
  self.set_host_port_to_config(host, port, user_config)
50
50
  end
51
51
 
52
+ if default_options[:Host]
53
+ file_config.set_default_host(default_options[:Host])
54
+ end
52
55
  self.set_host_port_to_config(default_options[:Host], default_options[:Port], default_config)
53
56
 
54
57
  user_config.app app
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.12.0
4
+ version: 3.12.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-13 00:00:00.000000000 Z
11
+ date: 2020-05-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server
14
14
  for Ruby/Rack applications. Puma is intended for use in both development and production
@@ -123,8 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  requirements: []
126
- rubyforge_project:
127
- rubygems_version: 2.7.6
126
+ rubygems_version: 3.0.3
128
127
  signing_key:
129
128
  specification_version: 4
130
129
  summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for