From 52a14fec844683bb5d4658562be51184b0314807 Mon Sep 17 00:00:00 2001 From: Denys Otrishko Date: Mon, 21 Jan 2019 23:16:46 +0200 Subject: [PATCH 1/3] src,test: fix JSON escaping in node-report Previously only simple escape sequences were handled (i.e. \n, \t, r etc.). This commit adds escaping of other control symbols in the range of 0x00 to 0x20. Also, this replaces multiple find+replace calls with a single pass replacer. --- node.gyp | 1 + src/node_report_utils.cc | 53 ++++++++++++++++++++------------- test/cctest/test_report_util.cc | 26 ++++++++++++++++ 3 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 test/cctest/test_report_util.cc diff --git a/node.gyp b/node.gyp index 91a6304049931a..8dc9187c5af2e8 100644 --- a/node.gyp +++ b/node.gyp @@ -981,6 +981,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 e93f230d318a6d..d27ac70b903770 100644 --- a/src/node_report_utils.cc +++ b/src/node_report_utils.cc @@ -271,28 +271,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) { + 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; + const 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..2fb4a938c22fcd --- /dev/null +++ b/test/cctest/test_report_util.cc @@ -0,0 +1,26 @@ +#include "node_report_utils.cc" + +#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\"")); + + 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] = { i }; + std::string input(symbols, 1); + EXPECT_EQ(expected[i], EscapeJsonChars(input)); + EXPECT_EQ("a" + expected[i], EscapeJsonChars("a" + input)); + } +} From 8f775a02fed2ce443e96e029499a9dafed310efb Mon Sep 17 00:00:00 2001 From: Denys Otrishko Date: Tue, 22 Jan 2019 00:39:59 +0200 Subject: [PATCH 2/3] fixup! src,test: fix JSON escaping in node-report --- src/node_report_utils.cc | 10 +++++----- test/cctest/test_report_util.cc | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/node_report_utils.cc b/src/node_report_utils.cc index d27ac70b903770..4c3a6d6ba61ffe 100644 --- a/src/node_report_utils.cc +++ b/src/node_report_utils.cc @@ -272,7 +272,7 @@ void WalkHandle(uv_handle_t* h, void* arg) { } std::string EscapeJsonChars(const std::string& str) { - std::string control_symbols[0x20] = { + 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", @@ -285,13 +285,13 @@ std::string EscapeJsonChars(const std::string& str) { size_t pos = 0; for (; pos < str.size(); ++pos) { std::string replace; - const char* ch = &str[pos]; - if (*ch == '\\') { + char ch = str[pos]; + if (ch == '\\') { replace = "\\\\"; - } else if (*ch == '\"') { + } else if (ch == '\"') { replace = "\\\""; } else { - size_t num = static_cast(*ch); + size_t num = static_cast(ch); if (num < 0x20) replace = control_symbols[num]; } if (!replace.empty()) { diff --git a/test/cctest/test_report_util.cc b/test/cctest/test_report_util.cc index 2fb4a938c22fcd..ea0d40e47ba8bf 100644 --- a/test/cctest/test_report_util.cc +++ b/test/cctest/test_report_util.cc @@ -10,7 +10,7 @@ TEST(ReportUtilTest, EscapeJsonChars) { EXPECT_EQ("abc\\\\", EscapeJsonChars("abc\\")); EXPECT_EQ("abc\\\"", EscapeJsonChars("abc\"")); - std::string expected[0x20] = { + 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", @@ -18,7 +18,7 @@ TEST(ReportUtilTest, EscapeJsonChars) { "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f" }; for (int i = 0; i < 0x20; ++i) { - char symbols[1] = { 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)); From 741526112ca9706126bec528e97746a71a772980 Mon Sep 17 00:00:00 2001 From: Denys Otrishko Date: Tue, 22 Jan 2019 13:13:23 +0200 Subject: [PATCH 3/3] fixup! src,test: fix JSON escaping in node-report --- test/cctest/test_report_util.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cctest/test_report_util.cc b/test/cctest/test_report_util.cc index ea0d40e47ba8bf..e32558ef75b5e8 100644 --- a/test/cctest/test_report_util.cc +++ b/test/cctest/test_report_util.cc @@ -1,4 +1,4 @@ -#include "node_report_utils.cc" +#include "node_report.h" #include "gtest/gtest.h"