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

Unified Diff: components/json_schema/json_schema_validator.cc

Issue 195193002: Add regular expression support in json_schema component (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: two major changes Created 6 years, 9 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/json_schema/json_schema_validator.cc
diff --git a/components/json_schema/json_schema_validator.cc b/components/json_schema/json_schema_validator.cc
index 18558d0e111213bd789ac96633b8bc43afaaa53f..2a3e60d93100ee6e7ca62b931076255f4a906b39 100644
--- a/components/json_schema/json_schema_validator.cc
+++ b/components/json_schema/json_schema_validator.cc
@@ -7,13 +7,17 @@
#include <algorithm>
#include <cfloat>
#include <cmath>
+#include <vector>
#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "components/json_schema/json_schema_constants.h"
+#include "third_party/re2/re2/re2.h"
namespace schema = json_schema_constants;
@@ -86,6 +90,8 @@ bool IsValidSchema(const base::DictionaryValue* dict,
{ schema::kMinLength, base::Value::TYPE_INTEGER },
{ schema::kMinimum, base::Value::TYPE_DOUBLE },
{ schema::kOptional, base::Value::TYPE_BOOLEAN },
+ { schema::kPattern, base::Value::TYPE_STRING },
+ { schema::kPatternProperties, base::Value::TYPE_DICTIONARY },
{ schema::kProperties, base::Value::TYPE_DICTIONARY },
{ schema::kTitle, base::Value::TYPE_STRING },
};
@@ -186,10 +192,27 @@ bool IsValidSchema(const base::DictionaryValue* dict,
// Validate the "properties" attribute. Each entry maps a key to a schema.
if (it.key() == schema::kProperties) {
it.value().GetAsDictionary(&dictionary_value);
- for (base::DictionaryValue::Iterator it(*dictionary_value);
- !it.IsAtEnd(); it.Advance()) {
- if (!it.value().GetAsDictionary(&dictionary_value)) {
- *error = "Invalid value for properties attribute";
+ for (base::DictionaryValue::Iterator iter(*dictionary_value);
+ !iter.IsAtEnd(); iter.Advance()) {
+ if (!iter.value().GetAsDictionary(&dictionary_value)) {
+ *error = "property must be a dictionary";
Joao da Silva 2014/03/13 15:10:52 properties
binjin 2014/03/20 15:14:30 Done.
+ return false;
+ }
+ if (!IsValidSchema(dictionary_value, options, error)) {
+ DCHECK(!error->empty());
+ return false;
+ }
+ }
+ }
+
+ // Validate the "patternProperties" attribute. Each entry maps a valid
+ // regular expression to a schema.
+ if (it.key() == schema::kPatternProperties) {
+ it.value().GetAsDictionary(&dictionary_value);
+ for (base::DictionaryValue::Iterator iter(*dictionary_value);
+ !iter.IsAtEnd(); iter.Advance()) {
+ if (!iter.value().GetAsDictionary(&dictionary_value)) {
+ *error = "patternProperty must be a dictionary";
return false;
}
if (!IsValidSchema(dictionary_value, options, error)) {
@@ -551,8 +574,7 @@ void JSONSchemaValidator::ValidateObject(const base::DictionaryValue* instance,
const base::DictionaryValue* schema,
const std::string& path) {
const base::DictionaryValue* properties = NULL;
- schema->GetDictionary(schema::kProperties, &properties);
- if (properties) {
+ if (schema->GetDictionary(schema::kProperties, &properties)) {
for (base::DictionaryValue::Iterator it(*properties); !it.IsAtEnd();
it.Advance()) {
std::string prop_path = path.empty() ? it.key() : (path + "." + it.key());
@@ -574,17 +596,51 @@ void JSONSchemaValidator::ValidateObject(const base::DictionaryValue* instance,
}
}
+ // Allowing any additional items will ignore pattern properties as well.
const base::DictionaryValue* additional_properties_schema = NULL;
- if (SchemaAllowsAnyAdditionalItems(schema, &additional_properties_schema))
- return;
+ bool allow_any_additional_properties =
+ SchemaAllowsAnyAdditionalItems(schema, &additional_properties_schema);
- // Validate additional properties.
+ const base::DictionaryValue* pattern_properties = NULL;
+ ScopedVector<re2::RE2> pattern_properties_pattern;
+ std::vector<const base::DictionaryValue*> pattern_properties_schema;
+
+ if (schema->GetDictionary(schema::kPatternProperties, &pattern_properties)) {
+ for (base::DictionaryValue::Iterator it(*pattern_properties); !it.IsAtEnd();
+ it.Advance()) {
+ re2::RE2* prop_pattern = new re2::RE2(it.key());
+ if (!prop_pattern->ok()) {
+ LOG(WARNING) << "Regular expression in schema is not valid: /"
+ << it.key() << "/.";
Joao da Silva 2014/03/13 15:10:52 LOG prop_pattern.error() and push it as an error t
binjin 2014/03/20 15:14:30 Done.
+ }
+ const base::DictionaryValue* prop_schema = NULL;
+ CHECK(it.value().GetAsDictionary(&prop_schema));
+ pattern_properties_pattern.push_back(prop_pattern);
+ pattern_properties_schema.push_back(prop_schema);
+ }
+ }
+
+ // Validate pattern properties and additional properties.
for (base::DictionaryValue::Iterator it(*instance); !it.IsAtEnd();
it.Advance()) {
- if (properties && properties->HasKey(it.key()))
- continue;
Joao da Silva 2014/03/13 15:10:52 nit: remove newline
binjin 2014/03/20 15:14:30 Done.
std::string prop_path = path.empty() ? it.key() : path + "." + it.key();
+
+ bool found_matching_pattern = false;
+ for (size_t index = 0; index < pattern_properties_pattern.size(); ++index) {
+ if (pattern_properties_pattern[index]->ok() &&
+ re2::RE2::PartialMatch(it.key(),
+ *pattern_properties_pattern[index])) {
+ found_matching_pattern = true;
+ Validate(&it.value(), pattern_properties_schema[index], prop_path);
+ break;
+ }
+ }
+
+ if (found_matching_pattern || allow_any_additional_properties ||
+ (properties && properties->HasKey(it.key())))
+ continue;
+
if (!additional_properties_schema) {
errors_.push_back(Error(prop_path, kUnexpectedProperty));
} else {
@@ -707,7 +763,17 @@ void JSONSchemaValidator::ValidateString(const base::Value* instance,
}
}
- CHECK(!schema->HasKey(schema::kPattern)) << "Pattern is not supported.";
+ std::string pattern;
+ if (schema->GetString(schema::kPattern, &pattern)) {
+ re2::RE2 compiled_regex(pattern);
+ if (!compiled_regex.ok()) {
+ LOG(WARNING) << "Regular expression in schema is not valid: /" << pattern
+ << "/.";
Joao da Silva 2014/03/13 15:10:52 This should push an error too. Otherwise a typo wi
Joao da Silva 2014/03/13 15:10:52 Include compiled_regex.error() in the LOG and the
binjin 2014/03/20 15:14:30 Done.
+ } else if (!re2::RE2::PartialMatch(value, compiled_regex)) {
+ errors_.push_back(
+ Error(path, FormatErrorMessage(kStringPattern, pattern)));
+ }
+ }
}
void JSONSchemaValidator::ValidateNumber(const base::Value* instance,

Powered by Google App Engine
This is Rietveld 408576698