From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-3.0 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00, RP_MATCHES_RCVD shortcircuit=no autolearn=unavailable version=3.3.2 X-Original-To: yahns-public@yhbt.net Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 4036420276 for ; Tue, 2 Feb 2016 01:50:34 +0000 (UTC) From: Eric Wong To: yahns-public@yhbt.net Subject: [REJECT] proxy: return requested HTTP version for 1.0 responses Date: Tue, 2 Feb 2016 01:50:34 +0000 Message-Id: <20160202015034.25233-1-e@80x24.org> List-Id: (A work-in-progress). Rejecting this for now, not sure if it's worth it given how HTTP/1.0 clients tend to be able to process Content-Length: just fine. --- lib/yahns/proxy_http_response.rb | 69 +++++++++++++++++++++++----------------- test/test_proxy_pass.rb | 7 ++-- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/lib/yahns/proxy_http_response.rb b/lib/yahns/proxy_http_response.rb index 0a7e722..8ccf20c 100644 --- a/lib/yahns/proxy_http_response.rb +++ b/lib/yahns/proxy_http_response.rb @@ -70,42 +70,51 @@ def proxy_response_start(res, tip, kcar, req_res) alive = @hs.next? && self.class.persistent_connections response_headers = env['yahns.proxy_pass.response_headers'] - res = "HTTP/1.1 #{msg ? %Q(#{code} #{msg}) : status}\r\n".dup - headers.each do |key,value| # n.b.: headers is an Array of 2-element Arrays - case key - when /\A(?:Connection|Keep-Alive)\z/i - next # do not let some upstream headers leak through - when %r{\AContent-Length\z}i - flags |= MSG_MORE if have_body && value.to_i > 0 + if ver = env['HTTP_VERSION'] + zero = ver == 'HTTP/1.0'.freeze + res = "#{ver} #{msg ? %Q(#{code} #{msg}) : status}\r\n".dup + # n.b.: headers is an Array of 2-element Arrays + headers.each do |key,value| + case key + when /\A(?:Connection|Keep-Alive)\z/i + next # do not let some upstream headers leak through + when %r{\AContent-Length\z}i + next if zero + flags |= MSG_MORE if have_body && value.to_i > 0 + end + + # response header mapping + case val = response_headers[key] + when :ignore + next + when String + value = val + end + + res << "#{key}: #{value}\r\n" end - # response header mapping - case val = response_headers[key] - when :ignore - next - when String - value = val + # For now, do not add a Date: header, assume upstream already did it + # but do not care if they did not + if zero + res << "\r\n".freeze + else + res << (alive ? "Connection: keep-alive\r\n\r\n".freeze + : "Connection: close\r\n\r\n".freeze) end - res << "#{key}: #{value}\r\n" + # send the headers + case rv = kgio_syssend(res, flags) + when nil then break # all done, likely + when String # partial write, highly unlikely + flags = MSG_DONTWAIT + res = rv # hope the skb grows + when :wait_writable, :wait_readable # highly unlikely in real apps + wbuf = proxy_write(nil, res, alive) + break # keep buffering as much as possible + end while true end - # For now, do not add a Date: header, assume upstream already did it - # but do not care if they did not - res << (alive ? "Connection: keep-alive\r\n\r\n".freeze - : "Connection: close\r\n\r\n".freeze) - - # send the headers - case rv = kgio_syssend(res, flags) - when nil then break # all done, likely - when String # partial write, highly unlikely - flags = MSG_DONTWAIT - res = rv # hope the skb grows - when :wait_writable, :wait_readable # highly unlikely in real apps - wbuf = proxy_write(nil, res, alive) - break # keep buffering as much as possible - end while true - rbuf = Thread.current[:yahns_rbuf] tip = tip.empty? ? [] : [ tip ] diff --git a/test/test_proxy_pass.rb b/test/test_proxy_pass.rb index f6e0efd..f5dfde1 100644 --- a/test/test_proxy_pass.rb +++ b/test/test_proxy_pass.rb @@ -371,7 +371,6 @@ def test_proxy_pass h10 = TCPSocket.new(host, port) h10.write "GET /chunky-slow-#{delay} HTTP/1.0\r\n\r\n" res = Timeout.timeout(60) { h10.read } - assert_match %r{^Connection: close\r\n}, res assert_match %r{^Content-Type: text/pain\r\n}, res assert_match %r{\r\n\r\nHI!\z}, res refute_match %r{^Transfer-Encoding:}, res @@ -515,7 +514,7 @@ def check_slow_giant_body(host, port) assert_raises(EOFError) { loop { str << s.readpartial(400, buf) } } h, b = str.split(/\r\n\r\n/, 2) assert_equal OMFG, b - assert_match %r{\AHTTP/1\.1 200\b}, h + assert_match %r{\AHTTP/1\.0 200\b}, h ensure s.close if s end @@ -576,14 +575,14 @@ def check_eof_body(host, port) s = TCPSocket.new(host, port) s.write("GET /eof-body-fast HTTP/1.0\r\n\r\n") res = s.read - assert_match %r{\AHTTP/1\.1 200 OK\r\n}, res + assert_match %r{\AHTTP/1\.0 200 OK\r\n}, res assert_match %r{\r\n\r\neof-body-fast\z}, res s.close s = TCPSocket.new(host, port) s.write("GET /eof-body-slow HTTP/1.0\r\n\r\n") res = s.read - assert_match %r{\AHTTP/1\.1 200 OK\r\n}, res + assert_match %r{\AHTTP/1\.0 200 OK\r\n}, res assert_match %r{\r\n\r\neof-body-slow\z}, res s.close end -- EW