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

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: 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..698450672aedb887b5b8139df29f11f20892ea7d 100644
--- a/components/json_schema/json_schema_validator.cc
+++ b/components/json_schema/json_schema_validator.cc
@@ -7,13 +7,16 @@
#include <algorithm>
#include <cfloat>
#include <cmath>
+#include <vector>
#include "base/json/json_reader.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 +89,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 },
};
@@ -183,6 +188,14 @@ bool IsValidSchema(const base::DictionaryValue* dict,
}
}
+ if (it.key() == schema::kPattern) {
+ it.value().GetAsString(&string_value);
+ if (!re2::RE2(string_value).ok()) {
not at google - send to devlin 2014/03/11 14:53:39 How often does Validate get called? If it's a lot
binjin 2014/03/11 16:27:36 Yes, regular expression compiling is not very chea
not at google - send to devlin 2014/03/11 18:37:16 Good point re uncachability of this stuff. Ok. You
+ *error = "Invalid regular expression in pattern attribute";
not at google - send to devlin 2014/03/11 14:53:39 Could you include the RE2 error message here? htt
binjin 2014/03/11 16:27:36 Done.
+ return false;
+ }
+ }
+
// Validate the "properties" attribute. Each entry maps a key to a schema.
if (it.key() == schema::kProperties) {
it.value().GetAsDictionary(&dictionary_value);
@@ -199,6 +212,27 @@ bool IsValidSchema(const base::DictionaryValue* dict,
}
}
+ // 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 it(*dictionary_value);
not at google - send to devlin 2014/03/11 14:53:39 huh, how does the |it| declaration here not kill t
Joao da Silva 2014/03/11 16:20:13 IIUC this is the same as shadowing an outer variab
binjin 2014/03/11 16:27:36 My bad, I just copy-and-modified code from above b
+ !it.IsAtEnd(); it.Advance()) {
+ if (!re2::RE2(it.key()).ok()) {
+ *error = "Invalid regular expression in patternProperties attribute";
not at google - send to devlin 2014/03/11 14:53:39 ditto error message
binjin 2014/03/11 16:27:36 Done.
+ return false;
+ }
+ if (!it.value().GetAsDictionary(&dictionary_value)) {
+ *error = "Invalid value for patternProperties attribute";
not at google - send to devlin 2014/03/11 14:53:39 How about "patternProperties must be a dictionary"
binjin 2014/03/11 16:27:36 Done(for this and above).
+ return false;
+ }
+ if (!IsValidSchema(dictionary_value, options, error)) {
+ DCHECK(!error->empty());
+ return false;
+ }
+ }
+ }
+
// Validate "additionalProperties" attribute, which is a schema.
if (it.key() == schema::kAdditionalProperties) {
it.value().GetAsDictionary(&dictionary_value);
@@ -574,17 +608,49 @@ 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;
- // Validate additional properties.
+ const base::DictionaryValue* pattern_properties = NULL;
+ ScopedVector<re2::RE2> pattern_properties_pattern;
+ std::vector<const base::DictionaryValue*> pattern_properties_schema;
+
+ schema->GetDictionary(schema::kPatternProperties, &pattern_properties);
+ if (pattern_properties) {
not at google - send to devlin 2014/03/11 14:53:39 usual style I see would be to have the schema->Get
binjin 2014/03/11 16:27:36 Done(for this and above).
+ for (base::DictionaryValue::Iterator it(*pattern_properties); !it.IsAtEnd();
+ it.Advance()) {
+ re2::RE2* prop_pattern = new re2::RE2(it.key());
+ CHECK(prop_pattern->ok());
not at google - send to devlin 2014/03/11 14:53:39 See comment above about caching these. In fact cou
+ 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;
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++) {
not at google - send to devlin 2014/03/11 14:53:39 ++index
binjin 2014/03/11 16:27:36 Done.
+ if (re2::RE2::PartialMatch(it.key(),
+ *pattern_properties_pattern[index])) {
+ found_matching_pattern = true;
+ Validate(&it.value(), pattern_properties_schema[index], prop_path);
+ break;
+ }
+ }
Joao da Silva 2014/03/11 16:20:13 The order of these checks is not correct. See http
binjin 2014/03/11 17:20:04 I just read the specification, and from what I und
+
+ if (found_matching_pattern)
+ continue;
+
if (!additional_properties_schema) {
errors_.push_back(Error(prop_path, kUnexpectedProperty));
} else {
@@ -707,7 +773,11 @@ 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::PartialMatch(value, pattern)) {
+ errors_.push_back(Error(path, FormatErrorMessage(kStringPattern, pattern)));
+ }
}
void JSONSchemaValidator::ValidateNumber(const base::Value* instance,
« no previous file with comments | « components/json_schema/json_schema_validator.h ('k') | components/json_schema/json_schema_validator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698