diff options
Diffstat (limited to 'test/cgi')
| -rw-r--r-- | test/cgi/test_cgi_cookie.rb | 121 | ||||
| -rw-r--r-- | test/cgi/test_cgi_core.rb | 162 | ||||
| -rw-r--r-- | test/cgi/test_cgi_header.rb | 85 | ||||
| -rw-r--r-- | test/cgi/test_cgi_modruby.rb | 17 | ||||
| -rw-r--r-- | test/cgi/test_cgi_multipart.rb | 124 | ||||
| -rw-r--r-- | test/cgi/test_cgi_session.rb | 55 | ||||
| -rw-r--r-- | test/cgi/test_cgi_tag_helper.rb | 36 | ||||
| -rw-r--r-- | test/cgi/test_cgi_util.rb | 287 | ||||
| -rw-r--r-- | test/cgi/update_env.rb | 9 |
9 files changed, 631 insertions, 265 deletions
diff --git a/test/cgi/test_cgi_cookie.rb b/test/cgi/test_cgi_cookie.rb index c1c6a30e70..eadae45313 100644 --- a/test/cgi/test_cgi_cookie.rb +++ b/test/cgi/test_cgi_cookie.rb @@ -1,21 +1,26 @@ +# frozen_string_literal: true require 'test/unit' require 'cgi' require 'stringio' +require_relative 'update_env' class CGICookieTest < Test::Unit::TestCase + include UpdateEnv def setup - ENV['REQUEST_METHOD'] = 'GET' - @str1="\xE3\x82\x86\xE3\x82\x93\xE3\x82\x86\xE3\x82\x93" + @environ = {} + update_env( + 'REQUEST_METHOD' => 'GET', + 'SCRIPT_NAME' => nil, + ) + @str1="\xE3\x82\x86\xE3\x82\x93\xE3\x82\x86\xE3\x82\x93".dup @str1.force_encoding("UTF-8") if defined?(::Encoding) end def teardown - %W[REQUEST_METHOD SCRIPT_NAME].each do |name| - ENV.delete(name) - end + ENV.update(@environ) end @@ -27,20 +32,22 @@ class CGICookieTest < Test::Unit::TestCase assert_nil(cookie.expires) assert_equal('', cookie.path) assert_equal(false, cookie.secure) + assert_equal(false, cookie.httponly) assert_equal("name1=val1&%26%3C%3E%22&%E3%82%86%E3%82%93%E3%82%86%E3%82%93; path=", cookie.to_s) end def test_cgi_cookie_new_complex t = Time.gm(2030, 12, 31, 23, 59, 59) - value = ['val1', '&<>"', "\xA5\xE0\xA5\xB9\xA5\xAB"] + value = ['val1', '&<>"', "\xA5\xE0\xA5\xB9\xA5\xAB".dup] value[2].force_encoding("EUC-JP") if defined?(::Encoding) cookie = CGI::Cookie.new('name'=>'name1', 'value'=>value, 'path'=>'/cgi-bin/myapp/', 'domain'=>'www.example.com', 'expires'=>t, - 'secure'=>true + 'secure'=>true, + 'httponly'=>true ) assert_equal('name1', cookie.name) assert_equal(value, cookie.value) @@ -48,7 +55,29 @@ class CGICookieTest < Test::Unit::TestCase assert_equal(t, cookie.expires) assert_equal('/cgi-bin/myapp/', cookie.path) assert_equal(true, cookie.secure) - assert_equal('name1=val1&%26%3C%3E%22&%A5%E0%A5%B9%A5%AB; domain=www.example.com; path=/cgi-bin/myapp/; expires=Tue, 31 Dec 2030 23:59:59 GMT; secure', cookie.to_s) + assert_equal(true, cookie.httponly) + assert_equal('name1=val1&%26%3C%3E%22&%A5%E0%A5%B9%A5%AB; domain=www.example.com; path=/cgi-bin/myapp/; expires=Tue, 31 Dec 2030 23:59:59 GMT; secure; HttpOnly', cookie.to_s) + end + + + def test_cgi_cookie_new_with_domain + h = {'name'=>'name1', 'value'=>'value1'} + cookie = CGI::Cookie.new(h.merge('domain'=>'a.example.com')) + assert_equal('a.example.com', cookie.domain) + + cookie = CGI::Cookie.new(h.merge('domain'=>'.example.com')) + assert_equal('.example.com', cookie.domain) + + cookie = CGI::Cookie.new(h.merge('domain'=>'1.example.com')) + assert_equal('1.example.com', cookie.domain, 'enhanced by RFC 1123') + + assert_raise(ArgumentError) { + CGI::Cookie.new(h.merge('domain'=>'-a.example.com')) + } + + assert_raise(ArgumentError) { + CGI::Cookie.new(h.merge('domain'=>'a-.example.com')) + } end @@ -80,9 +109,12 @@ class CGICookieTest < Test::Unit::TestCase assert_equal(name, cookie.name) assert_equal(value, cookie.value) end - ## ',' separator - cookie_str = 'name1=val1&val2, name2=val2&%26%3C%3E%22&%E3%82%86%E3%82%93%E3%82%86%E3%82%93,_session_id=12345' + ## don't allow ',' separator + cookie_str = 'name1=val1&val2, name2=val2' cookies = CGI::Cookie.parse(cookie_str) + list = [ + ['name1', ['val1', 'val2, name2=val2']], + ] list.each do |name, value| cookie = cookies[name] assert_equal(name, cookie.name) @@ -90,6 +122,11 @@ class CGICookieTest < Test::Unit::TestCase end end + def test_cgi_cookie_parse_not_decode_name + cookie_str = "%66oo=baz;foo=bar" + cookies = CGI::Cookie.parse(cookie_str) + assert_equal({"%66oo" => ["baz"], "foo" => ["bar"]}, cookies) + end def test_cgi_cookie_arrayinterface cookie = CGI::Cookie.new('name1', 'a', 'b', 'c') @@ -102,6 +139,70 @@ class CGICookieTest < Test::Unit::TestCase end + def test_cgi_cookie_domain_injection_into_name + name = "a=b; domain=example.com;" + path = "/" + domain = "example.jp" + assert_raise(ArgumentError) do + CGI::Cookie.new('name' => name, + 'value' => "value", + 'domain' => domain, + 'path' => path) + end + end + + + def test_cgi_cookie_newline_injection_into_name + name = "a=b;\r\nLocation: http://example.com#" + path = "/" + domain = "example.jp" + assert_raise(ArgumentError) do + CGI::Cookie.new('name' => name, + 'value' => "value", + 'domain' => domain, + 'path' => path) + end + end + + + def test_cgi_cookie_multibyte_injection_into_name + name = "a=b;\u3042" + path = "/" + domain = "example.jp" + assert_raise(ArgumentError) do + CGI::Cookie.new('name' => name, + 'value' => "value", + 'domain' => domain, + 'path' => path) + end + end + + + def test_cgi_cookie_injection_into_path + name = "name" + path = "/; samesite=none" + domain = "example.jp" + assert_raise(ArgumentError) do + CGI::Cookie.new('name' => name, + 'value' => "value", + 'domain' => domain, + 'path' => path) + end + end + + + def test_cgi_cookie_injection_into_domain + name = "name" + path = "/" + domain = "example.jp; samesite=none" + assert_raise(ArgumentError) do + CGI::Cookie.new('name' => name, + 'value' => "value", + 'domain' => domain, + 'path' => path) + end + end + instance_methods.each do |method| private method if method =~ /^test_(.*)/ && $1 != ENV['TEST'] diff --git a/test/cgi/test_cgi_core.rb b/test/cgi/test_cgi_core.rb index 171ff7b8bc..f7adb7e99f 100644 --- a/test/cgi/test_cgi_core.rb +++ b/test/cgi/test_cgi_core.rb @@ -1,12 +1,15 @@ +# frozen_string_literal: true require 'test/unit' require 'cgi' require 'stringio' +require_relative 'update_env' class CGICoreTest < Test::Unit::TestCase - + include UpdateEnv def setup + @environ = {} #@environ = { # 'SERVER_PROTOCOL' => 'HTTP/1.1', # 'REQUEST_METHOD' => 'GET', @@ -15,60 +18,36 @@ class CGICoreTest < Test::Unit::TestCase #ENV.update(@environ) end - def teardown - @environ.each do |key, val| ENV.delete(key) end + ENV.update(@environ) $stdout = STDOUT end def test_cgi_parse_illegal_query - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', 'QUERY_STRING' => 'a=111&&b=222&c&d=', 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;', 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } - ENV.update(@environ) + ) cgi = CGI.new - assert_equal(["a","b","c","d"],cgi.keys.sort) if RUBY_VERSION>="1.9" + assert_equal(["a","b","c","d"],cgi.keys.sort) assert_equal("",cgi["d"]) end def test_cgi_core_params_GET - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', 'QUERY_STRING' => 'id=123&id=456&id=&id&str=%40h+%3D%7E+%2F%5E%24%2F', 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;', 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } - ENV.update(@environ) + ) cgi = CGI.new ## cgi[] assert_equal('123', cgi['id']) assert_equal('@h =~ /^$/', cgi['str']) - ## cgi[][], cgi[].first, cgi[].to_ary (obsolete 1.9) - if RUBY_VERSION<"1.9" - $stderr = StringIO.new - begin - assert_equal('123', cgi['id'][0]) - assert_equal('456', cgi['id'][1]) - assert_equal('', cgi['id'][2]) - assert_nil(cgi['id'][3]) - assert_equal('@h =~ /^$/', cgi['str'][0]) - assert_nil(cgi['str'][1]) - assert_equal('123', cgi['id'].first) - assert_equal('123', cgi['id'].last) # should be '' ? - id1, id2, id3 = cgi['id'] - assert_equal(['123', '456', ''], [id1, id2, id3]) - str1, = cgi['str'] - assert_equal('@h =~ /^$/', str1) - assert_not_same(str1, cgi['str']) # necessary? - ensure - $stderr = STDERR - end - end ## cgi.params assert_equal(['123', '456', ''], cgi.params['id']) assert_equal(['@h =~ /^$/'], cgi.params['str']) @@ -89,14 +68,13 @@ class CGICoreTest < Test::Unit::TestCase def test_cgi_core_params_POST query_str = 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F' - @environ = { + update_env( 'REQUEST_METHOD' => 'POST', 'CONTENT_LENGTH' => query_str.length.to_s, 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;', 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } - ENV.update(@environ) + ) $stdin = StringIO.new $stdin << query_str $stdin.rewind @@ -110,17 +88,18 @@ class CGICoreTest < Test::Unit::TestCase ## invalid parameter name assert_equal('', cgi['*notfound*']) assert_equal([], cgi.params['*notfound*']) + ensure + $stdin = STDIN end def test_cgi_core_params_encoding_check query_str = 'str=%BE%BE%B9%BE' - @environ = { + update_env( 'REQUEST_METHOD' => 'POST', 'CONTENT_LENGTH' => query_str.length.to_s, 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } - ENV.update(@environ) + ) $stdin = StringIO.new $stdin << query_str $stdin.rewind @@ -128,11 +107,11 @@ class CGICoreTest < Test::Unit::TestCase hash={} cgi = CGI.new(:accept_charset=>"UTF-8"){|key,val|hash[key]=val} ## cgi[] - assert_equal("\xBE\xBE\xB9\xBE".force_encoding("UTF-8"), cgi['str']) + assert_equal("\xBE\xBE\xB9\xBE".dup.force_encoding("UTF-8"), cgi['str']) ## cgi.params - assert_equal(["\xBE\xBE\xB9\xBE".force_encoding("UTF-8")], cgi.params['str']) + assert_equal(["\xBE\xBE\xB9\xBE".dup.force_encoding("UTF-8")], cgi.params['str']) ## accept-charset error - assert_equal({"str"=>"\xBE\xBE\xB9\xBE".force_encoding("UTF-8")},hash) + assert_equal({"str"=>"\xBE\xBE\xB9\xBE".dup.force_encoding("UTF-8")},hash) $stdin.rewind assert_raise(CGI::InvalidEncoding) do @@ -142,24 +121,25 @@ class CGICoreTest < Test::Unit::TestCase $stdin.rewind cgi = CGI.new(:accept_charset=>"EUC-JP") ## cgi[] - assert_equal("\xBE\xBE\xB9\xBE".force_encoding("EUC-JP"), cgi['str']) + assert_equal("\xBE\xBE\xB9\xBE".dup.force_encoding("EUC-JP"), cgi['str']) ## cgi.params - assert_equal(["\xBE\xBE\xB9\xBE".force_encoding("EUC-JP")], cgi.params['str']) + assert_equal(["\xBE\xBE\xB9\xBE".dup.force_encoding("EUC-JP")], cgi.params['str']) else assert(true) end + ensure + $stdin = STDIN end def test_cgi_core_cookie - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F', 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;', 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } - ENV.update(@environ) + ) cgi = CGI.new assert_not_equal(nil,cgi.cookies) [ ['_session_id', ['12345'], ], @@ -177,11 +157,10 @@ class CGICoreTest < Test::Unit::TestCase def test_cgi_core_maxcontentlength - @environ = { + update_env( 'REQUEST_METHOD' => 'POST', 'CONTENT_LENGTH' => (64 * 1024 * 1024).to_s - } - ENV.update(@environ) + ) ex = assert_raise(StandardError) do CGI.new end @@ -190,57 +169,16 @@ class CGICoreTest < Test::Unit::TestCase def test_cgi_core_out - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F', 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;', 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } - ENV.update(@environ) + ) cgi = CGI.new - ## jis, euc, sjis string - jis_str = "\e$B8+$m!\"?M$,%4%_$N$h$&$@\e(B" + ## euc string euc_str = "\270\253\244\355\241\242\277\315\244\254\245\264\245\337\244\316\244\350\244\246\244\300" - sjis_str = "\214\251\202\353\201A\220l\202\252\203S\203~\202\314\202\346\202\244\202\276" - if RUBY_VERSION<"1.9" - ## iso-2022-jp - options = { 'charset'=>'iso-2022-jp' } - $stdout = StringIO.new - cgi.out(options) { euc_str } - assert_equal('ja', options['language']) - actual = $stdout.string - expected = "Content-Type: text/html; charset=iso-2022-jp\r\n" + - "Content-Length: 28\r\n" + - "Content-Language: ja\r\n" + - "\r\n" + - jis_str - assert_equal(expected,actual) - ## euc-jp - options = { 'charset'=>'EUC-JP' } - $stdout = StringIO.new - cgi.out(options) { euc_str } - assert_equal('ja', options['language']) - actual = $stdout.string - expected = "Content-Type: text/html; charset=EUC-JP\r\n" + - "Content-Length: 22\r\n" + - "Content-Language: ja\r\n" + - "\r\n" + - euc_str - assert_equal(expected, actual) - ## shift_jis - options = { 'charset'=>'Shift_JIS' } - $stdout = StringIO.new - cgi.out(options) { euc_str } - assert_equal('ja', options['language']) - actual = $stdout.string - expected = "Content-Type: text/html; charset=Shift_JIS\r\n" + - "Content-Length: 22\r\n" + - "Content-Language: ja\r\n" + - "\r\n" + - sjis_str - assert_equal(expected, actual) - end ## utf8 (not converted) options = { 'charset'=>'utf8' } $stdout = StringIO.new @@ -262,7 +200,7 @@ class CGICoreTest < Test::Unit::TestCase cgi.out(options) { euc_str } assert_equal('en', options['language']) ## HEAD method - ENV['REQUEST_METHOD'] = 'HEAD' + update_env('REQUEST_METHOD' => 'HEAD') options = { 'charset'=>'utf8' } $stdout = StringIO.new cgi.out(options) { euc_str } @@ -275,10 +213,9 @@ class CGICoreTest < Test::Unit::TestCase def test_cgi_core_print - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', - } - ENV.update(@environ) + ) cgi = CGI.new $stdout = StringIO.new str = "foobar" @@ -290,10 +227,9 @@ class CGICoreTest < Test::Unit::TestCase def test_cgi_core_environs - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', - } - ENV.update(@environ) + ) cgi = CGI.new ## list1 = %w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO @@ -307,9 +243,8 @@ class CGICoreTest < Test::Unit::TestCase # list2 = %w[ CONTENT_LENGTH SERVER_PORT ] ## string expected list1.each do |name| - @environ[name] = "**#{name}**" + update_env(name => "**#{name}**") end - ENV.update(@environ) list1.each do |name| method = name.sub(/\AHTTP_/, '').downcase actual = cgi.__send__ method @@ -317,50 +252,51 @@ class CGICoreTest < Test::Unit::TestCase assert_equal(expected, actual) end ## integer expected - ENV['CONTENT_LENGTH'] = '123' - ENV['SERVER_PORT'] = '8080' + update_env('CONTENT_LENGTH' => '123') + update_env('SERVER_PORT' => '8080') assert_equal(123, cgi.content_length) assert_equal(8080, cgi.server_port) ## raw cookie - ENV['HTTP_COOKIE'] = 'name1=val1' - ENV['HTTP_COOKIE2'] = 'name2=val2' + update_env('HTTP_COOKIE' => 'name1=val1') + update_env('HTTP_COOKIE2' => 'name2=val2') assert_equal('name1=val1', cgi.raw_cookie) assert_equal('name2=val2', cgi.raw_cookie2) end - def test_cgi_core_htmltype - @environ = { + def test_cgi_core_htmltype_header + update_env( 'REQUEST_METHOD' => 'GET', - } - ENV.update(@environ) + ) ## no htmltype cgi = CGI.new assert_raise(NoMethodError) do cgi.doctype end + assert_equal("Content-Type: text/html\r\n\r\n",cgi.header) ## html3 cgi = CGI.new('html3') expected = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">' assert_equal(expected, cgi.doctype) + assert_equal("Content-Type: text/html\r\n\r\n",cgi.header) ## html4 cgi = CGI.new('html4') expected = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' assert_equal(expected, cgi.doctype) + assert_equal("Content-Type: text/html\r\n\r\n",cgi.header) ## html4 transitional cgi = CGI.new('html4Tr') expected = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">' assert_equal(expected, cgi.doctype) + assert_equal("Content-Type: text/html\r\n\r\n",cgi.header) ## html4 frameset cgi = CGI.new('html4Fr') expected = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">' assert_equal(expected, cgi.doctype) + assert_equal("Content-Type: text/html\r\n\r\n",cgi.header) ## html5 cgi = CGI.new('html5') expected = '<!DOCTYPE HTML>' assert_equal(expected, cgi.doctype) - # cgi.header not broken - expected = "Content-Type: text/html\r\n\r\n" - actual = cgi.header - assert_equal(expected, actual) + assert_match(/^<HEADER><\/HEADER>$/i,cgi.header) end diff --git a/test/cgi/test_cgi_header.rb b/test/cgi/test_cgi_header.rb index 4d458b1a71..ec2f4deb72 100644 --- a/test/cgi/test_cgi_header.rb +++ b/test/cgi/test_cgi_header.rb @@ -1,48 +1,51 @@ +# frozen_string_literal: true require 'test/unit' require 'cgi' require 'time' +require_relative 'update_env' class CGIHeaderTest < Test::Unit::TestCase + include UpdateEnv def setup - @environ = { + @environ = {} + update_env( 'SERVER_PROTOCOL' => 'HTTP/1.1', 'REQUEST_METHOD' => 'GET', 'SERVER_SOFTWARE' => 'Apache 2.2.0', - } - ENV.update(@environ) + ) end def teardown - @environ.each do |key, val| ENV.delete(key) end + ENV.update(@environ) end - def test_cgi_header_simple + def test_cgi_http_header_simple cgi = CGI.new ## default content type expected = "Content-Type: text/html\r\n\r\n" - actual = cgi.header + actual = cgi.http_header assert_equal(expected, actual) ## content type specified as string expected = "Content-Type: text/xhtml; charset=utf8\r\n\r\n" - actual = cgi.header('text/xhtml; charset=utf8') + actual = cgi.http_header('text/xhtml; charset=utf8') assert_equal(expected, actual) ## content type specified as hash expected = "Content-Type: image/png\r\n\r\n" - actual = cgi.header('type'=>'image/png') + actual = cgi.http_header('type'=>'image/png') assert_equal(expected, actual) ## charset specified expected = "Content-Type: text/html; charset=utf8\r\n\r\n" - actual = cgi.header('charset'=>'utf8') + actual = cgi.http_header('charset'=>'utf8') assert_equal(expected, actual) end - def test_cgi_header_complex + def test_cgi_http_header_complex cgi = CGI.new options = { 'type' => 'text/xhtml', @@ -55,7 +58,7 @@ class CGIHeaderTest < Test::Unit::TestCase 'expires' => Time.gm(2000, 1, 23, 12, 34, 56), 'location' => 'http://www.ruby-lang.org/', } - expected = "Status: 302 Found\r\n" + expected = "Status: 302 Found\r\n".dup expected << "Server: webrick\r\n" expected << "Connection: close\r\n" expected << "Content-Type: text/xhtml; charset=utf8\r\n" @@ -64,26 +67,22 @@ class CGIHeaderTest < Test::Unit::TestCase expected << "Expires: Sun, 23 Jan 2000 12:34:56 GMT\r\n" expected << "location: http://www.ruby-lang.org/\r\n" expected << "\r\n" - actual = cgi.header(options) + actual = cgi.http_header(options) assert_equal(expected, actual) end - def test_cgi_header_argerr + def test_cgi_http_header_argerr cgi = CGI.new - #expected = NoMethodError # must be ArgumentError - if RUBY_VERSION>="1.9.0" - expected = ArgumentError # for CGIAlt - else - expected = NoMethodError # for Ruby1.8 - end + expected = ArgumentError + assert_raise(expected) do - cgi.header(nil) + cgi.http_header(nil) end end - def test_cgi_header_cookie + def test_cgi_http_header_cookie cgi = CGI.new cookie1 = CGI::Cookie.new('name1', 'abc', '123') cookie2 = CGI::Cookie.new('name'=>'name2', 'value'=>'value2', 'secure'=>true) @@ -92,67 +91,67 @@ class CGIHeaderTest < Test::Unit::TestCase c1 = "Set-Cookie: name1=abc&123; path=\r\n" c2 = "Set-Cookie: name2=value2; path=; secure\r\n" ## CGI::Cookie object - actual = cgi.header('cookie'=>cookie1) + actual = cgi.http_header('cookie'=>cookie1) expected = ctype + c1 + sep assert_equal(expected, actual) ## String - actual = cgi.header('cookie'=>cookie2.to_s) + actual = cgi.http_header('cookie'=>cookie2.to_s) expected = ctype + c2 + sep assert_equal(expected, actual) ## Array - actual = cgi.header('cookie'=>[cookie1, cookie2]) + actual = cgi.http_header('cookie'=>[cookie1, cookie2]) expected = ctype + c1 + c2 + sep assert_equal(expected, actual) ## Hash - actual = cgi.header('cookie'=>{'name1'=>cookie1, 'name2'=>cookie2}) + actual = cgi.http_header('cookie'=>{'name1'=>cookie1, 'name2'=>cookie2}) expected = ctype + c1 + c2 + sep assert_equal(expected, actual) end - def test_cgi_header_output_cookies + def test_cgi_http_header_output_cookies cgi = CGI.new ## output cookies cookies = [ CGI::Cookie.new('name1', 'abc', '123'), CGI::Cookie.new('name'=>'name2', 'value'=>'value2', 'secure'=>true), ] cgi.instance_variable_set('@output_cookies', cookies) - expected = "Content-Type: text/html; charset=utf8\r\n" + expected = "Content-Type: text/html; charset=utf8\r\n".dup expected << "Set-Cookie: name1=abc&123; path=\r\n" expected << "Set-Cookie: name2=value2; path=; secure\r\n" expected << "\r\n" ## header when string - actual = cgi.header('text/html; charset=utf8') + actual = cgi.http_header('text/html; charset=utf8') assert_equal(expected, actual) ## _header_for_string - actual = cgi.header('type'=>'text/html', 'charset'=>'utf8') + actual = cgi.http_header('type'=>'text/html', 'charset'=>'utf8') assert_equal(expected, actual) end - def test_cgi_header_nph + def test_cgi_http_header_nph time_start = Time.now.to_i cgi = CGI.new ## 'nph' is true ENV['SERVER_SOFTWARE'] = 'Apache 2.2.0' - actual1 = cgi.header('nph'=>true) + actual1 = cgi.http_header('nph'=>true) ## when old IIS, NPH-mode is forced ENV['SERVER_SOFTWARE'] = 'IIS/4.0' - actual2 = cgi.header - actual3 = cgi.header('status'=>'REDIRECT', 'location'=>'http://www.example.com/') + actual2 = cgi.http_header + actual3 = cgi.http_header('status'=>'REDIRECT', 'location'=>'http://www.example.com/') ## newer IIS doesn't require NPH-mode ## [ruby-dev:30537] ENV['SERVER_SOFTWARE'] = 'IIS/5.0' - actual4 = cgi.header - actual5 = cgi.header('status'=>'REDIRECT', 'location'=>'http://www.example.com/') + actual4 = cgi.http_header + actual5 = cgi.http_header('status'=>'REDIRECT', 'location'=>'http://www.example.com/') time_end = Time.now.to_i date = /^Date: ([A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4} \d\d:\d\d:\d\d GMT)\r\n/ [actual1, actual2, actual3].each do |actual| assert_match(date, actual) - assert_includes(time_start..time_end, date =~ actual && Time.parse($1).to_i) + assert_include(time_start..time_end, date =~ actual && Time.parse($1).to_i) actual.sub!(date, "Date: DATE_IS_REMOVED\r\n") end ## assertion - expected = "HTTP/1.1 200 OK\r\n" + expected = "HTTP/1.1 200 OK\r\n".dup expected << "Date: DATE_IS_REMOVED\r\n" expected << "Server: Apache 2.2.0\r\n" expected << "Connection: close\r\n" @@ -164,10 +163,10 @@ class CGIHeaderTest < Test::Unit::TestCase expected.sub!(/^HTTP\/1.1 200 OK\r\n/, "HTTP/1.1 302 Found\r\n") expected.sub!(/\r\n\r\n/, "\r\nlocation: http://www.example.com/\r\n\r\n") assert_equal(expected, actual3) - expected = "Content-Type: text/html\r\n" + expected = "Content-Type: text/html\r\n".dup expected << "\r\n" assert_equal(expected, actual4) - expected = "Status: 302 Found\r\n" + expected = "Status: 302 Found\r\n".dup expected << "Content-Type: text/html\r\n" expected << "location: http://www.example.com/\r\n" expected << "\r\n" @@ -177,6 +176,14 @@ class CGIHeaderTest < Test::Unit::TestCase end + def test_cgi_http_header_crlf_injection + cgi = CGI.new + assert_raise(RuntimeError) { cgi.http_header("text/xhtml\r\nBOO") } + assert_raise(RuntimeError) { cgi.http_header("type" => "text/xhtml\r\nBOO") } + assert_raise(RuntimeError) { cgi.http_header("status" => "200 OK\r\nBOO") } + assert_raise(RuntimeError) { cgi.http_header("location" => "text/xhtml\r\nBOO") } + end + instance_methods.each do |method| private method if method =~ /^test_(.*)/ && $1 != ENV['TEST'] diff --git a/test/cgi/test_cgi_modruby.rb b/test/cgi/test_cgi_modruby.rb index b41b9bd007..90132962b5 100644 --- a/test/cgi/test_cgi_modruby.rb +++ b/test/cgi/test_cgi_modruby.rb @@ -1,17 +1,20 @@ +# frozen_string_literal: true require 'test/unit' require 'cgi' +require_relative 'update_env' class CGIModrubyTest < Test::Unit::TestCase + include UpdateEnv def setup - @environ = { + @environ = {} + update_env( 'SERVER_PROTOCOL' => 'HTTP/1.1', 'REQUEST_METHOD' => 'GET', #'QUERY_STRING' => 'a=foo&b=bar', - } - ENV.update(@environ) + ) CGI.class_eval { const_set(:MOD_RUBY, true) } Apache._reset() #@cgi = CGI.new @@ -20,7 +23,7 @@ class CGIModrubyTest < Test::Unit::TestCase def teardown - @environ.each do |key, val| ENV.delete(key) end + ENV.update(@environ) CGI.class_eval { remove_const(:MOD_RUBY) } end @@ -30,7 +33,7 @@ class CGIModrubyTest < Test::Unit::TestCase cgi = CGI.new assert(req._setup_cgi_env_invoked?) assert(! req._send_http_header_invoked?) - actual = cgi.header + actual = cgi.http_header assert_equal('', actual) assert_equal('text/html', req.content_type) assert(req._send_http_header_invoked?) @@ -51,7 +54,7 @@ class CGIModrubyTest < Test::Unit::TestCase } assert(req._setup_cgi_env_invoked?) assert(! req._send_http_header_invoked?) - actual = cgi.header(options) + actual = cgi.http_header(options) assert_equal('', actual) assert_equal('image/gif', req.content_type) assert_equal('403 Forbidden', req.status_line) @@ -71,7 +74,7 @@ class CGIModrubyTest < Test::Unit::TestCase 'status' => '200 OK', 'location' => 'http://www.example.com/', } - cgi.header(options) + cgi.http_header(options) assert_equal('200 OK', req.status_line) # should be '302 Found' ? assert_equal(302, req.status) assert_equal('http://www.example.com/', req.headers_out['location']) diff --git a/test/cgi/test_cgi_multipart.rb b/test/cgi/test_cgi_multipart.rb index e39003d7c3..5e8ec25390 100644 --- a/test/cgi/test_cgi_multipart.rb +++ b/test/cgi/test_cgi_multipart.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true require 'test/unit' require 'cgi' require 'tempfile' require 'stringio' +require_relative 'update_env' ## @@ -31,7 +33,7 @@ class MultiPart def initialize(boundary=nil) @boundary = boundary || create_boundary() - @buf = '' + @buf = ''.dup @buf.force_encoding(::Encoding::ASCII_8BIT) if defined?(::Encoding) end attr_reader :boundary @@ -44,15 +46,14 @@ class MultiPart buf << "Content-Disposition: form-data: name=\"#{name}\"#{s}\r\n" buf << "Content-Type: #{content_type}\r\n" if content_type buf << "\r\n" - value = value.dup.force_encoding(::Encoding::ASCII_8BIT) if defined?(::Encoding) - buf << value + buf << value.b buf << "\r\n" return self end def close buf = @buf - @buf = '' + @buf = ''.dup return buf << "--#{boundary}--\r\n" end @@ -104,17 +105,26 @@ end class CGIMultipartTest < Test::Unit::TestCase + include UpdateEnv + def setup - ENV['REQUEST_METHOD'] = 'POST' + @environ = {} + update_env( + 'REQUEST_METHOD' => 'POST', + 'CONTENT_TYPE' => nil, + 'CONTENT_LENGTH' => nil, + ) + @tempfiles = [] end def teardown - %w[ REQUEST_METHOD CONTENT_TYPE CONTENT_LENGTH REQUEST_METHOD ].each do |name| - ENV.delete(name) - end + ENV.update(@environ) $stdin.close() if $stdin.is_a?(Tempfile) $stdin = STDIN + @tempfiles.each {|t| + t.close! + } end def _prepare(data) @@ -133,41 +143,50 @@ class CGIMultipartTest < Test::Unit::TestCase ENV['REQUEST_METHOD'] = 'POST' ## set $stdin tmpfile = Tempfile.new('test_cgi_multipart') + @tempfiles << tmpfile tmpfile.binmode tmpfile << input tmpfile.rewind() $stdin = tmpfile end - def _test_multipart + def _test_multipart(cgi_options={}) caller(0).find {|s| s =~ /in `test_(.*?)'/ } #testname = $1 #$stderr.puts "*** debug: testname=#{testname.inspect}" _prepare(@data) - cgi = RUBY_VERSION>="1.9" ? CGI.new(:accept_charset=>"UTF-8") : CGI.new + options = {:accept_charset=>"UTF-8"} + options.merge! cgi_options + cgi = CGI.new(options) expected_names = @data.collect{|hash| hash[:name] }.sort assert_equal(expected_names, cgi.params.keys.sort) threshold = 1024*10 @data.each do |hash| name = hash[:name] expected = hash[:value] - if RUBY_VERSION>="1.9" - if hash[:filename] #if file - expected_class = @expected_class || (hash[:value].length < threshold ? StringIO : Tempfile) - assert(cgi.files.keys.member?(hash[:name])) - else - expected_class = String - assert_equal(expected, cgi[name]) - assert_equal(false,cgi.files.keys.member?(hash[:name])) - end - else + if hash[:filename] #if file expected_class = @expected_class || (hash[:value].length < threshold ? StringIO : Tempfile) + assert(cgi.files.keys.member?(hash[:name])) + else + expected_class = String + assert_equal(expected, cgi[name]) + assert_equal(false,cgi.files.keys.member?(hash[:name])) end assert_kind_of(expected_class, cgi[name]) assert_equal(expected, cgi[name].read()) assert_equal(hash[:filename] || '', cgi[name].original_filename) #if hash[:filename] assert_equal(hash[:content_type] || '', cgi[name].content_type) #if hash[:content_type] end + ensure + if cgi + cgi.params.each {|name, vals| + vals.each {|val| + if val.kind_of?(Tempfile) && val.path + val.close! + end + } + } + end end @@ -183,7 +202,7 @@ class CGIMultipartTest < Test::Unit::TestCase @boundary = '----WebKitFormBoundaryAAfvAII+YL9102cX' @data = [ {:name=>'hidden1', :value=>'foobar'}, - {:name=>'text1', :value=>"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A"}, + {:name=>'text1', :value=>"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A".dup}, {:name=>'file1', :value=>_read('file1.html'), :filename=>'file1.html', :content_type=>'text/html'}, {:name=>'image1', :value=>_read('small.png'), @@ -199,7 +218,7 @@ class CGIMultipartTest < Test::Unit::TestCase @boundary = '----WebKitFormBoundaryAAfvAII+YL9102cX' @data = [ {:name=>'hidden1', :value=>'foobar'}, - {:name=>'text1', :value=>"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A"}, + {:name=>'text1', :value=>"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A".dup}, {:name=>'file1', :value=>_read('file1.html'), :filename=>'file1.html', :content_type=>'text/html'}, {:name=>'image1', :value=>_read('large.png'), @@ -227,16 +246,29 @@ class CGIMultipartTest < Test::Unit::TestCase {:name=>'image1', :value=>_read('large.png'), :filename=>'large.png', :content_type=>'image/png'}, # large image ] - original = _set_const(CGI, :MAX_MULTIPART_LENGTH, 2 * 1024) begin ex = assert_raise(StandardError) do - _test_multipart() + _test_multipart(:max_multipart_length=>2 * 1024) # set via simple scalar end assert_equal("too large multipart data.", ex.message) ensure - _set_const(CGI, :MAX_MULTIPART_LENGTH, original) end - end if CGI.const_defined?(:MAX_MULTIPART_LENGTH) + end + + + def test_cgi_multipart_maxmultipartlength_lambda + @data = [ + {:name=>'image1', :value=>_read('large.png'), + :filename=>'large.png', :content_type=>'image/png'}, # large image + ] + begin + ex = assert_raise(StandardError) do + _test_multipart(:max_multipart_length=>lambda{2*1024}) # set via lambda + end + assert_equal("too large multipart data.", ex.message) + ensure + end + end def test_cgi_multipart_maxmultipartcount @@ -270,7 +302,7 @@ class CGIMultipartTest < Test::Unit::TestCase input2 end ex = assert_raise(EOFError) do - RUBY_VERSION>="1.9" ? CGI.new(:accept_charset=>"UTF-8") : CGI.new + CGI.new(:accept_charset=>"UTF-8") end assert_equal("bad content body", ex.message) # @@ -281,7 +313,7 @@ class CGIMultipartTest < Test::Unit::TestCase input2 end ex = assert_raise(EOFError) do - RUBY_VERSION>="1.9" ? CGI.new(:accept_charset=>"UTF-8") : CGI.new + CGI.new(:accept_charset=>"UTF-8") end assert_equal("bad content body", ex.message) end @@ -291,15 +323,15 @@ class CGIMultipartTest < Test::Unit::TestCase @boundary = '(.|\n)*' @data = [ {:name=>'hidden1', :value=>'foobar'}, - {:name=>'text1', :value=>"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A"}, + {:name=>'text1', :value=>"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A".dup}, {:name=>'file1', :value=>_read('file1.html'), :filename=>'file1.html', :content_type=>'text/html'}, {:name=>'image1', :value=>_read('small.png'), :filename=>'small.png', :content_type=>'image/png'}, # small image ] - @data[1][:value].force_encoding("UTF-8") if RUBY_VERSION>="1.9" + @data[1][:value].force_encoding("UTF-8") _prepare(@data) - cgi = RUBY_VERSION>="1.9" ? CGI.new(:accept_charset=>"UTF-8") : CGI.new + cgi = CGI.new(:accept_charset=>"UTF-8") assert_equal('file1.html', cgi['file1'].original_filename) end @@ -311,9 +343,37 @@ class CGIMultipartTest < Test::Unit::TestCase {:name=>'foo', :value=>"bar"}, ] _prepare(@data) - cgi = RUBY_VERSION>="1.9" ? CGI.new(:accept_charset=>"UTF-8") : CGI.new + cgi = CGI.new(:accept_charset=>"UTF-8") assert_equal(cgi['foo'], 'bar') assert_equal(cgi['file'].read, 'b'*10134) + cgi['file'].close! if cgi['file'].kind_of? Tempfile + end + + def test_cgi_multipart_without_tempfile + assert_in_out_err([], <<-'EOM') + require 'cgi' + require 'stringio' + ENV['REQUEST_METHOD'] = 'POST' + ENV['CONTENT_TYPE'] = 'multipart/form-data; boundary=foobar1234' + body = <<-BODY.gsub(/\n/, "\r\n") +--foobar1234 +Content-Disposition: form-data: name=\"name1\" + +value1 +--foobar1234 +Content-Disposition: form-data: name=\"file1\"; filename=\"file1.html\" +Content-Type: text/html + +<html> +<body><p>Hello</p></body> +</html> + +--foobar1234-- +BODY + ENV['CONTENT_LENGTH'] = body.size.to_s + $stdin = StringIO.new(body) + CGI.new + EOM end ### diff --git a/test/cgi/test_cgi_session.rb b/test/cgi/test_cgi_session.rb index 8bd51776ff..b16b69766e 100644 --- a/test/cgi/test_cgi_session.rb +++ b/test/cgi/test_cgi_session.rb @@ -1,33 +1,37 @@ +# frozen_string_literal: true require 'test/unit' require 'cgi' require 'cgi/session' require 'cgi/session/pstore' require 'stringio' require 'tmpdir' +require_relative 'update_env' class CGISessionTest < Test::Unit::TestCase + include UpdateEnv + def setup + @environ = {} @session_dir = Dir.mktmpdir(%w'session dir') end def teardown - @environ.each do |key, val| ENV.delete(key) end + ENV.update(@environ) $stdout = STDOUT FileUtils.rm_rf(@session_dir) end def test_cgi_session_filestore - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', # 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F', # 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;', 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } + ) value1="value1" - value2="\x8F\xBC\x8D]" + value2="\x8F\xBC\x8D]".dup value2.force_encoding("SJIS") if defined?(::Encoding) - ENV.update(@environ) cgi = CGI.new session = CGI::Session.new(cgi,"tmpdir"=>@session_dir) session["key1"]=value1 @@ -38,14 +42,13 @@ class CGISessionTest < Test::Unit::TestCase $stdout = StringIO.new cgi.out{""} - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', # 'HTTP_COOKIE' => "_session_id=#{session_id}", 'QUERY_STRING' => "_session_id=#{session.session_id}", 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } - ENV.update(@environ) + ) cgi = CGI.new session = CGI::Session.new(cgi,"tmpdir"=>@session_dir) $stdout = StringIO.new @@ -55,17 +58,16 @@ class CGISessionTest < Test::Unit::TestCase end def test_cgi_session_pstore - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', # 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F', # 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;', 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } + ) value1="value1" - value2="\x8F\xBC\x8D]" + value2="\x8F\xBC\x8D]".dup value2.force_encoding("SJIS") if defined?(::Encoding) - ENV.update(@environ) cgi = CGI.new session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"database_manager"=>CGI::Session::PStore) session["key1"]=value1 @@ -76,14 +78,13 @@ class CGISessionTest < Test::Unit::TestCase $stdout = StringIO.new cgi.out{""} - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', # 'HTTP_COOKIE' => "_session_id=#{session_id}", 'QUERY_STRING' => "_session_id=#{session.session_id}", 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } - ENV.update(@environ) + ) cgi = CGI.new session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"database_manager"=>CGI::Session::PStore) $stdout = StringIO.new @@ -92,17 +93,16 @@ class CGISessionTest < Test::Unit::TestCase session.close end def test_cgi_session_specify_session_id - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', # 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F', # 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;', 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } + ) value1="value1" - value2="\x8F\xBC\x8D]" + value2="\x8F\xBC\x8D]".dup value2.force_encoding("SJIS") if defined?(::Encoding) - ENV.update(@environ) cgi = CGI.new session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"session_id"=>"foo") session["key1"]=value1 @@ -115,14 +115,13 @@ class CGISessionTest < Test::Unit::TestCase $stdout = StringIO.new cgi.out{""} - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', # 'HTTP_COOKIE' => "_session_id=#{session_id}", 'QUERY_STRING' => "_session_id=#{session.session_id}", 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } - ENV.update(@environ) + ) cgi = CGI.new session = CGI::Session.new(cgi,"tmpdir"=>@session_dir) $stdout = StringIO.new @@ -132,17 +131,16 @@ class CGISessionTest < Test::Unit::TestCase session.close end def test_cgi_session_specify_session_key - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', # 'QUERY_STRING' => 'id=123&id=456&id=&str=%40h+%3D%7E+%2F%5E%24%2F', # 'HTTP_COOKIE' => '_session_id=12345; name1=val1&val2;', 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } + ) value1="value1" - value2="\x8F\xBC\x8D]" + value2="\x8F\xBC\x8D]".dup value2.force_encoding("SJIS") if defined?(::Encoding) - ENV.update(@environ) cgi = CGI.new session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"session_key"=>"bar") session["key1"]=value1 @@ -154,14 +152,13 @@ class CGISessionTest < Test::Unit::TestCase $stdout = StringIO.new cgi.out{""} - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', 'HTTP_COOKIE' => "bar=#{session_id}", # 'QUERY_STRING' => "bar=#{session.session_id}", 'SERVER_SOFTWARE' => 'Apache 2.2.0', 'SERVER_PROTOCOL' => 'HTTP/1.1', - } - ENV.update(@environ) + ) cgi = CGI.new session = CGI::Session.new(cgi,"tmpdir"=>@session_dir,"session_key"=>"bar") $stdout = StringIO.new diff --git a/test/cgi/test_cgi_tag_helper.rb b/test/cgi/test_cgi_tag_helper.rb index 29306578b0..0b99dfc1bc 100644 --- a/test/cgi/test_cgi_tag_helper.rb +++ b/test/cgi/test_cgi_tag_helper.rb @@ -1,12 +1,16 @@ +# frozen_string_literal: true require 'test/unit' require 'cgi' require 'stringio' +require_relative 'update_env' class CGITagHelperTest < Test::Unit::TestCase + include UpdateEnv def setup + @environ = {} #@environ = { # 'SERVER_PROTOCOL' => 'HTTP/1.1', # 'REQUEST_METHOD' => 'GET', @@ -17,16 +21,15 @@ class CGITagHelperTest < Test::Unit::TestCase def teardown - @environ.each do |key, val| ENV.delete(key) end + ENV.update(@environ) $stdout = STDOUT end def test_cgi_tag_helper_html3 - @environ = { + update_env( 'REQUEST_METHOD' => 'GET', - } - ENV.update(@environ) + ) ## html3 cgi = CGI.new('html3') assert_equal('<A HREF=""></A>',cgi.a) @@ -318,13 +321,11 @@ class CGITagHelperTest < Test::Unit::TestCase assert_match(/^<INPUT .*TYPE="checkbox".*>bb<INPUT .*TYPE="checkbox".*>dd$/,str) assert_match(/^<INPUT .*NAME="foo".*>bb<INPUT .*NAME="foo".*>dd$/,str) assert_match(/^<INPUT .*>bb<INPUT .*CHECKED.*>dd$/,str) - assert_match(/<INPUT .*TYPE="text".*>/,cgi.text_field(:name=>"name",:value=>"value")) if RUBY_VERSION>="1.9" - if RUBY_VERSION>="1.9" - str=cgi.radio_group("foo",["aa","bb"],["cc","dd",false]) - assert_match(/^<INPUT .*VALUE="aa".*>bb<INPUT .*VALUE="cc".*>dd$/,str) - assert_match(/^<INPUT .*TYPE="radio".*>bb<INPUT .*TYPE="radio".*>dd$/,str) - assert_match(/^<INPUT .*NAME="foo".*>bb<INPUT .*NAME="foo".*>dd$/,str) - end + assert_match(/<INPUT .*TYPE="text".*>/,cgi.text_field(:name=>"name",:value=>"value")) + str=cgi.radio_group("foo",["aa","bb"],["cc","dd",false]) + assert_match(/^<INPUT .*VALUE="aa".*>bb<INPUT .*VALUE="cc".*>dd$/,str) + assert_match(/^<INPUT .*TYPE="radio".*>bb<INPUT .*TYPE="radio".*>dd$/,str) + assert_match(/^<INPUT .*NAME="foo".*>bb<INPUT .*NAME="foo".*>dd$/,str) end =begin @@ -338,4 +339,17 @@ class CGITagHelperTest < Test::Unit::TestCase end =end + def test_cgi_tag_helper_html5 + update_env( + 'REQUEST_METHOD' => 'GET', + ) + ## html5 + cgi = CGI.new('html5') + assert_equal('<HEADER></HEADER>',cgi.header) + assert_equal('<FOOTER></FOOTER>',cgi.footer) + assert_equal('<ARTICLE></ARTICLE>',cgi.article) + assert_equal('<SECTION></SECTION>',cgi.section) + assert_equal('<!DOCTYPE HTML><HTML BLA="TEST"></HTML>',cgi.html("BLA"=>"TEST"){}) + end + end diff --git a/test/cgi/test_cgi_util.rb b/test/cgi/test_cgi_util.rb index 2c003a0300..d058cccd86 100644 --- a/test/cgi/test_cgi_util.rb +++ b/test/cgi/test_cgi_util.rb @@ -1,64 +1,303 @@ +# frozen_string_literal: true require 'test/unit' require 'cgi' require 'stringio' +require_relative 'update_env' class CGIUtilTest < Test::Unit::TestCase - + include CGI::Util + include UpdateEnv def setup - ENV['REQUEST_METHOD'] = 'GET' - @str1="&<>\" \xE3\x82\x86\xE3\x82\x93\xE3\x82\x86\xE3\x82\x93" + @environ = {} + update_env( + 'REQUEST_METHOD' => 'GET', + 'SCRIPT_NAME' => nil, + ) + @str1="&<>\" \xE3\x82\x86\xE3\x82\x93\xE3\x82\x86\xE3\x82\x93".dup @str1.force_encoding("UTF-8") if defined?(::Encoding) end def teardown - %W[REQUEST_METHOD SCRIPT_NAME].each do |name| - ENV.delete(name) - end + ENV.update(@environ) end - def test_cgi_escape - assert_equal('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93', CGI::escape(@str1)) - assert_equal('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93'.ascii_only?, CGI::escape(@str1).ascii_only?) if defined?(::Encoding) + assert_equal('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93', CGI.escape(@str1)) + assert_equal('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93'.ascii_only?, CGI.escape(@str1).ascii_only?) if defined?(::Encoding) + end + + def test_cgi_escape_with_unreserved_characters + assert_equal("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~", + CGI.escape("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"), + "should not escape any unreserved characters, as per RFC3986 Section 2.3") end def test_cgi_escape_with_invalid_byte_sequence - assert_nothing_raised(ArgumentError) do - assert_equal('%C0%3C%3C', CGI::escape("\xC0<<".force_encoding("UTF-8"))) - end + assert_equal('%C0%3C%3C', CGI.escape("\xC0\<\<".dup.force_encoding("UTF-8"))) end def test_cgi_escape_preserve_encoding - assert_equal(Encoding::US_ASCII, CGI::escape("\xC0<<".force_encoding("US-ASCII")).encoding) - assert_equal(Encoding::ASCII_8BIT, CGI::escape("\xC0<<".force_encoding("ASCII-8BIT")).encoding) - assert_equal(Encoding::UTF_8, CGI::escape("\xC0<<".force_encoding("UTF-8")).encoding) + assert_equal(Encoding::US_ASCII, CGI.escape("\xC0\<\<".dup.force_encoding("US-ASCII")).encoding) + assert_equal(Encoding::ASCII_8BIT, CGI.escape("\xC0\<\<".dup.force_encoding("ASCII-8BIT")).encoding) + assert_equal(Encoding::UTF_8, CGI.escape("\xC0\<\<".dup.force_encoding("UTF-8")).encoding) end def test_cgi_unescape - assert_equal(@str1, CGI::unescape('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93')) - assert_equal(@str1.encoding, CGI::unescape('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93').encoding) if defined?(::Encoding) + str = CGI.unescape('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93') + assert_equal(@str1, str) + return unless defined?(::Encoding) + + assert_equal(@str1.encoding, str.encoding) assert_equal("\u{30E1 30E2 30EA 691C 7D22}", CGI.unescape("\u{30E1 30E2 30EA}%E6%A4%9C%E7%B4%A2")) end def test_cgi_unescape_preserve_encoding - assert_equal(Encoding::US_ASCII, CGI::unescape("%C0%3C%3C".force_encoding("US-ASCII")).encoding) - assert_equal(Encoding::ASCII_8BIT, CGI::unescape("%C0%3C%3C".force_encoding("ASCII-8BIT")).encoding) - assert_equal(Encoding::UTF_8, CGI::unescape("%C0%3C%3C".force_encoding("UTF-8")).encoding) + assert_equal(Encoding::US_ASCII, CGI.unescape("%C0%3C%3C".dup.force_encoding("US-ASCII")).encoding) + assert_equal(Encoding::ASCII_8BIT, CGI.unescape("%C0%3C%3C".dup.force_encoding("ASCII-8BIT")).encoding) + assert_equal(Encoding::UTF_8, CGI.unescape("%C0%3C%3C".dup.force_encoding("UTF-8")).encoding) + end + + def test_cgi_unescape_accept_charset + return unless defined?(::Encoding) + + assert_raise(TypeError) {CGI.unescape('', nil)} + assert_separately(%w[-rcgi/util], "#{<<-"begin;"}\n#{<<-"end;"}") + begin; + assert_equal("", CGI.unescape('')) + end; + end + + def test_cgi_escapeURIComponent + assert_equal('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93', CGI.escapeURIComponent(@str1)) + assert_equal('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93'.ascii_only?, CGI.escapeURIComponent(@str1).ascii_only?) if defined?(::Encoding) + end + + def test_cgi_escapeURIComponent_with_unreserved_characters + assert_equal("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~", + CGI.escapeURIComponent("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"), + "should not encode any unreserved characters, as per RFC3986 Section 2.3") + end + + def test_cgi_escapeURIComponent_with_invalid_byte_sequence + assert_equal('%C0%3C%3C', CGI.escapeURIComponent("\xC0\<\<".dup.force_encoding("UTF-8"))) + end + + def test_cgi_escapeURIComponent_preserve_encoding + assert_equal(Encoding::US_ASCII, CGI.escapeURIComponent("\xC0\<\<".dup.force_encoding("US-ASCII")).encoding) + assert_equal(Encoding::ASCII_8BIT, CGI.escapeURIComponent("\xC0\<\<".dup.force_encoding("ASCII-8BIT")).encoding) + assert_equal(Encoding::UTF_8, CGI.escapeURIComponent("\xC0\<\<".dup.force_encoding("UTF-8")).encoding) + end + + def test_cgi_unescapeURIComponent + str = CGI.unescapeURIComponent('%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93') + assert_equal(@str1, str) + return unless defined?(::Encoding) + + assert_equal("foo+bar", CGI.unescapeURIComponent("foo+bar")) + + assert_equal(@str1.encoding, str.encoding) + assert_equal("\u{30E1 30E2 30EA 691C 7D22}", CGI.unescapeURIComponent("\u{30E1 30E2 30EA}%E6%A4%9C%E7%B4%A2")) + end + + def test_cgi_unescapeURIComponent_preserve_encoding + assert_equal(Encoding::US_ASCII, CGI.unescapeURIComponent("%C0%3C%3C".dup.force_encoding("US-ASCII")).encoding) + assert_equal(Encoding::ASCII_8BIT, CGI.unescapeURIComponent("%C0%3C%3C".dup.force_encoding("ASCII-8BIT")).encoding) + assert_equal(Encoding::UTF_8, CGI.unescapeURIComponent("%C0%3C%3C".dup.force_encoding("UTF-8")).encoding) + end + + def test_cgi_unescapeURIComponent_accept_charset + return unless defined?(::Encoding) + + assert_raise(TypeError) {CGI.unescapeURIComponent('', nil)} + assert_separately(%w[-rcgi/util], "#{<<-"begin;"}\n#{<<-"end;"}") + begin; + assert_equal("", CGI.unescapeURIComponent('')) + end; end def test_cgi_pretty - assert_equal("<HTML>\n <BODY>\n </BODY>\n</HTML>\n",CGI::pretty("<HTML><BODY></BODY></HTML>")) - assert_equal("<HTML>\n\t<BODY>\n\t</BODY>\n</HTML>\n",CGI::pretty("<HTML><BODY></BODY></HTML>","\t")) + assert_equal("<HTML>\n <BODY>\n </BODY>\n</HTML>\n",CGI.pretty("<HTML><BODY></BODY></HTML>")) + assert_equal("<HTML>\n\t<BODY>\n\t</BODY>\n</HTML>\n",CGI.pretty("<HTML><BODY></BODY></HTML>","\t")) end def test_cgi_escapeHTML - assert_equal(CGI::escapeHTML("'&\"><"),"'&"><") + assert_equal("'&"><", CGI.escapeHTML("'&\"><")) + end + + def test_cgi_escape_html_duplicated + orig = "Ruby".dup.force_encoding("US-ASCII") + str = CGI.escapeHTML(orig) + assert_equal(orig, str) + assert_not_same(orig, str) + end + + def assert_cgi_escape_html_preserve_encoding(str, encoding) + assert_equal(encoding, CGI.escapeHTML(str.dup.force_encoding(encoding)).encoding) + end + + def test_cgi_escape_html_preserve_encoding + Encoding.list do |enc| + assert_cgi_escape_html_preserve_encoding("'&\"><", enc) + assert_cgi_escape_html_preserve_encoding("Ruby", enc) + end + end + + def test_cgi_escape_html_dont_freeze + assert_not_predicate CGI.escapeHTML("'&\"><".dup), :frozen? + assert_not_predicate CGI.escapeHTML("'&\"><".freeze), :frozen? + assert_not_predicate CGI.escapeHTML("Ruby".dup), :frozen? + assert_not_predicate CGI.escapeHTML("Ruby".freeze), :frozen? + end + + def test_cgi_escape_html_large + return if RUBY_ENGINE == 'jruby' + ulong_max, size_max = RbConfig::LIMITS.values_at("ULONG_MAX", "SIZE_MAX") + return unless ulong_max < size_max # Platforms not concerned + + size = (ulong_max / 6 + 1) + begin + str = '"' * size + escaped = CGI.escapeHTML(str) + rescue NoMemoryError + omit "Not enough memory" + rescue => e + end + assert_raise_with_message(ArgumentError, /overflow/, ->{"length = #{escaped.length}"}) do + raise e if e + end end def test_cgi_unescapeHTML - assert_equal(CGI::unescapeHTML("'&"><"),"'&\"><") + assert_equal("'&\"><", CGI.unescapeHTML("'&"><")) end + def test_cgi_unescapeHTML_invalid + assert_equal('&<&>"&abcdefghijklmn', CGI.unescapeHTML('&<&>"&abcdefghijklmn')) + end + + Encoding.list.each do |enc| + begin + escaped = "'&"><".encode(enc) + unescaped = "'&\"><".encode(enc) + rescue Encoding::ConverterNotFoundError + next + else + define_method("test_cgi_escapeHTML:#{enc.name}") do + assert_equal(escaped, CGI.escapeHTML(unescaped)) + end + define_method("test_cgi_unescapeHTML:#{enc.name}") do + assert_equal(unescaped, CGI.unescapeHTML(escaped)) + end + end + end + + Encoding.list.each do |enc| + next unless enc.ascii_compatible? + begin + escaped = "%25+%2B" + unescaped = "% +".encode(enc) + rescue Encoding::ConverterNotFoundError + next + else + define_method("test_cgi_escape:#{enc.name}") do + assert_equal(escaped, CGI.escape(unescaped)) + end + define_method("test_cgi_unescape:#{enc.name}") do + assert_equal(unescaped, CGI.unescape(escaped, enc)) + end + end + end + + def test_cgi_unescapeHTML_uppercasecharacter + assert_equal("\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86", CGI.unescapeHTML("あいう")) + end + + def test_cgi_include_escape + assert_equal('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93', escape(@str1)) + end + + def test_cgi_include_escapeHTML + assert_equal("'&"><", escapeHTML("'&\"><")) + end + + def test_cgi_include_h + assert_equal("'&"><", h("'&\"><")) + end + + def test_cgi_include_unescape + str = unescape('%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93') + assert_equal(@str1, str) + return unless defined?(::Encoding) + + assert_equal(@str1.encoding, str.encoding) + assert_equal("\u{30E1 30E2 30EA 691C 7D22}", unescape("\u{30E1 30E2 30EA}%E6%A4%9C%E7%B4%A2")) + end + + def test_cgi_include_unescapeHTML + assert_equal("'&\"><", unescapeHTML("'&"><")) + end + + def test_cgi_escapeElement + assert_equal("<BR><A HREF="url"></A>", escapeElement('<BR><A HREF="url"></A>', "A", "IMG")) + assert_equal("<BR><A HREF="url"></A>", escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"])) + assert_equal("<BR><A HREF="url"></A>", escape_element('<BR><A HREF="url"></A>', "A", "IMG")) + assert_equal("<BR><A HREF="url"></A>", escape_element('<BR><A HREF="url"></A>', ["A", "IMG"])) + + assert_equal("<A <A HREF="url"></A>", escapeElement('<A <A HREF="url"></A>', "A", "IMG")) + assert_equal("<A <A HREF="url"></A>", escapeElement('<A <A HREF="url"></A>', ["A", "IMG"])) + assert_equal("<A <A HREF="url"></A>", escape_element('<A <A HREF="url"></A>', "A", "IMG")) + assert_equal("<A <A HREF="url"></A>", escape_element('<A <A HREF="url"></A>', ["A", "IMG"])) + + assert_equal("<A <A ", escapeElement('<A <A ', "A", "IMG")) + assert_equal("<A <A ", escapeElement('<A <A ', ["A", "IMG"])) + end + + + def test_cgi_unescapeElement + assert_equal('<BR><A HREF="url"></A>', unescapeElement(escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")) + assert_equal('<BR><A HREF="url"></A>', unescapeElement(escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])) + assert_equal('<BR><A HREF="url"></A>', unescape_element(escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")) + assert_equal('<BR><A HREF="url"></A>', unescape_element(escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])) + + assert_equal('<A <A HREF="url"></A>', unescapeElement(escapeHTML('<A <A HREF="url"></A>'), "A", "IMG")) + assert_equal('<A <A HREF="url"></A>', unescapeElement(escapeHTML('<A <A HREF="url"></A>'), ["A", "IMG"])) + assert_equal('<A <A HREF="url"></A>', unescape_element(escapeHTML('<A <A HREF="url"></A>'), "A", "IMG")) + assert_equal('<A <A HREF="url"></A>', unescape_element(escapeHTML('<A <A HREF="url"></A>'), ["A", "IMG"])) + + assert_equal('<A <A ', unescapeElement(escapeHTML('<A <A '), "A", "IMG")) + assert_equal('<A <A ', unescapeElement(escapeHTML('<A <A '), ["A", "IMG"])) + assert_equal('<A <A ', unescape_element(escapeHTML('<A <A '), "A", "IMG")) + assert_equal('<A <A ', unescape_element(escapeHTML('<A <A '), ["A", "IMG"])) + end +end + +class CGIUtilPureRubyTest < Test::Unit::TestCase + def setup + CGI::Escape.module_eval do + alias _escapeHTML escapeHTML + remove_method :escapeHTML + alias _unescapeHTML unescapeHTML + remove_method :unescapeHTML + end + end + + def teardown + CGI::Escape.module_eval do + alias escapeHTML _escapeHTML + remove_method :_escapeHTML + alias unescapeHTML _unescapeHTML + remove_method :_unescapeHTML + end + end + + def test_cgi_escapeHTML_with_invalid_byte_sequence + assert_equal("<\xA4??>", CGI.escapeHTML(%[<\xA4??>])) + end + + def test_cgi_unescapeHTML_with_invalid_byte_sequence + input = "\xFF&" + assert_equal(input, CGI.unescapeHTML(input)) + end end diff --git a/test/cgi/update_env.rb b/test/cgi/update_env.rb new file mode 100644 index 0000000000..cbc8dc13c6 --- /dev/null +++ b/test/cgi/update_env.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: false +module UpdateEnv + def update_env(environ) + environ.each do |key, val| + @environ[key] = ENV[key] unless @environ.key?(key) + ENV[key] = val + end + end +end |
