From 13a09dec6c029e01e8d959b0bf0feb94d72ae32d Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 2 Nov 2013 01:00:00 +0000 Subject: account for truncated/expanded static files When running a static file server, we must account for filesystem activity outside of our control where files may grow/shrink as they're being served. For truncated files, we must abort any persistent connections downloading a truncated file to avoid confusing clients because the Content-Length header was already set to the big value. We also must ensure (we already did so before this commit, this just adds a test for it) we do not send additional data when a file grows on us after we've started sending the response. --- test/server_helper.rb | 14 ++++++++++ test/test_output_buffering.rb | 14 ---------- test/test_serve_static.rb | 61 +++++++++++++++++++++++++++++++++++++++++++ test/test_wbuf.rb | 7 +---- 4 files changed, 76 insertions(+), 20 deletions(-) (limited to 'test') diff --git a/test/server_helper.rb b/test/server_helper.rb index 52b08c7..2f9266a 100644 --- a/test/server_helper.rb +++ b/test/server_helper.rb @@ -78,6 +78,20 @@ module ServerHelper Yahns::Server.new(cfg).start.join end end + + def wait_for_full(c) + prev = 0 + prev_time = Time.now + begin + nr = c.nread + break if nr > 0 && nr == prev && (Time.now - prev_time) > 0.5 + if nr != prev + prev = nr + prev_time = Time.now + end + Thread.pass + end while sleep(0.1) + end end module TrywriteBlocked diff --git a/test/test_output_buffering.rb b/test/test_output_buffering.rb index a448062..7b99418 100644 --- a/test/test_output_buffering.rb +++ b/test/test_output_buffering.rb @@ -86,20 +86,6 @@ class TestOutputBuffering < Testcase quit_wait(pid) end - def wait_for_full(c) - prev = 0 - prev_time = Time.now - begin - nr = c.nread - break if nr > 0 && nr == prev && (Time.now - prev_time) > 0.5 - if nr != prev - prev = nr - prev_time = Time.now - end - Thread.pass - end while sleep(0.1) - end - def md5sum(c) dig = Digest::MD5.new buf = "" diff --git a/test/test_serve_static.rb b/test/test_serve_static.rb index b1817f7..4f33b6f 100644 --- a/test/test_serve_static.rb +++ b/test/test_serve_static.rb @@ -73,4 +73,65 @@ class TestServeStatic < Testcase ensure quit_wait(pid) end + + def mksparse(tmpdir) + sparse = "#{tmpdir}/sparse" + off = 100 * 1024 * 1024 + File.open(sparse, "w") do |fp| + fp.sysseek(off) + fp.syswrite '.' + end + [ off + 1, sparse ] + end + + def test_truncated_sendfile + tmpdir = Dir.mktmpdir + size, sparse = mksparse(tmpdir) + err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1] + pid = mkserver(cfg) do + cfg.instance_eval do + app(:rack, Rack::File.new(tmpdir)) { listen "#{host}:#{port}" } + stderr_path err.path + end + end + c = get_tcp_client(host, port) + c.write "GET /sparse HTTP/1.1\r\nHost: example.com\r\n\r\n" + wait_for_full(c) + File.truncate(sparse, 5) + buf = Timeout.timeout(60) { c.read } + c.close + assert_operator buf.size, :<, size + ensure + quit_wait(pid) + FileUtils.rm_rf(tmpdir) + end + + def test_expanded_sendfile + tmpdir = Dir.mktmpdir + size, sparse = mksparse(tmpdir) + err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1] + pid = mkserver(cfg) do + cfg.instance_eval do + app(:rack, Rack::File.new(tmpdir)) { listen "#{host}:#{port}" } + stderr_path err.path + end + end + c = get_tcp_client(host, port) + c.write "GET /sparse\r\n\r\n" + wait_for_full(c) + + File.open(sparse, "w") do |fp| + fp.sysseek(size * 2) + fp.syswrite '.' + end + Timeout.timeout(60) do + bytes = IO.copy_stream(c, "/dev/null") + assert_equal bytes, size + assert_raises(EOFError) { c.readpartial 1 } + end + c.close + ensure + quit_wait(pid) + FileUtils.rm_rf(tmpdir) + end end diff --git a/test/test_wbuf.rb b/test/test_wbuf.rb index a9dc717..25cdeba 100644 --- a/test/test_wbuf.rb +++ b/test/test_wbuf.rb @@ -82,12 +82,7 @@ class TestWbuf < Testcase b.read(nr - 2) if nr > 2 assert_equal b, IO.select([b], nil, nil, 5)[0][0] assert_equal "HI", b.read(2) - begin - wbuf.wbuf_flush(a) - assert false - rescue => e - end - assert_match(%r{BUG: EOF on tmpio}, e.message) + assert_equal false, wbuf.wbuf_flush(a) ensure a.close b.close -- cgit v1.2.3-24-ge0c7