diff options
Diffstat (limited to 'lib/yahns/req_res.rb')
-rw-r--r-- | lib/yahns/req_res.rb | 51 |
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 |