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=-2.9 required=3.0 tests=ALL_TRUSTED,BAYES_00, T_RP_MATCHES_RCVD,URIBL_BLOCKED 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 D63A5200CD for ; Tue, 7 Apr 2015 22:30:59 +0000 (UTC) From: Eric Wong To: yahns-public@yhbt.net Subject: [PATCH] extras/proxy_pass: reinstate synchronous version Date: Tue, 7 Apr 2015 22:30:59 +0000 Message-Id: <1428445859-15815-1-git-send-email-e@80x24.org> List-Id: Since yahns/proxy_pass is not a drop-in replacement, reinstate the old, synchronous version to avoid breaking existing setups which require Rack middleware support. --- extras/proxy_pass.rb | 222 ++++++++++++++++++++++++++++++++++++++++- test/test_extras_proxy_pass.rb | 103 +++++++++++++++++++ 2 files changed, 320 insertions(+), 5 deletions(-) create mode 100644 test/test_extras_proxy_pass.rb diff --git a/extras/proxy_pass.rb b/extras/proxy_pass.rb index af6fb7c..b7fc87a 100644 --- a/extras/proxy_pass.rb +++ b/extras/proxy_pass.rb @@ -1,9 +1,221 @@ +# -*- encoding: binary -*- +# Copyright (C) 2013-2015 all contributors +# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt) +require 'time' +require 'socket' +require 'kgio' +require 'kcar' # gem install kcar +require 'rack/request' +require 'thread' +require 'timeout' + # compatibility class warn < e + retry if ures && ures.fail_retryable? && request_method != "POST" + if defined?(Yahns::Log) + logger = env['rack.logger'] and + Yahns::Log.exception(logger, 'proxy_pass', e) + end + [ 502, [ %w(Content-Length 0), %w(Content-Type text/plain) ], [] ] + end + + def send_body(input, ures, chunked) + buf = Thread.current[:proxy_pass_buf] ||= "" + + if chunked # unlikely + while input.read(16384, buf) + buf.replace("#{buf.size.to_s(16)}\r\n#{buf}\r\n") + ures.req_write(buf, @timeout) + end + ures.req_write("0\r\n\r\n", @timeout) + else # common if we hit uploads + while input.read(16384, buf) + ures.req_write(buf, @timeout) + end + end + end +end diff --git a/test/test_extras_proxy_pass.rb b/test/test_extras_proxy_pass.rb new file mode 100644 index 0000000..495a920 --- /dev/null +++ b/test/test_extras_proxy_pass.rb @@ -0,0 +1,103 @@ +# Copyright (C) 2015 all contributors +# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt) +require_relative 'server_helper' + +class TestExtrasProxyPass < Testcase + ENV["N"].to_i > 1 and parallelize_me! + include ServerHelper + + class ProxiedApp + def call(env) + h = [ %w(Content-Length 3), %w(Content-Type text/plain) ] + case env['REQUEST_METHOD'] + when 'GET' + [ 200, h, [ "hi\n"] ] + when 'HEAD' + [ 200, h, [] ] + when 'PUT' + buf = env['rack.input'].read + [ 201, { + 'Content-Length' => buf.bytesize.to_s, + 'Content-Type' => 'text/plain', + }, [ buf ] ] + end + end + end + + def setup + @srv2 = TCPServer.new(ENV["TEST_HOST"] || "127.0.0.1", 0) + server_helper_setup + end + + def teardown + @srv2.close if defined?(@srv2) && !@srv2.closed? + server_helper_teardown + end + + def test_proxy_pass + err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1] + host2, port2 = @srv2.addr[3], @srv2.addr[1] + pid = mkserver(cfg) do + $LOAD_PATH.unshift "#{Dir.pwd}/extras" + olderr = $stderr + $stderr = StringIO.new + require 'proxy_pass' + $stderr = olderr + @srv2.close + cfg.instance_eval do + app(:rack, ProxyPass.new("http://#{host2}:#{port2}/")) do + listen "#{host}:#{port}" + end + stderr_path err.path + end + end + + pid2 = mkserver(cfg, @srv2) do + @srv.close + cfg.instance_eval do + app(:rack, ProxiedApp.new) do + listen "#{host2}:#{port2}" + end + stderr_path err.path + end + end + + gplv3 = File.open('COPYING') + + Net::HTTP.start(host, port) do |http| + res = http.request(Net::HTTP::Get.new('/')) + assert_equal 200, res.code.to_i + n = res.body.bytesize + assert_operator n, :>, 1 + res = http.request(Net::HTTP::Head.new('/')) + assert_equal 200, res.code.to_i + assert_equal n, res['Content-Length'].to_i + assert_nil res.body + + # chunked encoding + req = Net::HTTP::Put.new('/') + req.body_stream = gplv3 + req.content_type = 'application/octet-stream' + req['Transfer-Encoding'] = 'chunked' + res = http.request(req) + gplv3.rewind + assert_equal gplv3.read, res.body + assert_equal 201, res.code.to_i + + # normal content-length + gplv3.rewind + req = Net::HTTP::Put.new('/') + req.body_stream = gplv3 + req.content_type = 'application/octet-stream' + req.content_length = gplv3.size + res = http.request(req) + gplv3.rewind + assert_equal gplv3.read, res.body + assert_equal 201, res.code.to_i + end + ensure + gplv3.close if gplv3 + quit_wait pid + quit_wait pid2 + end +end -- EW