1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_COMMON_JSON_SCHEMA_VALIDATOR_H_ 6 #define CHROME_COMMON_JSON_SCHEMA_VALIDATOR_H_ 7 8 #include <map> 9 #include <string> 10 #include <vector> 11 12 #include "base/basictypes.h" 13 14 class DictionaryValue; 15 class FundamentalValue; 16 class ListValue; 17 class StringValue; 18 class Value; 19 20 //============================================================================== 21 // This class implements a subset of JSON Schema. 22 // See: http://www.json.com/json-schema-proposal/ for more details. 23 // 24 // There is also an older JavaScript implementation of the same functionality in 25 // chrome/renderer/resources/json_schema.js. 26 // 27 // The following features of JSON Schema are not implemented: 28 // - requires 29 // - unique 30 // - disallow 31 // - union types (but replaced with 'choices') 32 // - number.maxDecimal 33 // - string.pattern 34 // 35 // The following properties are not applicable to the interface exposed by 36 // this class: 37 // - options 38 // - readonly 39 // - title 40 // - description 41 // - format 42 // - default 43 // - transient 44 // - hidden 45 // 46 // There are also these departures from the JSON Schema proposal: 47 // - null counts as 'unspecified' for optional values 48 // - added the 'choices' property, to allow specifying a list of possible types 49 // for a value 50 // - by default an "object" typed schema does not allow additional properties. 51 // if present, "additionalProperties" is to be a schema against which all 52 // additional properties will be validated. 53 //============================================================================== 54 class JSONSchemaValidator { 55 public: 56 // Details about a validation error. 57 struct Error { 58 Error(); 59 60 explicit Error(const std::string& message); 61 62 Error(const std::string& path, const std::string& message); 63 64 // The path to the location of the error in the JSON structure. 65 std::string path; 66 67 // An english message describing the error. 68 std::string message; 69 }; 70 71 // Error messages. 72 static const char kUnknownTypeReference[]; 73 static const char kInvalidChoice[]; 74 static const char kInvalidEnum[]; 75 static const char kObjectPropertyIsRequired[]; 76 static const char kUnexpectedProperty[]; 77 static const char kArrayMinItems[]; 78 static const char kArrayMaxItems[]; 79 static const char kArrayItemRequired[]; 80 static const char kStringMinLength[]; 81 static const char kStringMaxLength[]; 82 static const char kStringPattern[]; 83 static const char kNumberMinimum[]; 84 static const char kNumberMaximum[]; 85 static const char kInvalidType[]; 86 87 // Classifies a Value as one of the JSON schema primitive types. 88 static std::string GetJSONSchemaType(Value* value); 89 90 // Utility methods to format error messages. The first method can have one 91 // wildcard represented by '*', which is replaced with s1. The second method 92 // can have two, which are replaced by s1 and s2. 93 static std::string FormatErrorMessage(const std::string& format, 94 const std::string& s1); 95 static std::string FormatErrorMessage(const std::string& format, 96 const std::string& s1, 97 const std::string& s2); 98 99 // Creates a validator for the specified schema. 100 // 101 // NOTE: This constructor assumes that |schema| is well formed and valid. 102 // Errors will result in CHECK at runtime; this constructor should not be used 103 // with untrusted schemas. 104 explicit JSONSchemaValidator(DictionaryValue* schema); 105 106 // Creates a validator for the specified schema and user-defined types. Each 107 // type must be a valid JSONSchema type description with an additional "id" 108 // field. Schema objects in |schema| can refer to these types with the "$ref" 109 // property. 110 // 111 // NOTE: This constructor assumes that |schema| and |types| are well-formed 112 // and valid. Errors will result in CHECK at runtime; this constructor should 113 // not be used with untrusted schemas. 114 JSONSchemaValidator(DictionaryValue* schema, ListValue* types); 115 116 ~JSONSchemaValidator(); 117 118 // Whether the validator allows additional items for objects and lists, beyond 119 // those defined by their schema, by default. 120 // 121 // This setting defaults to false: all items in an instance list or object 122 // must be defined by the corresponding schema. 123 // 124 // This setting can be overridden on individual object and list schemas by 125 // setting the "additionalProperties" field. 126 bool default_allow_additional_properties() const { 127 return default_allow_additional_properties_; 128 } 129 130 void set_default_allow_additional_properties(bool val) { 131 default_allow_additional_properties_ = val; 132 } 133 134 // Returns any errors from the last call to to Validate(). 135 const std::vector<Error>& errors() const { 136 return errors_; 137 } 138 139 // Validates a JSON value. Returns true if the instance is valid, false 140 // otherwise. If false is returned any errors are available from the errors() 141 // getter. 142 bool Validate(Value* instance); 143 144 private: 145 typedef std::map<std::string, DictionaryValue*> TypeMap; 146 147 // Each of the below methods handle a subset of the validation process. The 148 // path paramater is the path to |instance| from the root of the instance tree 149 // and is used in error messages. 150 151 // Validates any instance node against any schema node. This is called for 152 // every node in the instance tree, and it just decides which of the more 153 // detailed methods to call. 154 void Validate(Value* instance, DictionaryValue* schema, 155 const std::string& path); 156 157 // Validates a node against a list of possible schemas. If any one of the 158 // schemas match, the node is valid. 159 void ValidateChoices(Value* instance, ListValue* choices, 160 const std::string& path); 161 162 // Validates a node against a list of exact primitive values, eg 42, "foobar". 163 void ValidateEnum(Value* instance, ListValue* choices, 164 const std::string& path); 165 166 // Validates a JSON object against an object schema node. 167 void ValidateObject(DictionaryValue* instance, DictionaryValue* schema, 168 const std::string& path); 169 170 // Validates a JSON array against an array schema node. 171 void ValidateArray(ListValue* instance, DictionaryValue* schema, 172 const std::string& path); 173 174 // Validates a JSON array against an array schema node configured to be a 175 // tuple. In a tuple, there is one schema node for each item expected in the 176 // array. 177 void ValidateTuple(ListValue* instance, DictionaryValue* schema, 178 const std::string& path); 179 180 // Validate a JSON string against a string schema node. 181 void ValidateString(StringValue* instance, DictionaryValue* schema, 182 const std::string& path); 183 184 // Validate a JSON number against a number schema node. 185 void ValidateNumber(Value* instance, DictionaryValue* schema, 186 const std::string& path); 187 188 // Validates that the JSON node |instance| has |expected_type|. 189 bool ValidateType(Value* instance, const std::string& expected_type, 190 const std::string& path); 191 192 // Returns true if |schema| will allow additional items of any type. 193 bool SchemaAllowsAnyAdditionalItems( 194 DictionaryValue* schema, DictionaryValue** addition_items_schema); 195 196 // The root schema node. 197 DictionaryValue* schema_root_; 198 199 // Map of user-defined name to type. 200 TypeMap types_; 201 202 // Whether we allow additional properties on objects by default. This can be 203 // overridden by the allow_additional_properties flag on an Object schema. 204 bool default_allow_additional_properties_; 205 206 // Errors accumulated since the last call to Validate(). 207 std::vector<Error> errors_; 208 209 210 DISALLOW_COPY_AND_ASSIGN(JSONSchemaValidator); 211 }; 212 213 #endif // CHROME_COMMON_JSON_SCHEMA_VALIDATOR_H_ 214