1d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/string_escape.h" 6d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 7d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)#include "base/strings/string_util.h" 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)TEST(JSONStringEscapeTest, EscapeUTF8) { 14d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) const struct { 15d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) const char* to_escape; 16d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) const char* escaped; 17d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) } cases[] = { 18d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) {"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"}, 19d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) {"a\b\f\n\r\t\v\1\\.\"z", 20d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"}, 21d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) {"b\x0f\x7f\xf0\xff!", // \xf0\xff is not a valid UTF-8 unit. 22d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) "b\\u000F\x7F\xEF\xBF\xBD\xEF\xBF\xBD!"}, 23d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) {"c<>d", "c\\u003C>d"}, 24d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) }; 25d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 26d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { 27d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) const char* in_ptr = cases[i].to_escape; 2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::string in_str = in_ptr; 29d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string out; 31d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeJSONString(in_ptr, false, &out); 32d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_EQ(std::string(cases[i].escaped), out); 33d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 34d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) out.erase(); 36d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) bool convert_ok = EscapeJSONString(in_str, false, &out); 37d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_EQ(std::string(cases[i].escaped), out); 38d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 39d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 40d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) if (convert_ok) { 41d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) std::string fooout = GetQuotedJSONString(in_str); 42d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", fooout); 43d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 44d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) } 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 47d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) std::string in = cases[0].to_escape; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string out; 49d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeJSONString(in, false, &out); 50d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // test quoting 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string out_quoted; 54d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeJSONString(in, true, &out_quoted); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(out.length() + 2, out_quoted.length()); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(out_quoted.find(out), 1U); 57d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out_quoted)); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // now try with a NULL in the string 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string null_prepend = "test"; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) null_prepend.push_back(0); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in = null_prepend + in; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string expected = "test\\u0000"; 64d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) expected += cases[0].escaped; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out.clear(); 66d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeJSONString(in, false, &out); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(expected, out); 68d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 71d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)TEST(JSONStringEscapeTest, EscapeUTF16) { 72d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) const struct { 73d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) const wchar_t* to_escape; 74d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) const char* escaped; 75d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) } cases[] = { 76d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) {L"b\uffb1\u00ff", "b\xEF\xBE\xB1\xC3\xBF"}, 77d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) {L"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"}, 78d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) {L"a\b\f\n\r\t\v\1\\.\"z", 79d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"}, 80d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) {L"b\x0f\x7f\xf0\xff!", "b\\u000F\x7F\xC3\xB0\xC3\xBF!"}, 81d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) {L"c<>d", "c\\u003C>d"}, 82d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) }; 83d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 84d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { 85d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) string16 in = WideToUTF16(cases[i].to_escape); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string out; 88d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeJSONString(in, false, &out); 89d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_EQ(std::string(cases[i].escaped), out); 90d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 91d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 92d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) out = GetQuotedJSONString(in); 93d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", out); 94d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 97d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) string16 in = WideToUTF16(cases[0].to_escape); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string out; 99d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeJSONString(in, false, &out); 100d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // test quoting 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string out_quoted; 104d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeJSONString(in, true, &out_quoted); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(out.length() + 2, out_quoted.length()); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(out_quoted.find(out), 1U); 107d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // now try with a NULL in the string 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 null_prepend = WideToUTF16(L"test"); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) null_prepend.push_back(0); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in = null_prepend + in; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string expected = "test\\u0000"; 114d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) expected += cases[0].escaped; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out.clear(); 116d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeJSONString(in, false, &out); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(expected, out); 118d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(IsStringUTF8(out)); 119d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)} 120d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 121d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)TEST(JSONStringEscapeTest, EscapeUTF16OutsideBMP) { 122d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) { 123d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) // {a, U+10300, !}, SMP. 124d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) string16 test; 125d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) test.push_back('a'); 126d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) test.push_back(0xD800); 127d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) test.push_back(0xDF00); 128d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) test.push_back('!'); 129d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) std::string actual; 130d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(EscapeJSONString(test, false, &actual)); 131d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_EQ("a\xF0\x90\x8C\x80!", actual); 132d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) } 133d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) { 134d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) // {U+20021, U+2002B}, SIP. 135d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) string16 test; 136d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) test.push_back(0xD840); 137d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) test.push_back(0xDC21); 138d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) test.push_back(0xD840); 139d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) test.push_back(0xDC2B); 140d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) std::string actual; 141d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_TRUE(EscapeJSONString(test, false, &actual)); 142d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_EQ("\xF0\xA0\x80\xA1\xF0\xA0\x80\xAB", actual); 143d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) } 144d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) { 145d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) // {?, U+D800, @}, lone surrogate. 146d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) string16 test; 147d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) test.push_back('?'); 148d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) test.push_back(0xD800); 149d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) test.push_back('@'); 150d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) std::string actual; 151d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_FALSE(EscapeJSONString(test, false, &actual)); 152d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_EQ("?\xEF\xBF\xBD@", actual); 153d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) } 154d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)} 155d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 156d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles)TEST(JSONStringEscapeTest, EscapeBytes) { 157d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) const struct { 158d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) const char* to_escape; 159d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) const char* escaped; 160d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) } cases[] = { 161d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) {"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"}, 162d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) {"\xe5\xc4\x4f\x05\xb6\xfd\0", "\\u00E5\\u00C4O\\u0005\\u00B6\\u00FD"}, 163d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) }; 164d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 165d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { 166d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) std::string in = std::string(cases[i].to_escape); 167d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_FALSE(IsStringUTF8(in)); 168d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 169d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_EQ(std::string(cases[i].escaped), 170d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeBytesAsInvalidJSONString(in, false)); 171d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", 172d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeBytesAsInvalidJSONString(in, true)); 173d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) } 174d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) 175d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) const char kEmbedNull[] = { '\xab', '\x39', '\0', '\x9f', '\xab' }; 176d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) std::string in(kEmbedNull, ARRAYSIZE_UNSAFE(kEmbedNull)); 177d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_FALSE(IsStringUTF8(in)); 178d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EXPECT_EQ(std::string("\\u00AB9\\u0000\\u009F\\u00AB"), 179d57369da7c6519fef57db42085f7b42d4c8845c1Torne (Richard Coles) EscapeBytesAsInvalidJSONString(in, false)); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 183