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

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: fix a bug and enhance tests 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 38627df2634c95aea755e2d1305ed528a35ab10c..e4694d41e1846c296e387ba7c87ea2d65ea43541 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_STRICT;
+}
+
+SchemaOnErrorStrategy StrategyForNextLevel(SchemaOnErrorStrategy strategy) {
+ static SchemaOnErrorStrategy next_level_strategy[] = {
+ SCHEMA_STRICT, // SCHEMA_STRICT
+ SCHEMA_STRICT, // SCHEMA_ALLOW_UNKNOWN_TOPLEVEL
+ SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_UNKNOWN
+ SCHEMA_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 {
Joao da Silva 2014/01/23 15:52:36 std::string* error The style guide says that the
binjin 2014/01/23 17:20:13 Done.
if (!valid()) {
- // Schema not found, invalid entry.
+ *error = "The schema is invalid.";
return false;
}
- if (!value.IsType(type()))
+ if (!value.IsType(type())) {
+ *error = "The value type doesn't match the schema type.";
return false;
+ }
const base::DictionaryValue* dict = NULL;
const base::ListValue* list = NULL;
@@ -625,26 +651,128 @@ 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 {
+ std::string sub_error;
+ if (!subschema.Validate(it.value(),
+ StrategyForNextLevel(strategy), &sub_error)) {
Joao da Silva 2014/01/23 15:52:36 The style guide says that arguments should be alig
binjin 2014/01/23 17:20:13 Done.
+ // Invalid property was detected.
+ if (!StrategyAllowInvalidOnTopLevel(strategy)) {
+ *error = sub_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))
- return false;
+ if (!*it || !GetItems().Validate(**it,
+ StrategyForNextLevel(strategy), error)) {
Joao da Silva 2014/01/23 15:52:36 Run clang-format on this line too
binjin 2014/01/23 17:20:13 Done.
+ // Invalid list item was detected.
+ if (!StrategyAllowInvalidOnTopLevel(strategy))
+ 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 = "The schema is invalid.";
+ return false;
+ }
+
+ if (!value->IsType(type())) {
Joao da Silva 2014/01/23 15:52:36 We could handle INTEGER to DOUBLE promotion here,
binjin 2014/01/23 17:20:13 I added special check to allow Integer to Double p
+ *error = "The value type doesn't match the schema type.";
+ return false;
+ }
+
+ base::DictionaryValue* dict = NULL;
+ base::ListValue* list = NULL;
+ if (value->GetAsDictionary(&dict)) {
+ std::vector<std::string> drop_list; // Contains the keys to drop.
+ 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 {
+ base::Value* sub_value = NULL;
+ dict->GetWithoutPathExpansion(it.key(), &sub_value);
+ std::string sub_error;
+ if (!subschema.Normalize(sub_value,
+ StrategyForNextLevel(strategy), &sub_error)) {
Joao da Silva 2014/01/23 15:52:36 Run clang-format on this line
binjin 2014/01/23 17:20:13 Done.
+ // Invalid property was detected.
+ if (StrategyAllowInvalidOnTopLevel(strategy)) {
+ drop_list.push_back(it.key());
+ } else {
+ *error = sub_error;
+ return false;
+ }
+ }
+ }
+ }
+ for (std::vector<std::string>::const_iterator it = drop_list.begin();
+ it != drop_list.end(); ++it) {
+ dict->Remove(*it, NULL);
Joao da Silva 2014/01/23 15:52:36 RemoveWithoutPathExpansion
binjin 2014/01/23 17:20:13 Done.
+ }
+ return true;
+ } else if (value->GetAsList(&list)) {
+ std::vector<size_t> drop_list; // Contains the indexes to drop.
+ for (size_t index = 0; index < list->GetSize(); index++) {
+ base::Value* sub_value = NULL;
+ std::string sub_error;
+ list->Get(index, &sub_value);
+ if (!sub_value || !GetItems().Normalize(sub_value,
+ StrategyForNextLevel(strategy), &sub_error)) {
Joao da Silva 2014/01/23 15:52:36 Run clang-format on this line
binjin 2014/01/23 17:20:13 Done.
+ // Invalid list item was detected.
+ if (StrategyAllowInvalidOnTopLevel(strategy)) {
+ drop_list.push_back(index);
+ } else {
+ *error = sub_error;
+ return false;
+ }
+ }
+ }
+ for (std::vector<size_t>::reverse_iterator it = drop_list.rbegin();
+ it != drop_list.rend(); ++it) {
+ list->Remove(*it, NULL);
Joao da Silva 2014/01/23 15:52:36 This is expensive, because it will search for the
binjin 2014/01/23 17:20:13 The type of *it is size_t, and I actually called L
Joao da Silva 2014/01/23 20:18:47 I was confused by the drop_list of the dictionary,
+ }
+ return true;
+ }
+
+ 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