OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/policy/core/common/schema.h" | 5 #include "components/policy/core/common/schema.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <climits> | 8 #include <climits> |
9 #include <map> | 9 #include <map> |
10 #include <utility> | 10 #include <utility> |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/memory/scoped_vector.h" | 15 #include "base/memory/scoped_vector.h" |
16 #include "base/strings/stringprintf.h" | |
16 #include "components/json_schema/json_schema_constants.h" | 17 #include "components/json_schema/json_schema_constants.h" |
17 #include "components/json_schema/json_schema_validator.h" | 18 #include "components/json_schema/json_schema_validator.h" |
18 #include "components/policy/core/common/schema_internal.h" | 19 #include "components/policy/core/common/schema_internal.h" |
19 | 20 |
20 namespace schema = json_schema_constants; | 21 namespace schema = json_schema_constants; |
21 | 22 |
22 namespace policy { | 23 namespace policy { |
23 | 24 |
24 using internal::PropertiesNode; | 25 using internal::PropertiesNode; |
25 using internal::PropertyNode; | 26 using internal::PropertyNode; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 SCHEMA_STRICT, // SCHEMA_STRICT | 98 SCHEMA_STRICT, // SCHEMA_STRICT |
98 SCHEMA_STRICT, // SCHEMA_ALLOW_UNKNOWN_TOPLEVEL | 99 SCHEMA_STRICT, // SCHEMA_ALLOW_UNKNOWN_TOPLEVEL |
99 SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_UNKNOWN | 100 SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_UNKNOWN |
100 SCHEMA_STRICT, // SCHEMA_ALLOW_INVALID_TOPLEVEL | 101 SCHEMA_STRICT, // SCHEMA_ALLOW_INVALID_TOPLEVEL |
101 SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_INVALID_TOPLEVEL_AND_ALLOW_UNKNOWN | 102 SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_INVALID_TOPLEVEL_AND_ALLOW_UNKNOWN |
102 SCHEMA_ALLOW_INVALID, // SCHEMA_ALLOW_INVALID | 103 SCHEMA_ALLOW_INVALID, // SCHEMA_ALLOW_INVALID |
103 }; | 104 }; |
104 return next_level_strategy[(int)strategy]; | 105 return next_level_strategy[(int)strategy]; |
105 } | 106 } |
106 | 107 |
108 void SchemaFindError(std::string* error_path,std::string *error, | |
Joao da Silva
2014/01/23 20:59:31
A better name for this is ErrorFound
binjin
2014/01/23 21:21:58
Done.
| |
109 const std::string& msg) { | |
Joao da Silva
2014/01/23 20:59:31
Format this. One argument per line:
void SchemaFi
binjin
2014/01/23 21:21:58
Done.
| |
110 if (error_path) | |
111 *error_path = ""; | |
112 *error = msg; | |
113 } | |
114 | |
115 void AddListIndexPrefixToPath(int index, std::string* path) { | |
116 if (path) { | |
117 if (path->size() == 0) | |
Joao da Silva
2014/01/23 20:59:31
path->empty
binjin
2014/01/23 21:21:58
Done.
| |
118 *path = base::StringPrintf("items[%d]", index); | |
119 else | |
120 *path = base::StringPrintf("items[%d].", index) + *path; | |
Joao da Silva
2014/01/23 20:59:31
Maybe just "[%d]" without the "items" looks OK?
E
binjin
2014/01/23 21:21:58
root schema can be a list, and things like "[4].fi
| |
121 } | |
122 } | |
123 | |
124 void AddDictKeyPrefixToPath(const std::string& key, std::string* path) { | |
125 if (path) { | |
126 if (path->size() == 0) | |
Joao da Silva
2014/01/23 20:59:31
path->empty
binjin
2014/01/23 21:21:58
Done.
| |
127 *path = key; | |
128 else | |
129 *path = key + "." + *path; | |
130 } | |
131 } | |
132 | |
107 } // namespace | 133 } // namespace |
108 | 134 |
109 // Contains the internal data representation of a Schema. This can either wrap | 135 // Contains the internal data representation of a Schema. This can either wrap |
110 // a SchemaData owned elsewhere (currently used to wrap the Chrome schema, which | 136 // a SchemaData owned elsewhere (currently used to wrap the Chrome schema, which |
111 // is generated at compile time), or it can own its own SchemaData. | 137 // is generated at compile time), or it can own its own SchemaData. |
112 class Schema::InternalStorage | 138 class Schema::InternalStorage |
113 : public base::RefCountedThreadSafe<InternalStorage> { | 139 : public base::RefCountedThreadSafe<InternalStorage> { |
114 public: | 140 public: |
115 static scoped_refptr<const InternalStorage> Wrap(const SchemaData* data); | 141 static scoped_refptr<const InternalStorage> Wrap(const SchemaData* data); |
116 | 142 |
(...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
626 } | 652 } |
627 | 653 |
628 // static | 654 // static |
629 Schema Schema::Wrap(const SchemaData* data) { | 655 Schema Schema::Wrap(const SchemaData* data) { |
630 scoped_refptr<const InternalStorage> storage = InternalStorage::Wrap(data); | 656 scoped_refptr<const InternalStorage> storage = InternalStorage::Wrap(data); |
631 return Schema(storage, storage->root_node()); | 657 return Schema(storage, storage->root_node()); |
632 } | 658 } |
633 | 659 |
634 bool Schema::Validate(const base::Value& value, | 660 bool Schema::Validate(const base::Value& value, |
635 SchemaOnErrorStrategy strategy, | 661 SchemaOnErrorStrategy strategy, |
662 std::string* error_path, | |
636 std::string* error) const { | 663 std::string* error) const { |
637 if (!valid()) { | 664 if (!valid()) { |
638 *error = "The schema is invalid."; | 665 SchemaFindError(error_path, error, "The schema is invalid."); |
639 return false; | 666 return false; |
640 } | 667 } |
641 | 668 |
642 if (!value.IsType(type())) { | 669 if (!value.IsType(type())) { |
643 // Allow the integer to double promition. Note that range restriction on | 670 // Allow the integer to double promition. Note that range restriction on |
644 // double is not supported now. | 671 // double is not supported now. |
645 if (value.IsType(base::Value::TYPE_INTEGER) && | 672 if (value.IsType(base::Value::TYPE_INTEGER) && |
646 type() == base::Value::TYPE_DOUBLE) | 673 type() == base::Value::TYPE_DOUBLE) |
647 return true; | 674 return true; |
648 | 675 |
649 *error = "The value type doesn't match the schema type."; | 676 SchemaFindError(error_path, error, |
677 "The value type doesn't match the schema type."); | |
Joao da Silva
2014/01/23 20:59:31
Format this line.
binjin
2014/01/23 21:21:58
Done.
| |
650 return false; | 678 return false; |
651 } | 679 } |
652 | 680 |
653 const base::DictionaryValue* dict = NULL; | 681 const base::DictionaryValue* dict = NULL; |
654 const base::ListValue* list = NULL; | 682 const base::ListValue* list = NULL; |
655 int int_value; | 683 int int_value; |
656 std::string str_value; | 684 std::string str_value; |
657 if (value.GetAsDictionary(&dict)) { | 685 if (value.GetAsDictionary(&dict)) { |
658 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); | 686 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); |
659 it.Advance()) { | 687 it.Advance()) { |
660 Schema subschema = GetProperty(it.key()); | 688 Schema subschema = GetProperty(it.key()); |
661 if (!subschema.valid()) { | 689 if (!subschema.valid()) { |
662 // Unknown property was detected. | 690 // Unknown property was detected. |
663 if (!StrategyAllowUnknownOnTopLevel(strategy)) { | 691 SchemaFindError(error_path, error, "Unknown property: " + it.key()); |
664 *error = "Unknown property: " + it.key(); | 692 if (!StrategyAllowUnknownOnTopLevel(strategy)) |
665 return false; | 693 return false; |
666 } | 694 } else if (!subschema.Validate(it.value(), |
667 } else { | 695 StrategyForNextLevel(strategy), error_path, error)) { |
Joao da Silva
2014/01/23 20:59:31
Format this line
binjin
2014/01/23 21:21:58
Done.
| |
668 std::string sub_error; | 696 // Invalid property was detected. |
669 if (!subschema.Validate( | 697 AddDictKeyPrefixToPath(it.key(), error_path); |
670 it.value(), StrategyForNextLevel(strategy), &sub_error)) { | 698 if (!StrategyAllowInvalidOnTopLevel(strategy)) |
671 // Invalid property was detected. | 699 return false; |
672 if (!StrategyAllowInvalidOnTopLevel(strategy)) { | |
673 *error = sub_error; | |
674 return false; | |
675 } | |
676 } | |
677 } | 700 } |
678 } | 701 } |
679 } else if (value.GetAsList(&list)) { | 702 } else if (value.GetAsList(&list)) { |
680 for (base::ListValue::const_iterator it = list->begin(); it != list->end(); | 703 for (base::ListValue::const_iterator it = list->begin(); it != list->end(); |
681 ++it) { | 704 ++it) { |
682 if (!*it || | 705 if (!*it || |
683 !GetItems().Validate(**it, StrategyForNextLevel(strategy), error)) { | 706 !GetItems().Validate( |
707 **it, StrategyForNextLevel(strategy), error_path, error)) { | |
684 // Invalid list item was detected. | 708 // Invalid list item was detected. |
709 AddListIndexPrefixToPath(it - list->begin(), error_path); | |
685 if (!StrategyAllowInvalidOnTopLevel(strategy)) | 710 if (!StrategyAllowInvalidOnTopLevel(strategy)) |
686 return false; | 711 return false; |
687 } | 712 } |
688 } | 713 } |
689 } else if (value.GetAsInteger(&int_value)) { | 714 } else if (value.GetAsInteger(&int_value)) { |
690 if (node_->extra != kInvalid && | 715 if (node_->extra != kInvalid && |
691 !ValidateIntegerRestriction(node_->extra, int_value)) { | 716 !ValidateIntegerRestriction(node_->extra, int_value)) { |
692 *error = "Invalid value for integer"; | 717 SchemaFindError(error_path, error, "Invalid value for integer"); |
693 return false; | 718 return false; |
694 } | 719 } |
695 } else if (value.GetAsString(&str_value)) { | 720 } else if (value.GetAsString(&str_value)) { |
696 if (node_->extra != kInvalid && | 721 if (node_->extra != kInvalid && |
697 !ValidateStringRestriction(node_->extra, str_value.c_str())) { | 722 !ValidateStringRestriction(node_->extra, str_value.c_str())) { |
698 *error = "Invalid value for string"; | 723 SchemaFindError(error_path, error, "Invalid value for string"); |
699 return false; | 724 return false; |
700 } | 725 } |
701 } | 726 } |
702 | 727 |
703 return true; | 728 return true; |
704 } | 729 } |
705 | 730 |
706 bool Schema::Normalize(base::Value* value, | 731 bool Schema::Normalize(base::Value* value, |
707 SchemaOnErrorStrategy strategy, | 732 SchemaOnErrorStrategy strategy, |
733 std::string* error_path, | |
708 std::string* error) const { | 734 std::string* error) const { |
709 if (!valid()) { | 735 if (!valid()) { |
710 *error = "The schema is invalid."; | 736 SchemaFindError(error_path, error, "The schema is invalid."); |
711 return false; | 737 return false; |
712 } | 738 } |
713 | 739 |
714 | 740 |
715 if (!value->IsType(type())) { | 741 if (!value->IsType(type())) { |
716 // Allow the integer to double promition. Note that range restriction on | 742 // Allow the integer to double promition. Note that range restriction on |
717 // double is not supported now. | 743 // double is not supported now. |
718 if (value->IsType(base::Value::TYPE_INTEGER) && | 744 if (value->IsType(base::Value::TYPE_INTEGER) && |
719 type() == base::Value::TYPE_DOUBLE) | 745 type() == base::Value::TYPE_DOUBLE) |
720 return true; | 746 return true; |
721 | 747 |
722 *error = "The value type doesn't match the schema type."; | 748 SchemaFindError(error_path, error, |
749 "The value type doesn't match the schema type."); | |
Joao da Silva
2014/01/23 20:59:31
Format this line
binjin
2014/01/23 21:21:58
Done.
| |
723 return false; | 750 return false; |
724 } | 751 } |
725 | 752 |
726 base::DictionaryValue* dict = NULL; | 753 base::DictionaryValue* dict = NULL; |
727 base::ListValue* list = NULL; | 754 base::ListValue* list = NULL; |
728 if (value->GetAsDictionary(&dict)) { | 755 if (value->GetAsDictionary(&dict)) { |
729 std::vector<std::string> drop_list; // Contains the keys to drop. | 756 std::vector<std::string> drop_list; // Contains the keys to drop. |
730 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); | 757 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); |
731 it.Advance()) { | 758 it.Advance()) { |
732 Schema subschema = GetProperty(it.key()); | 759 Schema subschema = GetProperty(it.key()); |
733 if (!subschema.valid()) { | 760 if (!subschema.valid()) { |
734 // Unknown property was detected. | 761 // Unknown property was detected. |
735 if (StrategyAllowUnknownOnTopLevel(strategy)) { | 762 SchemaFindError(error_path, error, "Unknown property: " + it.key()); |
763 if (StrategyAllowUnknownOnTopLevel(strategy)) | |
736 drop_list.push_back(it.key()); | 764 drop_list.push_back(it.key()); |
737 } else { | 765 else |
738 *error = "Unknown property: " + it.key(); | |
739 return false; | 766 return false; |
740 } | |
741 } else { | 767 } else { |
742 base::Value* sub_value = NULL; | 768 base::Value* sub_value = NULL; |
743 dict->GetWithoutPathExpansion(it.key(), &sub_value); | 769 dict->GetWithoutPathExpansion(it.key(), &sub_value); |
744 std::string sub_error; | 770 if (!subschema.Normalize(sub_value, |
745 if (!subschema.Normalize( | 771 StrategyForNextLevel(strategy), |
746 sub_value, StrategyForNextLevel(strategy), &sub_error)) { | 772 error_path, |
773 error)) { | |
747 // Invalid property was detected. | 774 // Invalid property was detected. |
748 if (StrategyAllowInvalidOnTopLevel(strategy)) { | 775 AddDictKeyPrefixToPath(it.key(), error_path); |
776 if (StrategyAllowInvalidOnTopLevel(strategy)) | |
749 drop_list.push_back(it.key()); | 777 drop_list.push_back(it.key()); |
750 } else { | 778 else |
751 *error = sub_error; | |
752 return false; | 779 return false; |
753 } | |
754 } | 780 } |
755 } | 781 } |
756 } | 782 } |
757 for (std::vector<std::string>::const_iterator it = drop_list.begin(); | 783 for (std::vector<std::string>::const_iterator it = drop_list.begin(); |
758 it != drop_list.end(); | 784 it != drop_list.end(); |
759 ++it) { | 785 ++it) { |
760 dict->RemoveWithoutPathExpansion(*it, NULL); | 786 dict->RemoveWithoutPathExpansion(*it, NULL); |
761 } | 787 } |
762 return true; | 788 return true; |
763 } else if (value->GetAsList(&list)) { | 789 } else if (value->GetAsList(&list)) { |
764 std::vector<size_t> drop_list; // Contains the indexes to drop. | 790 std::vector<size_t> drop_list; // Contains the indexes to drop. |
765 for (size_t index = 0; index < list->GetSize(); index++) { | 791 for (size_t index = 0; index < list->GetSize(); index++) { |
766 base::Value* sub_value = NULL; | 792 base::Value* sub_value = NULL; |
767 std::string sub_error; | |
768 list->Get(index, &sub_value); | 793 list->Get(index, &sub_value); |
769 if (!sub_value || | 794 if (!sub_value || |
770 !GetItems().Normalize( | 795 !GetItems().Normalize( |
771 sub_value, StrategyForNextLevel(strategy), &sub_error)) { | 796 sub_value, StrategyForNextLevel(strategy), error_path, error)) { |
772 // Invalid list item was detected. | 797 // Invalid list item was detected. |
773 if (StrategyAllowInvalidOnTopLevel(strategy)) { | 798 AddListIndexPrefixToPath(index, error_path); |
799 if (StrategyAllowInvalidOnTopLevel(strategy)) | |
774 drop_list.push_back(index); | 800 drop_list.push_back(index); |
775 } else { | 801 else |
776 *error = sub_error; | |
777 return false; | 802 return false; |
778 } | |
779 } | 803 } |
780 } | 804 } |
781 for (std::vector<size_t>::reverse_iterator it = drop_list.rbegin(); | 805 for (std::vector<size_t>::reverse_iterator it = drop_list.rbegin(); |
782 it != drop_list.rend(); ++it) { | 806 it != drop_list.rend(); ++it) { |
783 list->Remove(*it, NULL); | 807 list->Remove(*it, NULL); |
784 } | 808 } |
785 return true; | 809 return true; |
786 } | 810 } |
787 | 811 |
788 return Validate(*value, strategy, error); | 812 return Validate(*value, strategy, error_path, error); |
789 } | 813 } |
790 | 814 |
791 // static | 815 // static |
792 Schema Schema::Parse(const std::string& content, std::string* error) { | 816 Schema Schema::Parse(const std::string& content, std::string* error) { |
793 // Validate as a generic JSON schema, and ignore unknown attributes; they | 817 // Validate as a generic JSON schema, and ignore unknown attributes; they |
794 // may become used in a future version of the schema format. | 818 // may become used in a future version of the schema format. |
795 scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema( | 819 scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema( |
796 content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error); | 820 content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error); |
797 if (!dict) | 821 if (!dict) |
798 return Schema(); | 822 return Schema(); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
883 } else { | 907 } else { |
884 for (int i = rnode->enumeration_restriction.offset_begin; | 908 for (int i = rnode->enumeration_restriction.offset_begin; |
885 i < rnode->enumeration_restriction.offset_end; i++) { | 909 i < rnode->enumeration_restriction.offset_end; i++) { |
886 if (*storage_->int_enums(i) == value) | 910 if (*storage_->int_enums(i) == value) |
887 return true; | 911 return true; |
888 } | 912 } |
889 return false; | 913 return false; |
890 } | 914 } |
891 } | 915 } |
892 | 916 |
893 bool Schema::ValidateStringRestriction(int index, const char *str) const { | 917 bool Schema::ValidateStringRestriction(int index, const char* str) const { |
894 const RestrictionNode* rnode = storage_->restriction(index); | 918 const RestrictionNode* rnode = storage_->restriction(index); |
895 for (int i = rnode->enumeration_restriction.offset_begin; | 919 for (int i = rnode->enumeration_restriction.offset_begin; |
896 i < rnode->enumeration_restriction.offset_end; i++) { | 920 i < rnode->enumeration_restriction.offset_end; i++) { |
897 if (strcmp(*storage_->string_enums(i), str) == 0) | 921 if (strcmp(*storage_->string_enums(i), str) == 0) |
898 return true; | 922 return true; |
899 } | 923 } |
900 return false; | 924 return false; |
901 } | 925 } |
902 | 926 |
903 } // namespace policy | 927 } // namespace policy |
OLD | NEW |