Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / api / declarative_content / content_condition.cc
blobbfdd6c958e155b7fa58020acf9b48c01f7f883bf
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.
5 #include "chrome/browser/extensions/api/declarative_content/content_condition.h"
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 #include "extensions/common/extension.h"
12 #include "extensions/common/permissions/permissions_data.h"
14 using url_matcher::URLMatcherConditionSet;
16 namespace extensions {
18 namespace {
19 static URLMatcherConditionSet::ID g_next_id = 0;
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 kInvalidTypeOfParameter[] = "Attribute '%s' has an invalid type";
30 const char kIsBookmarkedRequiresBookmarkPermission[] =
31 "Property 'isBookmarked' requires 'bookmarks' permission";
33 bool HasBookmarkAPIPermission(const Extension* extension) {
34 return extension->permissions_data()->HasAPIPermission(
35 APIPermission::kBookmark);
38 } // namespace
40 namespace keys = declarative_content_constants;
42 RendererContentMatchData::RendererContentMatchData() : is_bookmarked(false) {}
43 RendererContentMatchData::~RendererContentMatchData() {}
45 ContentCondition::ContentCondition(
46 scoped_refptr<const Extension> extension,
47 scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set,
48 const std::vector<std::string>& css_selectors,
49 BookmarkedStateMatch bookmarked_state)
50 : extension_(extension.Pass()),
51 url_matcher_condition_set_(url_matcher_condition_set),
52 css_selectors_(css_selectors),
53 bookmarked_state_(bookmarked_state) {
54 DCHECK(url_matcher_condition_set_.get());
57 ContentCondition::~ContentCondition() {}
59 bool ContentCondition::IsFulfilled(
60 const RendererContentMatchData& renderer_data) const {
61 if (!ContainsKey(renderer_data.page_url_matches,
62 url_matcher_condition_set_->id()))
63 return false;
65 // All attributes must be fulfilled for a fulfilled condition.
66 for (const std::string& css_selector : css_selectors_) {
67 if (!ContainsKey(renderer_data.css_selectors, css_selector))
68 return false;
71 if (HasBookmarkAPIPermission(extension_.get())) {
72 if ((bookmarked_state_ == BOOKMARKED && !renderer_data.is_bookmarked) ||
73 (bookmarked_state_ == NOT_BOOKMARKED && renderer_data.is_bookmarked)) {
74 return false;
78 return true;
81 // static
82 scoped_ptr<ContentCondition> ContentCondition::Create(
83 scoped_refptr<const Extension> extension,
84 url_matcher::URLMatcherConditionFactory* url_matcher_condition_factory,
85 const base::Value& condition,
86 std::string* error) {
87 const base::DictionaryValue* condition_dict = NULL;
88 if (!condition.GetAsDictionary(&condition_dict)) {
89 *error = kExpectedDictionary;
90 return scoped_ptr<ContentCondition>();
93 // Verify that we are dealing with a Condition whose type we understand.
94 std::string instance_type;
95 if (!condition_dict->GetString(keys::kInstanceType, &instance_type)) {
96 *error = kConditionWithoutInstanceType;
97 return scoped_ptr<ContentCondition>();
99 if (instance_type != keys::kPageStateMatcherType) {
100 *error = kExpectedOtherConditionType;
101 return scoped_ptr<ContentCondition>();
104 scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set;
105 std::vector<std::string> css_rules;
106 BookmarkedStateMatch bookmarked_state = DONT_CARE;
108 for (base::DictionaryValue::Iterator iter(*condition_dict);
109 !iter.IsAtEnd(); iter.Advance()) {
110 const std::string& condition_attribute_name = iter.key();
111 const base::Value& condition_attribute_value = iter.value();
112 if (condition_attribute_name == keys::kInstanceType) {
113 // Skip this.
114 } else if (condition_attribute_name == keys::kPageUrl) {
115 const base::DictionaryValue* dict = NULL;
116 if (!condition_attribute_value.GetAsDictionary(&dict)) {
117 *error = base::StringPrintf(kInvalidTypeOfParameter,
118 condition_attribute_name.c_str());
119 } else {
120 url_matcher_condition_set =
121 url_matcher::URLMatcherFactory::CreateFromURLFilterDictionary(
122 url_matcher_condition_factory, dict, ++g_next_id, error);
124 } else if (condition_attribute_name == keys::kCss) {
125 const base::ListValue* css_rules_value = NULL;
126 if (condition_attribute_value.GetAsList(&css_rules_value)) {
127 for (size_t i = 0; i < css_rules_value->GetSize(); ++i) {
128 std::string css_rule;
129 if (!css_rules_value->GetString(i, &css_rule)) {
130 *error = base::StringPrintf(kInvalidTypeOfParameter,
131 condition_attribute_name.c_str());
132 break;
134 css_rules.push_back(css_rule);
136 } else {
137 *error = base::StringPrintf(kInvalidTypeOfParameter,
138 condition_attribute_name.c_str());
140 } else if (condition_attribute_name == keys::kIsBookmarked){
141 bool value;
142 if (condition_attribute_value.GetAsBoolean(&value)) {
143 if (!HasBookmarkAPIPermission(extension.get()))
144 *error = kIsBookmarkedRequiresBookmarkPermission;
145 else
146 bookmarked_state = value ? BOOKMARKED : NOT_BOOKMARKED;
147 } else {
148 *error = base::StringPrintf(kInvalidTypeOfParameter,
149 condition_attribute_name.c_str());
151 } else {
152 *error = base::StringPrintf(kUnknownConditionAttribute,
153 condition_attribute_name.c_str());
155 if (!error->empty())
156 return scoped_ptr<ContentCondition>();
159 if (!url_matcher_condition_set.get()) {
160 URLMatcherConditionSet::Conditions url_matcher_conditions;
161 url_matcher_conditions.insert(
162 url_matcher_condition_factory->CreateHostPrefixCondition(
163 std::string()));
164 url_matcher_condition_set =
165 new URLMatcherConditionSet(++g_next_id, url_matcher_conditions);
167 return make_scoped_ptr(
168 new ContentCondition(extension.Pass(), url_matcher_condition_set,
169 css_rules, bookmarked_state));
172 } // namespace extensions