puma 4.3.1 → 4.3.7
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 +23 -4
- data/ext/puma_http11/extconf.rb +1 -1
- data/ext/puma_http11/http11_parser.c +3 -1
- data/ext/puma_http11/http11_parser.rl +3 -1
- data/ext/puma_http11/puma_http11.c +1 -0
- data/lib/puma/app/status.rb +4 -2
- data/lib/puma/client.rb +31 -11
- data/lib/puma/const.rb +2 -1
- data/lib/puma/server.rb +39 -0
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13b795e06976ed8b1004a190e018db051811b3518acdbe3679d0490fee7ee730
|
4
|
+
data.tar.gz: ebef22a424d8e8bc59dd8647b0f728818b9d1ae788ca9ff64a778830e3030349
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98039dfcc8dac9fe7b7ac72cf9970649922c20b5510606a71d3078b83fb20ec8e83febe6be0a9d76bc9d01461937fe7bfd699622f5155e71e86b045fbbcc8dd9
|
7
|
+
data.tar.gz: bb502e59009a55d465b1903cc08f68e9841fbc832bda6f790bd46c7748f2684d5a1e9fc319225e3e49f073478ca2e270f6b5f3a37cc6e562846d84132796e164
|
data/History.md
CHANGED
@@ -1,10 +1,29 @@
|
|
1
|
-
##
|
1
|
+
## 4.3.7 / 2020-11-30
|
2
2
|
|
3
|
-
*
|
4
|
-
*
|
3
|
+
* Bugfixes
|
4
|
+
* Backport set CONTENT_LENGTH for chunked requests (Originally: #2287, backport: #2496)
|
5
|
+
|
6
|
+
## 4.3.6 / 2020-09-05
|
5
7
|
|
6
8
|
* Bugfixes
|
7
|
-
*
|
9
|
+
* Explicitly include ctype.h to fix compilation warning and build error on macOS with Xcode 12 (#2304)
|
10
|
+
* Don't require json at boot (#2269)
|
11
|
+
* Set `CONTENT_LENGTH` for chunked requests (#2287)
|
12
|
+
|
13
|
+
## 4.3.4/4.3.5 and 3.12.5/3.12.6 / 2020-05-22
|
14
|
+
|
15
|
+
Each patchlevel release contains a separate security fix. We recommend simply upgrading to 4.3.5/3.12.6.
|
16
|
+
|
17
|
+
## 4.3.3 and 3.12.4 / 2020-02-28
|
18
|
+
* Bugfixes
|
19
|
+
* Fix: Fixes a problem where we weren't splitting headers correctly on newlines (#2132)
|
20
|
+
* Security
|
21
|
+
* Fix: Prevent HTTP Response splitting via CR in early hints.
|
22
|
+
|
23
|
+
## 4.3.2 and 3.12.3 / 2020-02-27
|
24
|
+
|
25
|
+
* Security
|
26
|
+
* Fix: Prevent HTTP Response splitting via CR/LF in header values. CVE-2020-5247.
|
8
27
|
|
9
28
|
## 4.3.1 and 3.12.2 / 2019-12-05
|
10
29
|
|
data/ext/puma_http11/extconf.rb
CHANGED
@@ -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/app/status.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'json'
|
4
|
-
|
5
3
|
module Puma
|
6
4
|
module App
|
7
5
|
# Check out {#call}'s source code to see what actions this web application
|
@@ -19,6 +17,10 @@ module Puma
|
|
19
17
|
return rack_response(403, 'Invalid auth token', 'text/plain')
|
20
18
|
end
|
21
19
|
|
20
|
+
if env['PATH_INFO'] =~ /\/(gc-stats|stats|thread-backtraces)$/
|
21
|
+
require 'json'
|
22
|
+
end
|
23
|
+
|
22
24
|
case env['PATH_INFO']
|
23
25
|
when /\/stop$/
|
24
26
|
@cli.stop
|
data/lib/puma/client.rb
CHANGED
@@ -153,7 +153,7 @@ module Puma
|
|
153
153
|
|
154
154
|
begin
|
155
155
|
data = @io.read_nonblock(CHUNK_SIZE)
|
156
|
-
rescue
|
156
|
+
rescue IO::WaitReadable
|
157
157
|
return false
|
158
158
|
rescue SystemCallError, IOError, EOFError
|
159
159
|
raise ConnectionError, "Connection error detected during read"
|
@@ -285,8 +285,16 @@ module Puma
|
|
285
285
|
|
286
286
|
te = @env[TRANSFER_ENCODING2]
|
287
287
|
|
288
|
-
if te
|
289
|
-
|
288
|
+
if te
|
289
|
+
if te.include?(",")
|
290
|
+
te.split(",").each do |part|
|
291
|
+
if CHUNKED.casecmp(part.strip) == 0
|
292
|
+
return setup_chunked_body(body)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
elsif CHUNKED.casecmp(te) == 0
|
296
|
+
return setup_chunked_body(body)
|
297
|
+
end
|
290
298
|
end
|
291
299
|
|
292
300
|
@chunked_body = false
|
@@ -343,7 +351,7 @@ module Puma
|
|
343
351
|
|
344
352
|
begin
|
345
353
|
chunk = @io.read_nonblock(want)
|
346
|
-
rescue
|
354
|
+
rescue IO::WaitReadable
|
347
355
|
return false
|
348
356
|
rescue SystemCallError, IOError
|
349
357
|
raise ConnectionError, "Connection error detected during read"
|
@@ -389,7 +397,10 @@ module Puma
|
|
389
397
|
raise EOFError
|
390
398
|
end
|
391
399
|
|
392
|
-
|
400
|
+
if decode_chunk(chunk)
|
401
|
+
@env[CONTENT_LENGTH] = @chunked_content_length
|
402
|
+
return true
|
403
|
+
end
|
393
404
|
end
|
394
405
|
end
|
395
406
|
|
@@ -402,19 +413,28 @@ module Puma
|
|
402
413
|
@body.binmode
|
403
414
|
@tempfile = @body
|
404
415
|
|
405
|
-
|
416
|
+
@chunked_content_length = 0
|
417
|
+
|
418
|
+
if decode_chunk(body)
|
419
|
+
@env[CONTENT_LENGTH] = @chunked_content_length
|
420
|
+
return true
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
def write_chunk(str)
|
425
|
+
@chunked_content_length += @body.write(str)
|
406
426
|
end
|
407
427
|
|
408
428
|
def decode_chunk(chunk)
|
409
429
|
if @partial_part_left > 0
|
410
430
|
if @partial_part_left <= chunk.size
|
411
431
|
if @partial_part_left > 2
|
412
|
-
|
432
|
+
write_chunk(chunk[0..(@partial_part_left-3)]) # skip the \r\n
|
413
433
|
end
|
414
434
|
chunk = chunk[@partial_part_left..-1]
|
415
435
|
@partial_part_left = 0
|
416
436
|
else
|
417
|
-
|
437
|
+
write_chunk(chunk) if @partial_part_left > 2 # don't include the last \r\n
|
418
438
|
@partial_part_left -= chunk.size
|
419
439
|
return false
|
420
440
|
end
|
@@ -461,12 +481,12 @@ module Puma
|
|
461
481
|
|
462
482
|
case
|
463
483
|
when got == len
|
464
|
-
|
484
|
+
write_chunk(part[0..-3]) # to skip the ending \r\n
|
465
485
|
when got <= len - 2
|
466
|
-
|
486
|
+
write_chunk(part)
|
467
487
|
@partial_part_left = len - part.size
|
468
488
|
when got == len - 1 # edge where we get just \r but not \n
|
469
|
-
|
489
|
+
write_chunk(part[0..-2])
|
470
490
|
@partial_part_left = len - part.size
|
471
491
|
end
|
472
492
|
else
|
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 = "4.3.
|
103
|
+
PUMA_VERSION = VERSION = "4.3.7".freeze
|
104
104
|
CODE_NAME = "Mysterious Traveller".freeze
|
105
105
|
PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
|
106
106
|
|
@@ -228,6 +228,7 @@ module Puma
|
|
228
228
|
COLON = ": ".freeze
|
229
229
|
|
230
230
|
NEWLINE = "\n".freeze
|
231
|
+
HTTP_INJECTION_REGEX = /[\r\n]/.freeze
|
231
232
|
|
232
233
|
HIJACK_P = "rack.hijack?".freeze
|
233
234
|
HIJACK = "rack.hijack".freeze
|
data/lib/puma/server.rb
CHANGED
@@ -657,6 +657,7 @@ module Puma
|
|
657
657
|
headers.each_pair do |k, vs|
|
658
658
|
if vs.respond_to?(:to_s) && !vs.to_s.empty?
|
659
659
|
vs.to_s.split(NEWLINE).each do |v|
|
660
|
+
next if possible_header_injection?(v)
|
660
661
|
fast_write client, "#{k}: #{v}\r\n"
|
661
662
|
end
|
662
663
|
else
|
@@ -671,6 +672,37 @@ module Puma
|
|
671
672
|
}
|
672
673
|
end
|
673
674
|
|
675
|
+
# Fixup any headers with , in the name to have _ now. We emit
|
676
|
+
# headers with , in them during the parse phase to avoid ambiguity
|
677
|
+
# with the - to _ conversion for critical headers. But here for
|
678
|
+
# compatibility, we'll convert them back. This code is written to
|
679
|
+
# avoid allocation in the common case (ie there are no headers
|
680
|
+
# with , in their names), that's why it has the extra conditionals.
|
681
|
+
|
682
|
+
to_delete = nil
|
683
|
+
to_add = nil
|
684
|
+
|
685
|
+
env.each do |k,v|
|
686
|
+
if k.start_with?("HTTP_") and k.include?(",") and k != "HTTP_TRANSFER,ENCODING"
|
687
|
+
if to_delete
|
688
|
+
to_delete << k
|
689
|
+
else
|
690
|
+
to_delete = [k]
|
691
|
+
end
|
692
|
+
|
693
|
+
unless to_add
|
694
|
+
to_add = {}
|
695
|
+
end
|
696
|
+
|
697
|
+
to_add[k.tr(",", "_")] = v
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
701
|
+
if to_delete
|
702
|
+
to_delete.each { |k| env.delete(k) }
|
703
|
+
env.merge! to_add
|
704
|
+
end
|
705
|
+
|
674
706
|
# A rack extension. If the app writes #call'ables to this
|
675
707
|
# array, we will invoke them when the request is done.
|
676
708
|
#
|
@@ -758,6 +790,7 @@ module Puma
|
|
758
790
|
headers.each do |k, vs|
|
759
791
|
case k.downcase
|
760
792
|
when CONTENT_LENGTH2
|
793
|
+
next if possible_header_injection?(vs)
|
761
794
|
content_length = vs
|
762
795
|
next
|
763
796
|
when TRANSFER_ENCODING
|
@@ -770,6 +803,7 @@ module Puma
|
|
770
803
|
|
771
804
|
if vs.respond_to?(:to_s) && !vs.to_s.empty?
|
772
805
|
vs.to_s.split(NEWLINE).each do |v|
|
806
|
+
next if possible_header_injection?(v)
|
773
807
|
lines.append k, colon, v, line_ending
|
774
808
|
end
|
775
809
|
else
|
@@ -1040,5 +1074,10 @@ module Puma
|
|
1040
1074
|
def shutting_down?
|
1041
1075
|
@status == :stop || @status == :restart
|
1042
1076
|
end
|
1077
|
+
|
1078
|
+
def possible_header_injection?(header_value)
|
1079
|
+
HTTP_INJECTION_REGEX =~ header_value.to_s
|
1080
|
+
end
|
1081
|
+
private :possible_header_injection?
|
1043
1082
|
end
|
1044
1083
|
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: 4.3.
|
4
|
+
version: 4.3.7
|
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-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nio4r
|
@@ -121,7 +121,7 @@ licenses:
|
|
121
121
|
metadata:
|
122
122
|
msys2_mingw_dependencies: openssl
|
123
123
|
changelog_uri: https://github.com/puma/puma/blob/master/History.md
|
124
|
-
post_install_message:
|
124
|
+
post_install_message:
|
125
125
|
rdoc_options: []
|
126
126
|
require_paths:
|
127
127
|
- lib
|
@@ -136,8 +136,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
136
|
- !ruby/object:Gem::Version
|
137
137
|
version: '0'
|
138
138
|
requirements: []
|
139
|
-
rubygems_version: 3.
|
140
|
-
signing_key:
|
139
|
+
rubygems_version: 3.1.4
|
140
|
+
signing_key:
|
141
141
|
specification_version: 4
|
142
142
|
summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
|
143
143
|
Ruby/Rack applications
|