Index: chrome/browser/policy/policy_schema.cc |
diff --git a/chrome/browser/policy/policy_schema.cc b/chrome/browser/policy/policy_schema.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c693140d1f01170e1a0c319a1d8d4e3730e8a5f5 |
--- /dev/null |
+++ b/chrome/browser/policy/policy_schema.cc |
@@ -0,0 +1,244 @@ |
+// Copyright (c) 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. |
+ |
+#include "chrome/browser/policy/policy_schema.h" |
+ |
+#include "base/compiler_specific.h" |
+#include "base/logging.h" |
+#include "base/stl_util.h" |
+#include "chrome/common/json_schema/json_schema_constants.h" |
+#include "chrome/common/json_schema/json_schema_validator.h" |
+ |
+namespace policy { |
+ |
+namespace { |
+ |
+const char kJSONSchemaVersion[] = "http://json-schema.org/draft-03/schema#"; |
+ |
+// Describes the properties of a TYPE_DICTIONARY policy schema. |
+class DictionaryPolicySchema : public PolicySchema { |
+ public: |
+ static scoped_ptr<PolicySchema> Parse(const base::DictionaryValue& schema, |
+ std::string* error); |
+ |
+ virtual ~DictionaryPolicySchema(); |
+ |
+ virtual const PolicySchemaMap* GetProperties() const OVERRIDE; |
+ virtual const PolicySchema* GetSchemaForAdditionalProperties() const OVERRIDE; |
+ |
+ private: |
+ DictionaryPolicySchema(); |
+ |
+ PolicySchemaMap properties_; |
+ scoped_ptr<PolicySchema> additional_properties_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(DictionaryPolicySchema); |
+}; |
+ |
+// Describes the items of a TYPE_LIST policy schema. |
+class ListPolicySchema : public PolicySchema { |
+ public: |
+ static scoped_ptr<PolicySchema> Parse(const base::DictionaryValue& schema, |
+ std::string* error); |
+ |
+ virtual ~ListPolicySchema(); |
+ |
+ virtual const PolicySchema* GetSchemaForItems() const OVERRIDE; |
+ |
+ private: |
+ ListPolicySchema(); |
+ |
+ scoped_ptr<PolicySchema> items_schema_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ListPolicySchema); |
+}; |
+ |
+bool SchemaTypeToValueType(const std::string& type_string, |
+ base::Value::Type* type) { |
+ // Note: "any" is not an accepted type. |
+ static const struct { |
+ const char* schema_type; |
+ base::Value::Type value_type; |
+ } kSchemaToValueTypeMap[] = { |
+ { json_schema_constants::kArray, base::Value::TYPE_LIST }, |
+ { json_schema_constants::kBoolean, base::Value::TYPE_BOOLEAN }, |
+ { json_schema_constants::kInteger, base::Value::TYPE_INTEGER }, |
+ { json_schema_constants::kNull, base::Value::TYPE_NULL }, |
+ { json_schema_constants::kNumber, base::Value::TYPE_DOUBLE }, |
+ { json_schema_constants::kObject, base::Value::TYPE_DICTIONARY }, |
+ { json_schema_constants::kString, base::Value::TYPE_STRING }, |
+ }; |
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSchemaToValueTypeMap); ++i) { |
+ if (kSchemaToValueTypeMap[i].schema_type == type_string) { |
+ *type = kSchemaToValueTypeMap[i].value_type; |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+scoped_ptr<PolicySchema> ParseSchema(const base::DictionaryValue& schema, |
+ std::string* error) { |
+ std::string type_string; |
+ if (!schema.GetString(json_schema_constants::kType, &type_string)) { |
+ *error = "The schema type must be declared."; |
+ return scoped_ptr<PolicySchema>(); |
+ } |
+ |
+ base::Value::Type type = base::Value::TYPE_NULL; |
+ if (!SchemaTypeToValueType(type_string, &type)) { |
+ *error = "The \"any\" type can't be used."; |
+ return scoped_ptr<PolicySchema>(); |
+ } |
+ |
+ switch (type) { |
+ case base::Value::TYPE_DICTIONARY: |
+ return DictionaryPolicySchema::Parse(schema, error); |
+ case base::Value::TYPE_LIST: |
+ return ListPolicySchema::Parse(schema, error); |
+ default: |
+ return make_scoped_ptr(new PolicySchema(type)); |
+ } |
+} |
+ |
+DictionaryPolicySchema::DictionaryPolicySchema() |
+ : PolicySchema(base::Value::TYPE_DICTIONARY) {} |
+ |
+DictionaryPolicySchema::~DictionaryPolicySchema() { |
+ STLDeleteValues(&properties_); |
+} |
+ |
+const PolicySchemaMap* DictionaryPolicySchema::GetProperties() const { |
+ return &properties_; |
+} |
+ |
+const PolicySchema* |
+ DictionaryPolicySchema::GetSchemaForAdditionalProperties() const { |
+ return additional_properties_.get(); |
+} |
+ |
+// static |
+scoped_ptr<PolicySchema> DictionaryPolicySchema::Parse( |
+ const base::DictionaryValue& schema, |
+ std::string* error) { |
+ scoped_ptr<DictionaryPolicySchema> dict_schema(new DictionaryPolicySchema()); |
+ |
+ const base::DictionaryValue* dict = NULL; |
+ const base::DictionaryValue* properties = NULL; |
+ if (schema.GetDictionary(json_schema_constants::kProperties, &properties)) { |
+ for (base::DictionaryValue::Iterator it(*properties); |
+ !it.IsAtEnd(); it.Advance()) { |
+ // This should have been verified by the JSONSchemaValidator. |
+ CHECK(it.value().GetAsDictionary(&dict)); |
+ scoped_ptr<PolicySchema> sub_schema = ParseSchema(*dict, error); |
+ if (!sub_schema) |
+ return scoped_ptr<PolicySchema>(); |
+ dict_schema->properties_[it.key()] = sub_schema.release(); |
+ } |
+ } |
+ |
+ if (schema.GetDictionary(json_schema_constants::kAdditionalProperties, |
+ &dict)) { |
+ scoped_ptr<PolicySchema> sub_schema = ParseSchema(*dict, error); |
+ if (!sub_schema) |
+ return scoped_ptr<PolicySchema>(); |
+ dict_schema->additional_properties_ = sub_schema.Pass(); |
+ } |
+ |
+ return dict_schema.PassAs<PolicySchema>(); |
+} |
+ |
+ListPolicySchema::ListPolicySchema() |
+ : PolicySchema(base::Value::TYPE_LIST) {} |
+ |
+ListPolicySchema::~ListPolicySchema() {} |
+ |
+const PolicySchema* ListPolicySchema::GetSchemaForItems() const { |
+ return items_schema_.get(); |
+} |
+ |
+scoped_ptr<PolicySchema> ListPolicySchema::Parse( |
+ const base::DictionaryValue& schema, |
+ std::string* error) { |
+ const base::DictionaryValue* dict = NULL; |
+ if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) { |
+ *error = "Arrays must declare a single schema for their items."; |
+ return scoped_ptr<PolicySchema>(); |
+ } |
+ scoped_ptr<PolicySchema> items_schema = ParseSchema(*dict, error); |
+ if (!items_schema) |
+ return scoped_ptr<PolicySchema>(); |
+ |
+ scoped_ptr<ListPolicySchema> list_schema(new ListPolicySchema()); |
+ list_schema->items_schema_ = items_schema.Pass(); |
+ return list_schema.PassAs<PolicySchema>(); |
+} |
+ |
+} // namespace |
+ |
+PolicySchema::PolicySchema(base::Value::Type type) |
+ : type_(type) {} |
+ |
+PolicySchema::~PolicySchema() {} |
+ |
+const PolicySchemaMap* PolicySchema::GetProperties() const { |
+ NOTREACHED(); |
+ return NULL; |
+} |
+ |
+const PolicySchema* PolicySchema::GetSchemaForAdditionalProperties() const { |
+ NOTREACHED(); |
+ return NULL; |
+} |
+ |
+const PolicySchema* PolicySchema::GetSchemaForProperty( |
+ const std::string& key) const { |
+ const PolicySchemaMap* properties = GetProperties(); |
+ PolicySchemaMap::const_iterator it = properties->find(key); |
+ return it == properties->end() ? GetSchemaForAdditionalProperties() |
+ : it->second; |
+} |
+ |
+const PolicySchema* PolicySchema::GetSchemaForItems() const { |
+ NOTREACHED(); |
+ return NULL; |
+} |
+ |
+// static |
+scoped_ptr<PolicySchema> PolicySchema::Parse(const std::string& content, |
+ std::string* error) { |
+ // Validate as a generic JSON schema. |
+ scoped_ptr<base::DictionaryValue> dict = |
+ JSONSchemaValidator::IsValidSchema(content, error); |
+ if (!dict) |
+ return scoped_ptr<PolicySchema>(); |
+ |
+ // Validate the schema version. |
+ std::string string_value; |
+ if (!dict->GetString(json_schema_constants::kSchema, &string_value) || |
+ string_value != kJSONSchemaVersion) { |
+ *error = "Must declare JSON Schema v3 version in \"$schema\"."; |
+ return scoped_ptr<PolicySchema>(); |
+ } |
+ |
+ // Validate the main type. |
+ if (!dict->GetString(json_schema_constants::kType, &string_value) || |
+ string_value != json_schema_constants::kObject) { |
+ *error = |
+ "The main schema must have a type attribute with \"object\" value."; |
+ return scoped_ptr<PolicySchema>(); |
+ } |
+ |
+ // Checks for invalid attributes at the top-level. |
+ if (dict->HasKey(json_schema_constants::kAdditionalProperties) || |
+ dict->HasKey(json_schema_constants::kPatternProperties)) { |
+ *error = "\"additionalProperties\" and \"patternProperties\" are not " |
+ "supported at the main schema."; |
+ return scoped_ptr<PolicySchema>(); |
+ } |
+ |
+ return ParseSchema(*dict, error); |
+} |
+ |
+} // namespace policy |