Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(412)

Unified Diff: components/policy/core/common/schema.cc

Issue 134153005: Add strictness to Schema::Validate() (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@expand-policy-schema-2
Patch Set: pull from previous CL Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/policy/core/common/schema.cc
diff --git a/components/policy/core/common/schema.cc b/components/policy/core/common/schema.cc
index d9b400436a604bd6928747a93bb8dcc37e3185fd..954618ca3ebe4a2a2e9205dfdb4b48772e1cea81 100644
--- a/components/policy/core/common/schema.cc
+++ b/components/policy/core/common/schema.cc
@@ -82,6 +82,28 @@ bool SchemaTypeToValueType(const std::string& type_string,
return false;
}
+bool StrategyAllowInvalidOnTopLevel(SchemaOnErrorStrategy strategy) {
+ return strategy == SCHEMA_ALLOW_INVALID ||
+ strategy == SCHEMA_ALLOW_INVALID_TOPLEVEL ||
+ strategy == SCHEMA_ALLOW_INVALID_TOPLEVEL_AND_ALLOW_UNKNOWN;
+}
+
+bool StrategyAllowUnknownOnTopLevel(SchemaOnErrorStrategy strategy) {
+ return strategy != SCHEMA_VERY_STRICT;
+}
+
+SchemaOnErrorStrategy StrategyForNextLevel(SchemaOnErrorStrategy strategy) {
+ static SchemaOnErrorStrategy next_level_strategy[] = {
+ SCHEMA_VERY_STRICT, // SCHEMA_VERY_STRICT
+ SCHEMA_VERY_STRICT, // SCHEMA_ALLOW_UNKNOWN_TOPLEVEL
+ SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_UNKNOWN
+ SCHEMA_VERY_STRICT, // SCHEMA_ALLOW_INVALID_TOPLEVEL
+ SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_INVALID_TOPLEVEL_AND_ALLOW_UNKNOWN
+ SCHEMA_ALLOW_INVALID, // SCHEMA_ALLOW_INVALID
+ };
+ return next_level_strategy[(int)strategy];
+}
+
} // namespace
// Contains the internal data representation of a Schema. This can either wrap
@@ -609,14 +631,18 @@ Schema Schema::Wrap(const SchemaData* data) {
return Schema(storage, storage->root_node());
}
-bool Schema::Validate(const base::Value& value) const {
+bool Schema::Validate(const base::Value& value,
+ SchemaOnErrorStrategy strategy,
+ std::string *error) const {
if (!valid()) {
- // Schema not found, invalid entry.
+ *error = "Fatal error: The schema itself is invalid.";
Joao da Silva 2014/01/22 10:49:53 Just "The schema is invalid."
binjin 2014/01/23 12:01:31 Done.
return false;
}
- if (!value.IsType(type()))
+ if (!value.IsType(type())) {
+ *error = "The schema type and value type is not matched.";
Joao da Silva 2014/01/22 10:49:53 The value type doesn't match the schema type.
binjin 2014/01/23 12:01:31 Done.
return false;
+ }
const base::DictionaryValue* dict = NULL;
const base::ListValue* list = NULL;
@@ -625,26 +651,111 @@ bool Schema::Validate(const base::Value& value) const {
if (value.GetAsDictionary(&dict)) {
for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
it.Advance()) {
- if (!GetProperty(it.key()).Validate(it.value()))
- return false;
+ Schema subschema = GetProperty(it.key());
+ if (!subschema.valid()) {
+ // Unknown property was detected.
+ if (!StrategyAllowUnknownOnTopLevel(strategy)) {
+ *error = "Unknown property: " + it.key();
+ return false;
+ }
+ } else {
Joao da Silva 2014/01/22 10:49:53 The else part should just be: std::string sub_e
binjin 2014/01/22 12:46:53 The current approach is result of trade-off. In sh
+ std::string property_error;
+ if (subschema.node_->type == base::Value::TYPE_DICTIONARY) {
+ if (!subschema.Validate(it.value(),
+ StrategyForNextLevel(strategy), error)) {
+ return false;
+ }
+ } else if (!subschema.Validate(it.value(),
+ SCHEMA_VERY_STRICT, &property_error)) {
+ // Invalid property was detected.
+ if (!StrategyAllowInvalidOnTopLevel(strategy)) {
+ *error = property_error;
+ return false;
+ }
+ }
+ }
}
} else if (value.GetAsList(&list)) {
for (base::ListValue::const_iterator it = list->begin();
it != list->end(); ++it) {
- if (!*it || !GetItems().Validate(**it))
+ if (!*it || !GetItems().Validate(**it, strategy, error))
Joao da Silva 2014/01/22 10:49:53 Replace "strategy" with StrategyForNextLevel(strat
binjin 2014/01/22 12:46:53 For list-dict-nested schema(with list/list-list-ne
return false;
}
} else if (value.GetAsInteger(&int_value)) {
- return node_->extra == kInvalid ||
- ValidateIntegerRestriction(node_->extra, int_value);
+ if (node_->extra != kInvalid &&
+ !ValidateIntegerRestriction(node_->extra, int_value)) {
+ *error = "Invalid value for integer";
+ return false;
+ }
} else if (value.GetAsString(&str_value)) {
- return node_->extra == kInvalid ||
- ValidateStringRestriction(node_->extra, str_value.c_str());
+ if (node_->extra != kInvalid &&
+ !ValidateStringRestriction(node_->extra, str_value.c_str())) {
+ *error = "Invalid value for string";
+ return false;
+ }
}
return true;
}
+bool Schema::Normalize(base::Value* value,
+ SchemaOnErrorStrategy strategy,
+ std::string *error) const {
+ if (!valid()) {
+ *error = "Fatal error: The schema itself is invalid.";
Joao da Silva 2014/01/22 10:49:53 Just "The schema is invalid."
binjin 2014/01/23 12:01:31 Done.
+ return false;
+ }
+
+ if (!value->IsType(type())) {
+ *error = "The schema type and value type is not matched.";
Joao da Silva 2014/01/22 10:49:53 The value type doesn't match the schema type.
binjin 2014/01/23 12:01:31 Done.
+ return false;
+ }
+
+ base::DictionaryValue* dict = NULL;
+ if (value->GetAsDictionary(&dict)) {
+ std::vector<std::string> drop_list; // Contains the keys to remove.
+ for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
+ it.Advance()) {
+ Schema subschema = GetProperty(it.key());
+ if (!subschema.valid()) {
+ // Unknown property was detected.
+ if (StrategyAllowUnknownOnTopLevel(strategy)) {
+ drop_list.push_back(it.key());
+ } else {
+ *error = "Unknown property: " + it.key();
+ return false;
+ }
+ } else {
+ std::string property_error;
+ if (subschema.node_->type == base::Value::TYPE_DICTIONARY) {
+ base::DictionaryValue* subdict = NULL;
+ dict->GetDictionary(it.key(), &subdict);
+ if (!subschema.Normalize(subdict,
+ StrategyForNextLevel(strategy), error)) {
+ return false;
+ }
+ } else if (!subschema.Validate(it.value(),
+ SCHEMA_VERY_STRICT, &property_error)) {
+ // Invalid property was detected.
+ if (StrategyAllowInvalidOnTopLevel(strategy)) {
+ drop_list.push_back(it.key());
+ } else {
+ *error = property_error;
+ return false;
+ }
+ }
+ }
+ }
+ for (std::vector<std::string>::const_iterator it = drop_list.begin();
+ it != drop_list.end(); ++it) {
+ dict->Remove(*it, NULL);
+ }
+ return true;
+ }
Joao da Silva 2014/01/22 10:49:53 This needs to handle lists of dictionaries; the in
binjin 2014/01/22 12:46:53 Yes, it did break normalizing by list-dict-nested
+
+ return Validate(*value, strategy, error);
+}
+
// static
Schema Schema::Parse(const std::string& content, std::string* error) {
// Validate as a generic JSON schema, and ignore unknown attributes; they

Powered by Google App Engine
This is Rietveld 408576698