# -*- encoding: binary -*- require 'test/unit' require 'pp' require 'kcar' require 'rack' class TestParser < Test::Unit::TestCase def setup @hp = Kcar::Parser.new end def test_reset assert_nothing_raised { @hp.reset } end def test_parser_status_eof buf = "HTTP/1.0 200 OK\r\n\r\n" hdr = [] hdr_object_id = hdr.object_id response = @hp.headers(hdr, buf) assert_equal(["200 OK", hdr], response) assert hdr.empty? assert ! @hp.keepalive? assert_equal hdr_object_id, hdr.object_id assert_equal "", buf end def test_parser_status_eof_one_one buf = "HTTP/1.1 200 OK\r\n\r\n" hdr = [] response = @hp.headers(hdr, buf) assert_equal(["200 OK", hdr], response) assert hdr.empty? assert @hp.keepalive? # no content-length end def test_parser_status_with_content_length buf = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" hdr = [] response = @hp.headers(hdr, buf) assert_equal(["200 OK", hdr], response) assert_equal([%w(Content-Length 0)], hdr) assert @hp.keepalive? end def test_parser_content_length buf = "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n" rv = @hp.headers([], buf) assert_equal "200 OK", rv[0] assert_equal([ %w(Content-Length 5) ], rv[1]) assert_equal 2, rv.size assert_equal "", buf assert_equal 5, @hp.body_bytes_left end def test_parser_content_length_with_body buf = "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nabcde" rv = @hp.headers([], buf) assert_equal "200 OK", rv[0] assert_equal([ %w(Content-Length 5) ], rv[1]) assert_equal "abcde", buf assert_equal 5, @hp.body_bytes_left end def test_bad_crlf buf = "HTTP/1.1 200 OK\nContent-Length: 5\n\r\nabcde" rv = @hp.headers([], buf) assert_equal "200 OK", rv[0] assert_equal([ %w(Content-Length 5) ], rv[1]) assert_equal "abcde", buf assert_equal 5, @hp.body_bytes_left assert ! @hp.chunked? end def test_chunky_bad_crlf buf = "HTTP/1.1 200 OK\n" \ "Transfer-Encoding: chunked\n\n" \ "6\nabcdef\n0\n\n" rv = @hp.headers([], buf) assert_equal "200 OK", rv[0] assert_equal([ %w(Transfer-Encoding chunked) ], rv[1]) assert_equal "6\nabcdef\n0\n\n", buf assert_nil @hp.body_bytes_left assert @hp.chunked? assert_nil @hp.filter_body(tmp = "", buf) assert_equal "abcdef", tmp assert @hp.keepalive? end def test_chunky buf = "HTTP/1.1 200 OK\r\n" \ "Transfer-Encoding: chunked\r\n\r\n" \ "6\r\nabcdef\r\n0\r\n\r\n" rv = @hp.headers([], buf) assert_equal "200 OK", rv[0] assert_equal([ %w(Transfer-Encoding chunked) ], rv[1]) assert_equal "6\r\nabcdef\r\n0\r\n\r\n", buf assert_nil @hp.body_bytes_left assert @hp.chunked? assert_nil @hp.filter_body(tmp = "", buf) assert_equal "abcdef", tmp assert @hp.body_eof? assert @hp.keepalive? end def test_chunky_two_step buf = "HTTP/1.1 200 OK\r\n" \ "Transfer-Encoding: chunked\r\n\r\n" \ "6\r\nabcd" buf2 = "ef\r\n0\r\n\r\n" rv = @hp.headers([], buf) assert_equal "200 OK", rv[0] assert_equal([ %w(Transfer-Encoding chunked) ], rv[1]) assert_equal "6\r\nabcd", buf assert_nil @hp.body_bytes_left assert @hp.chunked? assert_nil @hp.filter_body(tmp = "", buf) assert_equal "abcd", tmp assert_equal "", buf assert ! @hp.body_eof? assert_nil @hp.filter_body(tmp = "", buf2) assert_equal "ef", tmp assert @hp.body_eof? assert_equal({}, @hp.trailers(tmp = {}, buf2)) assert @hp.keepalive? assert_nothing_raised { @hp.reset } end def test_trailers_ary buf = "HTTP/1.1 200 OK\r\n" \ "Trailer: Foo\r\n" \ "Transfer-Encoding: chunked\r\n\r\n" \ "6\r\nabcdef\r\n0\r\nFoo: bar\r\n\r\n" rv = @hp.headers([], buf) assert_equal "200 OK", rv[0] assert_equal([ %w(Trailer Foo), %w(Transfer-Encoding chunked) ], rv[1]) assert_equal "6\r\nabcdef\r\n0\r\nFoo: bar\r\n\r\n", buf assert_nil @hp.body_bytes_left assert @hp.chunked? assert_nil @hp.filter_body(tmp = "", buf) assert_equal "abcdef", tmp assert @hp.body_eof? expect = [ %w(Trailer Foo), %w(Transfer-Encoding chunked), %w(Foo bar) ] assert_equal(expect, @hp.trailers(rv[1], buf)) assert @hp.keepalive? assert_nothing_raised { @hp.reset } end def test_extract_trailers_ary tmp = [ %w(Trailer Foo), %w(Transfer-Encoding chunked), %w(Foo bar) ] assert_equal [ %w(Foo bar) ], @hp.extract_trailers(tmp) end def test_extract_trailers_hash tmp = { 'Trailer' => 'Foo', 'Transfer-Encoding' => 'chunked', 'Foo' => 'bar' } assert_equal [ %w(Foo bar) ], @hp.extract_trailers(tmp) end def test_extract_trailers_header_hash tmp = Rack::Utils::HeaderHash.new( 'Trailer' => 'foo', 'Transfer-Encoding' => 'chunked', 'Foo' => 'bar' ) assert_equal [ %w(foo bar) ], @hp.extract_trailers(tmp) end def test_repeated_headers_rack_hash hdr = Rack::Utils::HeaderHash.new buf = "HTTP/1.1 200 OK\r\nSet-Cookie: a=b\r\n" assert_nil @hp.headers(hdr, buf) assert_equal({ 'Set-Cookie' => 'a=b' }, hdr.to_hash) assert_nil @hp.headers(hdr, buf << "set-cookie: c=d\r\n") assert_equal([ "200 OK", hdr ], @hp.headers(hdr, buf << "\r\n")) assert_equal "", buf assert_equal({ 'Set-Cookie' => "a=b\nc=d" }, hdr.to_hash) end def test_repeated_headers_plain_hash hdr = {} buf = "HTTP/1.1 200 OK\r\nSet-Cookie: a=b\r\n" assert_nil @hp.headers(hdr, buf) assert_equal({ 'Set-Cookie' => 'a=b' }, hdr) assert_nil @hp.headers(hdr, buf << "set-cookie: c=d\r\n") assert_equal([ "200 OK", hdr ], @hp.headers(hdr, buf << "\r\n")) assert_equal "", buf assert_equal({ 'Set-Cookie' => 'a=b', 'set-cookie' => 'c=d' }, hdr) end def test_repeated_headers_array hdr = [] buf = "HTTP/1.1 200 OK\r\nSet-Cookie: a=b\r\n" assert_nil @hp.headers(hdr, buf) assert_equal([ %w(Set-Cookie a=b) ] , hdr) assert_nil @hp.headers(hdr, buf << "set-cookie: c=d\r\n") assert_equal([ "200 OK", hdr ], @hp.headers(hdr, buf << "\r\n")) assert_equal "", buf assert_equal([ %w(Set-Cookie a=b), %w(set-cookie c=d) ], hdr) end def test_long_line_headers_array hdr = [] buf = "HTTP/1.1 200 OK\r\na: b\r\n" assert_nil @hp.headers(hdr, buf) assert_equal([ %w(a b) ] , hdr) assert_nil @hp.headers(hdr, buf << " c\r\n") assert_equal([ [ 'a', 'b c'] ], hdr) assert_nil @hp.headers(hdr, buf << " d\n") assert_equal([ [ 'a', 'b c d'] ], hdr) assert_equal([ "200 OK", hdr ], @hp.headers(hdr, buf << "\r\n")) assert_equal([ [ 'a', 'b c d'] ], hdr) end def test_long_line_headers_plain_hash hdr = {} buf = "HTTP/1.1 200 OK\r\na: b\r\n" assert_nil @hp.headers(hdr, buf) assert_equal({ 'a' => 'b' }, hdr) assert_nil @hp.headers(hdr, buf << " c\r\n") assert_equal({ 'a' => 'b c' }, hdr) assert_nil @hp.headers(hdr, buf << " d\r\n") assert_equal({ 'a' => 'b c d' }, hdr) assert_equal([ "200 OK", hdr ], @hp.headers(hdr, buf << "\r\n")) assert_equal({ 'a' => 'b c d' }, hdr) end def test_long_line_headers_rack_hash hdr = Rack::Utils::HeaderHash.new buf = "HTTP/1.1 200 OK\r\na: b\r\n" assert_nil @hp.headers(hdr, buf) assert_equal({ 'a' => 'b' }, hdr.to_hash) assert_nil @hp.headers(hdr, buf << " c\r\n") assert_equal({ 'a' => 'b c' }, hdr) assert_nil @hp.headers(hdr, buf << " d\r\n") assert_equal({ 'a' => 'b c d' }, hdr) assert_nil @hp.headers(hdr, buf << "A: e\r\n") assert_equal([ "200 OK", hdr ], @hp.headers(hdr, buf << "\r\n")) assert_equal({ 'a' => "b c d\ne"}, hdr.to_hash) end def test_content_length_invalid assert_raises(Kcar::ParserError) do @hp.headers([], "HTTP/1.1 200 OK\r\nContent-Length: 5a\r\n\r\n") end assert_raises(Kcar::ParserError) do @hp.headers([], "HTTP/1.1 200 OK\r\nContent-Length: -1\r\n\r\n") end end end