diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/unit/test_http_parser.rb | 16 | ||||
-rw-r--r-- | test/unit/test_http_parser_ng.rb | 55 | ||||
-rw-r--r-- | test/unit/test_stream_input.rb | 160 | ||||
-rw-r--r-- | test/unit/test_tee_input.rb | 52 |
4 files changed, 255 insertions, 28 deletions
diff --git a/test/unit/test_http_parser.rb b/test/unit/test_http_parser.rb index 222c227..31cb2cb 100644 --- a/test/unit/test_http_parser.rb +++ b/test/unit/test_http_parser.rb @@ -76,12 +76,22 @@ class HttpParserTest < Test::Unit::TestCase assert parser.keepalive? end - def test_connection_keep_alive_ka_bad_method + def test_connection_keep_alive_no_body parser = HttpParser.new req = {} tmp = "POST / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n" assert_equal req.object_id, parser.headers(req, tmp).object_id - assert ! parser.keepalive? + assert parser.keepalive? + end + + def test_connection_keep_alive_no_body_empty + parser = HttpParser.new + req = {} + tmp = "POST / HTTP/1.1\r\n" \ + "Content-Length: 0\r\n" \ + "Connection: keep-alive\r\n\r\n" + assert_equal req.object_id, parser.headers(req, tmp).object_id + assert parser.keepalive? end def test_connection_keep_alive_ka_bad_version @@ -461,7 +471,7 @@ class HttpParserTest < Test::Unit::TestCase assert_equal 'page=1', req['QUERY_STRING'] assert_equal "", s assert_equal m, req['REQUEST_METHOD'] - assert ! parser.keepalive? # TODO: read HTTP/1.2 when it's final + assert parser.keepalive? # TODO: read HTTP/1.2 when it's final } end diff --git a/test/unit/test_http_parser_ng.rb b/test/unit/test_http_parser_ng.rb index 65b843e..ce6c6e6 100644 --- a/test/unit/test_http_parser_ng.rb +++ b/test/unit/test_http_parser_ng.rb @@ -11,6 +11,19 @@ class HttpParserNgTest < Test::Unit::TestCase @parser = HttpParser.new end + def test_default_keepalive_is_off + assert ! @parser.keepalive? + assert ! @parser.next? + assert_nothing_raised do + @parser.buf << "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" + @parser.parse + end + assert @parser.keepalive? + @parser.reset + assert ! @parser.keepalive? + assert ! @parser.next? + end + def test_identity_byte_headers req = {} str = "PUT / HTTP/1.1\r\n" @@ -27,6 +40,12 @@ class HttpParserNgTest < Test::Unit::TestCase assert ! @parser.keepalive? assert @parser.headers? assert_equal 123, @parser.content_length + dst = "" + buf = '.' * 123 + @parser.filter_body(dst, buf) + assert_equal '.' * 123, dst + assert_equal "", buf + assert @parser.keepalive? end def test_identity_step_headers @@ -41,6 +60,12 @@ class HttpParserNgTest < Test::Unit::TestCase assert_equal 0, str.size assert ! @parser.keepalive? assert @parser.headers? + dst = "" + buf = '.' * 123 + @parser.filter_body(dst, buf) + assert_equal '.' * 123, dst + assert_equal "", buf + assert @parser.keepalive? end def test_identity_oneshot_header @@ -50,6 +75,12 @@ class HttpParserNgTest < Test::Unit::TestCase assert_equal '123', req['CONTENT_LENGTH'] assert_equal 0, str.size assert ! @parser.keepalive? + assert @parser.headers? + dst = "" + buf = '.' * 123 + @parser.filter_body(dst, buf) + assert_equal '.' * 123, dst + assert_equal "", buf end def test_identity_oneshot_header_with_body @@ -67,7 +98,7 @@ class HttpParserNgTest < Test::Unit::TestCase assert_equal 0, str.size assert_equal tmp, body assert_equal "", @parser.filter_body(tmp, str) - assert ! @parser.keepalive? + assert @parser.keepalive? end def test_identity_oneshot_header_with_body_partial @@ -85,7 +116,7 @@ class HttpParserNgTest < Test::Unit::TestCase assert_nil rv assert_equal "", str assert_equal str.object_id, @parser.filter_body(tmp, str).object_id - assert ! @parser.keepalive? + assert @parser.keepalive? end def test_identity_oneshot_header_with_body_slop @@ -99,7 +130,7 @@ class HttpParserNgTest < Test::Unit::TestCase assert_equal "G", @parser.filter_body(tmp, str) assert_equal 1, tmp.size assert_equal "a", tmp - assert ! @parser.keepalive? + assert @parser.keepalive? end def test_chunked @@ -122,6 +153,10 @@ class HttpParserNgTest < Test::Unit::TestCase assert_equal rv.object_id, @parser.filter_body(tmp, rv).object_id assert_equal "PUT", rv assert ! @parser.keepalive? + rv << "TY: FOO\r\n\r\n" + assert_equal req, @parser.trailers(req, rv) + assert_equal "FOO", req["HTTP_PUTTY"] + assert @parser.keepalive? end def test_two_chunks @@ -177,7 +212,7 @@ class HttpParserNgTest < Test::Unit::TestCase assert_equal req, @parser.trailers(req, moo = "\r\n") assert_equal "", moo assert @parser.body_eof? - assert ! @parser.keepalive? + assert @parser.keepalive? end def test_two_chunks_oneshot @@ -237,7 +272,7 @@ class HttpParserNgTest < Test::Unit::TestCase assert_nil @parser.trailers(req, str << "\r") assert_equal req, @parser.trailers(req, str << "\nGET / ") assert_equal "GET / ", str - assert ! @parser.keepalive? + assert @parser.keepalive? end def test_trailers_slowly @@ -297,14 +332,12 @@ class HttpParserNgTest < Test::Unit::TestCase assert_equal req, @parser.headers(req, str) assert_nil @parser.content_length assert_raise(HttpParserError) { @parser.filter_body('', str) } - assert ! @parser.keepalive? end def test_overflow_content_length n = HttpParser::LENGTH_MAX + 1 str = "PUT / HTTP/1.1\r\nContent-Length: #{n}\r\n\r\n" assert_raise(HttpParserError) { @parser.headers({}, str) } - assert ! @parser.keepalive? end def test_bad_chunk @@ -315,13 +348,11 @@ class HttpParserNgTest < Test::Unit::TestCase assert_equal req, @parser.headers(req, str) assert_nil @parser.content_length assert_raise(HttpParserError) { @parser.filter_body('', str) } - assert ! @parser.keepalive? end def test_bad_content_length str = "PUT / HTTP/1.1\r\nContent-Length: 7ff\r\n\r\n" assert_raise(HttpParserError) { @parser.headers({}, str) } - assert ! @parser.keepalive? end def test_bad_trailers @@ -338,7 +369,6 @@ class HttpParserNgTest < Test::Unit::TestCase assert_equal '', str str << "Transfer-Encoding: identity\r\n\r\n" assert_raise(HttpParserError) { @parser.trailers(req, str) } - assert ! @parser.keepalive? end def test_repeat_headers @@ -492,8 +522,9 @@ class HttpParserNgTest < Test::Unit::TestCase env1 = @parser.parse.dup assert_equal expect, env1 assert_equal str, @parser.buf - assert @parser.keepalive? - @parser.reset + assert ! @parser.env.empty? + assert @parser.next? + assert @parser.env.empty? env2 = @parser.parse.dup assert_equal expect, env2 assert_equal "", @parser.buf diff --git a/test/unit/test_stream_input.rb b/test/unit/test_stream_input.rb new file mode 100644 index 0000000..adf4571 --- /dev/null +++ b/test/unit/test_stream_input.rb @@ -0,0 +1,160 @@ +# -*- encoding: binary -*- + +require 'test/unit' +require 'digest/sha1' +require 'unicorn' + +class TestStreamInput < Test::Unit::TestCase + def setup + @rs = $/ + @env = {} + @rd, @wr = Kgio::UNIXSocket.pair + @rd.sync = @wr.sync = true + @start_pid = $$ + end + + def teardown + return if $$ != @start_pid + $/ = @rs + @rd.close rescue nil + @wr.close rescue nil + Process.waitall + end + + def test_read_small + r = init_request('hello') + si = Unicorn::StreamInput.new(@rd, r) + assert_equal 'hello', si.read + assert_equal '', si.read + assert_nil si.read(5) + assert_nil si.gets + end + + def test_gets_oneliner + r = init_request('hello') + si = Unicorn::StreamInput.new(@rd, r) + assert_equal 'hello', si.gets + assert_nil si.gets + end + + def test_gets_multiline + r = init_request("a\nb\n\n") + si = Unicorn::StreamInput.new(@rd, r) + assert_equal "a\n", si.gets + assert_equal "b\n", si.gets + assert_equal "\n", si.gets + assert_nil si.gets + end + + def test_gets_empty_rs + $/ = nil + r = init_request("a\nb\n\n") + si = Unicorn::StreamInput.new(@rd, r) + assert_equal "a\nb\n\n", si.gets + assert_nil si.gets + end + + def test_read_with_equal_len + r = init_request("abcde") + si = Unicorn::StreamInput.new(@rd, r) + assert_equal "abcde", si.read(5) + assert_nil si.read(5) + end + + def test_big_body_multi + r = init_request('.', Unicorn::Const::MAX_BODY + 1) + si = Unicorn::StreamInput.new(@rd, r) + assert_equal Unicorn::Const::MAX_BODY, @parser.content_length + assert ! @parser.body_eof? + nr = Unicorn::Const::MAX_BODY / 4 + pid = fork { + @rd.close + nr.times { @wr.write('....') } + @wr.close + } + @wr.close + assert_equal '.', si.read(1) + nr.times { |x| + assert_equal '....', si.read(4), "nr=#{x}" + } + assert_nil si.read(1) + status = nil + assert_nothing_raised { pid, status = Process.waitpid2(pid) } + assert status.success? + end + + def test_gets_long + r = init_request("hello", 5 + (4096 * 4 * 3) + "#$/foo#$/".size) + si = Unicorn::StreamInput.new(@rd, r) + status = line = nil + pid = fork { + @rd.close + 3.times { @wr.write("ffff" * 4096) } + @wr.write "#$/foo#$/" + @wr.close + } + @wr.close + assert_nothing_raised { line = si.gets } + assert_equal(4096 * 4 * 3 + 5 + $/.size, line.size) + assert_equal("hello" << ("ffff" * 4096 * 3) << "#$/", line) + assert_nothing_raised { line = si.gets } + assert_equal "foo#$/", line + assert_nil si.gets + assert_nothing_raised { pid, status = Process.waitpid2(pid) } + assert status.success? + end + + def test_read_with_buffer + r = init_request('hello') + si = Unicorn::StreamInput.new(@rd, r) + buf = '' + rv = si.read(4, buf) + assert_equal 'hell', rv + assert_equal 'hell', buf + assert_equal rv.object_id, buf.object_id + assert_equal 'o', si.read + assert_equal nil, si.read(5, buf) + end + + def test_read_with_buffer_clobbers + r = init_request('hello') + si = Unicorn::StreamInput.new(@rd, r) + buf = 'foo' + assert_equal 'hello', si.read(nil, buf) + assert_equal 'hello', buf + assert_equal '', si.read(nil, buf) + assert_equal '', buf + buf = 'asdf' + assert_nil si.read(5, buf) + assert_equal '', buf + end + + def test_read_zero + r = init_request('hello') + si = Unicorn::StreamInput.new(@rd, r) + assert_equal '', si.read(0) + buf = 'asdf' + rv = si.read(0, buf) + assert_equal rv.object_id, buf.object_id + assert_equal '', buf + assert_equal 'hello', si.read + assert_nil si.read(5) + assert_equal '', si.read(0) + buf = 'hello' + rv = si.read(0, buf) + assert_equal rv.object_id, buf.object_id + assert_equal '', rv + end + + def init_request(body, size = nil) + @parser = Unicorn::HttpParser.new + body = body.to_s.freeze + @buf = "POST / HTTP/1.1\r\n" \ + "Host: localhost\r\n" \ + "Content-Length: #{size || body.size}\r\n" \ + "\r\n#{body}" + assert_equal @env, @parser.headers(@env, @buf) + assert_equal body, @buf + @parser + end +end diff --git a/test/unit/test_tee_input.rb b/test/unit/test_tee_input.rb index a10ca34..e69c8f1 100644 --- a/test/unit/test_tee_input.rb +++ b/test/unit/test_tee_input.rb @@ -4,6 +4,10 @@ require 'test/unit' require 'digest/sha1' require 'unicorn' +class TeeInput < Unicorn::TeeInput + attr_accessor :tmp, :len +end + class TestTeeInput < Test::Unit::TestCase def setup @@ -28,7 +32,7 @@ class TestTeeInput < Test::Unit::TestCase def test_gets_long r = init_request("hello", 5 + (4096 * 4 * 3) + "#$/foo#$/".size) - ti = Unicorn::TeeInput.new(@rd, r) + ti = TeeInput.new(@rd, r) status = line = nil pid = fork { @rd.close @@ -49,7 +53,7 @@ class TestTeeInput < Test::Unit::TestCase def test_gets_short r = init_request("hello", 5 + "#$/foo".size) - ti = Unicorn::TeeInput.new(@rd, r) + ti = TeeInput.new(@rd, r) status = line = nil pid = fork { @rd.close @@ -68,7 +72,7 @@ class TestTeeInput < Test::Unit::TestCase def test_small_body r = init_request('hello') - ti = Unicorn::TeeInput.new(@rd, r) + ti = TeeInput.new(@rd, r) assert_equal 0, @parser.content_length assert @parser.body_eof? assert_equal StringIO, ti.tmp.class @@ -77,11 +81,12 @@ class TestTeeInput < Test::Unit::TestCase assert_equal 'hello', ti.read assert_equal '', ti.read assert_nil ti.read(4096) + assert_equal 5, ti.size end def test_read_with_buffer r = init_request('hello') - ti = Unicorn::TeeInput.new(@rd, r) + ti = TeeInput.new(@rd, r) buf = '' rv = ti.read(4, buf) assert_equal 'hell', rv @@ -96,7 +101,7 @@ class TestTeeInput < Test::Unit::TestCase def test_big_body r = init_request('.' * Unicorn::Const::MAX_BODY << 'a') - ti = Unicorn::TeeInput.new(@rd, r) + ti = TeeInput.new(@rd, r) assert_equal 0, @parser.content_length assert @parser.body_eof? assert_kind_of File, ti.tmp @@ -108,7 +113,7 @@ class TestTeeInput < Test::Unit::TestCase a, b = 300, 3 r = init_request('.' * b, 300) assert_equal 300, @parser.content_length - ti = Unicorn::TeeInput.new(@rd, r) + ti = TeeInput.new(@rd, r) pid = fork { @wr.write('.' * 197) sleep 1 # still a *potential* race here that would make the test moot... @@ -122,12 +127,11 @@ class TestTeeInput < Test::Unit::TestCase def test_big_body_multi r = init_request('.', Unicorn::Const::MAX_BODY + 1) - ti = Unicorn::TeeInput.new(@rd, r) + ti = TeeInput.new(@rd, r) assert_equal Unicorn::Const::MAX_BODY, @parser.content_length assert ! @parser.body_eof? assert_kind_of File, ti.tmp assert_equal 0, ti.tmp.pos - assert_equal 1, ti.tmp.size assert_equal Unicorn::Const::MAX_BODY + 1, ti.size nr = Unicorn::Const::MAX_BODY / 4 pid = fork { @@ -138,8 +142,8 @@ class TestTeeInput < Test::Unit::TestCase @wr.close assert_equal '.', ti.read(1) assert_equal Unicorn::Const::MAX_BODY + 1, ti.size - nr.times { - assert_equal '....', ti.read(4) + nr.times { |x| + assert_equal '....', ti.read(4), "nr=#{x}" assert_equal Unicorn::Const::MAX_BODY + 1, ti.size } assert_nil ti.read(1) @@ -163,7 +167,7 @@ class TestTeeInput < Test::Unit::TestCase @wr.write("0\r\n\r\n") } @wr.close - ti = Unicorn::TeeInput.new(@rd, @parser) + ti = TeeInput.new(@rd, @parser) assert_nil @parser.content_length assert_nil ti.len assert ! @parser.body_eof? @@ -201,7 +205,7 @@ class TestTeeInput < Test::Unit::TestCase end @wr.write("0\r\n\r\n") } - ti = Unicorn::TeeInput.new(@rd, @parser) + ti = TeeInput.new(@rd, @parser) assert_nil @parser.content_length assert_nil ti.len assert ! @parser.body_eof? @@ -230,7 +234,7 @@ class TestTeeInput < Test::Unit::TestCase @wr.write("Hello: World\r\n\r\n") } @wr.close - ti = Unicorn::TeeInput.new(@rd, @parser) + ti = TeeInput.new(@rd, @parser) assert_nil @parser.content_length assert_nil ti.len assert ! @parser.body_eof? @@ -241,6 +245,28 @@ class TestTeeInput < Test::Unit::TestCase assert status.success? end + def test_chunked_and_size_slow + @parser = Unicorn::HttpParser.new + @buf = "POST / HTTP/1.1\r\n" \ + "Host: localhost\r\n" \ + "Trailer: Hello\r\n" \ + "Transfer-Encoding: chunked\r\n" \ + "\r\n" + assert_equal @env, @parser.headers(@env, @buf) + assert_equal "", @buf + + @wr.write("9\r\nabcde") + ti = TeeInput.new(@rd, @parser) + assert_nil @parser.content_length + assert_equal "abcde", ti.read(9) + assert ! @parser.body_eof? + @wr.write("fghi\r\n0\r\nHello: World\r\n\r\n") + assert_equal 9, ti.size + assert_equal "fghi", ti.read(9) + assert_equal nil, ti.read(9) + assert_equal "World", @env['HTTP_HELLO'] + end + private def init_request(body, size = nil) |