Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(306)

Side by Side Diff: components/policy/core/common/schema.cc

Issue 134153005: Add strictness to Schema::Validate() (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@expand-policy-schema-2
Patch Set: minor fixes Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/policy/core/common/schema.h ('k') | components/policy/core/common/schema_map.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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_STRICT;
93 }
94
95 SchemaOnErrorStrategy StrategyForNextLevel(SchemaOnErrorStrategy strategy) {
96 static SchemaOnErrorStrategy next_level_strategy[] = {
97 SCHEMA_STRICT, // SCHEMA_STRICT
98 SCHEMA_STRICT, // SCHEMA_ALLOW_UNKNOWN_TOPLEVEL
99 SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_UNKNOWN
100 SCHEMA_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
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 = "The schema is invalid.";
615 return false; 639 return false;
616 } 640 }
617 641
618 if (!value.IsType(type())) 642 if (!value.IsType(type())) {
643 // Allow the integer to double promotion. Note that range restriction on
644 // double is not supported now.
645 if (value.IsType(base::Value::TYPE_INTEGER) &&
646 type() == base::Value::TYPE_DOUBLE) {
647 return true;
648 }
649
650 *error = "The value type doesn't match the schema type.";
619 return false; 651 return false;
652 }
620 653
621 const base::DictionaryValue* dict = NULL; 654 const base::DictionaryValue* dict = NULL;
622 const base::ListValue* list = NULL; 655 const base::ListValue* list = NULL;
623 int int_value; 656 int int_value;
624 std::string str_value; 657 std::string str_value;
625 if (value.GetAsDictionary(&dict)) { 658 if (value.GetAsDictionary(&dict)) {
626 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); 659 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
627 it.Advance()) { 660 it.Advance()) {
628 if (!GetProperty(it.key()).Validate(it.value())) 661 Schema subschema = GetProperty(it.key());
629 return false; 662 if (!subschema.valid()) {
663 // Unknown property was detected.
664 if (!StrategyAllowUnknownOnTopLevel(strategy)) {
665 *error = "Unknown property: " + it.key();
666 return false;
667 }
668 } else {
669 std::string sub_error;
670 if (!subschema.Validate(
671 it.value(), StrategyForNextLevel(strategy), &sub_error)) {
672 // Invalid property was detected.
673 if (!StrategyAllowInvalidOnTopLevel(strategy)) {
674 *error = sub_error;
675 return false;
676 }
677 }
678 }
630 } 679 }
631 } else if (value.GetAsList(&list)) { 680 } else if (value.GetAsList(&list)) {
632 for (base::ListValue::const_iterator it = list->begin(); 681 for (base::ListValue::const_iterator it = list->begin(); it != list->end();
633 it != list->end(); ++it) { 682 ++it) {
634 if (!*it || !GetItems().Validate(**it)) 683 if (!*it ||
635 return false; 684 !GetItems().Validate(**it, StrategyForNextLevel(strategy), error)) {
685 // Invalid list item was detected.
686 if (!StrategyAllowInvalidOnTopLevel(strategy))
687 return false;
688 }
636 } 689 }
637 } else if (value.GetAsInteger(&int_value)) { 690 } else if (value.GetAsInteger(&int_value)) {
638 return node_->extra == kInvalid || 691 if (node_->extra != kInvalid &&
639 ValidateIntegerRestriction(node_->extra, int_value); 692 !ValidateIntegerRestriction(node_->extra, int_value)) {
693 *error = "Invalid value for integer";
694 return false;
695 }
640 } else if (value.GetAsString(&str_value)) { 696 } else if (value.GetAsString(&str_value)) {
641 return node_->extra == kInvalid || 697 if (node_->extra != kInvalid &&
642 ValidateStringRestriction(node_->extra, str_value.c_str()); 698 !ValidateStringRestriction(node_->extra, str_value.c_str())) {
699 *error = "Invalid value for string";
700 return false;
701 }
643 } 702 }
644 703
645 return true; 704 return true;
646 } 705 }
647 706
707 bool Schema::Normalize(base::Value* value,
708 SchemaOnErrorStrategy strategy,
709 std::string* error) const {
710 if (!valid()) {
711 *error = "The schema is invalid.";
712 return false;
713 }
714
715 if (!value->IsType(type())) {
716 // Allow the integer to double promotion. Note that range restriction on
717 // double is not supported now.
718 if (value->IsType(base::Value::TYPE_INTEGER) &&
719 type() == base::Value::TYPE_DOUBLE) {
720 return true;
721 }
722
723 *error = "The value type doesn't match the schema type.";
724 return false;
725 }
726
727 base::DictionaryValue* dict = NULL;
728 base::ListValue* list = NULL;
729 if (value->GetAsDictionary(&dict)) {
730 std::vector<std::string> drop_list; // Contains the keys to drop.
731 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
732 it.Advance()) {
733 Schema subschema = GetProperty(it.key());
734 if (!subschema.valid()) {
735 // Unknown property was detected.
736 if (StrategyAllowUnknownOnTopLevel(strategy)) {
737 drop_list.push_back(it.key());
738 } else {
739 *error = "Unknown property: " + it.key();
740 return false;
741 }
742 } else {
743 base::Value* sub_value = NULL;
744 dict->GetWithoutPathExpansion(it.key(), &sub_value);
745 std::string sub_error;
746 if (!subschema.Normalize(
747 sub_value, StrategyForNextLevel(strategy), &sub_error)) {
748 // Invalid property was detected.
749 if (StrategyAllowInvalidOnTopLevel(strategy)) {
750 drop_list.push_back(it.key());
751 } else {
752 *error = sub_error;
753 return false;
754 }
755 }
756 }
757 }
758 for (std::vector<std::string>::const_iterator it = drop_list.begin();
759 it != drop_list.end();
760 ++it) {
761 dict->RemoveWithoutPathExpansion(*it, NULL);
762 }
763 return true;
764 } else if (value->GetAsList(&list)) {
765 std::vector<size_t> drop_list; // Contains the indexes to drop.
766 for (size_t index = 0; index < list->GetSize(); index++) {
767 base::Value* sub_value = NULL;
768 std::string sub_error;
769 list->Get(index, &sub_value);
770 if (!sub_value ||
771 !GetItems().Normalize(
772 sub_value, StrategyForNextLevel(strategy), &sub_error)) {
773 // Invalid list item was detected.
774 if (StrategyAllowInvalidOnTopLevel(strategy)) {
775 drop_list.push_back(index);
776 } else {
777 *error = sub_error;
778 return false;
779 }
780 }
781 }
782 for (std::vector<size_t>::reverse_iterator it = drop_list.rbegin();
783 it != drop_list.rend(); ++it) {
784 list->Remove(*it, NULL);
785 }
786 return true;
787 }
788
789 return Validate(*value, strategy, error);
790 }
791
648 // static 792 // static
649 Schema Schema::Parse(const std::string& content, std::string* error) { 793 Schema Schema::Parse(const std::string& content, std::string* error) {
650 // Validate as a generic JSON schema, and ignore unknown attributes; they 794 // Validate as a generic JSON schema, and ignore unknown attributes; they
651 // may become used in a future version of the schema format. 795 // may become used in a future version of the schema format.
652 scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema( 796 scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema(
653 content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error); 797 content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error);
654 if (!dict) 798 if (!dict)
655 return Schema(); 799 return Schema();
656 800
657 // Validate the main type. 801 // Validate the main type.
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
751 const RestrictionNode* rnode = storage_->restriction(index); 895 const RestrictionNode* rnode = storage_->restriction(index);
752 for (int i = rnode->enumeration_restriction.offset_begin; 896 for (int i = rnode->enumeration_restriction.offset_begin;
753 i < rnode->enumeration_restriction.offset_end; i++) { 897 i < rnode->enumeration_restriction.offset_end; i++) {
754 if (strcmp(*storage_->string_enums(i), str) == 0) 898 if (strcmp(*storage_->string_enums(i), str) == 0)
755 return true; 899 return true;
756 } 900 }
757 return false; 901 return false;
758 } 902 }
759 903
760 } // namespace policy 904 } // namespace policy
OLDNEW
« no previous file with comments | « components/policy/core/common/schema.h ('k') | components/policy/core/common/schema_map.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698