Index: components/policy/core/common/schema.cc |
diff --git a/components/policy/core/common/schema.cc b/components/policy/core/common/schema.cc |
index 3e40244c64f96d9c19c92f863d4b318bd4c25a08..180466b029ce57a2956fff3ca2dc15078da26683 100644 |
--- a/components/policy/core/common/schema.cc |
+++ b/components/policy/core/common/schema.cc |
@@ -13,6 +13,7 @@ |
#include "base/compiler_specific.h" |
#include "base/logging.h" |
#include "base/memory/scoped_vector.h" |
+#include "base/strings/stringprintf.h" |
#include "components/json_schema/json_schema_constants.h" |
#include "components/json_schema/json_schema_validator.h" |
#include "components/policy/core/common/schema_internal.h" |
@@ -104,6 +105,32 @@ SchemaOnErrorStrategy StrategyForNextLevel(SchemaOnErrorStrategy strategy) { |
return next_level_strategy[(int)strategy]; |
} |
+void SchemaErrorFound(std::string* error_path, |
+ std::string* error, |
+ const std::string& msg) { |
+ if (error_path) |
+ *error_path = ""; |
+ *error = msg; |
+} |
+ |
+void AddListIndexPrefixToPath(int index, std::string* path) { |
+ if (path) { |
+ if (path->empty()) |
+ *path = base::StringPrintf("items[%d]", index); |
+ else |
+ *path = base::StringPrintf("items[%d].", index) + *path; |
+ } |
+} |
+ |
+void AddDictKeyPrefixToPath(const std::string& key, std::string* path) { |
+ if (path) { |
+ if (path->empty()) |
+ *path = key; |
+ else |
+ *path = key + "." + *path; |
+ } |
+} |
+ |
} // namespace |
// Contains the internal data representation of a Schema. This can either wrap |
@@ -633,9 +660,10 @@ Schema Schema::Wrap(const SchemaData* data) { |
bool Schema::Validate(const base::Value& value, |
SchemaOnErrorStrategy strategy, |
+ std::string* error_path, |
std::string* error) const { |
if (!valid()) { |
- *error = "The schema is invalid."; |
+ SchemaErrorFound(error_path, error, "The schema is invalid."); |
return false; |
} |
@@ -647,7 +675,8 @@ bool Schema::Validate(const base::Value& value, |
return true; |
} |
- *error = "The value type doesn't match the schema type."; |
+ SchemaErrorFound( |
+ error_path, error, "The value type doesn't match the schema type."); |
return false; |
} |
@@ -661,28 +690,29 @@ bool Schema::Validate(const base::Value& value, |
Schema subschema = GetProperty(it.key()); |
if (!subschema.valid()) { |
// Unknown property was detected. |
- if (!StrategyAllowUnknownOnTopLevel(strategy)) { |
- *error = "Unknown property: " + it.key(); |
+ SchemaErrorFound(error_path, error, "Unknown property: " + it.key()); |
+ if (!StrategyAllowUnknownOnTopLevel(strategy)) |
+ return false; |
+ } else if (!subschema.Validate(it.value(), |
+ StrategyForNextLevel(strategy), |
+ error_path, |
+ error)) { |
+ // Invalid property was detected. |
+ AddDictKeyPrefixToPath(it.key(), error_path); |
+ if (!StrategyAllowInvalidOnTopLevel(strategy)) |
return false; |
- } |
- } else { |
- std::string sub_error; |
- if (!subschema.Validate( |
- it.value(), StrategyForNextLevel(strategy), &sub_error)) { |
- // 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, StrategyForNextLevel(strategy), error)) { |
+ !GetItems().Validate(**it, |
+ StrategyForNextLevel(strategy), |
+ error_path, |
+ error)) { |
// Invalid list item was detected. |
+ AddListIndexPrefixToPath(it - list->begin(), error_path); |
if (!StrategyAllowInvalidOnTopLevel(strategy)) |
return false; |
} |
@@ -690,13 +720,13 @@ bool Schema::Validate(const base::Value& value, |
} else if (value.GetAsInteger(&int_value)) { |
if (node_->extra != kInvalid && |
!ValidateIntegerRestriction(node_->extra, int_value)) { |
- *error = "Invalid value for integer"; |
+ SchemaErrorFound(error_path, error, "Invalid value for integer"); |
return false; |
} |
} else if (value.GetAsString(&str_value)) { |
if (node_->extra != kInvalid && |
!ValidateStringRestriction(node_->extra, str_value.c_str())) { |
- *error = "Invalid value for string"; |
+ SchemaErrorFound(error_path, error, "Invalid value for string"); |
return false; |
} |
} |
@@ -706,9 +736,10 @@ bool Schema::Validate(const base::Value& value, |
bool Schema::Normalize(base::Value* value, |
SchemaOnErrorStrategy strategy, |
+ std::string* error_path, |
std::string* error) const { |
if (!valid()) { |
- *error = "The schema is invalid."; |
+ SchemaErrorFound(error_path, error, "The schema is invalid."); |
return false; |
} |
@@ -720,7 +751,8 @@ bool Schema::Normalize(base::Value* value, |
return true; |
} |
- *error = "The value type doesn't match the schema type."; |
+ SchemaErrorFound( |
+ error_path, error, "The value type doesn't match the schema type."); |
return false; |
} |
@@ -733,25 +765,24 @@ bool Schema::Normalize(base::Value* value, |
Schema subschema = GetProperty(it.key()); |
if (!subschema.valid()) { |
// Unknown property was detected. |
- if (StrategyAllowUnknownOnTopLevel(strategy)) { |
+ SchemaErrorFound(error_path, error, "Unknown property: " + it.key()); |
+ if (StrategyAllowUnknownOnTopLevel(strategy)) |
drop_list.push_back(it.key()); |
- } else { |
- *error = "Unknown property: " + it.key(); |
+ else |
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)) { |
+ if (!subschema.Normalize(sub_value, |
+ StrategyForNextLevel(strategy), |
+ error_path, |
+ error)) { |
// Invalid property was detected. |
- if (StrategyAllowInvalidOnTopLevel(strategy)) { |
+ AddDictKeyPrefixToPath(it.key(), error_path); |
+ if (StrategyAllowInvalidOnTopLevel(strategy)) |
drop_list.push_back(it.key()); |
- } else { |
- *error = sub_error; |
+ else |
return false; |
- } |
} |
} |
} |
@@ -765,18 +796,18 @@ bool Schema::Normalize(base::Value* value, |
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)) { |
+ !GetItems().Normalize(sub_value, |
+ StrategyForNextLevel(strategy), |
+ error_path, |
+ error)) { |
// Invalid list item was detected. |
- if (StrategyAllowInvalidOnTopLevel(strategy)) { |
+ AddListIndexPrefixToPath(index, error_path); |
+ if (StrategyAllowInvalidOnTopLevel(strategy)) |
drop_list.push_back(index); |
- } else { |
- *error = sub_error; |
+ else |
return false; |
- } |
} |
} |
for (std::vector<size_t>::reverse_iterator it = drop_list.rbegin(); |
@@ -786,7 +817,7 @@ bool Schema::Normalize(base::Value* value, |
return true; |
} |
- return Validate(*value, strategy, error); |
+ return Validate(*value, strategy, error_path, error); |
} |
// static |
@@ -891,7 +922,7 @@ bool Schema::ValidateIntegerRestriction(int index, int value) const { |
} |
} |
-bool Schema::ValidateStringRestriction(int index, const char *str) const { |
+bool Schema::ValidateStringRestriction(int index, const char* str) const { |
const RestrictionNode* rnode = storage_->restriction(index); |
for (int i = rnode->enumeration_restriction.offset_begin; |
i < rnode->enumeration_restriction.offset_end; i++) { |