Permalink
Browse files

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.

PR-URL: #25626
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
  • Loading branch information...
lundibundi authored and addaleax committed Jan 21, 2019
1 parent f33d705 commit 4b43eeaf9a4528a21e69029d241b6760af8c9660
Showing with 60 additions and 20 deletions.
  1. +1 −0 node.gyp
  2. +33 −20 src/node_report_utils.cc
  3. +26 −0 test/cctest/test_report_util.cc
@@ -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'
@@ -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<size_t>(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;
}

@@ -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<char>(i) };
std::string input(symbols, 1);
EXPECT_EQ(expected[i], EscapeJsonChars(input));
EXPECT_EQ("a" + expected[i], EscapeJsonChars("a" + input));
}
}

0 comments on commit 4b43eea

Please sign in to comment.