• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
default_allow_additional_properties()126   bool default_allow_additional_properties() const {
127     return default_allow_additional_properties_;
128   }
129 
set_default_allow_additional_properties(bool val)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().
errors()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