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

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: pull from previous CL 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
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_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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698