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

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 Options enum 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 int options,
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, options, 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, options, 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()) {
160 if (options & JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES)
161 continue;
158 *error = base::StringPrintf("Invalid attribute %s", it.key().c_str()); 162 *error = base::StringPrintf("Invalid attribute %s", it.key().c_str());
159 return false; 163 return false;
160 } 164 }
165
161 if (!it.value().IsType(entry->type)) { 166 if (!it.value().IsType(entry->type)) {
162 *error = base::StringPrintf("Invalid value for %s attribute", 167 *error = base::StringPrintf("Invalid value for %s attribute",
163 it.key().c_str()); 168 it.key().c_str());
164 return false; 169 return false;
165 } 170 }
166 171
167 // base::Value::TYPE_INTEGER attributes must be >= 0. 172 // base::Value::TYPE_INTEGER attributes must be >= 0.
168 // This applies to "minItems", "maxItems", "minLength" and "maxLength". 173 // This applies to "minItems", "maxItems", "minLength" and "maxLength".
169 if (it.value().IsType(base::Value::TYPE_INTEGER)) { 174 if (it.value().IsType(base::Value::TYPE_INTEGER)) {
170 int integer_value; 175 int integer_value;
171 it.value().GetAsInteger(&integer_value); 176 it.value().GetAsInteger(&integer_value);
172 if (integer_value < 0) { 177 if (integer_value < 0) {
173 *error = base::StringPrintf("Value of %s must be >= 0, got %d", 178 *error = base::StringPrintf("Value of %s must be >= 0, got %d",
174 it.key().c_str(), integer_value); 179 it.key().c_str(), integer_value);
175 return false; 180 return false;
176 } 181 }
177 } 182 }
178 183
179 // Validate the "properties" attribute. Each entry maps a key to a schema. 184 // Validate the "properties" attribute. Each entry maps a key to a schema.
180 if (it.key() == schema::kProperties) { 185 if (it.key() == schema::kProperties) {
181 it.value().GetAsDictionary(&dictionary_value); 186 it.value().GetAsDictionary(&dictionary_value);
182 for (base::DictionaryValue::Iterator it(*dictionary_value); 187 for (base::DictionaryValue::Iterator it(*dictionary_value);
183 !it.IsAtEnd(); it.Advance()) { 188 !it.IsAtEnd(); it.Advance()) {
184 if (!it.value().GetAsDictionary(&dictionary_value)) { 189 if (!it.value().GetAsDictionary(&dictionary_value)) {
185 *error = "Invalid value for properties attribute"; 190 *error = "Invalid value for properties attribute";
186 return false; 191 return false;
187 } 192 }
188 if (!IsValidSchema(dictionary_value, error)) { 193 if (!IsValidSchema(dictionary_value, options, error)) {
189 DCHECK(!error->empty()); 194 DCHECK(!error->empty());
190 return false; 195 return false;
191 } 196 }
192 } 197 }
193 } 198 }
194 199
195 // Validate "additionalProperties" attribute, which is a schema. 200 // Validate "additionalProperties" attribute, which is a schema.
196 if (it.key() == schema::kAdditionalProperties) { 201 if (it.key() == schema::kAdditionalProperties) {
197 it.value().GetAsDictionary(&dictionary_value); 202 it.value().GetAsDictionary(&dictionary_value);
198 if (!IsValidSchema(dictionary_value, error)) { 203 if (!IsValidSchema(dictionary_value, options, error)) {
199 DCHECK(!error->empty()); 204 DCHECK(!error->empty());
200 return false; 205 return false;
201 } 206 }
202 } 207 }
203 208
204 // Validate the values contained in an "enum" attribute. 209 // Validate the values contained in an "enum" attribute.
205 if (it.key() == schema::kEnum) { 210 if (it.key() == schema::kEnum) {
206 it.value().GetAsList(&list_value); 211 it.value().GetAsList(&list_value);
207 for (size_t i = 0; i < list_value->GetSize(); ++i) { 212 for (size_t i = 0; i < list_value->GetSize(); ++i) {
208 const base::Value* value = NULL; 213 const base::Value* value = NULL;
(...skipping 20 matching lines...) Expand all
229 } 234 }
230 235
231 // Validate the schemas contained in a "choices" attribute. 236 // Validate the schemas contained in a "choices" attribute.
232 if (it.key() == schema::kChoices) { 237 if (it.key() == schema::kChoices) {
233 it.value().GetAsList(&list_value); 238 it.value().GetAsList(&list_value);
234 for (size_t i = 0; i < list_value->GetSize(); ++i) { 239 for (size_t i = 0; i < list_value->GetSize(); ++i) {
235 if (!list_value->GetDictionary(i, &dictionary_value)) { 240 if (!list_value->GetDictionary(i, &dictionary_value)) {
236 *error = "Invalid choices attribute"; 241 *error = "Invalid choices attribute";
237 return false; 242 return false;
238 } 243 }
239 if (!IsValidSchema(dictionary_value, error)) { 244 if (!IsValidSchema(dictionary_value, options, error)) {
240 DCHECK(!error->empty()); 245 DCHECK(!error->empty());
241 return false; 246 return false;
242 } 247 }
243 } 248 }
244 } 249 }
245 250
246 if (it.key() == schema::kRef) 251 if (it.key() == schema::kRef)
247 has_type_or_ref = true; 252 has_type_or_ref = true;
248 } 253 }
249 254
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 std::string ret_val = format; 354 std::string ret_val = format;
350 ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1); 355 ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
351 ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s2); 356 ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s2);
352 return ret_val; 357 return ret_val;
353 } 358 }
354 359
355 // static 360 // static
356 scoped_ptr<base::DictionaryValue> JSONSchemaValidator::IsValidSchema( 361 scoped_ptr<base::DictionaryValue> JSONSchemaValidator::IsValidSchema(
357 const std::string& schema, 362 const std::string& schema,
358 std::string* error) { 363 std::string* error) {
359 base::JSONParserOptions options = base::JSON_PARSE_RFC; 364 return JSONSchemaValidator::IsValidSchema(schema, 0, error);
365 }
366
367 // static
368 scoped_ptr<base::DictionaryValue> JSONSchemaValidator::IsValidSchema(
369 const std::string& schema,
370 int validator_options,
371 std::string* error) {
372 base::JSONParserOptions json_options = base::JSON_PARSE_RFC;
360 scoped_ptr<base::Value> json( 373 scoped_ptr<base::Value> json(
361 base::JSONReader::ReadAndReturnError(schema, options, NULL, error)); 374 base::JSONReader::ReadAndReturnError(schema, json_options, NULL, error));
362 if (!json) 375 if (!json)
363 return scoped_ptr<base::DictionaryValue>(); 376 return scoped_ptr<base::DictionaryValue>();
364 base::DictionaryValue* dict = NULL; 377 base::DictionaryValue* dict = NULL;
365 if (!json->GetAsDictionary(&dict)) { 378 if (!json->GetAsDictionary(&dict)) {
366 *error = "Schema must be a JSON object"; 379 *error = "Schema must be a JSON object";
367 return scoped_ptr<base::DictionaryValue>(); 380 return scoped_ptr<base::DictionaryValue>();
368 } 381 }
369 if (!::IsValidSchema(dict, error)) 382 if (!::IsValidSchema(dict, validator_options, error))
370 return scoped_ptr<base::DictionaryValue>(); 383 return scoped_ptr<base::DictionaryValue>();
371 ignore_result(json.release()); 384 ignore_result(json.release());
372 return make_scoped_ptr(dict); 385 return make_scoped_ptr(dict);
373 } 386 }
374 387
375 JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema) 388 JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema)
376 : schema_root_(schema), default_allow_additional_properties_(false) { 389 : schema_root_(schema), default_allow_additional_properties_(false) {
377 } 390 }
378 391
379 JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema, 392 JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema,
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 759
747 if (*additional_properties_schema) { 760 if (*additional_properties_schema) {
748 std::string additional_properties_type(schema::kAny); 761 std::string additional_properties_type(schema::kAny);
749 CHECK((*additional_properties_schema)->GetString( 762 CHECK((*additional_properties_schema)->GetString(
750 schema::kType, &additional_properties_type)); 763 schema::kType, &additional_properties_type));
751 return additional_properties_type == schema::kAny; 764 return additional_properties_type == schema::kAny;
752 } else { 765 } else {
753 return default_allow_additional_properties_; 766 return default_allow_additional_properties_;
754 } 767 }
755 } 768 }
OLDNEW
« 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