require "./test/helper" class TestInputSprayWithMD5 < Test::Unit::TestCase def setup @nr = 4 @addr, @port, @srv = start_server("./test/content-md5.ru", @nr) @sockaddr = Socket.pack_sockaddr_in(@port, @addr) @env = { "REQUEST_METHOD" => "PUT", "REQUEST_URI" => "/", "HTTP_HOST" => "example.com", } @tmpfiles = [] end def teardown Process.kill(:QUIT, @srv) Process.waitpid2(@srv) @tmpfiles.each { |tmp| tmp.closed? or tmp.close! } end def test_upload_with_valid_md5_sprayed str = rand_data(123) * (8 * 1021 * 13) expect_md5 = [Digest::MD5.digest(str)].pack("m0") @env["HTTP_CONTENT_MD5"] = expect_md5 expect = "expect=#{expect_md5}\nreaded=#{expect_md5}\n" @env["CONTENT_LENGTH"] = str.size.to_s @env["rack.input"] = StringIO.new(str) input = HTTP_Spew::ContentMD5.new(@env) sprayer = HTTP_Spew::InputSpray.new(@env, @nr, input) assert_nil @env["CONTENT_LENGTH"] assert_equal "chunked", @env["HTTP_TRANSFER_ENCODING"] reqs = sprayer.readers.map do |md5_input| HTTP_Spew::Request.new(@env, md5_input, @sockaddr) end assert_equal @nr, reqs.size rv = HTTP_Spew.wait_mt reqs.size, reqs, 3600 assert_equal @nr, rv.size rv.each do |resp| assert_equal 200, resp.response[0].to_i body = "" resp.response[2].each { |buf| body << buf } assert_equal expect, body end assert_equal expect_md5, input.content_md5 assert_equal 123 * 8 * 1021 * 13, input.bytes_digested end def test_upload_with_invalid_md5_sprayed str = rand_data(123) * (8 * 1021 * 13) expect = [Digest::MD5.digest(str + "HI")].pack("m0") @env["HTTP_CONTENT_MD5"] = expect @env["CONTENT_LENGTH"] = str.size.to_s @env["rack.input"] = StringIO.new(str) input = HTTP_Spew::ContentMD5.new(@env) sprayer = HTTP_Spew::InputSpray.new(@env, @nr, input) assert_nil @env["CONTENT_LENGTH"] assert_equal "chunked", @env["HTTP_TRANSFER_ENCODING"] reqs = sprayer.readers.map do |md5_input| HTTP_Spew::Request.new(@env, md5_input, @sockaddr) end assert_equal @nr, reqs.size t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC) rv = HTTP_Spew.wait_mt reqs.size, reqs, 3600 elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0 assert(elapsed <= 30, "took too long: #{elapsed}s") assert_equal @nr, rv.size rv.each { |r| assert_kind_of HTTP_Spew::ChecksumError, r.error } assert_nil input.content_md5 assert_equal str.size, input.bytes_digested end def test_upload_with_valid_md5_sprayed_one_failure str = rand_data(123) * (8 * 1021 * 13) expect_md5 = [Digest::MD5.digest(str)].pack("m0") @env["HTTP_CONTENT_MD5"] = expect_md5 expect = "expect=#{expect_md5}\nreaded=#{expect_md5}\n" @env["CONTENT_LENGTH"] = str.size.to_s @env["rack.input"] = StringIO.new(str) input = HTTP_Spew::ContentMD5.new(@env) sprayer = HTTP_Spew::InputSpray.new(@env, @nr, input) assert_nil @env["CONTENT_LENGTH"] assert_equal "chunked", @env["HTTP_TRANSFER_ENCODING"] reqs = [] sprayer.readers.each_with_index do |md5_input,i| env = @env.dup env["HTTP_X_FAIL"] = "true" if i == 0 reqs << HTTP_Spew::Request.new(env, md5_input, @sockaddr) end assert_equal @nr, reqs.size rv = HTTP_Spew.wait_mt reqs.size, reqs, 3600 assert_equal @nr, rv.size rv.each { |resp| assert reqs.include?(resp) } assert reqs[0].error (1..3).each do |n| resp = reqs[n] assert_equal 200, resp.response[0].to_i body = "" resp.response[2].each { |buf| body << buf } assert_equal expect, body end assert_equal expect_md5, input.content_md5 assert_equal 123 * 8 * 1021 * 13, input.bytes_digested end end if HAVE_UNICORN