diff --git a/node.gyp b/node.gyp index 3beeb71c1d3dff..d762b8c3015201 100644 --- a/node.gyp +++ b/node.gyp @@ -980,6 +980,7 @@ 'test/cctest/test_node_postmortem_metadata.cc', 'test/cctest/test_environment.cc', 'test/cctest/test_platform.cc', + 'test/cctest/test_report_util.cc', 'test/cctest/test_traced_value.cc', 'test/cctest/test_util.cc', 'test/cctest/test_url.cc' diff --git a/src/node_report_utils.cc b/src/node_report_utils.cc index 2cd92599b0a91e..75eb33250a2f98 100644 --- a/src/node_report_utils.cc +++ b/src/node_report_utils.cc @@ -214,28 +214,41 @@ void WalkHandle(uv_handle_t* h, void* arg) { writer->json_end(); } -static std::string findAndReplace(const std::string& str, - const std::string& old, - const std::string& neu) { - std::string ret = str; +std::string EscapeJsonChars(const std::string& str) { + const std::string control_symbols[0x20] = { + "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", + "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", + "\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", + "\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", + "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f" + }; + + std::string ret = ""; + size_t last_pos = 0; size_t pos = 0; - while ((pos = ret.find(old, pos)) != std::string::npos) { - ret.replace(pos, old.length(), neu); - pos += neu.length(); + for (; pos < str.size(); ++pos) { + std::string replace; + char ch = str[pos]; + if (ch == '\\') { + replace = "\\\\"; + } else if (ch == '\"') { + replace = "\\\""; + } else { + size_t num = static_cast(ch); + if (num < 0x20) replace = control_symbols[num]; + } + if (!replace.empty()) { + if (pos > last_pos) { + ret += str.substr(last_pos, pos - last_pos); + } + last_pos = pos + 1; + ret += replace; + } + } + // Append any remaining symbols. + if (last_pos < str.size()) { + ret += str.substr(last_pos, pos - last_pos); } - return ret; -} - -std::string EscapeJsonChars(const std::string& str) { - std::string ret = str; - ret = findAndReplace(ret, "\\", "\\\\"); - ret = findAndReplace(ret, "\\u", "\\u"); - ret = findAndReplace(ret, "\n", "\\n"); - ret = findAndReplace(ret, "\f", "\\f"); - ret = findAndReplace(ret, "\r", "\\r"); - ret = findAndReplace(ret, "\b", "\\b"); - ret = findAndReplace(ret, "\t", "\\t"); - ret = findAndReplace(ret, "\"", "\\\""); return ret; } diff --git a/test/cctest/test_report_util.cc b/test/cctest/test_report_util.cc new file mode 100644 index 00000000000000..e32558ef75b5e8 --- /dev/null +++ b/test/cctest/test_report_util.cc @@ -0,0 +1,26 @@ +#include "node_report.h" + +#include "gtest/gtest.h" + +TEST(ReportUtilTest, EscapeJsonChars) { + using report::EscapeJsonChars; + EXPECT_EQ("abc", EscapeJsonChars("abc")); + EXPECT_EQ("abc\\n", EscapeJsonChars("abc\n")); + EXPECT_EQ("abc\\nabc", EscapeJsonChars("abc\nabc")); + EXPECT_EQ("abc\\\\", EscapeJsonChars("abc\\")); + EXPECT_EQ("abc\\\"", EscapeJsonChars("abc\"")); + + const std::string expected[0x20] = { + "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", + "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", + "\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", + "\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", + "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f" + }; + for (int i = 0; i < 0x20; ++i) { + char symbols[1] = { static_cast(i) }; + std::string input(symbols, 1); + EXPECT_EQ(expected[i], EscapeJsonChars(input)); + EXPECT_EQ("a" + expected[i], EscapeJsonChars("a" + input)); + } +}