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

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 style 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 {
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 promition. Note that range restriction on
Joao da Silva 2014/01/23 20:18:47 "promotion"
binjin 2014/01/23 20:38:17 Done.
644 // double is not supported now.
645 if (value.IsType(base::Value::TYPE_INTEGER) &&
646 type() == base::Value::TYPE_DOUBLE)
647 return true;
Joao da Silva 2014/01/23 20:18:47 Use {} around the "if" body when the "if" test or
binjin 2014/01/23 20:38:17 Done.
648
649 *error = "The value type doesn't match the schema type.";
619 return false; 650 return false;
651 }
620 652
621 const base::DictionaryValue* dict = NULL; 653 const base::DictionaryValue* dict = NULL;
622 const base::ListValue* list = NULL; 654 const base::ListValue* list = NULL;
623 int int_value; 655 int int_value;
624 std::string str_value; 656 std::string str_value;
625 if (value.GetAsDictionary(&dict)) { 657 if (value.GetAsDictionary(&dict)) {
626 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); 658 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
627 it.Advance()) { 659 it.Advance()) {
628 if (!GetProperty(it.key()).Validate(it.value())) 660 Schema subschema = GetProperty(it.key());
629 return false; 661 if (!subschema.valid()) {
662 // Unknown property was detected.
663 if (!StrategyAllowUnknownOnTopLevel(strategy)) {
664 *error = "Unknown property: " + it.key();
665 return false;
666 }
667 } else {
668 std::string sub_error;
669 if (!subschema.Validate(
670 it.value(), StrategyForNextLevel(strategy), &sub_error)) {
671 // Invalid property was detected.
672 if (!StrategyAllowInvalidOnTopLevel(strategy)) {
673 *error = sub_error;
674 return false;
675 }
676 }
677 }
630 } 678 }
631 } else if (value.GetAsList(&list)) { 679 } else if (value.GetAsList(&list)) {
632 for (base::ListValue::const_iterator it = list->begin(); 680 for (base::ListValue::const_iterator it = list->begin(); it != list->end();
633 it != list->end(); ++it) { 681 ++it) {
634 if (!*it || !GetItems().Validate(**it)) 682 if (!*it ||
635 return false; 683 !GetItems().Validate(**it, StrategyForNextLevel(strategy), error)) {
684 // Invalid list item was detected.
685 if (!StrategyAllowInvalidOnTopLevel(strategy))
686 return false;
687 }
636 } 688 }
637 } else if (value.GetAsInteger(&int_value)) { 689 } else if (value.GetAsInteger(&int_value)) {
638 return node_->extra == kInvalid || 690 if (node_->extra != kInvalid &&
639 ValidateIntegerRestriction(node_->extra, int_value); 691 !ValidateIntegerRestriction(node_->extra, int_value)) {
692 *error = "Invalid value for integer";
693 return false;
694 }
640 } else if (value.GetAsString(&str_value)) { 695 } else if (value.GetAsString(&str_value)) {
641 return node_->extra == kInvalid || 696 if (node_->extra != kInvalid &&
642 ValidateStringRestriction(node_->extra, str_value.c_str()); 697 !ValidateStringRestriction(node_->extra, str_value.c_str())) {
698 *error = "Invalid value for string";
699 return false;
700 }
643 } 701 }
644 702
645 return true; 703 return true;
646 } 704 }
647 705
706 bool Schema::Normalize(base::Value* value,
707 SchemaOnErrorStrategy strategy,
708 std::string* error) const {
709 if (!valid()) {
710 *error = "The schema is invalid.";
711 return false;
712 }
713
714
Joao da Silva 2014/01/23 20:18:47 remove this newline
binjin 2014/01/23 20:38:17 Done.
715 if (!value->IsType(type())) {
716 // Allow the integer to double promition. Note that range restriction on
Joao da Silva 2014/01/23 20:18:47 "promotion"
binjin 2014/01/23 20:38:17 Done.
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 *error = "The value type doesn't match the schema type.";
723 return false;
724 }
725
726 base::DictionaryValue* dict = NULL;
727 base::ListValue* list = NULL;
728 if (value->GetAsDictionary(&dict)) {
729 std::vector<std::string> drop_list; // Contains the keys to drop.
730 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
731 it.Advance()) {
732 Schema subschema = GetProperty(it.key());
733 if (!subschema.valid()) {
734 // Unknown property was detected.
735 if (StrategyAllowUnknownOnTopLevel(strategy)) {
736 drop_list.push_back(it.key());
737 } else {
738 *error = "Unknown property: " + it.key();
739 return false;
740 }
741 } else {
742 base::Value* sub_value = NULL;
743 dict->GetWithoutPathExpansion(it.key(), &sub_value);
744 std::string sub_error;
745 if (!subschema.Normalize(
746 sub_value, StrategyForNextLevel(strategy), &sub_error)) {
747 // Invalid property was detected.
748 if (StrategyAllowInvalidOnTopLevel(strategy)) {
749 drop_list.push_back(it.key());
750 } else {
751 *error = sub_error;
752 return false;
753 }
754 }
755 }
756 }
757 for (std::vector<std::string>::const_iterator it = drop_list.begin();
758 it != drop_list.end();
759 ++it) {
760 dict->RemoveWithoutPathExpansion(*it, NULL);
761 }
762 return true;
763 } else if (value->GetAsList(&list)) {
764 std::vector<size_t> drop_list; // Contains the indexes to drop.
765 for (size_t index = 0; index < list->GetSize(); index++) {
766 base::Value* sub_value = NULL;
767 std::string sub_error;
768 list->Get(index, &sub_value);
769 if (!sub_value ||
770 !GetItems().Normalize(
771 sub_value, StrategyForNextLevel(strategy), &sub_error)) {
772 // Invalid list item was detected.
773 if (StrategyAllowInvalidOnTopLevel(strategy)) {
774 drop_list.push_back(index);
775 } else {
776 *error = sub_error;
777 return false;
778 }
779 }
780 }
781 for (std::vector<size_t>::reverse_iterator it = drop_list.rbegin();
782 it != drop_list.rend(); ++it) {
783 list->Remove(*it, NULL);
784 }
785 return true;
786 }
787
788 return Validate(*value, strategy, error);
789 }
790
648 // static 791 // static
649 Schema Schema::Parse(const std::string& content, std::string* error) { 792 Schema Schema::Parse(const std::string& content, std::string* error) {
650 // Validate as a generic JSON schema, and ignore unknown attributes; they 793 // Validate as a generic JSON schema, and ignore unknown attributes; they
651 // may become used in a future version of the schema format. 794 // may become used in a future version of the schema format.
652 scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema( 795 scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema(
653 content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error); 796 content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error);
654 if (!dict) 797 if (!dict)
655 return Schema(); 798 return Schema();
656 799
657 // Validate the main type. 800 // Validate the main type.
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
751 const RestrictionNode* rnode = storage_->restriction(index); 894 const RestrictionNode* rnode = storage_->restriction(index);
752 for (int i = rnode->enumeration_restriction.offset_begin; 895 for (int i = rnode->enumeration_restriction.offset_begin;
753 i < rnode->enumeration_restriction.offset_end; i++) { 896 i < rnode->enumeration_restriction.offset_end; i++) {
754 if (strcmp(*storage_->string_enums(i), str) == 0) 897 if (strcmp(*storage_->string_enums(i), str) == 0)
755 return true; 898 return true;
756 } 899 }
757 return false; 900 return false;
758 } 901 }
759 902
760 } // namespace policy 903 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698