dumping ground for random patches and texts
 help / color / mirror / Atom feed
* [PATCH 1/5] proxy_pass: simplify writing request bodies upstream
@ 2016-05-06  1:05 Eric Wong
  2016-05-06  1:05 ` [PATCH 2/5] proxy_pass: hoist out proxy_res_headers method Eric Wong
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Eric Wong @ 2016-05-06  1:05 UTC (permalink / raw)
  To: spew

The cost of extra branches inside is negligible compared to
the cost of all the other method calls we make.  Favor
smaller code instead and inline some (now) single-use methods.

Furthermore, this allows us to reuse the request header buffer
instead of relying on thread-local storage and potentially
having to to swap buffers.

In retrospect, there may be no such thing as a tight read-write
I/O loop where removing branches is beneficial given the cost of
reads and writes.
---
 lib/yahns/proxy_pass.rb | 112 +++++++++++++++++++++---------------------------
 1 file changed, 49 insertions(+), 63 deletions(-)

diff --git a/lib/yahns/proxy_pass.rb b/lib/yahns/proxy_pass.rb
index 148957b..a2d7d81 100644
--- a/lib/yahns/proxy_pass.rb
+++ b/lib/yahns/proxy_pass.rb
@@ -22,12 +22,6 @@ def req_start(c, req, input, chunked)
       Thread.current[:yahns_queue].queue_add(self, Yahns::Queue::QEV_WR)
     end
 
-    # we must reinitialize the thread-local rbuf if it may get beyond the
-    # current thread
-    def detach_rbuf!
-      Thread.current[:yahns_rbuf] = ''.dup
-    end
-
     def yahns_step # yahns event loop entry point
       c = @yahns_client
       case req = @rrstate
@@ -42,7 +36,9 @@ def yahns_step # yahns event loop entry point
             if res = req.headers(@hdr = [], rv)
               return c.proxy_response_start(res, rv, req, self)
             else # ugh, big headers or tricked response
-              buf = detach_rbuf!
+              # we must reinitialize the thread-local rbuf if it may
+              # live beyond the current thread
+              buf = Thread.current[:yahns_rbuf] = ''.dup
               @resbuf = rv
             end
             # continue looping in middle "case @resbuf" loop
@@ -83,64 +79,63 @@ def yahns_step # yahns event loop entry point
       c.proxy_err_response(502, self, e, wbuf)
     end
 
-    # returns :wait_readable if complete, :wait_writable if not
-    def send_req_body(req)
-      buf, input, chunked = req
-
-      # get the first buffered chunk or vector
+    def send_req_body_chunk(buf)
       case rv = String === buf ? kgio_trywrite(buf) : kgio_trywritev(buf)
       when String, Array
-        buf = rv # retry inner loop
-      when :wait_writable
-        req[0] = buf
-        return :wait_writable
-      when nil
-        break # onto writing body
+        buf.replace(rv) # retry loop on partial write
+      when :wait_writable, nil
+        # :wait_writable = upstream is reading slowly and making us wait
+        return rv
+      else
+        abort "BUG: #{rv.inspect} from kgio_trywrite*"
       end while true
+    end
 
-      buf = Thread.current[:yahns_rbuf]
+    # returns :wait_readable if complete, :wait_writable if not
+    def send_req_body(req) # @rrstate == [ (str|vec), rack.input, chunked? ]
+      buf, input, chunked = req
 
-      # 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
+      # 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
-        while input.read(0x2000, buf)
-          vec = [ "#{buf.size.to_s(16)}\r\n", buf, "\r\n".freeze ]
-          case rv = kgio_trywritev(vec)
-          when Array
-            vec = rv # partial write, retry in case loop
-          when :wait_writable
-            detach_rbuf!
-            req[0] = vec
-            return :wait_writable
-          when nil
-            break # continue onto reading next chunk
-          end while true
+        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...
         end
-        close_req_body(input)
-
-        # note: we do not send any trailer, they are folded into the header
-        # because this relies on full request buffering
-        send_req_buf("0\r\n\r\n".freeze)
-        # prepare_wait_readable already called by send_req_buf
-      else # identity request, easy:
-        while input.read(0x2000, buf)
-          case rv = kgio_trywrite(buf)
-          when String
-            buf = rv # partial write, retry in case loop
-          when :wait_writable
-            detach_rbuf!
-            req[0] = buf
-            return :wait_writable
-          when nil
-            break # continue onto reading next block
-          end while true
+      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
         end
+        rv = send_req_body_chunk(buf) and return rv # :wait_writable
+      end
+
+      rbuf.clear # all done, clear the big buffer
 
-        close_req_body(input)
-        prepare_wait_readable
+      # 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
+      when Yahns::TeeInput, IO
+        input.close
       end
+
+      # note: we do not send any trailer, they are folded into the header
+      # because this relies on full request buffering
+      # prepare_wait_readable is called by send_req_buf
+      chunked ? send_req_buf("0\r\n\r\n".freeze) : prepare_wait_readable
     rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN
       # no more reading off the client socket, just prepare to forward
       # the rejection response from the upstream (if any)
@@ -153,15 +148,6 @@ def prepare_wait_readable
       :wait_readable # all done sending the request, wait for response
     end
 
-    def close_req_body(input)
-      # 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
-      when Yahns::TeeInput, IO
-        input.close
-      end
-    end
-
     # n.b. buf must be a detached string not shared with
     # Thread.current[:yahns_rbuf] of any thread
     def send_req_buf(buf)

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/5] proxy_pass: hoist out proxy_res_headers method
  2016-05-06  1:05 [PATCH 1/5] proxy_pass: simplify writing request bodies upstream Eric Wong
@ 2016-05-06  1:05 ` Eric Wong
  2016-05-06  1:05 ` [PATCH 3/5] proxy_pass: WIP: simplify proxy_http_response Eric Wong
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Eric Wong @ 2016-05-06  1:05 UTC (permalink / raw)
  To: spew

proxy_response_start is gigantic an hard-to-read
---
 lib/yahns/proxy_http_response.rb | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/lib/yahns/proxy_http_response.rb b/lib/yahns/proxy_http_response.rb
index c5e7be5..731bcd6 100644
--- a/lib/yahns/proxy_http_response.rb
+++ b/lib/yahns/proxy_http_response.rb
@@ -61,11 +61,7 @@ def wait_on_upstream(req_res, alive, wbuf)
     :wait_readable # self remains in :ignore, wait on upstream
   end
 
-  # start streaming the response once upstream is done sending headers to us.
-  # returns :wait_readable if we need to read more from req_res
-  # returns :ignore if we yield control to the client(self)
-  # returns nil if completely done
-  def proxy_response_start(res, tip, kcar, req_res)
+  def proxy_res_headers(res)
     status, headers = res
     code = status.to_i
     msg = Rack::Utils::HTTP_STATUS_CODES[code]
@@ -121,7 +117,16 @@ def proxy_response_start(res, tip, kcar, req_res)
       wbuf = proxy_write(nil, res, alive)
       break # keep buffering as much as possible
     end while true
+    [ alive, wbuf, have_body ]
+  end
 
+  # start streaming the response once upstream is done sending headers to us.
+  # returns :wait_readable if we need to read more from req_res
+  # returns :ignore if we yield control to the client(self)
+  # returns nil if completely done
+  def proxy_response_start(res, tip, kcar, req_res)
+    alive, wbuf, have_body = proxy_res_headers(res)
+    res = nil # hopefully allow GC to release many header references
     rbuf = Thread.current[:yahns_rbuf]
     tip = tip.empty? ? [] : [ tip ]
 

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/5] proxy_pass: WIP: simplify proxy_http_response
  2016-05-06  1:05 [PATCH 1/5] proxy_pass: simplify writing request bodies upstream Eric Wong
  2016-05-06  1:05 ` [PATCH 2/5] proxy_pass: hoist out proxy_res_headers method Eric Wong
@ 2016-05-06  1:05 ` Eric Wong
  2016-05-06  1:05 ` [PATCH 4/5] wip Eric Wong
  2016-05-06  1:05 ` [PATCH 5/5] proxy_pass: cleanup proxy_response_finish, too Eric Wong
  3 siblings, 0 replies; 5+ messages in thread
From: Eric Wong @ 2016-05-06  1:05 UTC (permalink / raw)
  To: spew

---
 lib/yahns/proxy_http_response.rb | 76 ++++++++++++++++++----------------------
 1 file changed, 34 insertions(+), 42 deletions(-)

diff --git a/lib/yahns/proxy_http_response.rb b/lib/yahns/proxy_http_response.rb
index 731bcd6..2e4dc5e 100644
--- a/lib/yahns/proxy_http_response.rb
+++ b/lib/yahns/proxy_http_response.rb
@@ -131,38 +131,45 @@ def proxy_response_start(res, tip, kcar, req_res)
     tip = tip.empty? ? [] : [ tip ]
 
     if have_body
-      if len = kcar.body_bytes_left
+      req_res.proxy_trailers = nil # define to avoid uninitialized warnings
+      chunk = ''.dup if kcar.chunked?
+      tlr = nil
+      len = kcar.body_bytes_left
 
-        case tmp = tip.shift || req_res.kgio_tryread(0x2000, rbuf)
-        when String
-          len = kcar.body_bytes_left -= tmp.size
-          wbuf = proxy_write(wbuf, tmp, alive)
-        when nil # premature EOF
-          return proxy_err_response(nil, req_res, nil, wbuf)
-        when :wait_readable
-          return wait_on_upstream(req_res, alive, wbuf)
-        end until len == 0
-
-      elsif kcar.chunked? # nasty chunked body
-        req_res.proxy_trailers = nil # define to avoid warnings for now
-        buf = ''.dup
-        case tmp = tip.shift || req_res.kgio_tryread(0x2000, rbuf)
-        when String
-          kcar.filter_body(buf, tmp)
-          wbuf = proxy_write(wbuf, chunk_out(buf), alive) unless buf.empty?
-        when nil # premature EOF
-          return proxy_err_response(nil, req_res, nil, wbuf)
-        when :wait_readable
-          return wait_on_upstream(req_res, alive, wbuf)
-        end until kcar.body_eof?
+      case tmp = tip.shift || req_res.kgio_tryread(0x2000, rbuf)
+      when String
+        if len
+          kcar.body_bytes_left -= tmp.size # progress for body_eof? => true
+        elsif chunk
+          kcar.filter_body(chunk, rbuf = tmp) # progress for body_eof? => true
+          next if chunk.empty? # read req_res.kgio_tryread for more
+          tmp = chunk_out(chunk)
+        elsif alive # HTTP/1.0 upstream, HTTP/1.1 client
+          tmp = chunk_out(tmp)
+        # else # HTTP/1.0 upstream, HTTP/1.0 client, do nothing
+        end
+        wbuf = proxy_write(wbuf, tmp, alive)
+        chunk.clear if chunk
+      when nil # EOF
+        # HTTP/1.1 upstream, unexpected premature EOF:
+        return proxy_err_response(nil, req_res, nil, wbuf) if len || chunk
+
+        # HTTP/1.0 upstream:
+        wbuf = proxy_write(wbuf, "0\r\n\r\n".freeze, true) if alive
+        req_res.shutdown
+        break
+      when :wait_readable
+        return wait_on_upstream(req_res, alive, wbuf)
+      end until kcar.body_eof?
 
-        buf = tmp
-        req_res.proxy_trailers = [ buf, tlr = [] ]
+      if chunk
+        chunk = rbuf
+        req_res.proxy_trailers = [ chunk, tlr = [] ]
         rbuf = Thread.current[:yahns_rbuf] = ''.dup
-        until kcar.trailers(tlr, buf)
+        until kcar.trailers(tlr, chunk)
           case rv = req_res.kgio_tryread(0x2000, rbuf)
           when String
-            buf << rv
+            chunk << rv
           when :wait_readable
             return wait_on_upstream(req_res, alive, wbuf)
           when nil # premature EOF
@@ -170,21 +177,6 @@ def proxy_response_start(res, tip, kcar, req_res)
           end # no loop here
         end
         wbuf = proxy_write(wbuf, trailer_out(tlr), alive)
-
-      else # no Content-Length or Transfer-Encoding: chunked, wait on EOF!
-
-        case tmp = tip.shift || req_res.kgio_tryread(0x2000, rbuf)
-        when String
-          tmp = chunk_out(tmp) if alive
-          wbuf = proxy_write(wbuf, tmp, alive)
-        when nil
-          wbuf = proxy_write(wbuf, "0\r\n\r\n".freeze, true) if alive
-          req_res.shutdown
-          break
-        when :wait_readable
-          return wait_on_upstream(req_res, alive, wbuf)
-        end while true
-
       end
     end
 

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 4/5] wip
  2016-05-06  1:05 [PATCH 1/5] proxy_pass: simplify writing request bodies upstream Eric Wong
  2016-05-06  1:05 ` [PATCH 2/5] proxy_pass: hoist out proxy_res_headers method Eric Wong
  2016-05-06  1:05 ` [PATCH 3/5] proxy_pass: WIP: simplify proxy_http_response Eric Wong
@ 2016-05-06  1:05 ` Eric Wong
  2016-05-06  1:05 ` [PATCH 5/5] proxy_pass: cleanup proxy_response_finish, too Eric Wong
  3 siblings, 0 replies; 5+ messages in thread
From: Eric Wong @ 2016-05-06  1:05 UTC (permalink / raw)
  To: spew

---
 lib/yahns/proxy_http_response.rb | 105 +++++++++++++++++++++------------------
 1 file changed, 58 insertions(+), 47 deletions(-)

diff --git a/lib/yahns/proxy_http_response.rb b/lib/yahns/proxy_http_response.rb
index 2e4dc5e..044e1f3 100644
--- a/lib/yahns/proxy_http_response.rb
+++ b/lib/yahns/proxy_http_response.rb
@@ -120,6 +120,63 @@ def proxy_res_headers(res)
     [ alive, wbuf, have_body ]
   end
 
+  def proxy_read_body(tip, kcar, req_res, alive, wbuf)
+    chunk = ''.dup if kcar.chunked?
+    len = kcar.body_bytes_left
+    rbuf = Thread.current[:yahns_rbuf]
+
+    case tmp = tip.shift || req_res.kgio_tryread(0x2000, rbuf)
+    when String
+      if len
+        kcar.body_bytes_left -= tmp.size # progress for body_eof? => true
+      elsif chunk
+        kcar.filter_body(chunk, rbuf = tmp) # progress for body_eof? => true
+        next if chunk.empty? # call req_res.kgio_tryread for more
+        tmp = chunk_out(chunk)
+      elsif alive # HTTP/1.0 upstream, HTTP/1.1 client
+        tmp = chunk_out(tmp)
+      # else # HTTP/1.0 upstream, HTTP/1.0 client, do nothing
+      end
+      wbuf = proxy_write(wbuf, tmp, alive)
+      chunk.clear if chunk
+    when nil # EOF
+      # HTTP/1.1 upstream, unexpected premature EOF:
+      return proxy_err_response(nil, req_res, nil, wbuf) if len || chunk
+
+      # HTTP/1.0 upstream:
+      wbuf = proxy_write(wbuf, "0\r\n\r\n".freeze, true) if alive
+      req_res.shutdown
+      break
+    when :wait_readable
+      return wait_on_upstream(req_res, alive, wbuf)
+    end until kcar.body_eof?
+
+    if chunk
+      # tip is an empty array and becomes trailer storage
+      req_res.proxy_trailers = [ rbuf.dup, tip ]
+      return proxy_read_trailers(kcar, req_res, alive, wbuf)
+    end
+    wbuf ? proxy_busy_mod_blocked(wbuf, wbuf.busy) : proxy_busy_mod_done(alive)
+  end
+
+  def proxy_read_trailers(kcar, req_res, alive, wbuf)
+    chunk, tlr = req_res.proxy_trailers
+    rbuf = Thread.current[:yahns_rbuf]
+
+    until kcar.trailers(tlr, chunk)
+      case rv = req_res.kgio_tryread(0x2000, rbuf)
+      when String
+        chunk << rv
+      when :wait_readable
+        return wait_on_upstream(req_res, alive, wbuf)
+      when nil # premature EOF
+        return proxy_err_response(nil, req_res, nil, wbuf)
+      end # no loop here
+    end
+    wbuf = proxy_write(wbuf, trailer_out(tlr), alive)
+    wbuf ? proxy_busy_mod_blocked(wbuf, wbuf.busy) : proxy_busy_mod_done(alive)
+  end
+
   # start streaming the response once upstream is done sending headers to us.
   # returns :wait_readable if we need to read more from req_res
   # returns :ignore if we yield control to the client(self)
@@ -127,57 +184,11 @@ def proxy_res_headers(res)
   def proxy_response_start(res, tip, kcar, req_res)
     alive, wbuf, have_body = proxy_res_headers(res)
     res = nil # hopefully allow GC to release many header references
-    rbuf = Thread.current[:yahns_rbuf]
     tip = tip.empty? ? [] : [ tip ]
 
     if have_body
       req_res.proxy_trailers = nil # define to avoid uninitialized warnings
-      chunk = ''.dup if kcar.chunked?
-      tlr = nil
-      len = kcar.body_bytes_left
-
-      case tmp = tip.shift || req_res.kgio_tryread(0x2000, rbuf)
-      when String
-        if len
-          kcar.body_bytes_left -= tmp.size # progress for body_eof? => true
-        elsif chunk
-          kcar.filter_body(chunk, rbuf = tmp) # progress for body_eof? => true
-          next if chunk.empty? # read req_res.kgio_tryread for more
-          tmp = chunk_out(chunk)
-        elsif alive # HTTP/1.0 upstream, HTTP/1.1 client
-          tmp = chunk_out(tmp)
-        # else # HTTP/1.0 upstream, HTTP/1.0 client, do nothing
-        end
-        wbuf = proxy_write(wbuf, tmp, alive)
-        chunk.clear if chunk
-      when nil # EOF
-        # HTTP/1.1 upstream, unexpected premature EOF:
-        return proxy_err_response(nil, req_res, nil, wbuf) if len || chunk
-
-        # HTTP/1.0 upstream:
-        wbuf = proxy_write(wbuf, "0\r\n\r\n".freeze, true) if alive
-        req_res.shutdown
-        break
-      when :wait_readable
-        return wait_on_upstream(req_res, alive, wbuf)
-      end until kcar.body_eof?
-
-      if chunk
-        chunk = rbuf
-        req_res.proxy_trailers = [ chunk, tlr = [] ]
-        rbuf = Thread.current[:yahns_rbuf] = ''.dup
-        until kcar.trailers(tlr, chunk)
-          case rv = req_res.kgio_tryread(0x2000, rbuf)
-          when String
-            chunk << rv
-          when :wait_readable
-            return wait_on_upstream(req_res, alive, wbuf)
-          when nil # premature EOF
-            return proxy_err_response(nil, req_res, nil, wbuf)
-          end # no loop here
-        end
-        wbuf = proxy_write(wbuf, trailer_out(tlr), alive)
-      end
+      return proxy_read_body(tip, kcar, req_res, alive, wbuf)
     end
 
     # all done reading response from upstream, req_res will be discarded

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 5/5] proxy_pass: cleanup proxy_response_finish, too
  2016-05-06  1:05 [PATCH 1/5] proxy_pass: simplify writing request bodies upstream Eric Wong
                   ` (2 preceding siblings ...)
  2016-05-06  1:05 ` [PATCH 4/5] wip Eric Wong
@ 2016-05-06  1:05 ` Eric Wong
  3 siblings, 0 replies; 5+ messages in thread
From: Eric Wong @ 2016-05-06  1:05 UTC (permalink / raw)
  To: spew

Die duplicate code, die!
---
 lib/yahns/proxy_http_response.rb | 66 ++--------------------------------------
 1 file changed, 3 insertions(+), 63 deletions(-)

diff --git a/lib/yahns/proxy_http_response.rb b/lib/yahns/proxy_http_response.rb
index 044e1f3..9e3a5ad 100644
--- a/lib/yahns/proxy_http_response.rb
+++ b/lib/yahns/proxy_http_response.rb
@@ -199,69 +199,9 @@ def proxy_response_start(res, tip, kcar, req_res)
   end
 
   def proxy_response_finish(kcar, wbuf, req_res)
-    rbuf = Thread.current[:yahns_rbuf]
-    if len = kcar.body_bytes_left # known Content-Length
-
-      case tmp = req_res.kgio_tryread(0x2000, rbuf)
-      when String
-        len = kcar.body_bytes_left -= tmp.size
-        wbuf.wbuf_write(self, tmp)
-      when nil # premature EOF
-        return proxy_err_response(nil, req_res, nil, wbuf)
-      when :wait_readable
-        return :wait_readable # self remains in :ignore, wait on upstream
-      end while len != 0
-
-    elsif kcar.chunked? # nasty chunked response body
-      buf = ''.dup
-
-      unless req_res.proxy_trailers
-        # are we done dechunking the main body, yet?
-        case tmp = req_res.kgio_tryread(0x2000, rbuf)
-        when String
-          kcar.filter_body(buf, tmp)
-          buf.empty? or wbuf.wbuf_write(self, chunk_out(buf))
-        when nil # premature EOF
-          return proxy_err_response(nil, req_res, nil, wbuf)
-        when :wait_readable
-          return :wait_readable # self remains in :ignore, wait on upstream
-        end until kcar.body_eof?
-        req_res.proxy_trailers = [ tmp, [] ] # onto trailers!
-        rbuf = Thread.current[:yahns_rbuf] = ''.dup
-      end
-
-      buf, tlr = *req_res.proxy_trailers
-      until kcar.trailers(tlr, buf)
-        case rv = req_res.kgio_tryread(0x2000, rbuf)
-        when String
-          buf << rv
-        when :wait_readable
-          return :wait_readable
-        when nil # premature EOF
-          return proxy_err_response(nil, req_res, nil, wbuf)
-        end # no loop here
-      end
-      wbuf.wbuf_write(self, trailer_out(tlr))
-
-    else # no Content-Length or Transfer-Encoding: chunked, wait on EOF!
-
-      alive = wbuf.wbuf_persist
-      case tmp = req_res.kgio_tryread(0x2000, rbuf)
-      when String
-        tmp = chunk_out(tmp) if alive
-        wbuf.wbuf_write(self, tmp)
-      when nil
-        wbuf.wbuf_write(self, "0\r\n\r\n".freeze) if alive
-        req_res.shutdown
-        break
-      when :wait_readable
-        return :wait_readable # self remains in :ignore, wait on upstream
-      end while true
-
-    end
-
-    busy = wbuf.busy and return proxy_busy_mod_blocked(wbuf, busy)
-    proxy_busy_mod_done(wbuf.wbuf_persist) # returns nil to close req_res
+    alive = wbuf.wbuf_persist
+    req_res.proxy_trailers ? proxy_read_trailers(kcar, req_res, alive, wbuf)
+                           : proxy_read_body([], kcar, req_res, alive, wbuf)
   end
 
   def proxy_wait_next(qflags)

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-05-06  1:05 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-05-06  1:05 [PATCH 1/5] proxy_pass: simplify writing request bodies upstream Eric Wong
2016-05-06  1:05 ` [PATCH 2/5] proxy_pass: hoist out proxy_res_headers method Eric Wong
2016-05-06  1:05 ` [PATCH 3/5] proxy_pass: WIP: simplify proxy_http_response Eric Wong
2016-05-06  1:05 ` [PATCH 4/5] wip Eric Wong
2016-05-06  1:05 ` [PATCH 5/5] proxy_pass: cleanup proxy_response_finish, too Eric Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).