diff options
author | Eric Wong <normalperson@yhbt.net> | 2009-08-09 03:41:34 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2009-08-09 03:43:49 -0700 |
commit | ff37b3fe17f04db80e31cb070e3ce8fa1f9eae39 (patch) | |
tree | 54578226bd260fa9d9a82959f6895f3719aa4b82 | |
parent | 81026ea66279695206ea53287427c05281662572 (diff) | |
download | unicorn-ff37b3fe17f04db80e31cb070e3ce8fa1f9eae39.tar.gz |
We're bound by the maximum value of off_t when handling input bodies (we need to buffer to disk). Also ensure we stop bad clients that send us unparseable lengths.
-rw-r--r-- | ext/unicorn_http/unicorn_http.rl | 16 | ||||
-rw-r--r-- | test/unit/test_http_parser_ng.rb | 50 |
2 files changed, 66 insertions, 0 deletions
diff --git a/ext/unicorn_http/unicorn_http.rl b/ext/unicorn_http/unicorn_http.rl index 5a5c053..edf39ae 100644 --- a/ext/unicorn_http/unicorn_http.rl +++ b/ext/unicorn_http/unicorn_http.rl @@ -478,6 +478,22 @@ void Init_unicorn_http(void) rb_define_method(cHttpParser, "trailers", HttpParser_headers, 2); rb_define_method(cHttpParser, "content_length", HttpParser_content_length, 0); rb_define_method(cHttpParser, "body_eof?", HttpParser_body_eof, 0); + + /* + * The maximum size a single chunk when using chunked transfer encoding. + * This is only a theoretical maximum used to detect errors in clients, + * it is highly unlikely to encounter clients that send more than + * several kilobytes at once. + */ + rb_define_const(cHttpParser, "CHUNK_MAX", OFFT2NUM(UH_OFF_T_MAX)); + + /* + * The maximum size of the body as specified by Content-Length. + * This is only a theoretical maximum, the actual limit is subject + * to the limits of the file system used for +Dir::tmpdir+ + */ + rb_define_const(cHttpParser, "LENGTH_MAX", OFFT2NUM(UH_OFF_T_MAX)); + init_common_fields(); SET_GLOBAL(g_http_host, "HOST"); SET_GLOBAL(g_http_trailer, "TRAILER"); diff --git a/test/unit/test_http_parser_ng.rb b/test/unit/test_http_parser_ng.rb index 55cccdf..b91013d 100644 --- a/test/unit/test_http_parser_ng.rb +++ b/test/unit/test_http_parser_ng.rb @@ -186,4 +186,54 @@ class HttpParserNgTest < Test::Unit::TestCase assert_equal "GET / ", str end + def test_max_chunk + str = "PUT / HTTP/1.1\r\n" \ + "transfer-Encoding: chunked\r\n\r\n" \ + "#{HttpParser::CHUNK_MAX.to_s(16)}\r\na\r\n2\r\n..\r\n0\r\n" + req = {} + assert_equal req, @parser.headers(req, str) + assert_nil @parser.content_length + assert_nothing_raised { @parser.read_body('', str) } + end + + def test_max_body + n = HttpParser::LENGTH_MAX + str = "PUT / HTTP/1.1\r\nContent-Length: #{n}\r\n\r\n" + req = {} + assert_nothing_raised { @parser.headers(req, str) } + assert_equal n, req['CONTENT_LENGTH'].to_i + end + + def test_overflow_chunk + n = HttpParser::CHUNK_MAX + 1 + str = "PUT / HTTP/1.1\r\n" \ + "transfer-Encoding: chunked\r\n\r\n" \ + "#{n.to_s(16)}\r\na\r\n2\r\n..\r\n0\r\n" + req = {} + assert_equal req, @parser.headers(req, str) + assert_nil @parser.content_length + assert_raise(HttpParserError) { @parser.read_body('', str) } + 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) } + end + + def test_bad_chunk + str = "PUT / HTTP/1.1\r\n" \ + "transfer-Encoding: chunked\r\n\r\n" \ + "#zzz\r\na\r\n2\r\n..\r\n0\r\n" + req = {} + assert_equal req, @parser.headers(req, str) + assert_nil @parser.content_length + assert_raise(HttpParserError) { @parser.read_body('', str) } + 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) } + end + end |