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/test_serve_static.rb | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'test/test_serve_static.rb') 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 -- cgit v1.2.3-24-ge0c7