1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/extensions/api/declarative_content/content_condition.h" 6 7 #include "base/strings/stringprintf.h" 8 #include "base/values.h" 9 #include "chrome/browser/extensions/api/declarative_content/content_constants.h" 10 #include "components/url_matcher/url_matcher_factory.h" 11 12 using url_matcher::URLMatcherConditionFactory; 13 using url_matcher::URLMatcherConditionSet; 14 using url_matcher::URLMatcherFactory; 15 16 namespace keys = extensions::declarative_content_constants; 17 18 namespace { 19 static URLMatcherConditionSet::ID g_next_id = 0; 20 21 // TODO(jyasskin): improve error messaging to give more meaningful messages 22 // to the extension developer. 23 // Error messages: 24 const char kExpectedDictionary[] = "A condition has to be a dictionary."; 25 const char kConditionWithoutInstanceType[] = "A condition had no instanceType"; 26 const char kExpectedOtherConditionType[] = "Expected a condition of type " 27 "declarativeContent.PageStateMatcher"; 28 const char kUnknownConditionAttribute[] = "Unknown condition attribute '%s'"; 29 const char kInvalidTypeOfParamter[] = "Attribute '%s' has an invalid type"; 30 } // namespace 31 32 namespace extensions { 33 34 namespace keys = declarative_content_constants; 35 36 RendererContentMatchData::RendererContentMatchData() {} 37 RendererContentMatchData::~RendererContentMatchData() {} 38 39 // 40 // ContentCondition 41 // 42 43 ContentCondition::ContentCondition( 44 scoped_refptr<URLMatcherConditionSet> url_matcher_conditions, 45 const std::vector<std::string>& css_selectors) 46 : url_matcher_conditions_(url_matcher_conditions), 47 css_selectors_(css_selectors) { 48 CHECK(url_matcher_conditions.get()); 49 } 50 51 ContentCondition::~ContentCondition() {} 52 53 bool ContentCondition::IsFulfilled( 54 const RendererContentMatchData& renderer_data) const { 55 if (!ContainsKey(renderer_data.page_url_matches, 56 url_matcher_conditions_->id())) 57 return false; 58 59 // All attributes must be fulfilled for a fulfilled condition. 60 for (std::vector<std::string>::const_iterator i = 61 css_selectors_.begin(); i != css_selectors_.end(); ++i) { 62 if (!ContainsKey(renderer_data.css_selectors, *i)) 63 return false; 64 } 65 return true; 66 } 67 68 // static 69 scoped_ptr<ContentCondition> ContentCondition::Create( 70 const Extension* extension, 71 URLMatcherConditionFactory* url_matcher_condition_factory, 72 const base::Value& condition, 73 std::string* error) { 74 const base::DictionaryValue* condition_dict = NULL; 75 if (!condition.GetAsDictionary(&condition_dict)) { 76 *error = kExpectedDictionary; 77 return scoped_ptr<ContentCondition>(); 78 } 79 80 // Verify that we are dealing with a Condition whose type we understand. 81 std::string instance_type; 82 if (!condition_dict->GetString(keys::kInstanceType, &instance_type)) { 83 *error = kConditionWithoutInstanceType; 84 return scoped_ptr<ContentCondition>(); 85 } 86 if (instance_type != keys::kPageStateMatcherType) { 87 *error = kExpectedOtherConditionType; 88 return scoped_ptr<ContentCondition>(); 89 } 90 91 scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set; 92 std::vector<std::string> css_rules; 93 94 for (base::DictionaryValue::Iterator iter(*condition_dict); 95 !iter.IsAtEnd(); iter.Advance()) { 96 const std::string& condition_attribute_name = iter.key(); 97 const base::Value& condition_attribute_value = iter.value(); 98 if (condition_attribute_name == keys::kInstanceType) { 99 // Skip this. 100 } else if (condition_attribute_name == keys::kPageUrl) { 101 const base::DictionaryValue* dict = NULL; 102 if (!condition_attribute_value.GetAsDictionary(&dict)) { 103 *error = base::StringPrintf(kInvalidTypeOfParamter, 104 condition_attribute_name.c_str()); 105 } else { 106 url_matcher_condition_set = 107 URLMatcherFactory::CreateFromURLFilterDictionary( 108 url_matcher_condition_factory, dict, ++g_next_id, error); 109 } 110 } else if (condition_attribute_name == keys::kCss) { 111 const base::ListValue* css_rules_value = NULL; 112 if (condition_attribute_value.GetAsList(&css_rules_value)) { 113 for (size_t i = 0; i < css_rules_value->GetSize(); ++i) { 114 std::string css_rule; 115 if (!css_rules_value->GetString(i, &css_rule)) { 116 *error = base::StringPrintf(kInvalidTypeOfParamter, 117 condition_attribute_name.c_str()); 118 break; 119 } 120 css_rules.push_back(css_rule); 121 } 122 } else { 123 *error = base::StringPrintf(kInvalidTypeOfParamter, 124 condition_attribute_name.c_str()); 125 } 126 } else { 127 *error = base::StringPrintf(kUnknownConditionAttribute, 128 condition_attribute_name.c_str()); 129 } 130 if (!error->empty()) 131 return scoped_ptr<ContentCondition>(); 132 } 133 134 if (!url_matcher_condition_set.get()) { 135 URLMatcherConditionSet::Conditions url_matcher_conditions; 136 url_matcher_conditions.insert( 137 url_matcher_condition_factory->CreateHostPrefixCondition( 138 std::string())); 139 url_matcher_condition_set = 140 new URLMatcherConditionSet(++g_next_id, url_matcher_conditions); 141 } 142 return scoped_ptr<ContentCondition>( 143 new ContentCondition(url_matcher_condition_set, css_rules)); 144 } 145 146 } // namespace extensions 147