failIfExtra

1. failing regression tests, from #164 and #107
2. implemented; tests pass
3. allow trailing comments
This commit is contained in:
Christopher Dunn 2015-02-12 12:34:23 -06:00
parent aa13a8ba40
commit f4be815c86
3 changed files with 140 additions and 0 deletions

View File

@ -315,6 +315,9 @@ public:
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

View File

@ -914,6 +914,7 @@ public:
bool strictRoot_;
bool allowDroppedNullPlaceholders_;
bool allowNumericKeys_;
bool failIfExtra_;
int stackLimit_;
}; // OurFeatures
@ -1083,6 +1084,12 @@ bool OurReader::parse(const char* beginDoc,
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 @@ CharReader* CharReaderBuilder::newCharReader() const
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 @@ static void getValidReaderKeys(std::set<std::string>* valid_keys)
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 @@ void CharReaderBuilder::strictMode(Json::Value* settings)
(*settings)["strictRoot"] = true;
(*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false;
(*settings)["failIfExtra"] = true;
//! [CharReaderBuilderStrictMode]
}
// static
@ -1920,6 +1930,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings)
(*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false;
(*settings)["stackLimit"] = 1000;
(*settings)["failIfExtra"] = false;
//! [CharReaderBuilderDefaults]
}

View File

@ -1741,6 +1741,126 @@ JSONTEST_FIXTURE(CharReaderTest, parseWithStackLimit) {
}
}
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 @@ int main(int argc, const char* argv[]) {
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);