File chunked-request-handling.patch of Package rubygem-puma.15815

commit b01169b5a98bc703b0e10a66f10ad57f3b8ad4cd
Author: Evan Phoenix <evan@phx.io>
Date:   Sun Jul 24 22:02:23 2016 -0700

    Implement chunked request handling. Fixes #620
    
    (cherry picked from commit 5ec232d1d47283195275acccf8d53010b22416f2)
    
    Packager's note: this is needed for CVE-2020-11076.patch to apply.

diff --git a/lib/puma/client.rb b/lib/puma/client.rb
index ac2609a3a79e..c02b7baf90ba 100644
--- a/lib/puma/client.rb
+++ b/lib/puma/client.rb
@@ -7,6 +7,7 @@ class IO
 end
 
 require 'puma/detect'
+require 'tempfile'
 
 if Puma::IS_JRUBY
   # We have to work around some OpenSSL buffer/io-readiness bugs
@@ -113,9 +114,116 @@ module Puma
     # no body share this one object since it has no state.
     EmptyBody = NullIO.new
 
+    def setup_chunked_body(body)
+      @chunked_body = true
+      @partial_part_left = 0
+      @prev_chunk = ""
+
+      @body = Tempfile.new(Const::PUMA_TMP_BASE)
+      @body.binmode
+      @tempfile = @body
+
+      return decode_chunk(body)
+    end
+
+    def decode_chunk(chunk)
+      if @partial_part_left > 0
+        if @partial_part_left <= chunk.size
+          @body << chunk[0..(@partial_part_left-3)] # skip the \r\n
+          chunk = chunk[@partial_part_left..-1]
+        else
+          @body << chunk
+          @partial_part_left -= chunk.size
+          return false
+        end
+      end
+
+      if @prev_chunk.empty?
+        io = StringIO.new(chunk)
+      else
+        io = StringIO.new(@prev_chunk+chunk)
+        @prev_chunk = ""
+      end
+
+      while !io.eof?
+        line = io.gets
+        if line.end_with?("\r\n")
+          len = line.strip.to_i(16)
+          if len == 0
+            @body.rewind
+            @buffer = nil
+            @requests_served += 1
+            @ready = true
+            return true
+          end
+
+          len += 2
+
+          part = io.read(len)
+
+          unless part
+            @partial_part_left = len
+            next
+          end
+
+          got = part.size
+
+          case
+          when got == len
+            @body << part[0..-3] # to skip the ending \r\n
+          when got <= len - 2
+            @body << part
+            @partial_part_left = len - part.size
+          when got == len - 1 # edge where we get just \r but not \n
+            @body << part[0..-2]
+            @partial_part_left = len - part.size
+          end
+        else
+          @prev_chunk = line
+          return false
+        end
+      end
+
+      return false
+    end
+
+    def read_chunked_body
+      while true
+        begin
+          chunk = @io.read_nonblock(4096)
+        rescue Errno::EAGAIN
+          return false
+        rescue SystemCallError, IOError
+          raise ConnectionError, "Connection error detected during read"
+        end
+
+        # No chunk means a closed socket
+        unless chunk
+          @body.close
+          @buffer = nil
+          @requests_served += 1
+          @ready = true
+          raise EOFError
+        end
+
+        return true if decode_chunk(chunk)
+      end
+    end
+
     def setup_body
       @in_data_phase = true
+      @read_header = false
+
       body = @parser.body
+
+      te = @env[TRANSFER_ENCODING2]
+
+      if te == CHUNKED
+        return setup_chunked_body(body)
+      end
+
+      @chunked_body = false
+
       cl = @env[CONTENT_LENGTH]
 
       unless cl
@@ -150,8 +258,6 @@ module Puma
 
       @body_remain = remain
 
-      @read_header = false
-
       return false
     end
 
@@ -242,6 +348,10 @@ module Puma
     end
 
     def read_body
+      if @chunked_body
+        return read_chunked_body
+      end
+
       # Read an odd sized chunk so we can read even sized ones
       # after this
       remain = @body_remain
diff --git a/lib/puma/const.rb b/lib/puma/const.rb
index d074ad23b925..7bf0efc2b4e0 100644
--- a/lib/puma/const.rb
+++ b/lib/puma/const.rb
@@ -228,6 +228,7 @@ module Puma
     CONTENT_LENGTH2 = "content-length".freeze
     CONTENT_LENGTH_S = "Content-Length: ".freeze
     TRANSFER_ENCODING = "transfer-encoding".freeze
+    TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING".freeze
 
     CONNECTION_CLOSE = "Connection: close\r\n".freeze
     CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n".freeze
@@ -235,6 +236,8 @@ module Puma
     TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n".freeze
     CLOSE_CHUNKED = "0\r\n\r\n".freeze
 
+    CHUNKED = "chunked".freeze
+
     COLON = ": ".freeze
 
     NEWLINE = "\n".freeze
openSUSE Build Service is sponsored by