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

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: fix a bug and enhance tests 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_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 {
Joao da Silva 2014/01/23 15:52:36 std::string* error The style guide says that the
binjin 2014/01/23 17:20:13 Done.
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 *error = "The value type doesn't match the schema type.";
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 {
662 std::string sub_error;
663 if (!subschema.Validate(it.value(),
664 StrategyForNextLevel(strategy), &sub_error)) {
Joao da Silva 2014/01/23 15:52:36 The style guide says that arguments should be alig
binjin 2014/01/23 17:20:13 Done.
665 // Invalid property was detected.
666 if (!StrategyAllowInvalidOnTopLevel(strategy)) {
667 *error = sub_error;
668 return false;
669 }
670 }
671 }
630 } 672 }
631 } else if (value.GetAsList(&list)) { 673 } else if (value.GetAsList(&list)) {
632 for (base::ListValue::const_iterator it = list->begin(); 674 for (base::ListValue::const_iterator it = list->begin();
633 it != list->end(); ++it) { 675 it != list->end(); ++it) {
634 if (!*it || !GetItems().Validate(**it)) 676 if (!*it || !GetItems().Validate(**it,
635 return false; 677 StrategyForNextLevel(strategy), error)) {
Joao da Silva 2014/01/23 15:52:36 Run clang-format on this line too
binjin 2014/01/23 17:20:13 Done.
678 // Invalid list item was detected.
679 if (!StrategyAllowInvalidOnTopLevel(strategy))
680 return false;
681 }
636 } 682 }
637 } else if (value.GetAsInteger(&int_value)) { 683 } else if (value.GetAsInteger(&int_value)) {
638 return node_->extra == kInvalid || 684 if (node_->extra != kInvalid &&
639 ValidateIntegerRestriction(node_->extra, int_value); 685 !ValidateIntegerRestriction(node_->extra, int_value)) {
686 *error = "Invalid value for integer";
687 return false;
688 }
640 } else if (value.GetAsString(&str_value)) { 689 } else if (value.GetAsString(&str_value)) {
641 return node_->extra == kInvalid || 690 if (node_->extra != kInvalid &&
642 ValidateStringRestriction(node_->extra, str_value.c_str()); 691 !ValidateStringRestriction(node_->extra, str_value.c_str())) {
692 *error = "Invalid value for string";
693 return false;
694 }
643 } 695 }
644 696
645 return true; 697 return true;
646 } 698 }
647 699
700 bool Schema::Normalize(base::Value* value,
701 SchemaOnErrorStrategy strategy,
702 std::string *error) const {
703 if (!valid()) {
704 *error = "The schema is invalid.";
705 return false;
706 }
707
708 if (!value->IsType(type())) {
Joao da Silva 2014/01/23 15:52:36 We could handle INTEGER to DOUBLE promotion here,
binjin 2014/01/23 17:20:13 I added special check to allow Integer to Double p
709 *error = "The value type doesn't match the schema type.";
710 return false;
711 }
712
713 base::DictionaryValue* dict = NULL;
714 base::ListValue* list = NULL;
715 if (value->GetAsDictionary(&dict)) {
716 std::vector<std::string> drop_list; // Contains the keys to drop.
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 base::Value* sub_value = NULL;
730 dict->GetWithoutPathExpansion(it.key(), &sub_value);
731 std::string sub_error;
732 if (!subschema.Normalize(sub_value,
733 StrategyForNextLevel(strategy), &sub_error)) {
Joao da Silva 2014/01/23 15:52:36 Run clang-format on this line
binjin 2014/01/23 17:20:13 Done.
734 // Invalid property was detected.
735 if (StrategyAllowInvalidOnTopLevel(strategy)) {
736 drop_list.push_back(it.key());
737 } else {
738 *error = sub_error;
739 return false;
740 }
741 }
742 }
743 }
744 for (std::vector<std::string>::const_iterator it = drop_list.begin();
745 it != drop_list.end(); ++it) {
746 dict->Remove(*it, NULL);
Joao da Silva 2014/01/23 15:52:36 RemoveWithoutPathExpansion
binjin 2014/01/23 17:20:13 Done.
747 }
748 return true;
749 } else if (value->GetAsList(&list)) {
750 std::vector<size_t> drop_list; // Contains the indexes to drop.
751 for (size_t index = 0; index < list->GetSize(); index++) {
752 base::Value* sub_value = NULL;
753 std::string sub_error;
754 list->Get(index, &sub_value);
755 if (!sub_value || !GetItems().Normalize(sub_value,
756 StrategyForNextLevel(strategy), &sub_error)) {
Joao da Silva 2014/01/23 15:52:36 Run clang-format on this line
binjin 2014/01/23 17:20:13 Done.
757 // Invalid list item was detected.
758 if (StrategyAllowInvalidOnTopLevel(strategy)) {
759 drop_list.push_back(index);
760 } else {
761 *error = sub_error;
762 return false;
763 }
764 }
765 }
766 for (std::vector<size_t>::reverse_iterator it = drop_list.rbegin();
767 it != drop_list.rend(); ++it) {
768 list->Remove(*it, NULL);
Joao da Silva 2014/01/23 15:52:36 This is expensive, because it will search for the
binjin 2014/01/23 17:20:13 The type of *it is size_t, and I actually called L
Joao da Silva 2014/01/23 20:18:47 I was confused by the drop_list of the dictionary,
769 }
770 return true;
771 }
772
773 return Validate(*value, strategy, error);
774 }
775
648 // static 776 // static
649 Schema Schema::Parse(const std::string& content, std::string* error) { 777 Schema Schema::Parse(const std::string& content, std::string* error) {
650 // Validate as a generic JSON schema, and ignore unknown attributes; they 778 // Validate as a generic JSON schema, and ignore unknown attributes; they
651 // may become used in a future version of the schema format. 779 // may become used in a future version of the schema format.
652 scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema( 780 scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema(
653 content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error); 781 content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error);
654 if (!dict) 782 if (!dict)
655 return Schema(); 783 return Schema();
656 784
657 // Validate the main type. 785 // Validate the main type.
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
751 const RestrictionNode* rnode = storage_->restriction(index); 879 const RestrictionNode* rnode = storage_->restriction(index);
752 for (int i = rnode->enumeration_restriction.offset_begin; 880 for (int i = rnode->enumeration_restriction.offset_begin;
753 i < rnode->enumeration_restriction.offset_end; i++) { 881 i < rnode->enumeration_restriction.offset_end; i++) {
754 if (strcmp(*storage_->string_enums(i), str) == 0) 882 if (strcmp(*storage_->string_enums(i), str) == 0)
755 return true; 883 return true;
756 } 884 }
757 return false; 885 return false;
758 } 886 }
759 887
760 } // namespace policy 888 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698