Revert 285173 "Removed InProcessBrowserTest::CleanUpOnMainThread()"
[chromium-blink-merge.git] / chrome / browser / extensions / api / content_settings / content_settings_store.cc
blob12f9a270e504fd8a25b945ccc169a4b3d9739422
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/content_settings/content_settings_store.h"
7 #include <set>
9 #include "base/debug/alias.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/scoped_vector.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_util.h"
15 #include "base/values.h"
16 #include "chrome/browser/content_settings/content_settings_origin_identifier_value_map.h"
17 #include "chrome/browser/content_settings/content_settings_rule.h"
18 #include "chrome/browser/content_settings/content_settings_utils.h"
19 #include "chrome/browser/extensions/api/content_settings/content_settings_api_constants.h"
20 #include "chrome/browser/extensions/api/content_settings/content_settings_helpers.h"
21 #include "content/public/browser/browser_thread.h"
23 using content::BrowserThread;
24 using content_settings::ConcatenationIterator;
25 using content_settings::Rule;
26 using content_settings::RuleIterator;
27 using content_settings::OriginIdentifierValueMap;
28 using content_settings::ResourceIdentifier;
29 using content_settings::ValueToContentSetting;
31 namespace extensions {
33 namespace helpers = content_settings_helpers;
34 namespace keys = content_settings_api_constants;
36 struct ContentSettingsStore::ExtensionEntry {
37 // Extension id
38 std::string id;
39 // Whether extension is enabled in the profile.
40 bool enabled;
41 // Content settings.
42 OriginIdentifierValueMap settings;
43 // Persistent incognito content settings.
44 OriginIdentifierValueMap incognito_persistent_settings;
45 // Session-only incognito content settings.
46 OriginIdentifierValueMap incognito_session_only_settings;
49 ContentSettingsStore::ContentSettingsStore() {
50 DCHECK(OnCorrectThread());
53 ContentSettingsStore::~ContentSettingsStore() {
54 STLDeleteValues(&entries_);
57 RuleIterator* ContentSettingsStore::GetRuleIterator(
58 ContentSettingsType type,
59 const content_settings::ResourceIdentifier& identifier,
60 bool incognito) const {
61 ScopedVector<RuleIterator> iterators;
62 // Iterate the extensions based on install time (last installed extensions
63 // first).
64 ExtensionEntryMap::const_reverse_iterator entry;
66 // The individual |RuleIterators| shouldn't lock; pass |lock_| to the
67 // |ConcatenationIterator| in a locked state.
68 scoped_ptr<base::AutoLock> auto_lock(new base::AutoLock(lock_));
70 for (entry = entries_.rbegin(); entry != entries_.rend(); ++entry) {
71 if (!entry->second->enabled)
72 continue;
74 if (incognito) {
75 iterators.push_back(
76 entry->second->incognito_session_only_settings.GetRuleIterator(
77 type,
78 identifier,
79 NULL));
80 iterators.push_back(
81 entry->second->incognito_persistent_settings.GetRuleIterator(
82 type,
83 identifier,
84 NULL));
85 } else {
86 iterators.push_back(
87 entry->second->settings.GetRuleIterator(type, identifier, NULL));
90 return new ConcatenationIterator(&iterators, auto_lock.release());
93 void ContentSettingsStore::SetExtensionContentSetting(
94 const std::string& ext_id,
95 const ContentSettingsPattern& primary_pattern,
96 const ContentSettingsPattern& secondary_pattern,
97 ContentSettingsType type,
98 const content_settings::ResourceIdentifier& identifier,
99 ContentSetting setting,
100 ExtensionPrefsScope scope) {
102 base::AutoLock lock(lock_);
103 OriginIdentifierValueMap* map = GetValueMap(ext_id, scope);
104 if (setting == CONTENT_SETTING_DEFAULT) {
105 map->DeleteValue(primary_pattern, secondary_pattern, type, identifier);
106 } else {
107 map->SetValue(primary_pattern, secondary_pattern, type, identifier,
108 new base::FundamentalValue(setting));
112 // Send notification that content settings changed.
113 // TODO(markusheintz): Notifications should only be sent if the set content
114 // setting is effective and not hidden by another setting of another
115 // extension installed more recently.
116 NotifyOfContentSettingChanged(ext_id,
117 scope != kExtensionPrefsScopeRegular);
120 void ContentSettingsStore::RegisterExtension(
121 const std::string& ext_id,
122 const base::Time& install_time,
123 bool is_enabled) {
124 base::AutoLock lock(lock_);
125 ExtensionEntryMap::iterator i = FindEntry(ext_id);
126 ExtensionEntry* entry;
127 if (i != entries_.end()) {
128 entry = i->second;
129 } else {
130 entry = new ExtensionEntry;
131 entries_.insert(std::make_pair(install_time, entry));
134 entry->id = ext_id;
135 entry->enabled = is_enabled;
138 void ContentSettingsStore::UnregisterExtension(
139 const std::string& ext_id) {
140 bool notify = false;
141 bool notify_incognito = false;
143 base::AutoLock lock(lock_);
144 ExtensionEntryMap::iterator i = FindEntry(ext_id);
145 if (i == entries_.end())
146 return;
147 notify = !i->second->settings.empty();
148 notify_incognito = !i->second->incognito_persistent_settings.empty() ||
149 !i->second->incognito_session_only_settings.empty();
151 delete i->second;
152 entries_.erase(i);
154 if (notify)
155 NotifyOfContentSettingChanged(ext_id, false);
156 if (notify_incognito)
157 NotifyOfContentSettingChanged(ext_id, true);
160 void ContentSettingsStore::SetExtensionState(
161 const std::string& ext_id, bool is_enabled) {
162 bool notify = false;
163 bool notify_incognito = false;
165 base::AutoLock lock(lock_);
166 ExtensionEntryMap::const_iterator i = FindEntry(ext_id);
167 if (i == entries_.end())
168 return;
169 notify = !i->second->settings.empty();
170 notify_incognito = !i->second->incognito_persistent_settings.empty() ||
171 !i->second->incognito_session_only_settings.empty();
173 i->second->enabled = is_enabled;
175 if (notify)
176 NotifyOfContentSettingChanged(ext_id, false);
177 if (notify_incognito)
178 NotifyOfContentSettingChanged(ext_id, true);
181 OriginIdentifierValueMap* ContentSettingsStore::GetValueMap(
182 const std::string& ext_id,
183 ExtensionPrefsScope scope) {
184 ExtensionEntryMap::const_iterator i = FindEntry(ext_id);
185 if (i != entries_.end()) {
186 switch (scope) {
187 case kExtensionPrefsScopeRegular:
188 return &(i->second->settings);
189 case kExtensionPrefsScopeRegularOnly:
190 // TODO(bauerb): Implement regular-only content settings.
191 NOTREACHED();
192 return NULL;
193 case kExtensionPrefsScopeIncognitoPersistent:
194 return &(i->second->incognito_persistent_settings);
195 case kExtensionPrefsScopeIncognitoSessionOnly:
196 return &(i->second->incognito_session_only_settings);
199 return NULL;
202 const OriginIdentifierValueMap* ContentSettingsStore::GetValueMap(
203 const std::string& ext_id,
204 ExtensionPrefsScope scope) const {
205 ExtensionEntryMap::const_iterator i = FindEntry(ext_id);
206 if (i == entries_.end())
207 return NULL;
209 switch (scope) {
210 case kExtensionPrefsScopeRegular:
211 return &(i->second->settings);
212 case kExtensionPrefsScopeRegularOnly:
213 // TODO(bauerb): Implement regular-only content settings.
214 NOTREACHED();
215 return NULL;
216 case kExtensionPrefsScopeIncognitoPersistent:
217 return &(i->second->incognito_persistent_settings);
218 case kExtensionPrefsScopeIncognitoSessionOnly:
219 return &(i->second->incognito_session_only_settings);
222 NOTREACHED();
223 return NULL;
226 void ContentSettingsStore::ClearContentSettingsForExtension(
227 const std::string& ext_id,
228 ExtensionPrefsScope scope) {
229 bool notify = false;
231 base::AutoLock lock(lock_);
232 OriginIdentifierValueMap* map = GetValueMap(ext_id, scope);
233 if (!map) {
234 // Fail gracefully in Release builds.
235 NOTREACHED();
236 return;
238 notify = !map->empty();
239 map->clear();
241 if (notify) {
242 NotifyOfContentSettingChanged(ext_id, scope != kExtensionPrefsScopeRegular);
246 base::ListValue* ContentSettingsStore::GetSettingsForExtension(
247 const std::string& extension_id,
248 ExtensionPrefsScope scope) const {
249 base::AutoLock lock(lock_);
250 const OriginIdentifierValueMap* map = GetValueMap(extension_id, scope);
251 if (!map)
252 return NULL;
253 base::ListValue* settings = new base::ListValue();
254 OriginIdentifierValueMap::EntryMap::const_iterator it;
255 for (it = map->begin(); it != map->end(); ++it) {
256 scoped_ptr<RuleIterator> rule_iterator(
257 map->GetRuleIterator(it->first.content_type,
258 it->first.resource_identifier,
259 NULL)); // We already hold the lock.
260 while (rule_iterator->HasNext()) {
261 const Rule& rule = rule_iterator->Next();
262 base::DictionaryValue* setting_dict = new base::DictionaryValue();
263 setting_dict->SetString(keys::kPrimaryPatternKey,
264 rule.primary_pattern.ToString());
265 setting_dict->SetString(keys::kSecondaryPatternKey,
266 rule.secondary_pattern.ToString());
267 setting_dict->SetString(
268 keys::kContentSettingsTypeKey,
269 helpers::ContentSettingsTypeToString(it->first.content_type));
270 setting_dict->SetString(keys::kResourceIdentifierKey,
271 it->first.resource_identifier);
272 ContentSetting content_setting = ValueToContentSetting(rule.value.get());
273 DCHECK_NE(CONTENT_SETTING_DEFAULT, content_setting);
274 setting_dict->SetString(
275 keys::kContentSettingKey,
276 helpers::ContentSettingToString(content_setting));
277 settings->Append(setting_dict);
280 return settings;
283 void ContentSettingsStore::SetExtensionContentSettingFromList(
284 const std::string& extension_id,
285 const base::ListValue* list,
286 ExtensionPrefsScope scope) {
287 for (base::ListValue::const_iterator it = list->begin();
288 it != list->end(); ++it) {
289 if ((*it)->GetType() != base::Value::TYPE_DICTIONARY) {
290 NOTREACHED();
291 continue;
293 base::DictionaryValue* dict = static_cast<base::DictionaryValue*>(*it);
294 std::string primary_pattern_str;
295 dict->GetString(keys::kPrimaryPatternKey, &primary_pattern_str);
296 ContentSettingsPattern primary_pattern =
297 ContentSettingsPattern::FromString(primary_pattern_str);
298 DCHECK(primary_pattern.IsValid());
300 std::string secondary_pattern_str;
301 dict->GetString(keys::kSecondaryPatternKey, &secondary_pattern_str);
302 ContentSettingsPattern secondary_pattern =
303 ContentSettingsPattern::FromString(secondary_pattern_str);
304 DCHECK(secondary_pattern.IsValid());
306 std::string content_settings_type_str;
307 dict->GetString(keys::kContentSettingsTypeKey, &content_settings_type_str);
308 ContentSettingsType content_settings_type =
309 helpers::StringToContentSettingsType(content_settings_type_str);
310 DCHECK_NE(CONTENT_SETTINGS_TYPE_DEFAULT, content_settings_type);
312 std::string resource_identifier;
313 dict->GetString(keys::kResourceIdentifierKey, &resource_identifier);
315 std::string content_setting_string;
316 dict->GetString(keys::kContentSettingKey, &content_setting_string);
317 ContentSetting setting = CONTENT_SETTING_DEFAULT;
318 bool result =
319 helpers::StringToContentSetting(content_setting_string, &setting);
320 DCHECK(result);
322 SetExtensionContentSetting(extension_id,
323 primary_pattern,
324 secondary_pattern,
325 content_settings_type,
326 resource_identifier,
327 setting,
328 scope);
332 void ContentSettingsStore::AddObserver(Observer* observer) {
333 DCHECK(OnCorrectThread());
334 observers_.AddObserver(observer);
337 void ContentSettingsStore::RemoveObserver(Observer* observer) {
338 DCHECK(OnCorrectThread());
339 observers_.RemoveObserver(observer);
342 void ContentSettingsStore::NotifyOfContentSettingChanged(
343 const std::string& extension_id,
344 bool incognito) {
345 FOR_EACH_OBSERVER(
346 ContentSettingsStore::Observer,
347 observers_,
348 OnContentSettingChanged(extension_id, incognito));
351 bool ContentSettingsStore::OnCorrectThread() {
352 // If there is no UI thread, we're most likely in a unit test.
353 return !BrowserThread::IsThreadInitialized(BrowserThread::UI) ||
354 BrowserThread::CurrentlyOn(BrowserThread::UI);
357 ContentSettingsStore::ExtensionEntryMap::iterator
358 ContentSettingsStore::FindEntry(const std::string& ext_id) {
359 ExtensionEntryMap::iterator i;
360 for (i = entries_.begin(); i != entries_.end(); ++i) {
361 if (i->second->id == ext_id)
362 return i;
364 return entries_.end();
367 ContentSettingsStore::ExtensionEntryMap::const_iterator
368 ContentSettingsStore::FindEntry(const std::string& ext_id) const {
369 ExtensionEntryMap::const_iterator i;
370 for (i = entries_.begin(); i != entries_.end(); ++i) {
371 if (i->second->id == ext_id)
372 return i;
374 return entries_.end();
377 } // namespace extensions