252 lines
9.5 KiB
C++
252 lines
9.5 KiB
C++
// Copyright 2013 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef COMPONENTS_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_H_
|
|
#define COMPONENTS_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_H_
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "base/macros.h"
|
|
|
|
namespace base {
|
|
class DictionaryValue;
|
|
class ListValue;
|
|
class Value;
|
|
}
|
|
|
|
//==============================================================================
|
|
// This class implements a subset of JSON Schema.
|
|
// See: http://www.json.com/json-schema-proposal/ for more details.
|
|
//
|
|
// There is also an older JavaScript implementation of the same functionality in
|
|
// chrome/renderer/resources/json_schema.js.
|
|
//
|
|
// The following features of JSON Schema are not implemented:
|
|
// - requires
|
|
// - unique
|
|
// - disallow
|
|
// - union types (but replaced with 'choices')
|
|
// - number.maxDecimal
|
|
//
|
|
// The following properties are not applicable to the interface exposed by
|
|
// this class:
|
|
// - options
|
|
// - readonly
|
|
// - title
|
|
// - description
|
|
// - format
|
|
// - default
|
|
// - transient
|
|
// - hidden
|
|
//
|
|
// There are also these departures from the JSON Schema proposal:
|
|
// - null counts as 'unspecified' for optional values
|
|
// - added the 'choices' property, to allow specifying a list of possible types
|
|
// for a value
|
|
// - by default an "object" typed schema does not allow additional properties.
|
|
// if present, "additionalProperties" is to be a schema against which all
|
|
// additional properties will be validated.
|
|
// - regular expression supports all syntaxes that re2 accepts.
|
|
// See https://github.com/google/re2/blob/master/doc/syntax.txt for details.
|
|
//==============================================================================
|
|
class JSONSchemaValidator {
|
|
public:
|
|
// Details about a validation error.
|
|
struct Error {
|
|
Error();
|
|
|
|
explicit Error(const std::string& message);
|
|
|
|
Error(const std::string& path, const std::string& message);
|
|
|
|
// The path to the location of the error in the JSON structure.
|
|
std::string path;
|
|
|
|
// An english message describing the error.
|
|
std::string message;
|
|
};
|
|
|
|
enum Options {
|
|
// Ignore unknown attributes. If this option is not set then unknown
|
|
// attributes will make the schema validation fail.
|
|
OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES = 1 << 0,
|
|
};
|
|
|
|
// Error messages.
|
|
static const char kUnknownTypeReference[];
|
|
static const char kInvalidChoice[];
|
|
static const char kInvalidEnum[];
|
|
static const char kObjectPropertyIsRequired[];
|
|
static const char kUnexpectedProperty[];
|
|
static const char kArrayMinItems[];
|
|
static const char kArrayMaxItems[];
|
|
static const char kArrayItemRequired[];
|
|
static const char kStringMinLength[];
|
|
static const char kStringMaxLength[];
|
|
static const char kStringPattern[];
|
|
static const char kNumberMinimum[];
|
|
static const char kNumberMaximum[];
|
|
static const char kInvalidType[];
|
|
static const char kInvalidTypeIntegerNumber[];
|
|
static const char kInvalidRegex[];
|
|
|
|
// Classifies a Value as one of the JSON schema primitive types.
|
|
static std::string GetJSONSchemaType(const base::Value* value);
|
|
|
|
// Utility methods to format error messages. The first method can have one
|
|
// wildcard represented by '*', which is replaced with s1. The second method
|
|
// can have two, which are replaced by s1 and s2.
|
|
static std::string FormatErrorMessage(const std::string& format,
|
|
const std::string& s1);
|
|
static std::string FormatErrorMessage(const std::string& format,
|
|
const std::string& s1,
|
|
const std::string& s2);
|
|
|
|
// Verifies if |schema| is a valid JSON v3 schema. When this validation passes
|
|
// then |schema| is valid JSON that can be parsed into a DictionaryValue,
|
|
// and that DictionaryValue can be used to build a JSONSchemaValidator.
|
|
// Returns the parsed DictionaryValue when |schema| validated, otherwise
|
|
// returns NULL. In that case, |error| contains an error description.
|
|
// For performance reasons, currently IsValidSchema() won't check the
|
|
// correctness of regular expressions used in "pattern" and
|
|
// "patternProperties" and in Validate() invalid regular expression don't
|
|
// accept any strings.
|
|
static std::unique_ptr<base::DictionaryValue> IsValidSchema(
|
|
const std::string& schema,
|
|
std::string* error);
|
|
|
|
// Same as above but with |options|, which is a bitwise-OR combination of the
|
|
// Options above.
|
|
static std::unique_ptr<base::DictionaryValue>
|
|
IsValidSchema(const std::string& schema, int options, std::string* error);
|
|
|
|
// Creates a validator for the specified schema.
|
|
//
|
|
// NOTE: This constructor assumes that |schema| is well formed and valid.
|
|
// Errors will result in CHECK at runtime; this constructor should not be used
|
|
// with untrusted schemas.
|
|
explicit JSONSchemaValidator(base::DictionaryValue* schema);
|
|
|
|
// Creates a validator for the specified schema and user-defined types. Each
|
|
// type must be a valid JSONSchema type description with an additional "id"
|
|
// field. Schema objects in |schema| can refer to these types with the "$ref"
|
|
// property.
|
|
//
|
|
// NOTE: This constructor assumes that |schema| and |types| are well-formed
|
|
// and valid. Errors will result in CHECK at runtime; this constructor should
|
|
// not be used with untrusted schemas.
|
|
JSONSchemaValidator(base::DictionaryValue* schema, base::ListValue* types);
|
|
|
|
~JSONSchemaValidator();
|
|
|
|
// Whether the validator allows additional items for objects and lists, beyond
|
|
// those defined by their schema, by default.
|
|
//
|
|
// This setting defaults to false: all items in an instance list or object
|
|
// must be defined by the corresponding schema.
|
|
//
|
|
// This setting can be overridden on individual object and list schemas by
|
|
// setting the "additionalProperties" field.
|
|
bool default_allow_additional_properties() const {
|
|
return default_allow_additional_properties_;
|
|
}
|
|
|
|
void set_default_allow_additional_properties(bool val) {
|
|
default_allow_additional_properties_ = val;
|
|
}
|
|
|
|
// Returns any errors from the last call to to Validate().
|
|
const std::vector<Error>& errors() const {
|
|
return errors_;
|
|
}
|
|
|
|
// Validates a JSON value. Returns true if the instance is valid, false
|
|
// otherwise. If false is returned any errors are available from the errors()
|
|
// getter.
|
|
bool Validate(const base::Value* instance);
|
|
|
|
private:
|
|
typedef std::map<std::string, const base::DictionaryValue*> TypeMap;
|
|
|
|
// Each of the below methods handle a subset of the validation process. The
|
|
// path paramater is the path to |instance| from the root of the instance tree
|
|
// and is used in error messages.
|
|
|
|
// Validates any instance node against any schema node. This is called for
|
|
// every node in the instance tree, and it just decides which of the more
|
|
// detailed methods to call.
|
|
void Validate(const base::Value* instance,
|
|
const base::DictionaryValue* schema,
|
|
const std::string& path);
|
|
|
|
// Validates a node against a list of possible schemas. If any one of the
|
|
// schemas match, the node is valid.
|
|
void ValidateChoices(const base::Value* instance,
|
|
const base::ListValue* choices,
|
|
const std::string& path);
|
|
|
|
// Validates a node against a list of exact primitive values, eg 42, "foobar".
|
|
void ValidateEnum(const base::Value* instance,
|
|
const base::ListValue* choices,
|
|
const std::string& path);
|
|
|
|
// Validates a JSON object against an object schema node.
|
|
void ValidateObject(const base::DictionaryValue* instance,
|
|
const base::DictionaryValue* schema,
|
|
const std::string& path);
|
|
|
|
// Validates a JSON array against an array schema node.
|
|
void ValidateArray(const base::ListValue* instance,
|
|
const base::DictionaryValue* schema,
|
|
const std::string& path);
|
|
|
|
// Validates a JSON array against an array schema node configured to be a
|
|
// tuple. In a tuple, there is one schema node for each item expected in the
|
|
// array.
|
|
void ValidateTuple(const base::ListValue* instance,
|
|
const base::DictionaryValue* schema,
|
|
const std::string& path);
|
|
|
|
// Validate a JSON string against a string schema node.
|
|
void ValidateString(const base::Value* instance,
|
|
const base::DictionaryValue* schema,
|
|
const std::string& path);
|
|
|
|
// Validate a JSON number against a number schema node.
|
|
void ValidateNumber(const base::Value* instance,
|
|
const base::DictionaryValue* schema,
|
|
const std::string& path);
|
|
|
|
// Validates that the JSON node |instance| has |expected_type|.
|
|
bool ValidateType(const base::Value* instance,
|
|
const std::string& expected_type,
|
|
const std::string& path);
|
|
|
|
// Returns true if |schema| will allow additional items of any type.
|
|
bool SchemaAllowsAnyAdditionalItems(
|
|
const base::DictionaryValue* schema,
|
|
const base::DictionaryValue** addition_items_schema);
|
|
|
|
// The root schema node.
|
|
base::DictionaryValue* schema_root_;
|
|
|
|
// Map of user-defined name to type.
|
|
TypeMap types_;
|
|
|
|
// Whether we allow additional properties on objects by default. This can be
|
|
// overridden by the allow_additional_properties flag on an Object schema.
|
|
bool default_allow_additional_properties_;
|
|
|
|
// Errors accumulated since the last call to Validate().
|
|
std::vector<Error> errors_;
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(JSONSchemaValidator);
|
|
};
|
|
|
|
#endif // COMPONENTS_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_H_
|