about summary refs log tree commit homepage
path: root/lib/yahns/req_res.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/yahns/req_res.rb')
-rw-r--r--lib/yahns/req_res.rb51
1 files changed, 24 insertions, 27 deletions
diff --git a/lib/yahns/req_res.rb b/lib/yahns/req_res.rb
index 0fa4285..958015a 100644
--- a/lib/yahns/req_res.rb
+++ b/lib/yahns/req_res.rb
@@ -1,7 +1,7 @@
 # -*- encoding: binary -*-
 # Copyright (C) 2013-2016 all contributors <yahns-public@yhbt.net>
 # License: GPL-3.0+ (https://www.gnu.org/licenses/gpl-3.0.txt)
-# frozen_string_literal: true
+# frozen_string_literal: false
 # Only used by Yahns::ProxyPass
 require 'kcar' # gem install kcar
 require 'kgio'
@@ -64,7 +64,7 @@ class Yahns::ReqRes < Kgio::Socket # :nodoc:
 
       end while true # case @resbuf
 
-    when Array # [ (str|vec), rack.input, chunked? ]
+    when Array # [ str, rack.input, chunked? ]
       send_req_body(req) # returns nil or :wait_writable
     when String # buffered request header
       send_req_buf(req)
@@ -80,11 +80,14 @@ class Yahns::ReqRes < Kgio::Socket # :nodoc:
   end
 
   def send_req_body_chunk(buf)
-    case rv = String === buf ? kgio_trywrite(buf) : kgio_trywritev(buf)
-    when String, Array
+    case rv = kgio_trywrite(buf)
+    when nil
+      return rv # done
+    when String
       buf.replace(rv) # retry loop on partial write
-    when :wait_writable, nil
+    when :wait_writable
       # :wait_writable = upstream is reading slowly and making us wait
+      @rrstate[0] = buf # for the next time we're called
       return rv
     else
       abort "BUG: #{rv.inspect} from kgio_trywrite*"
@@ -92,39 +95,33 @@ class Yahns::ReqRes < Kgio::Socket # :nodoc:
   end
 
   # returns :wait_readable if complete, :wait_writable if not
-  def send_req_body(req) # @rrstate == [ (str|vec), rack.input, chunked? ]
+  def send_req_body(req) # @rrstate == [ str, rack.input, chunked? ]
     buf, input, chunked = req
 
     # send the first buffered chunk or vector
     rv = send_req_body_chunk(buf) and return rv # :wait_writable
 
     # yay, sent the first chunk, now read the body!
-    rbuf = buf
     if chunked
-      if String === buf # initial body
-        req[0] = buf = []
-      else
-        # try to reuse the biggest non-frozen buffer we just wrote;
-        rbuf = buf.max_by(&:size)
-        rbuf = ''.dup if rbuf.frozen? # unlikely...
+      # Note: input (env['rack.input']) is fully-buffered by default so
+      # we should not be waiting on a slow network resource when reading
+      # input.  However, some weird configs may disable this on LANs
+      # and we may wait indefinitely on input.read here...
+
+      rbuf = buf
+      while input.read(0x2000, rbuf)
+        buf = "#{rbuf.size.to_s(16)}\r\n#{rbuf}\r\n"
+        rbuf.clear
+        rv = send_req_body_chunk(buf) and return rv # :wait_writable
+        buf.clear
       end
-    end
-
-    # Note: input (env['rack.input']) is fully-buffered by default so
-    # we should not be waiting on a slow network resource when reading
-    # input.  However, some weird configs may disable this on LANs
-    # and we may wait indefinitely on input.read here...
-    while input.read(0x2000, rbuf)
-      if chunked
-        buf[0] = "#{rbuf.size.to_s(16)}\r\n".freeze
-        buf[1] = rbuf
-        buf[2] = "\r\n".freeze
+    else
+      while input.read(0x2000, buf)
+        rv = send_req_body_chunk(buf) and return rv # :wait_writable
       end
-      rv = send_req_body_chunk(buf) and return rv # :wait_writable
+      buf.clear # all done, clear the big buffer
     end
 
-    rbuf.clear # all done, clear the big buffer
-
     # we cannot use respond_to?(:close) here since Rack::Lint::InputWrapper
     # tries to prevent that (and hijack means all Rack specs go out the door)
     case input