From f38e54f8d54f8cdfdc15f43b2394f0acfff5d413 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 26 Oct 2013 01:13:29 +0000 Subject: output_buffering handles odd EAGAIN cases The tiny responses for check_client_connection and "100-Continue" responses may occasionally fail with EAGAIN. We must be prepared for those corner cases and buffer the output appropriately. We can safely use a string for buffering here (for once(!)), since the buffer sizes are bounded and known at buffer time, unlike the response headers/bodies sent by the Rack application. --- test/test_expect_100.rb | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'test/test_expect_100.rb') diff --git a/test/test_expect_100.rb b/test/test_expect_100.rb index 338a50a..5b1ffa8 100644 --- a/test/test_expect_100.rb +++ b/test/test_expect_100.rb @@ -14,10 +14,18 @@ class TestExpect100 < Testcase code = env["HTTP_X_FORCE_RCODE"] || 100 [ code, h, [] ] else + env["rack.input"].read [ 201, h, [] ] end end + module TrywriteBlocked + def kgio_trywrite(*args) + return :wait_writable if $_tw_block_on.include?($_tw_blocked += 1) + super + end + end + def test_buffer_noccc; _test_expect_100(true, false); end def test_nobuffer_noccc; _test_expect_100(false, false); end def test_lazybuffer_noccc; _test_expect_100(:lazy, false); end @@ -88,4 +96,90 @@ class TestExpect100 < Testcase def test_reject_true_noccc; _test_reject(false, false); end def test_reject_lazy_ccc; _test_reject(:lazy, true); end def test_reject_true_ccc; _test_reject(false, true); end + + def test_swait_t_t; _swait(true, true, [1]); end + def test_swait_f_f; _swait(false, false, [1]); end + def test_swait_t_f; _swait(true, false, [1]); end + def test_swait_f_t; _swait(false, true, [1]); end + def test_swait_l_t; _swait(:lazy, true, [1]); end + def test_swait_l_f; _swait(:lazy, false, [1]); end + + def test_swait2_t_t; _swait(true, true, [1,2]); end + def test_swait2_f_f; _swait(false, false, [1,2]); end + def test_swait2_t_f; _swait(true, false, [1,2]); end + def test_swait2_f_t; _swait(false, true, [1,2]); end + def test_swait2_l_t; _swait(:lazy, true, [1,2]); end + def test_swait2_l_f; _swait(:lazy, false, [1,2]); end + + def test_swait3_t_t; _swait(true, true, [1,3]); end + def test_swait3_f_f; _swait(false, false, [1,3]); end + def test_swait3_t_f; _swait(true, false, [1,3]); end + def test_swait3_f_t; _swait(false, true, [1,3]); end + def test_swait3_l_t; _swait(:lazy, true, [1,3]); end + def test_swait3_l_f; _swait(:lazy, false, [1,3]); end + + def test_swait_t_t_ccc; _swait(true, true, [1], true); end + def test_swait_f_f_ccc; _swait(false, false, [1], true); end + def test_swait_t_f_ccc; _swait(true, false, [1], true); end + def test_swait_f_t_ccc; _swait(false, true, [1], true); end + def test_swait_l_t_ccc; _swait(:lazy, true, [1], true); end + def test_swait_l_f_ccc; _swait(:lazy, false, [1], true); end + + def test_swait2_t_t_ccc; _swait(true, true, [1,2], true); end + def test_swait2_f_f_ccc; _swait(false, false, [1,2], true); end + def test_swait2_t_f_ccc; _swait(true, false, [1,2], true); end + def test_swait2_f_t_ccc; _swait(false, true, [1,2], true); end + def test_swait2_l_t_ccc; _swait(:lazy, true, [1,2], true); end + def test_swait2_l_f_ccc; _swait(:lazy, false, [1,2], true); end + + def test_swait3_t_t_ccc; _swait(true, true, [1,3], true); end + def test_swait3_f_f_ccc; _swait(false, false, [1,3], true); end + def test_swait3_t_f_ccc; _swait(true, false, [1,3], true); end + def test_swait3_f_t_ccc; _swait(false, true, [1,3], true); end + def test_swait3_l_t_ccc; _swait(:lazy, true, [1,3], true); end + def test_swait3_l_f_ccc; _swait(:lazy, false, [1,3], true); end + + def test_swait3_t_t_ccc_body; _swait(true, true, [1,3], true, "HI"); end + def test_swait3_f_f_ccc_body; _swait(false, false, [1,3], true, "HI"); end + def test_swait3_t_f_ccc_body; _swait(true, false, [1,3], true, "HI"); end + def test_swait3_f_t_ccc_body; _swait(false, true, [1,3], true, "HI"); end + def test_swait3_l_t_ccc_body; _swait(:lazy, true, [1,3], true, "HI"); end + def test_swait3_l_f_ccc_body; _swait(:lazy, false, [1,3], true, "HI"); end + + def _swait(ibtype, obtype, block_on, ccc = false, body = "") + err = @err + cfg = Yahns::Config.new + host, port = @srv.addr[3], @srv.addr[1] + cfg.instance_eval do + stderr_path err.path + GTL.synchronize { + app(:rack, APP) { + listen "#{host}:#{port}" + output_buffering obtype + input_buffering ibtype + check_client_connection ccc + } + } + end + pid = fork do + ENV["YAHNS_FD"] = @srv.fileno.to_s + $_tw_blocked = 0 + $_tw_block_on = block_on + Yahns::HttpClient.__send__(:include, TrywriteBlocked) + Yahns::Server.new(cfg).start.join + end + c = get_tcp_client(host, port) + if body.size > 0 + r = "PUT / HTTP/1.0\r\nExpect: 100-continue\r\n" + r << "Content-Length: #{body.size}\r\n\r\n#{body}" + else + r = "PUT / HTTP/1.0\r\nExpect: 100-continue\r\n\r\n" + end + c.write(r) + assert c.wait(10), "timed out" + buf = c.read + assert_match(%r{\AHTTP/1\.1 100 Continue\r\n\r\nHTTP/1\.1 201}, buf) + ensure + quit_wait(pid) + end end -- cgit v1.2.3-24-ge0c7