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
3// found in the LICENSE file.
4
5#ifndef COMPONENTS_POLICY_CORE_COMMON_SCHEMA_H_
6#define COMPONENTS_POLICY_CORE_COMMON_SCHEMA_H_
7
8#include <string>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/memory/ref_counted.h"
13#include "base/values.h"
14#include "components/policy/policy_export.h"
15
16namespace policy {
17namespace internal {
18
19struct POLICY_EXPORT SchemaData;
20struct POLICY_EXPORT SchemaNode;
21struct POLICY_EXPORT PropertyNode;
22struct POLICY_EXPORT PropertiesNode;
23
24}  // namespace internal
25
26// Option flags passed to Schema::Validate() and Schema::Normalize(), describing
27// the strategy to handle unknown properties or invalid values for dict type.
28// Note that in Schema::Normalize() allowed errors will be dropped and thus
29// ignored.
30// Unknown error indicates that some value in a dictionary (may or may not be
31// the one in root) have unknown property name according to schema.
32// Invalid error indicates a validation failure against the schema. As
33// validation is done recursively, a validation failure of dict properties or
34// list items might be ignored (or dropped in Normalize()) or trigger whole
35// dictionary/list validation failure.
36enum SchemaOnErrorStrategy {
37  // No errors will be allowed.
38  SCHEMA_STRICT = 0,
39  // Unknown properties in the top-level dictionary will be ignored.
40  SCHEMA_ALLOW_UNKNOWN_TOPLEVEL,
41  // Unknown properties in any dictionary will be ignored.
42  SCHEMA_ALLOW_UNKNOWN,
43  // Mismatched values will be ignored at the toplevel.
44  SCHEMA_ALLOW_INVALID_TOPLEVEL,
45  // Mismatched values will be ignored at the top-level value.
46  // Unknown properties in any dictionary will be ignored.
47  SCHEMA_ALLOW_INVALID_TOPLEVEL_AND_ALLOW_UNKNOWN,
48  // Mismatched values will be ignored.
49  SCHEMA_ALLOW_INVALID,
50};
51
52class Schema;
53
54typedef std::vector<Schema> SchemaList;
55
56// Describes the expected type of one policy. Also recursively describes the
57// types of inner elements, for structured types.
58// Objects of this class refer to external, immutable data and are cheap to
59// copy.
60class POLICY_EXPORT Schema {
61 public:
62  // Used internally to store shared data.
63  class InternalStorage;
64
65  // Builds an empty, invalid schema.
66  Schema();
67
68  // Makes a copy of |schema| that shares the same internal storage.
69  Schema(const Schema& schema);
70
71  ~Schema();
72
73  Schema& operator=(const Schema& schema);
74
75  // Returns a Schema that references static data. This can be used by
76  // the embedder to pass structures generated at compile time, which can then
77  // be quickly loaded at runtime.
78  static Schema Wrap(const internal::SchemaData* data);
79
80  // Parses the JSON schema in |schema| and returns a Schema that owns
81  // the internal representation. If |schema| is invalid then an invalid Schema
82  // is returned and |error| contains a reason for the failure.
83  static Schema Parse(const std::string& schema, std::string* error);
84
85  // Returns true if this Schema is valid. Schemas returned by the methods below
86  // may be invalid, and in those cases the other methods must not be used.
87  bool valid() const { return node_ != NULL; }
88
89  base::Value::Type type() const;
90
91  // Validate |value| against current schema, |strategy| is the strategy to
92  // handle unknown properties or invalid values. Allowed errors will be
93  // ignored. |error_path| and |error| will contain the last error location and
94  // detailed message if |value| doesn't strictly conform to the schema. If
95  // |value| doesn't conform to the schema even within the allowance of
96  // |strategy|, false will be returned and |error_path| and |error| will
97  // contain the corresponding error that caused the failure. |error_path| can
98  // be NULL and in that case no error path will be returned.
99  bool Validate(const base::Value& value,
100                SchemaOnErrorStrategy strategy,
101                std::string* error_path,
102                std::string* error) const;
103
104  // Similar to Validate() but drop values with errors instead of ignoring them.
105  // |changed| is a pointer to a boolean value, and indicate whether |value|
106  // is changed or not (probably dropped properties or items). Be sure to set
107  // the bool that |changed| pointed to to false before calling Normalize().
108  // |changed| can be NULL and in that case no boolean will be set.
109  // This function will also take the ownership of dropped base::Value and
110  // destroy them.
111  bool Normalize(base::Value* value,
112                 SchemaOnErrorStrategy strategy,
113                 std::string* error_path,
114                 std::string* error,
115                 bool* changed) const;
116
117  // Used to iterate over the known properties of TYPE_DICTIONARY schemas.
118  class POLICY_EXPORT Iterator {
119   public:
120    Iterator(const scoped_refptr<const InternalStorage>& storage,
121             const internal::PropertiesNode* node);
122    Iterator(const Iterator& iterator);
123    ~Iterator();
124
125    Iterator& operator=(const Iterator& iterator);
126
127    // The other methods must not be called if the iterator is at the end.
128    bool IsAtEnd() const;
129
130    // Advances the iterator to the next property.
131    void Advance();
132
133    // Returns the name of the current property.
134    const char* key() const;
135
136    // Returns the Schema for the current property. This Schema is always valid.
137    Schema schema() const;
138
139   private:
140    scoped_refptr<const InternalStorage> storage_;
141    const internal::PropertyNode* it_;
142    const internal::PropertyNode* end_;
143  };
144
145  // These methods should be called only if type() == TYPE_DICTIONARY,
146  // otherwise invalid memory will be read. A CHECK is currently enforcing this.
147
148  // Returns an iterator that goes over the named properties of this schema.
149  // The returned iterator is at the beginning.
150  Iterator GetPropertiesIterator() const;
151
152  // Returns the Schema for the property named |key|. If |key| is not a known
153  // property name then the returned Schema is not valid.
154  Schema GetKnownProperty(const std::string& key) const;
155
156  // Returns all Schemas from pattern properties that match |key|. May be empty.
157  SchemaList GetPatternProperties(const std::string& key) const;
158
159  // Returns the Schema for additional properties. If additional properties are
160  // not allowed for this Schema then the Schema returned is not valid.
161  Schema GetAdditionalProperties() const;
162
163  // Returns the Schema for |key| if it is a known property, otherwise returns
164  // the Schema for additional properties.
165  // DEPRECATED: This function didn't consider patternProperties, use
166  // GetMatchingProperties() instead.
167  // TODO(binjin): Replace calls to this function with GetKnownProperty() or
168  // GetMatchingProperties() and remove this later.
169  Schema GetProperty(const std::string& key) const;
170
171  // Returns all Schemas that are supposed to be validated against for |key|.
172  // May be empty.
173  SchemaList GetMatchingProperties(const std::string& key) const;
174
175  // Returns the Schema for items of an array.
176  // This method should be called only if type() == TYPE_LIST,
177  // otherwise invalid memory will be read. A CHECK is currently enforcing this.
178  Schema GetItems() const;
179
180 private:
181  // Builds a schema pointing to the inner structure of |storage|,
182  // rooted at |node|.
183  Schema(const scoped_refptr<const InternalStorage>& storage,
184         const internal::SchemaNode* node);
185
186  bool ValidateIntegerRestriction(int index, int value) const;
187  bool ValidateStringRestriction(int index, const char* str) const;
188
189  scoped_refptr<const InternalStorage> storage_;
190  const internal::SchemaNode* node_;
191};
192
193}  // namespace policy
194
195#endif  // COMPONENTS_POLICY_CORE_COMMON_SCHEMA_H_
196