Skip to content

Commit 4b43eea

Browse files
lundibundiaddaleax
authored andcommitted
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>
1 parent f33d705 commit 4b43eea

File tree

3 files changed

+60
-20
lines changed

3 files changed

+60
-20
lines changed

node.gyp

+1
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,7 @@
981981
'test/cctest/test_node_postmortem_metadata.cc',
982982
'test/cctest/test_environment.cc',
983983
'test/cctest/test_platform.cc',
984+
'test/cctest/test_report_util.cc',
984985
'test/cctest/test_traced_value.cc',
985986
'test/cctest/test_util.cc',
986987
'test/cctest/test_url.cc'

src/node_report_utils.cc

+33-20
Original file line numberDiff line numberDiff line change
@@ -214,28 +214,41 @@ void WalkHandle(uv_handle_t* h, void* arg) {
214214
writer->json_end();
215215
}
216216

217-
static std::string findAndReplace(const std::string& str,
218-
const std::string& old,
219-
const std::string& neu) {
220-
std::string ret = str;
217+
std::string EscapeJsonChars(const std::string& str) {
218+
const std::string control_symbols[0x20] = {
219+
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005",
220+
"\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r",
221+
"\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013",
222+
"\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019",
223+
"\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f"
224+
};
225+
226+
std::string ret = "";
227+
size_t last_pos = 0;
221228
size_t pos = 0;
222-
while ((pos = ret.find(old, pos)) != std::string::npos) {
223-
ret.replace(pos, old.length(), neu);
224-
pos += neu.length();
229+
for (; pos < str.size(); ++pos) {
230+
std::string replace;
231+
char ch = str[pos];
232+
if (ch == '\\') {
233+
replace = "\\\\";
234+
} else if (ch == '\"') {
235+
replace = "\\\"";
236+
} else {
237+
size_t num = static_cast<size_t>(ch);
238+
if (num < 0x20) replace = control_symbols[num];
239+
}
240+
if (!replace.empty()) {
241+
if (pos > last_pos) {
242+
ret += str.substr(last_pos, pos - last_pos);
243+
}
244+
last_pos = pos + 1;
245+
ret += replace;
246+
}
247+
}
248+
// Append any remaining symbols.
249+
if (last_pos < str.size()) {
250+
ret += str.substr(last_pos, pos - last_pos);
225251
}
226-
return ret;
227-
}
228-
229-
std::string EscapeJsonChars(const std::string& str) {
230-
std::string ret = str;
231-
ret = findAndReplace(ret, "\\", "\\\\");
232-
ret = findAndReplace(ret, "\\u", "\\u");
233-
ret = findAndReplace(ret, "\n", "\\n");
234-
ret = findAndReplace(ret, "\f", "\\f");
235-
ret = findAndReplace(ret, "\r", "\\r");
236-
ret = findAndReplace(ret, "\b", "\\b");
237-
ret = findAndReplace(ret, "\t", "\\t");
238-
ret = findAndReplace(ret, "\"", "\\\"");
239252
return ret;
240253
}
241254

test/cctest/test_report_util.cc

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include "node_report.h"
2+
3+
#include "gtest/gtest.h"
4+
5+
TEST(ReportUtilTest, EscapeJsonChars) {
6+
using report::EscapeJsonChars;
7+
EXPECT_EQ("abc", EscapeJsonChars("abc"));
8+
EXPECT_EQ("abc\\n", EscapeJsonChars("abc\n"));
9+
EXPECT_EQ("abc\\nabc", EscapeJsonChars("abc\nabc"));
10+
EXPECT_EQ("abc\\\\", EscapeJsonChars("abc\\"));
11+
EXPECT_EQ("abc\\\"", EscapeJsonChars("abc\""));
12+
13+
const std::string expected[0x20] = {
14+
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005",
15+
"\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r",
16+
"\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013",
17+
"\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019",
18+
"\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f"
19+
};
20+
for (int i = 0; i < 0x20; ++i) {
21+
char symbols[1] = { static_cast<char>(i) };
22+
std::string input(symbols, 1);
23+
EXPECT_EQ(expected[i], EscapeJsonChars(input));
24+
EXPECT_EQ("a" + expected[i], EscapeJsonChars("a" + input));
25+
}
26+
}

0 commit comments

Comments
 (0)