diff options
author | Eric Wong <normalperson@yhbt.net> | 2011-06-13 23:42:54 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2011-06-13 23:42:54 +0000 |
commit | c297fde2000dcc8bdf7cb9f912fb2ea07be1c282 (patch) | |
tree | bc85e7c18aa4620b38ad0083e3ebc0eb32ff481d | |
parent | 131c241840990753f7b75344092058ef7434ea8b (diff) | |
download | unicorn-c297fde2000dcc8bdf7cb9f912fb2ea07be1c282.tar.gz |
This allows one to enter the dechunker without parsing HTTP headers beforehand. Since we skipped header parsing, trailer parsing is not supported since we don't know what trailers might be (to our knowledge, nobody uses trailers anyways)
-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 |