failIfExtra
1. failing regression tests, from #164 and #107
2. implemented; tests pass
3. allow trailing comments
diff --git a/include/json/reader.h b/include/json/reader.h
index 255ff8e..b59e183 100644
--- a/include/json/reader.h
+++ b/include/json/reader.h
@@ -315,6 +315,9 @@
cause an exception.
- This is a security issue (seg-faults caused by deeply nested JSON),
so the default is low.
+ - `"failIfExtra": false or true`
+ - If true, `parse()` returns false when extra non-whitespace trails
+ the JSON value in the input string.
You can examine 'settings_` yourself
to see the defaults. You can also write and read them just like any
diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp
index 103bf67..2e78ff0 100644
--- a/src/lib_json/json_reader.cpp
+++ b/src/lib_json/json_reader.cpp
@@ -914,6 +914,7 @@
bool strictRoot_;
bool allowDroppedNullPlaceholders_;
bool allowNumericKeys_;
+ bool failIfExtra_;
int stackLimit_;
}; // OurFeatures
@@ -1083,6 +1084,12 @@
bool successful = readValue();
Token token;
skipCommentTokens(token);
+ if (features_.failIfExtra_) {
+ if (token.type_ != tokenError && token.type_ != tokenEndOfStream) {
+ addError("Extra non-whitespace after JSON value.", token);
+ return false;
+ }
+ }
if (collectComments_ && !commentsBefore_.empty())
root.setComment(commentsBefore_, commentAfter);
if (features_.strictRoot_) {
@@ -1870,6 +1877,7 @@
features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool();
features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
features.stackLimit_ = settings_["stackLimit"].asInt();
+ features.failIfExtra_ = settings_["failIfExtra"].asBool();
return new OurCharReader(collectComments, features);
}
static void getValidReaderKeys(std::set<std::string>* valid_keys)
@@ -1881,6 +1889,7 @@
valid_keys->insert("allowDroppedNullPlaceholders");
valid_keys->insert("allowNumericKeys");
valid_keys->insert("stackLimit");
+ valid_keys->insert("failIfExtra");
}
bool CharReaderBuilder::validate(Json::Value* invalid) const
{
@@ -1908,6 +1917,7 @@
(*settings)["strictRoot"] = true;
(*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false;
+ (*settings)["failIfExtra"] = true;
//! [CharReaderBuilderStrictMode]
}
// static
@@ -1920,6 +1930,7 @@
(*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false;
(*settings)["stackLimit"] = 1000;
+ (*settings)["failIfExtra"] = false;
//! [CharReaderBuilderDefaults]
}
diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp
index 30c80e2..bc8b9ae 100644
--- a/src/test_lib_json/main.cpp
+++ b/src/test_lib_json/main.cpp
@@ -1741,6 +1741,126 @@
}
}
+struct CharReaderFailIfExtraTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue164) {
+ // This is interpretted as a string value followed by a colon.
+ Json::CharReaderBuilder b;
+ Json::Value root;
+ char const doc[] =
+ " \"property\" : \"value\" }";
+ {
+ b.settings_["failIfExtra"] = false;
+ Json::CharReader* reader(b.newCharReader());
+ std::string errs;
+ bool ok = reader->parse(
+ doc, doc + std::strlen(doc),
+ &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs == "");
+ JSONTEST_ASSERT_EQUAL("property", root);
+ delete reader;
+ }
+ {
+ b.settings_["failIfExtra"] = true;
+ Json::CharReader* reader(b.newCharReader());
+ std::string errs;
+ bool ok = reader->parse(
+ doc, doc + std::strlen(doc),
+ &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL(errs,
+ "* Line 1, Column 13\n"
+ " Extra non-whitespace after JSON value.\n");
+ JSONTEST_ASSERT_EQUAL("property", root);
+ delete reader;
+ }
+ {
+ b.settings_["failIfExtra"] = false;
+ b.strictMode(&b.settings_);
+ Json::CharReader* reader(b.newCharReader());
+ std::string errs;
+ bool ok = reader->parse(
+ doc, doc + std::strlen(doc),
+ &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL(errs,
+ "* Line 1, Column 13\n"
+ " Extra non-whitespace after JSON value.\n");
+ JSONTEST_ASSERT_EQUAL("property", root);
+ delete reader;
+ }
+}
+JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue107) {
+ // This is interpretted as an int value followed by a colon.
+ Json::CharReaderBuilder b;
+ Json::Value root;
+ char const doc[] =
+ "1:2:3";
+ b.settings_["failIfExtra"] = true;
+ Json::CharReader* reader(b.newCharReader());
+ std::string errs;
+ bool ok = reader->parse(
+ doc, doc + std::strlen(doc),
+ &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "* Line 1, Column 2\n"
+ " Extra non-whitespace after JSON value.\n",
+ errs);
+ JSONTEST_ASSERT_EQUAL(1, root.asInt());
+ delete reader;
+}
+JSONTEST_FIXTURE(CharReaderFailIfExtraTest, commentAfterObject) {
+ Json::CharReaderBuilder b;
+ Json::Value root;
+ {
+ char const doc[] =
+ "{ \"property\" : \"value\" } //trailing\n//comment\n";
+ b.settings_["failIfExtra"] = true;
+ Json::CharReader* reader(b.newCharReader());
+ std::string errs;
+ bool ok = reader->parse(
+ doc, doc + std::strlen(doc),
+ &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL("value", root["property"]);
+ delete reader;
+ }
+}
+JSONTEST_FIXTURE(CharReaderFailIfExtraTest, commentAfterArray) {
+ Json::CharReaderBuilder b;
+ Json::Value root;
+ char const doc[] =
+ "[ \"property\" , \"value\" ] //trailing\n//comment\n";
+ b.settings_["failIfExtra"] = true;
+ Json::CharReader* reader(b.newCharReader());
+ std::string errs;
+ bool ok = reader->parse(
+ doc, doc + std::strlen(doc),
+ &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL("value", root[1u]);
+ delete reader;
+}
+JSONTEST_FIXTURE(CharReaderFailIfExtraTest, commentAfterBool) {
+ Json::CharReaderBuilder b;
+ Json::Value root;
+ char const doc[] =
+ " true /*trailing\ncomment*/";
+ b.settings_["failIfExtra"] = true;
+ Json::CharReader* reader(b.newCharReader());
+ std::string errs;
+ bool ok = reader->parse(
+ doc, doc + std::strlen(doc),
+ &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL(true, root.asBool());
+ delete reader;
+}
int main(int argc, const char* argv[]) {
JsonTest::Runner runner;
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
@@ -1779,6 +1899,12 @@
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithDetailError);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithStackLimit);
+ JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue164);
+ JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue107);
+ JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterObject);
+ JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterArray);
+ JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterBool);
+
JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders);
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);