diff --git a/lib/cgi/escape.rb b/lib/cgi/escape.rb index bdcdcdf..2fe773c 100644 --- a/lib/cgi/escape.rb +++ b/lib/cgi/escape.rb @@ -33,8 +33,8 @@ def escape(string) # # => "'Stop!' said Fred" def unescape(string, encoding = @@accept_charset) string = string_value(string) - str = string.tr('+', ' ') - str = str.b + str = string.b + str.tr!('+', ' ') str.gsub!(/((?:%[0-9a-fA-F]{2})+)/) do |m| [m.delete('%')].pack('H*') end diff --git a/test/cgi/test_cgi_escape.rb b/test/cgi/test_cgi_escape.rb index 3278bde..93a2e00 100644 --- a/test/cgi/test_cgi_escape.rb +++ b/test/cgi/test_cgi_escape.rb @@ -83,6 +83,18 @@ def test_cgi_unescape_nil assert_raise(TypeError) { CGI.unescape(nil) } end + def test_cgi_unescape_invalid_byte_sequence + # unescape must not raise on bytes that are invalid in the string's own + # encoding; escape and unescapeURIComponent already decode on a binary copy. + s = "\x80&".dup.force_encoding("UTF-8") + assert_equal(s.b, CGI.unescape(s.dup).b) + assert_equal(s.b, CGI.unescapeURIComponent(s.dup).b) + # ordinary decoding is unchanged + assert_equal("a b", CGI.unescape("a+b")) + assert_equal("+", CGI.unescape("%2B")) + assert_equal("'Stop!' said Fred", CGI.unescape("%27Stop%21%27+said+Fred")) + 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)