• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
RendererContentMatchData()36 RendererContentMatchData::RendererContentMatchData() {}
~RendererContentMatchData()37 RendererContentMatchData::~RendererContentMatchData() {}
38 
39 //
40 // ContentCondition
41 //
42 
ContentCondition(scoped_refptr<URLMatcherConditionSet> url_matcher_conditions,const std::vector<std::string> & css_selectors)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 
~ContentCondition()51 ContentCondition::~ContentCondition() {}
52 
IsFulfilled(const RendererContentMatchData & renderer_data) const53 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
Create(const Extension * extension,URLMatcherConditionFactory * url_matcher_condition_factory,const base::Value & condition,std::string * error)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 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