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

Side by Side Diff: components/json_schema/json_schema_validator.cc

Issue 94043003: Ignore unknown attributes when parsing JSON schemas. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: added flag Created 7 years 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/json_schema/json_schema_validator.h" 5 #include "components/json_schema/json_schema_validator.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cfloat> 8 #include <cfloat>
9 #include <cmath> 9 #include <cmath>
10 10
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 const base::Value* ExtractNameFromDictionary(const base::Value* value) { 58 const base::Value* ExtractNameFromDictionary(const base::Value* value) {
59 const base::DictionaryValue* value_dict = NULL; 59 const base::DictionaryValue* value_dict = NULL;
60 const base::Value* name_value = NULL; 60 const base::Value* name_value = NULL;
61 if (value->GetAsDictionary(&value_dict)) { 61 if (value->GetAsDictionary(&value_dict)) {
62 value_dict->Get("name", &name_value); 62 value_dict->Get("name", &name_value);
63 return name_value; 63 return name_value;
64 } 64 }
65 return value; 65 return value;
66 } 66 }
67 67
68 bool IsValidSchema(const base::DictionaryValue* dict, std::string* error) { 68 bool IsValidSchema(const base::DictionaryValue* dict,
69 bool ignore_unknown_attrs,
70 std::string* error) {
69 // This array must be sorted, so that std::lower_bound can perform a 71 // This array must be sorted, so that std::lower_bound can perform a
70 // binary search. 72 // binary search.
71 static const ExpectedType kExpectedTypes[] = { 73 static const ExpectedType kExpectedTypes[] = {
72 // Note: kRef == "$ref", kSchema == "$schema" 74 // Note: kRef == "$ref", kSchema == "$schema"
73 { schema::kRef, base::Value::TYPE_STRING }, 75 { schema::kRef, base::Value::TYPE_STRING },
74 { schema::kSchema, base::Value::TYPE_STRING }, 76 { schema::kSchema, base::Value::TYPE_STRING },
75 77
76 { schema::kAdditionalProperties, base::Value::TYPE_DICTIONARY }, 78 { schema::kAdditionalProperties, base::Value::TYPE_DICTIONARY },
77 { schema::kChoices, base::Value::TYPE_LIST }, 79 { schema::kChoices, base::Value::TYPE_LIST },
78 { schema::kDescription, base::Value::TYPE_STRING }, 80 { schema::kDescription, base::Value::TYPE_STRING },
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 *error = "Invalid value for type attribute"; 121 *error = "Invalid value for type attribute";
120 return false; 122 return false;
121 } 123 }
122 has_type_or_ref = true; 124 has_type_or_ref = true;
123 continue; 125 continue;
124 } 126 }
125 127
126 // Validate the "items" attribute, which is a schema or a list of schemas. 128 // Validate the "items" attribute, which is a schema or a list of schemas.
127 if (it.key() == schema::kItems) { 129 if (it.key() == schema::kItems) {
128 if (it.value().GetAsDictionary(&dictionary_value)) { 130 if (it.value().GetAsDictionary(&dictionary_value)) {
129 if (!IsValidSchema(dictionary_value, error)) { 131 if (!IsValidSchema(dictionary_value, ignore_unknown_attrs, error)) {
130 DCHECK(!error->empty()); 132 DCHECK(!error->empty());
131 return false; 133 return false;
132 } 134 }
133 } else if (it.value().GetAsList(&list_value)) { 135 } else if (it.value().GetAsList(&list_value)) {
134 for (size_t i = 0; i < list_value->GetSize(); ++i) { 136 for (size_t i = 0; i < list_value->GetSize(); ++i) {
135 if (!list_value->GetDictionary(i, &dictionary_value)) { 137 if (!list_value->GetDictionary(i, &dictionary_value)) {
136 *error = base::StringPrintf( 138 *error = base::StringPrintf(
137 "Invalid entry in items attribute at index %d", 139 "Invalid entry in items attribute at index %d",
138 static_cast<int>(i)); 140 static_cast<int>(i));
139 return false; 141 return false;
140 } 142 }
141 if (!IsValidSchema(dictionary_value, error)) { 143 if (!IsValidSchema(dictionary_value, ignore_unknown_attrs, error)) {
142 DCHECK(!error->empty()); 144 DCHECK(!error->empty());
143 return false; 145 return false;
144 } 146 }
145 } 147 }
146 } else { 148 } else {
147 *error = "Invalid value for items attribute"; 149 *error = "Invalid value for items attribute";
148 return false; 150 return false;
149 } 151 }
150 continue; 152 continue;
151 } 153 }
152 154
153 // All the other attributes have a single valid type. 155 // All the other attributes have a single valid type.
154 const ExpectedType* end = kExpectedTypes + arraysize(kExpectedTypes); 156 const ExpectedType* end = kExpectedTypes + arraysize(kExpectedTypes);
155 const ExpectedType* entry = std::lower_bound( 157 const ExpectedType* entry = std::lower_bound(
156 kExpectedTypes, end, it.key(), CompareToString); 158 kExpectedTypes, end, it.key(), CompareToString);
157 if (entry == end || entry->key != it.key()) { 159 if (entry == end || entry->key != it.key()) {
158 *error = base::StringPrintf("Invalid attribute %s", it.key().c_str()); 160 if (!ignore_unknown_attrs) {
not at google - send to devlin 2013/12/06 18:12:26 i.e. an option such that this would be if (!(opti
159 return false; 161 *error = base::StringPrintf("Invalid attribute %s", it.key().c_str());
162 return false;
163 }
164 continue;
160 } 165 }
166
161 if (!it.value().IsType(entry->type)) { 167 if (!it.value().IsType(entry->type)) {
162 *error = base::StringPrintf("Invalid value for %s attribute", 168 *error = base::StringPrintf("Invalid value for %s attribute",
163 it.key().c_str()); 169 it.key().c_str());
164 return false; 170 return false;
165 } 171 }
166 172
167 // base::Value::TYPE_INTEGER attributes must be >= 0. 173 // base::Value::TYPE_INTEGER attributes must be >= 0.
168 // This applies to "minItems", "maxItems", "minLength" and "maxLength". 174 // This applies to "minItems", "maxItems", "minLength" and "maxLength".
169 if (it.value().IsType(base::Value::TYPE_INTEGER)) { 175 if (it.value().IsType(base::Value::TYPE_INTEGER)) {
170 int integer_value; 176 int integer_value;
171 it.value().GetAsInteger(&integer_value); 177 it.value().GetAsInteger(&integer_value);
172 if (integer_value < 0) { 178 if (integer_value < 0) {
173 *error = base::StringPrintf("Value of %s must be >= 0, got %d", 179 *error = base::StringPrintf("Value of %s must be >= 0, got %d",
174 it.key().c_str(), integer_value); 180 it.key().c_str(), integer_value);
175 return false; 181 return false;
176 } 182 }
177 } 183 }
178 184
179 // Validate the "properties" attribute. Each entry maps a key to a schema. 185 // Validate the "properties" attribute. Each entry maps a key to a schema.
180 if (it.key() == schema::kProperties) { 186 if (it.key() == schema::kProperties) {
181 it.value().GetAsDictionary(&dictionary_value); 187 it.value().GetAsDictionary(&dictionary_value);
182 for (base::DictionaryValue::Iterator it(*dictionary_value); 188 for (base::DictionaryValue::Iterator it(*dictionary_value);
183 !it.IsAtEnd(); it.Advance()) { 189 !it.IsAtEnd(); it.Advance()) {
184 if (!it.value().GetAsDictionary(&dictionary_value)) { 190 if (!it.value().GetAsDictionary(&dictionary_value)) {
185 *error = "Invalid value for properties attribute"; 191 *error = "Invalid value for properties attribute";
186 return false; 192 return false;
187 } 193 }
188 if (!IsValidSchema(dictionary_value, error)) { 194 if (!IsValidSchema(dictionary_value, ignore_unknown_attrs, error)) {
189 DCHECK(!error->empty()); 195 DCHECK(!error->empty());
190 return false; 196 return false;
191 } 197 }
192 } 198 }
193 } 199 }
194 200
195 // Validate "additionalProperties" attribute, which is a schema. 201 // Validate "additionalProperties" attribute, which is a schema.
196 if (it.key() == schema::kAdditionalProperties) { 202 if (it.key() == schema::kAdditionalProperties) {
197 it.value().GetAsDictionary(&dictionary_value); 203 it.value().GetAsDictionary(&dictionary_value);
198 if (!IsValidSchema(dictionary_value, error)) { 204 if (!IsValidSchema(dictionary_value, ignore_unknown_attrs, error)) {
199 DCHECK(!error->empty()); 205 DCHECK(!error->empty());
200 return false; 206 return false;
201 } 207 }
202 } 208 }
203 209
204 // Validate the values contained in an "enum" attribute. 210 // Validate the values contained in an "enum" attribute.
205 if (it.key() == schema::kEnum) { 211 if (it.key() == schema::kEnum) {
206 it.value().GetAsList(&list_value); 212 it.value().GetAsList(&list_value);
207 for (size_t i = 0; i < list_value->GetSize(); ++i) { 213 for (size_t i = 0; i < list_value->GetSize(); ++i) {
208 const base::Value* value = NULL; 214 const base::Value* value = NULL;
(...skipping 20 matching lines...) Expand all
229 } 235 }
230 236
231 // Validate the schemas contained in a "choices" attribute. 237 // Validate the schemas contained in a "choices" attribute.
232 if (it.key() == schema::kChoices) { 238 if (it.key() == schema::kChoices) {
233 it.value().GetAsList(&list_value); 239 it.value().GetAsList(&list_value);
234 for (size_t i = 0; i < list_value->GetSize(); ++i) { 240 for (size_t i = 0; i < list_value->GetSize(); ++i) {
235 if (!list_value->GetDictionary(i, &dictionary_value)) { 241 if (!list_value->GetDictionary(i, &dictionary_value)) {
236 *error = "Invalid choices attribute"; 242 *error = "Invalid choices attribute";
237 return false; 243 return false;
238 } 244 }
239 if (!IsValidSchema(dictionary_value, error)) { 245 if (!IsValidSchema(dictionary_value, ignore_unknown_attrs, error)) {
240 DCHECK(!error->empty()); 246 DCHECK(!error->empty());
241 return false; 247 return false;
242 } 248 }
243 } 249 }
244 } 250 }
245 251
246 if (it.key() == schema::kRef) 252 if (it.key() == schema::kRef)
247 has_type_or_ref = true; 253 has_type_or_ref = true;
248 } 254 }
249 255
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 const std::string& s2) { 354 const std::string& s2) {
349 std::string ret_val = format; 355 std::string ret_val = format;
350 ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1); 356 ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
351 ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s2); 357 ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s2);
352 return ret_val; 358 return ret_val;
353 } 359 }
354 360
355 // static 361 // static
356 scoped_ptr<base::DictionaryValue> JSONSchemaValidator::IsValidSchema( 362 scoped_ptr<base::DictionaryValue> JSONSchemaValidator::IsValidSchema(
357 const std::string& schema, 363 const std::string& schema,
364 bool ignore_unknown_attributes,
358 std::string* error) { 365 std::string* error) {
359 base::JSONParserOptions options = base::JSON_PARSE_RFC; 366 base::JSONParserOptions options = base::JSON_PARSE_RFC;
360 scoped_ptr<base::Value> json( 367 scoped_ptr<base::Value> json(
361 base::JSONReader::ReadAndReturnError(schema, options, NULL, error)); 368 base::JSONReader::ReadAndReturnError(schema, options, NULL, error));
362 if (!json) 369 if (!json)
363 return scoped_ptr<base::DictionaryValue>(); 370 return scoped_ptr<base::DictionaryValue>();
364 base::DictionaryValue* dict = NULL; 371 base::DictionaryValue* dict = NULL;
365 if (!json->GetAsDictionary(&dict)) { 372 if (!json->GetAsDictionary(&dict)) {
366 *error = "Schema must be a JSON object"; 373 *error = "Schema must be a JSON object";
367 return scoped_ptr<base::DictionaryValue>(); 374 return scoped_ptr<base::DictionaryValue>();
368 } 375 }
369 if (!::IsValidSchema(dict, error)) 376 if (!::IsValidSchema(dict, ignore_unknown_attributes, error))
370 return scoped_ptr<base::DictionaryValue>(); 377 return scoped_ptr<base::DictionaryValue>();
371 ignore_result(json.release()); 378 ignore_result(json.release());
372 return make_scoped_ptr(dict); 379 return make_scoped_ptr(dict);
373 } 380 }
374 381
375 JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema) 382 JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema)
376 : schema_root_(schema), default_allow_additional_properties_(false) { 383 : schema_root_(schema), default_allow_additional_properties_(false) {
377 } 384 }
378 385
379 JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema, 386 JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema,
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 753
747 if (*additional_properties_schema) { 754 if (*additional_properties_schema) {
748 std::string additional_properties_type(schema::kAny); 755 std::string additional_properties_type(schema::kAny);
749 CHECK((*additional_properties_schema)->GetString( 756 CHECK((*additional_properties_schema)->GetString(
750 schema::kType, &additional_properties_type)); 757 schema::kType, &additional_properties_type));
751 return additional_properties_type == schema::kAny; 758 return additional_properties_type == schema::kAny;
752 } else { 759 } else {
753 return default_allow_additional_properties_; 760 return default_allow_additional_properties_;
754 } 761 }
755 } 762 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698