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

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

Issue 139853013: Improve error message display for Schema::Validate() (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@expand-policy-schema-3
Patch Set: reupload 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>
11 #include <vector> 11 #include <vector>
12 12
13 #include "base/compiler_specific.h" 13 #include "base/compiler_specific.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/memory/scoped_vector.h" 15 #include "base/memory/scoped_vector.h"
16 #include "base/strings/stringprintf.h"
16 #include "components/json_schema/json_schema_constants.h" 17 #include "components/json_schema/json_schema_constants.h"
17 #include "components/json_schema/json_schema_validator.h" 18 #include "components/json_schema/json_schema_validator.h"
18 #include "components/policy/core/common/schema_internal.h" 19 #include "components/policy/core/common/schema_internal.h"
19 20
20 namespace schema = json_schema_constants; 21 namespace schema = json_schema_constants;
21 22
22 namespace policy { 23 namespace policy {
23 24
24 using internal::PropertiesNode; 25 using internal::PropertiesNode;
25 using internal::PropertyNode; 26 using internal::PropertyNode;
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 SCHEMA_STRICT, // SCHEMA_STRICT 98 SCHEMA_STRICT, // SCHEMA_STRICT
98 SCHEMA_STRICT, // SCHEMA_ALLOW_UNKNOWN_TOPLEVEL 99 SCHEMA_STRICT, // SCHEMA_ALLOW_UNKNOWN_TOPLEVEL
99 SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_UNKNOWN 100 SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_UNKNOWN
100 SCHEMA_STRICT, // SCHEMA_ALLOW_INVALID_TOPLEVEL 101 SCHEMA_STRICT, // SCHEMA_ALLOW_INVALID_TOPLEVEL
101 SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_INVALID_TOPLEVEL_AND_ALLOW_UNKNOWN 102 SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_INVALID_TOPLEVEL_AND_ALLOW_UNKNOWN
102 SCHEMA_ALLOW_INVALID, // SCHEMA_ALLOW_INVALID 103 SCHEMA_ALLOW_INVALID, // SCHEMA_ALLOW_INVALID
103 }; 104 };
104 return next_level_strategy[(int)strategy]; 105 return next_level_strategy[(int)strategy];
105 } 106 }
106 107
108 void SchemaFindError(std::string* error_path,std::string *error,
Joao da Silva 2014/01/23 20:59:31 A better name for this is ErrorFound
binjin 2014/01/23 21:21:58 Done.
109 const std::string& msg) {
Joao da Silva 2014/01/23 20:59:31 Format this. One argument per line: void SchemaFi
binjin 2014/01/23 21:21:58 Done.
110 if (error_path)
111 *error_path = "";
112 *error = msg;
113 }
114
115 void AddListIndexPrefixToPath(int index, std::string* path) {
116 if (path) {
117 if (path->size() == 0)
Joao da Silva 2014/01/23 20:59:31 path->empty
binjin 2014/01/23 21:21:58 Done.
118 *path = base::StringPrintf("items[%d]", index);
119 else
120 *path = base::StringPrintf("items[%d].", index) + *path;
Joao da Silva 2014/01/23 20:59:31 Maybe just "[%d]" without the "items" looks OK? E
binjin 2014/01/23 21:21:58 root schema can be a list, and things like "[4].fi
121 }
122 }
123
124 void AddDictKeyPrefixToPath(const std::string& key, std::string* path) {
125 if (path) {
126 if (path->size() == 0)
Joao da Silva 2014/01/23 20:59:31 path->empty
binjin 2014/01/23 21:21:58 Done.
127 *path = key;
128 else
129 *path = key + "." + *path;
130 }
131 }
132
107 } // namespace 133 } // namespace
108 134
109 // Contains the internal data representation of a Schema. This can either wrap 135 // Contains the internal data representation of a Schema. This can either wrap
110 // a SchemaData owned elsewhere (currently used to wrap the Chrome schema, which 136 // a SchemaData owned elsewhere (currently used to wrap the Chrome schema, which
111 // is generated at compile time), or it can own its own SchemaData. 137 // is generated at compile time), or it can own its own SchemaData.
112 class Schema::InternalStorage 138 class Schema::InternalStorage
113 : public base::RefCountedThreadSafe<InternalStorage> { 139 : public base::RefCountedThreadSafe<InternalStorage> {
114 public: 140 public:
115 static scoped_refptr<const InternalStorage> Wrap(const SchemaData* data); 141 static scoped_refptr<const InternalStorage> Wrap(const SchemaData* data);
116 142
(...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after
626 } 652 }
627 653
628 // static 654 // static
629 Schema Schema::Wrap(const SchemaData* data) { 655 Schema Schema::Wrap(const SchemaData* data) {
630 scoped_refptr<const InternalStorage> storage = InternalStorage::Wrap(data); 656 scoped_refptr<const InternalStorage> storage = InternalStorage::Wrap(data);
631 return Schema(storage, storage->root_node()); 657 return Schema(storage, storage->root_node());
632 } 658 }
633 659
634 bool Schema::Validate(const base::Value& value, 660 bool Schema::Validate(const base::Value& value,
635 SchemaOnErrorStrategy strategy, 661 SchemaOnErrorStrategy strategy,
662 std::string* error_path,
636 std::string* error) const { 663 std::string* error) const {
637 if (!valid()) { 664 if (!valid()) {
638 *error = "The schema is invalid."; 665 SchemaFindError(error_path, error, "The schema is invalid.");
639 return false; 666 return false;
640 } 667 }
641 668
642 if (!value.IsType(type())) { 669 if (!value.IsType(type())) {
643 // Allow the integer to double promition. Note that range restriction on 670 // Allow the integer to double promition. Note that range restriction on
644 // double is not supported now. 671 // double is not supported now.
645 if (value.IsType(base::Value::TYPE_INTEGER) && 672 if (value.IsType(base::Value::TYPE_INTEGER) &&
646 type() == base::Value::TYPE_DOUBLE) 673 type() == base::Value::TYPE_DOUBLE)
647 return true; 674 return true;
648 675
649 *error = "The value type doesn't match the schema type."; 676 SchemaFindError(error_path, error,
677 "The value type doesn't match the schema type.");
Joao da Silva 2014/01/23 20:59:31 Format this line.
binjin 2014/01/23 21:21:58 Done.
650 return false; 678 return false;
651 } 679 }
652 680
653 const base::DictionaryValue* dict = NULL; 681 const base::DictionaryValue* dict = NULL;
654 const base::ListValue* list = NULL; 682 const base::ListValue* list = NULL;
655 int int_value; 683 int int_value;
656 std::string str_value; 684 std::string str_value;
657 if (value.GetAsDictionary(&dict)) { 685 if (value.GetAsDictionary(&dict)) {
658 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); 686 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
659 it.Advance()) { 687 it.Advance()) {
660 Schema subschema = GetProperty(it.key()); 688 Schema subschema = GetProperty(it.key());
661 if (!subschema.valid()) { 689 if (!subschema.valid()) {
662 // Unknown property was detected. 690 // Unknown property was detected.
663 if (!StrategyAllowUnknownOnTopLevel(strategy)) { 691 SchemaFindError(error_path, error, "Unknown property: " + it.key());
664 *error = "Unknown property: " + it.key(); 692 if (!StrategyAllowUnknownOnTopLevel(strategy))
665 return false; 693 return false;
666 } 694 } else if (!subschema.Validate(it.value(),
667 } else { 695 StrategyForNextLevel(strategy), error_path, error)) {
Joao da Silva 2014/01/23 20:59:31 Format this line
binjin 2014/01/23 21:21:58 Done.
668 std::string sub_error; 696 // Invalid property was detected.
669 if (!subschema.Validate( 697 AddDictKeyPrefixToPath(it.key(), error_path);
670 it.value(), StrategyForNextLevel(strategy), &sub_error)) { 698 if (!StrategyAllowInvalidOnTopLevel(strategy))
671 // Invalid property was detected. 699 return false;
672 if (!StrategyAllowInvalidOnTopLevel(strategy)) {
673 *error = sub_error;
674 return false;
675 }
676 }
677 } 700 }
678 } 701 }
679 } else if (value.GetAsList(&list)) { 702 } else if (value.GetAsList(&list)) {
680 for (base::ListValue::const_iterator it = list->begin(); it != list->end(); 703 for (base::ListValue::const_iterator it = list->begin(); it != list->end();
681 ++it) { 704 ++it) {
682 if (!*it || 705 if (!*it ||
683 !GetItems().Validate(**it, StrategyForNextLevel(strategy), error)) { 706 !GetItems().Validate(
707 **it, StrategyForNextLevel(strategy), error_path, error)) {
684 // Invalid list item was detected. 708 // Invalid list item was detected.
709 AddListIndexPrefixToPath(it - list->begin(), error_path);
685 if (!StrategyAllowInvalidOnTopLevel(strategy)) 710 if (!StrategyAllowInvalidOnTopLevel(strategy))
686 return false; 711 return false;
687 } 712 }
688 } 713 }
689 } else if (value.GetAsInteger(&int_value)) { 714 } else if (value.GetAsInteger(&int_value)) {
690 if (node_->extra != kInvalid && 715 if (node_->extra != kInvalid &&
691 !ValidateIntegerRestriction(node_->extra, int_value)) { 716 !ValidateIntegerRestriction(node_->extra, int_value)) {
692 *error = "Invalid value for integer"; 717 SchemaFindError(error_path, error, "Invalid value for integer");
693 return false; 718 return false;
694 } 719 }
695 } else if (value.GetAsString(&str_value)) { 720 } else if (value.GetAsString(&str_value)) {
696 if (node_->extra != kInvalid && 721 if (node_->extra != kInvalid &&
697 !ValidateStringRestriction(node_->extra, str_value.c_str())) { 722 !ValidateStringRestriction(node_->extra, str_value.c_str())) {
698 *error = "Invalid value for string"; 723 SchemaFindError(error_path, error, "Invalid value for string");
699 return false; 724 return false;
700 } 725 }
701 } 726 }
702 727
703 return true; 728 return true;
704 } 729 }
705 730
706 bool Schema::Normalize(base::Value* value, 731 bool Schema::Normalize(base::Value* value,
707 SchemaOnErrorStrategy strategy, 732 SchemaOnErrorStrategy strategy,
733 std::string* error_path,
708 std::string* error) const { 734 std::string* error) const {
709 if (!valid()) { 735 if (!valid()) {
710 *error = "The schema is invalid."; 736 SchemaFindError(error_path, error, "The schema is invalid.");
711 return false; 737 return false;
712 } 738 }
713 739
714 740
715 if (!value->IsType(type())) { 741 if (!value->IsType(type())) {
716 // Allow the integer to double promition. Note that range restriction on 742 // Allow the integer to double promition. Note that range restriction on
717 // double is not supported now. 743 // double is not supported now.
718 if (value->IsType(base::Value::TYPE_INTEGER) && 744 if (value->IsType(base::Value::TYPE_INTEGER) &&
719 type() == base::Value::TYPE_DOUBLE) 745 type() == base::Value::TYPE_DOUBLE)
720 return true; 746 return true;
721 747
722 *error = "The value type doesn't match the schema type."; 748 SchemaFindError(error_path, error,
749 "The value type doesn't match the schema type.");
Joao da Silva 2014/01/23 20:59:31 Format this line
binjin 2014/01/23 21:21:58 Done.
723 return false; 750 return false;
724 } 751 }
725 752
726 base::DictionaryValue* dict = NULL; 753 base::DictionaryValue* dict = NULL;
727 base::ListValue* list = NULL; 754 base::ListValue* list = NULL;
728 if (value->GetAsDictionary(&dict)) { 755 if (value->GetAsDictionary(&dict)) {
729 std::vector<std::string> drop_list; // Contains the keys to drop. 756 std::vector<std::string> drop_list; // Contains the keys to drop.
730 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); 757 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
731 it.Advance()) { 758 it.Advance()) {
732 Schema subschema = GetProperty(it.key()); 759 Schema subschema = GetProperty(it.key());
733 if (!subschema.valid()) { 760 if (!subschema.valid()) {
734 // Unknown property was detected. 761 // Unknown property was detected.
735 if (StrategyAllowUnknownOnTopLevel(strategy)) { 762 SchemaFindError(error_path, error, "Unknown property: " + it.key());
763 if (StrategyAllowUnknownOnTopLevel(strategy))
736 drop_list.push_back(it.key()); 764 drop_list.push_back(it.key());
737 } else { 765 else
738 *error = "Unknown property: " + it.key();
739 return false; 766 return false;
740 }
741 } else { 767 } else {
742 base::Value* sub_value = NULL; 768 base::Value* sub_value = NULL;
743 dict->GetWithoutPathExpansion(it.key(), &sub_value); 769 dict->GetWithoutPathExpansion(it.key(), &sub_value);
744 std::string sub_error; 770 if (!subschema.Normalize(sub_value,
745 if (!subschema.Normalize( 771 StrategyForNextLevel(strategy),
746 sub_value, StrategyForNextLevel(strategy), &sub_error)) { 772 error_path,
773 error)) {
747 // Invalid property was detected. 774 // Invalid property was detected.
748 if (StrategyAllowInvalidOnTopLevel(strategy)) { 775 AddDictKeyPrefixToPath(it.key(), error_path);
776 if (StrategyAllowInvalidOnTopLevel(strategy))
749 drop_list.push_back(it.key()); 777 drop_list.push_back(it.key());
750 } else { 778 else
751 *error = sub_error;
752 return false; 779 return false;
753 }
754 } 780 }
755 } 781 }
756 } 782 }
757 for (std::vector<std::string>::const_iterator it = drop_list.begin(); 783 for (std::vector<std::string>::const_iterator it = drop_list.begin();
758 it != drop_list.end(); 784 it != drop_list.end();
759 ++it) { 785 ++it) {
760 dict->RemoveWithoutPathExpansion(*it, NULL); 786 dict->RemoveWithoutPathExpansion(*it, NULL);
761 } 787 }
762 return true; 788 return true;
763 } else if (value->GetAsList(&list)) { 789 } else if (value->GetAsList(&list)) {
764 std::vector<size_t> drop_list; // Contains the indexes to drop. 790 std::vector<size_t> drop_list; // Contains the indexes to drop.
765 for (size_t index = 0; index < list->GetSize(); index++) { 791 for (size_t index = 0; index < list->GetSize(); index++) {
766 base::Value* sub_value = NULL; 792 base::Value* sub_value = NULL;
767 std::string sub_error;
768 list->Get(index, &sub_value); 793 list->Get(index, &sub_value);
769 if (!sub_value || 794 if (!sub_value ||
770 !GetItems().Normalize( 795 !GetItems().Normalize(
771 sub_value, StrategyForNextLevel(strategy), &sub_error)) { 796 sub_value, StrategyForNextLevel(strategy), error_path, error)) {
772 // Invalid list item was detected. 797 // Invalid list item was detected.
773 if (StrategyAllowInvalidOnTopLevel(strategy)) { 798 AddListIndexPrefixToPath(index, error_path);
799 if (StrategyAllowInvalidOnTopLevel(strategy))
774 drop_list.push_back(index); 800 drop_list.push_back(index);
775 } else { 801 else
776 *error = sub_error;
777 return false; 802 return false;
778 }
779 } 803 }
780 } 804 }
781 for (std::vector<size_t>::reverse_iterator it = drop_list.rbegin(); 805 for (std::vector<size_t>::reverse_iterator it = drop_list.rbegin();
782 it != drop_list.rend(); ++it) { 806 it != drop_list.rend(); ++it) {
783 list->Remove(*it, NULL); 807 list->Remove(*it, NULL);
784 } 808 }
785 return true; 809 return true;
786 } 810 }
787 811
788 return Validate(*value, strategy, error); 812 return Validate(*value, strategy, error_path, error);
789 } 813 }
790 814
791 // static 815 // static
792 Schema Schema::Parse(const std::string& content, std::string* error) { 816 Schema Schema::Parse(const std::string& content, std::string* error) {
793 // Validate as a generic JSON schema, and ignore unknown attributes; they 817 // Validate as a generic JSON schema, and ignore unknown attributes; they
794 // may become used in a future version of the schema format. 818 // may become used in a future version of the schema format.
795 scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema( 819 scoped_ptr<base::DictionaryValue> dict = JSONSchemaValidator::IsValidSchema(
796 content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error); 820 content, JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, error);
797 if (!dict) 821 if (!dict)
798 return Schema(); 822 return Schema();
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
883 } else { 907 } else {
884 for (int i = rnode->enumeration_restriction.offset_begin; 908 for (int i = rnode->enumeration_restriction.offset_begin;
885 i < rnode->enumeration_restriction.offset_end; i++) { 909 i < rnode->enumeration_restriction.offset_end; i++) {
886 if (*storage_->int_enums(i) == value) 910 if (*storage_->int_enums(i) == value)
887 return true; 911 return true;
888 } 912 }
889 return false; 913 return false;
890 } 914 }
891 } 915 }
892 916
893 bool Schema::ValidateStringRestriction(int index, const char *str) const { 917 bool Schema::ValidateStringRestriction(int index, const char* str) const {
894 const RestrictionNode* rnode = storage_->restriction(index); 918 const RestrictionNode* rnode = storage_->restriction(index);
895 for (int i = rnode->enumeration_restriction.offset_begin; 919 for (int i = rnode->enumeration_restriction.offset_begin;
896 i < rnode->enumeration_restriction.offset_end; i++) { 920 i < rnode->enumeration_restriction.offset_end; i++) {
897 if (strcmp(*storage_->string_enums(i), str) == 0) 921 if (strcmp(*storage_->string_enums(i), str) == 0)
898 return true; 922 return true;
899 } 923 }
900 return false; 924 return false;
901 } 925 }
902 926
903 } // namespace policy 927 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698