puma 3.12.1 → 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 +4 -4
- data/History.md +18 -1
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/ext/puma_http11/http11_parser.c +3 -1
- data/ext/puma_http11/http11_parser.rl +3 -1
- data/lib/puma/client.rb +10 -2
- data/lib/puma/const.rb +9 -1
- data/lib/puma/server.rb +54 -1
- metadata +6 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da843833fd17b4bb2283f4c5161a1aa9367a6613455b8fbf31bae49393db4f80
|
4
|
+
data.tar.gz: bd9259270bd27f8421827c66e7f515044f51a7672c3dc755836d2a6b1240e84d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74d807145c97b7714c04ebf7858af57b1cdf00e87217b8a88428494718893f7670ffd27216c31164f57bd96984cd8e79f3c7f856d39c1b54c192965fe8ecdec8
|
7
|
+
data.tar.gz: e0616e41dceddc3b8aad69a5baab5b49007053d151bf2689de173495f3160900269bab94c539a47fe2bbdd2db1aab98a0df8177ece857a06bea6261c5d37a704
|
data/History.md
CHANGED
@@ -4,7 +4,24 @@
|
|
4
4
|
|
5
5
|
* x bugfixes
|
6
6
|
|
7
|
-
|
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
|
8
25
|
|
9
26
|
* 1 features
|
10
27
|
* Internal strings are frozen (#1649)
|
Binary file
|
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
|
}
|
data/lib/puma/client.rb
CHANGED
@@ -244,8 +244,16 @@ module Puma
|
|
244
244
|
|
245
245
|
te = @env[TRANSFER_ENCODING2]
|
246
246
|
|
247
|
-
if te
|
248
|
-
|
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
|
249
257
|
end
|
250
258
|
|
251
259
|
@chunked_body = false
|
data/lib/puma/const.rb
CHANGED
@@ -100,7 +100,7 @@ module Puma
|
|
100
100
|
# too taxing on performance.
|
101
101
|
module Const
|
102
102
|
|
103
|
-
PUMA_VERSION = VERSION = "3.12.
|
103
|
+
PUMA_VERSION = VERSION = "3.12.6".freeze
|
104
104
|
CODE_NAME = "Llamas in Pajamas".freeze
|
105
105
|
PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
|
106
106
|
|
@@ -118,6 +118,13 @@ module Puma
|
|
118
118
|
# sending data back
|
119
119
|
WRITE_TIMEOUT = 10
|
120
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
|
+
|
121
128
|
# The original URI requested by the client.
|
122
129
|
REQUEST_URI= 'REQUEST_URI'.freeze
|
123
130
|
REQUEST_PATH = 'REQUEST_PATH'.freeze
|
@@ -221,6 +228,7 @@ module Puma
|
|
221
228
|
COLON = ": ".freeze
|
222
229
|
|
223
230
|
NEWLINE = "\n".freeze
|
231
|
+
HTTP_INJECTION_REGEX = /[\r\n]/.freeze
|
224
232
|
|
225
233
|
HIJACK_P = "rack.hijack?".freeze
|
226
234
|
HIJACK = "rack.hijack".freeze
|
data/lib/puma/server.rb
CHANGED
@@ -470,6 +470,8 @@ module Puma
|
|
470
470
|
clean_thread_locals = @options[:clean_thread_locals]
|
471
471
|
close_socket = true
|
472
472
|
|
473
|
+
requests = 0
|
474
|
+
|
473
475
|
while true
|
474
476
|
case handle_request(client, buffer)
|
475
477
|
when false
|
@@ -483,7 +485,19 @@ module Puma
|
|
483
485
|
|
484
486
|
ThreadPool.clean_thread_locals if clean_thread_locals
|
485
487
|
|
486
|
-
|
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)
|
487
501
|
close_socket = false
|
488
502
|
client.set_timeout @persistent_timeout
|
489
503
|
@reactor.add client
|
@@ -639,6 +653,7 @@ module Puma
|
|
639
653
|
headers.each_pair do |k, vs|
|
640
654
|
if vs.respond_to?(:to_s) && !vs.to_s.empty?
|
641
655
|
vs.to_s.split(NEWLINE).each do |v|
|
656
|
+
next if possible_header_injection?(v)
|
642
657
|
fast_write client, "#{k}: #{v}\r\n"
|
643
658
|
end
|
644
659
|
else
|
@@ -650,6 +665,37 @@ module Puma
|
|
650
665
|
}
|
651
666
|
end
|
652
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
|
+
|
653
699
|
# A rack extension. If the app writes #call'ables to this
|
654
700
|
# array, we will invoke them when the request is done.
|
655
701
|
#
|
@@ -737,6 +783,7 @@ module Puma
|
|
737
783
|
headers.each do |k, vs|
|
738
784
|
case k.downcase
|
739
785
|
when CONTENT_LENGTH2
|
786
|
+
next if possible_header_injection?(vs)
|
740
787
|
content_length = vs
|
741
788
|
next
|
742
789
|
when TRANSFER_ENCODING
|
@@ -749,6 +796,7 @@ module Puma
|
|
749
796
|
|
750
797
|
if vs.respond_to?(:to_s) && !vs.to_s.empty?
|
751
798
|
vs.to_s.split(NEWLINE).each do |v|
|
799
|
+
next if possible_header_injection?(v)
|
752
800
|
lines.append k, colon, v, line_ending
|
753
801
|
end
|
754
802
|
else
|
@@ -1015,5 +1063,10 @@ module Puma
|
|
1015
1063
|
def shutting_down?
|
1016
1064
|
@status == :stop || @status == :restart
|
1017
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?
|
1018
1071
|
end
|
1019
1072
|
end
|
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.
|
4
|
+
version: 3.12.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Phoenix
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
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
|
@@ -108,7 +108,7 @@ licenses:
|
|
108
108
|
- BSD-3-Clause
|
109
109
|
metadata:
|
110
110
|
msys2_mingw_dependencies: openssl
|
111
|
-
post_install_message:
|
111
|
+
post_install_message:
|
112
112
|
rdoc_options: []
|
113
113
|
require_paths:
|
114
114
|
- lib
|
@@ -123,9 +123,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
125
|
requirements: []
|
126
|
-
|
127
|
-
|
128
|
-
signing_key:
|
126
|
+
rubygems_version: 3.0.3
|
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
|
131
130
|
Ruby/Rack applications
|