diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c index 65058820c..f53e6964c 100644 --- a/ext/json/ext/generator/generator.c +++ b/ext/json/ext/generator/generator.c @@ -226,7 +226,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string) unsigned long len = RSTRING_LEN(string), start = 0, end = 0; const char *escape = NULL; int escape_len; - unsigned char c; + unsigned char c, last_c = -1; char buf[6] = { '\\', 'u' }; for (start = 0, end = 0; end < len;) { @@ -271,13 +271,20 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string) escape_len = 2; break; default: - end++; - continue; + if (c == '/' && last_c == '<') { + escape = "\\/"; + escape_len = 2; + } else { + last_c = c; + end++; + continue; + } break; } } fbuffer_append(buffer, ptr + start, end - start); fbuffer_append(buffer, escape, escape_len); + last_c = c; start = ++end; escape = NULL; } diff --git a/java/src/json/ext/StringEncoder.java b/java/src/json/ext/StringEncoder.java index 57bd19bce..85da9ce1b 100644 --- a/java/src/json/ext/StringEncoder.java +++ b/java/src/json/ext/StringEncoder.java @@ -40,14 +40,17 @@ final class StringEncoder extends ByteListTranscoder { void encode(ByteList src, ByteList out) { init(src, out); append('"'); + int lastChar = -1; while (hasNext()) { - handleChar(readUtf8Char()); + int newChar = readUtf8Char(); + handleChar(newChar, lastChar); + lastChar = newChar; } quoteStop(pos); append('"'); } - private void handleChar(int c) { + private void handleChar(int c, int lastChar) { switch (c) { case '"': case '\\': @@ -68,6 +71,13 @@ private void handleChar(int c) { case '\b': escapeChar('b'); break; + case '/': + if (lastChar == '<') { + escapeChar('/'); + } else { + quoteStart(); + } + break; default: if (c >= 0x20 && c <= 0x7f || (c >= 0x80 && !asciiOnly)) { diff --git a/lib/json/pure/generator.rb b/lib/json/pure/generator.rb index 44cca605f..070ee0bf3 100644 --- a/lib/json/pure/generator.rb +++ b/lib/json/pure/generator.rb @@ -44,6 +44,7 @@ def utf8_to_json(string) # :nodoc: string << '' # XXX workaround: avoid buffer sharing string.force_encoding(::Encoding::ASCII_8BIT) string.gsub!(/["\\\x0-\x1f]/) { MAP[$&] } + string.gsub!("" string.force_encoding(::Encoding::UTF_8) string end @@ -65,6 +66,7 @@ def utf8_to_json_ascii(string) # :nodoc: s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0] s.gsub!(/.{4}/n, '\\\\u\&') } + string.gsub!("" string.force_encoding(::Encoding::UTF_8) string rescue => e @@ -72,7 +74,9 @@ def utf8_to_json_ascii(string) # :nodoc: end else def utf8_to_json(string) # :nodoc: - string.gsub(/["\\\x0-\x1f]/) { MAP[$&] } + string = string.gsub(/["\\\x0-\x1f]/) { MAP[$&] } + string.gsub!("" + string end def utf8_to_json_ascii(string) # :nodoc: @@ -89,6 +93,7 @@ def utf8_to_json_ascii(string) # :nodoc: s = JSON.iconv('utf-16be', 'utf-8', c).unpack('H*')[0] s.gsub!(/.{4}/n, '\\\\u\&') } + string.gsub!("" string rescue => e raise GeneratorError, "Caught #{e.class}: #{e}" diff --git a/tests/test_json_generate.rb b/tests/test_json_generate.rb index e6219df0f..f73b76941 100755 --- a/tests/test_json_generate.rb +++ b/tests/test_json_generate.rb @@ -176,4 +176,10 @@ def test_depth assert_raises(JSON::NestingError) { ary.to_json(s) } assert_equal 19, s.depth end + + + def test_no_close_tag + assert_equal '["<\/script>"]', generate([""]) + assert_equal '["<\/SCRIPT>"]', generate([""]) + end end