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> |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
75 }; | 75 }; |
76 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSchemaToValueTypeMap); ++i) { | 76 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSchemaToValueTypeMap); ++i) { |
77 if (kSchemaToValueTypeMap[i].schema_type == type_string) { | 77 if (kSchemaToValueTypeMap[i].schema_type == type_string) { |
78 *type = kSchemaToValueTypeMap[i].value_type; | 78 *type = kSchemaToValueTypeMap[i].value_type; |
79 return true; | 79 return true; |
80 } | 80 } |
81 } | 81 } |
82 return false; | 82 return false; |
83 } | 83 } |
84 | 84 |
85 bool StrategyAllowInvalidOnTopLevel(SchemaOnErrorStrategy strategy) { | |
86 return strategy == SCHEMA_ALLOW_INVALID || | |
87 strategy == SCHEMA_ALLOW_INVALID_TOPLEVEL || | |
88 strategy == SCHEMA_ALLOW_INVALID_TOPLEVEL_AND_ALLOW_UNKNOWN; | |
89 } | |
90 | |
91 bool StrategyAllowUnknownOnTopLevel(SchemaOnErrorStrategy strategy) { | |
92 return strategy != SCHEMA_VERY_STRICT; | |
93 } | |
94 | |
95 SchemaOnErrorStrategy StrategyForNextLevel(SchemaOnErrorStrategy strategy) { | |
96 static SchemaOnErrorStrategy next_level_strategy[] = { | |
97 SCHEMA_VERY_STRICT, // SCHEMA_VERY_STRICT | |
98 SCHEMA_VERY_STRICT, // SCHEMA_ALLOW_UNKNOWN_TOPLEVEL | |
99 SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_UNKNOWN | |
100 SCHEMA_VERY_STRICT, // SCHEMA_ALLOW_INVALID_TOPLEVEL | |
101 SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_INVALID_TOPLEVEL_AND_ALLOW_UNKNOWN | |
102 SCHEMA_ALLOW_INVALID, // SCHEMA_ALLOW_INVALID | |
103 }; | |
104 return next_level_strategy[(int)strategy]; | |
105 } | |
106 | |
85 } // namespace | 107 } // namespace |
86 | 108 |
87 // Contains the internal data representation of a Schema. This can either wrap | 109 // Contains the internal data representation of a Schema. This can either wrap |
88 // a SchemaData owned elsewhere (currently used to wrap the Chrome schema, which | 110 // a SchemaData owned elsewhere (currently used to wrap the Chrome schema, which |
89 // is generated at compile time), or it can own its own SchemaData. | 111 // is generated at compile time), or it can own its own SchemaData. |
90 class Schema::InternalStorage | 112 class Schema::InternalStorage |
91 : public base::RefCountedThreadSafe<InternalStorage> { | 113 : public base::RefCountedThreadSafe<InternalStorage> { |
92 public: | 114 public: |
93 static scoped_refptr<const InternalStorage> Wrap(const SchemaData* data); | 115 static scoped_refptr<const InternalStorage> Wrap(const SchemaData* data); |
94 | 116 |
(...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
602 node_ = schema.node_; | 624 node_ = schema.node_; |
603 return *this; | 625 return *this; |
604 } | 626 } |
605 | 627 |
606 // static | 628 // static |
607 Schema Schema::Wrap(const SchemaData* data) { | 629 Schema Schema::Wrap(const SchemaData* data) { |
608 scoped_refptr<const InternalStorage> storage = InternalStorage::Wrap(data); | 630 scoped_refptr<const InternalStorage> storage = InternalStorage::Wrap(data); |
609 return Schema(storage, storage->root_node()); | 631 return Schema(storage, storage->root_node()); |
610 } | 632 } |
611 | 633 |
612 bool Schema::Validate(const base::Value& value) const { | 634 bool Schema::Validate(const base::Value& value, |
635 SchemaOnErrorStrategy strategy, | |
636 std::string *error) const { | |
613 if (!valid()) { | 637 if (!valid()) { |
614 // Schema not found, invalid entry. | 638 *error = "Fatal error: The schema itself is invalid."; |
Joao da Silva
2014/01/22 10:49:53
Just "The schema is invalid."
binjin
2014/01/23 12:01:31
Done.
| |
615 return false; | 639 return false; |
616 } | 640 } |
617 | 641 |
618 if (!value.IsType(type())) | 642 if (!value.IsType(type())) { |
643 *error = "The schema type and value type is not matched."; | |
Joao da Silva
2014/01/22 10:49:53
The value type doesn't match the schema type.
binjin
2014/01/23 12:01:31
Done.
| |
619 return false; | 644 return false; |
645 } | |
620 | 646 |
621 const base::DictionaryValue* dict = NULL; | 647 const base::DictionaryValue* dict = NULL; |
622 const base::ListValue* list = NULL; | 648 const base::ListValue* list = NULL; |
623 int int_value; | 649 int int_value; |
624 std::string str_value; | 650 std::string str_value; |
625 if (value.GetAsDictionary(&dict)) { | 651 if (value.GetAsDictionary(&dict)) { |
626 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); | 652 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); |
627 it.Advance()) { | 653 it.Advance()) { |
628 if (!GetProperty(it.key()).Validate(it.value())) | 654 Schema subschema = GetProperty(it.key()); |
629 return false; | 655 if (!subschema.valid()) { |
656 // Unknown property was detected. | |
657 if (!StrategyAllowUnknownOnTopLevel(strategy)) { | |
658 *error = "Unknown property: " + it.key(); | |
659 return false; | |
660 } | |
661 } else { | |
Joao da Silva
2014/01/22 10:49:53
The else part should just be:
std::string sub_e
binjin
2014/01/22 12:46:53
The current approach is result of trade-off. In sh
| |
662 std::string property_error; | |
663 if (subschema.node_->type == base::Value::TYPE_DICTIONARY) { | |
664 if (!subschema.Validate(it.value(), | |
665 StrategyForNextLevel(strategy), error)) { | |
666 return false; | |
667 } | |
668 } else if (!subschema.Validate(it.value(), | |
669 SCHEMA_VERY_STRICT, &property_error)) { | |
670 // Invalid property was detected. | |
671 if (!StrategyAllowInvalidOnTopLevel(strategy)) { | |
672 *error = property_error; | |
673 return false; | |
674 } | |
675 } | |
676 } | |
630 } | 677 } |
631 } else if (value.GetAsList(&list)) { | 678 } else if (value.GetAsList(&list)) { |
632 for (base::ListValue::const_iterator it = list->begin(); | 679 for (base::ListValue::const_iterator it = list->begin(); |
633 it != list->end(); ++it) { | 680 it != list->end(); ++it) { |
634 if (!*it || !GetItems().Validate(**it)) | 681 if (!*it || !GetItems().Validate(**it, strategy, error)) |
Joao da Silva
2014/01/22 10:49:53
Replace "strategy" with StrategyForNextLevel(strat
binjin
2014/01/22 12:46:53
For list-dict-nested schema(with list/list-list-ne
| |
635 return false; | 682 return false; |
636 } | 683 } |
637 } else if (value.GetAsInteger(&int_value)) { | 684 } else if (value.GetAsInteger(&int_value)) { |
638 return node_->extra == kInvalid || | 685 if (node_->extra != kInvalid && |
639 ValidateIntegerRestriction(node_->extra, int_value); | 686 !ValidateIntegerRestriction(node_->extra, int_value)) { |
687 *error = "Invalid value for integer"; | |
688 return false; | |
689 } | |
640 } else if (value.GetAsString(&str_value)) { | 690 } else if (value.GetAsString(&str_value)) { |
641 return node_->extra == kInvalid || | 691 if (node_->extra != kInvalid && |
642 ValidateStringRestriction(node_->extra, str_value.c_str()); | 692 !ValidateStringRestriction(node_->extra, str_value.c_str())) { |
693 *error = "Invalid value for string"; | |
694 return false; | |
695 } | |
643 } | 696 } |
644 | 697 |
645 return true; | 698 return true; |
646 } | 699 } |
647 | 700 |
701 bool Schema::Normalize(base::Value* value, | |
702 SchemaOnErrorStrategy strategy, | |
703 std::string *error) const { | |
704 if (!valid()) { | |
705 *error = "Fatal error: The schema itself is invalid."; | |
Joao da Silva
2014/01/22 10:49:53
Just "The schema is invalid."
binjin
2014/01/23 12:01:31
Done.
| |
706 return false; | |
707 } | |
708 | |
709 if (!value->IsType(type())) { | |
710 *error = "The schema type and value type is not matched."; | |
Joao da Silva
2014/01/22 10:49:53
The value type doesn't match the schema type.
binjin
2014/01/23 12:01:31
Done.
| |
711 return false; | |
712 } | |
713 | |
714 base::DictionaryValue* dict = NULL; | |
715 if (value->GetAsDictionary(&dict)) { | |
716 std::vector<std::string> drop_list; // Contains the keys to remove. | |
717 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); | |
718 it.Advance()) { | |
719 Schema subschema = GetProperty(it.key()); | |
720 if (!subschema.valid()) { | |
721 // Unknown property was detected. | |
722 if (StrategyAllowUnknownOnTopLevel(strategy)) { | |
723 drop_list.push_back(it.key()); | |
724 } else { | |
725 *error = "Unknown property: " + it.key(); | |
726 return false; | |
727 } | |
728 } else { | |
729 std::string property_error; | |
730 if (subschema.node_->type == base::Value::TYPE_DICTIONARY) { | |
731 base::DictionaryValue* subdict = NULL; | |
732 dict->GetDictionary(it.key(), &subdict); | |
733 if (!subschema.Normalize(subdict, | |
734 StrategyForNextLevel(strategy), error)) { | |
735 return false; | |
736 } | |
737 } else if (!subschema.Validate(it.value(), | |
738 SCHEMA_VERY_STRICT, &property_error)) { | |
739 // Invalid property was detected. | |
740 if (StrategyAllowInvalidOnTopLevel(strategy)) { | |
741 drop_list.push_back(it.key()); | |
742 } else { | |
743 *error = property_error; | |
744 return false; | |
745 } | |
746 } | |
747 } | |
748 } | |
749 for (std::vector<std::string>::const_iterator it = drop_list.begin(); | |
750 it != drop_list.end(); ++it) { | |
751 dict->Remove(*it, NULL); | |
752 } | |
753 return true; | |
754 } | |
Joao da Silva
2014/01/22 10:49:53
This needs to handle lists of dictionaries; the in
binjin
2014/01/22 12:46:53
Yes, it did break normalizing by list-dict-nested
| |
755 | |
756 return Validate(*value, strategy, error); | |
757 } | |
758 | |
648 // static | 759 // static |
649 Schema Schema::Parse(const std::string& content, std::string* error) { | 760 Schema Schema::Parse(const std::string& content, std::string* error) { |
650 // Validate as a generic JSON schema, and ignore unknown attributes; they | 761 // Validate as a generic JSON schema, and ignore unknown attributes; they |
651 // may become used in a future version of the schema format. | 762 // may become used in a future version of the schema format. |
652 scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema( | 763 scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema( |
653 content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error); | 764 content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error); |
654 if (!dict) | 765 if (!dict) |
655 return Schema(); | 766 return Schema(); |
656 | 767 |
657 // Validate the main type. | 768 // Validate the main type. |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
753 const RestrictionNode* rnode = storage_->restriction(index); | 864 const RestrictionNode* rnode = storage_->restriction(index); |
754 for (int i = rnode->enumeration_restriction.offset_begin; | 865 for (int i = rnode->enumeration_restriction.offset_begin; |
755 i < rnode->enumeration_restriction.offset_end; i++) { | 866 i < rnode->enumeration_restriction.offset_end; i++) { |
756 if (strcmp(*storage_->string_enums(i), str) == 0) | 867 if (strcmp(*storage_->string_enums(i), str) == 0) |
757 return true; | 868 return true; |
758 } | 869 } |
759 return false; | 870 return false; |
760 } | 871 } |
761 | 872 |
762 } // namespace policy | 873 } // namespace policy |
OLD | NEW |