diff options
-rw-r--r-- | ext/unicorn_http/unicorn_http.rl | 29 | ||||
-rw-r--r-- | test/unit/test_http_parser_ng.rb | 54 |
2 files changed, 83 insertions, 0 deletions
diff --git a/ext/unicorn_http/unicorn_http.rl b/ext/unicorn_http/unicorn_http.rl index 106cc6b..f799337 100644 --- a/ext/unicorn_http/unicorn_http.rl +++ b/ext/unicorn_http/unicorn_http.rl @@ -631,6 +631,34 @@ static VALUE HttpParser_clear(VALUE self) /** * call-seq: + * parser.chunk_ready! => parser + * + * Resets the parser to a state suitable for dechunking response bodies + * + */ +static VALUE HttpParser_dechunk_bang(VALUE self) +{ + struct http_parser *hp = data_get(self); + + http_parser_init(hp); + + /* + * we don't care about trailers in dechunk-only mode, + * but if we did we'd set UH_FL_HASTRAILER and clear hp->env + */ + if (0) { + rb_funcall(hp->env, id_clear, 0); + hp->flags = UH_FL_HASTRAILER; + } + + hp->flags |= UH_FL_HASBODY | UH_FL_INBODY | UH_FL_CHUNKED; + hp->cs = http_parser_en_ChunkedBody; + + return self; +} + +/** + * call-seq: * parser.reset => nil * * Resets the parser to it's initial state so that you can reuse it @@ -954,6 +982,7 @@ void Init_unicorn_http(void) rb_define_method(cHttpParser, "initialize", HttpParser_init, 0); rb_define_method(cHttpParser, "clear", HttpParser_clear, 0); rb_define_method(cHttpParser, "reset", HttpParser_reset, 0); + rb_define_method(cHttpParser, "dechunk!", HttpParser_dechunk_bang, 0); rb_define_method(cHttpParser, "parse", HttpParser_parse, 0); rb_define_method(cHttpParser, "add_parse", HttpParser_add_parse, 1); rb_define_method(cHttpParser, "headers", HttpParser_headers, 2); diff --git a/test/unit/test_http_parser_ng.rb b/test/unit/test_http_parser_ng.rb index e57428c..2b2fe41 100644 --- a/test/unit/test_http_parser_ng.rb +++ b/test/unit/test_http_parser_ng.rb @@ -237,6 +237,17 @@ class HttpParserNgTest < Test::Unit::TestCase assert @parser.keepalive? end + def test_chunked_empty + str = @parser.buf + req = @parser.env + str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n" + assert_equal req, @parser.parse, "msg=#{str}" + assert_equal 0, str.size + tmp = "" + assert_equal str, @parser.filter_body(tmp, str << "0\r\n\r\n") + assert_equal "", tmp + end + def test_two_chunks str = @parser.buf str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n" @@ -651,4 +662,47 @@ class HttpParserNgTest < Test::Unit::TestCase assert_equal expect, @parser.parse assert ! @parser.next? end + + def test_chunk_only + tmp = "" + assert_equal @parser, @parser.dechunk! + assert_nil @parser.filter_body(tmp, "6\r\n") + assert_equal "", tmp + assert_nil @parser.filter_body(tmp, "abcdef") + assert_equal "abcdef", tmp + assert_nil @parser.filter_body(tmp, "\r\n") + assert_equal "", tmp + src = "0\r\n\r\n" + assert_equal src.object_id, @parser.filter_body(tmp, src).object_id + assert_equal "", tmp + end + + def test_chunk_only_bad_align + tmp = "" + assert_equal @parser, @parser.dechunk! + assert_nil @parser.filter_body(tmp, "6\r\na") + assert_equal "a", tmp + assert_nil @parser.filter_body(tmp, "bcde") + assert_equal "bcde", tmp + assert_nil @parser.filter_body(tmp, "f\r") + assert_equal "f", tmp + src = "\n0\r\n\r\n" + assert_equal src.object_id, @parser.filter_body(tmp, src).object_id + assert_equal "", tmp + end + + def test_chunk_only_reset_ok + tmp = "" + assert_equal @parser, @parser.dechunk! + src = "1\r\na\r\n0\r\n\r\n" + assert_nil @parser.filter_body(tmp, src) + assert_equal "a", tmp + assert_equal src.object_id, @parser.filter_body(tmp, src).object_id + + assert_equal @parser, @parser.dechunk! + src = "0\r\n\r\n" + assert_equal src.object_id, @parser.filter_body(tmp, src).object_id + assert_equal "", tmp + assert_equal src, @parser.filter_body(tmp, src) + end end |