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"
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
{
39 // Whether extension is enabled in the profile.
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
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
)
76 entry
->second
->incognito_session_only_settings
.GetRuleIterator(
81 entry
->second
->incognito_persistent_settings
.GetRuleIterator(
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
);
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
,
124 base::AutoLock
lock(lock_
);
125 ExtensionEntryMap::iterator i
= FindEntry(ext_id
);
126 ExtensionEntry
* entry
;
127 if (i
!= entries_
.end()) {
130 entry
= new ExtensionEntry
;
131 entries_
.insert(std::make_pair(install_time
, entry
));
135 entry
->enabled
= is_enabled
;
138 void ContentSettingsStore::UnregisterExtension(
139 const std::string
& ext_id
) {
141 bool notify_incognito
= false;
143 base::AutoLock
lock(lock_
);
144 ExtensionEntryMap::iterator i
= FindEntry(ext_id
);
145 if (i
== entries_
.end())
147 notify
= !i
->second
->settings
.empty();
148 notify_incognito
= !i
->second
->incognito_persistent_settings
.empty() ||
149 !i
->second
->incognito_session_only_settings
.empty();
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
) {
163 bool notify_incognito
= false;
165 base::AutoLock
lock(lock_
);
166 ExtensionEntryMap::const_iterator i
= FindEntry(ext_id
);
167 if (i
== entries_
.end())
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
;
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()) {
187 case kExtensionPrefsScopeRegular
:
188 return &(i
->second
->settings
);
189 case kExtensionPrefsScopeRegularOnly
:
190 // TODO(bauerb): Implement regular-only content settings.
193 case kExtensionPrefsScopeIncognitoPersistent
:
194 return &(i
->second
->incognito_persistent_settings
);
195 case kExtensionPrefsScopeIncognitoSessionOnly
:
196 return &(i
->second
->incognito_session_only_settings
);
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())
210 case kExtensionPrefsScopeRegular
:
211 return &(i
->second
->settings
);
212 case kExtensionPrefsScopeRegularOnly
:
213 // TODO(bauerb): Implement regular-only content settings.
216 case kExtensionPrefsScopeIncognitoPersistent
:
217 return &(i
->second
->incognito_persistent_settings
);
218 case kExtensionPrefsScopeIncognitoSessionOnly
:
219 return &(i
->second
->incognito_session_only_settings
);
226 void ContentSettingsStore::ClearContentSettingsForExtension(
227 const std::string
& ext_id
,
228 ExtensionPrefsScope scope
) {
231 base::AutoLock
lock(lock_
);
232 OriginIdentifierValueMap
* map
= GetValueMap(ext_id
, scope
);
234 // Fail gracefully in Release builds.
238 notify
= !map
->empty();
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
);
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
);
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
) {
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
;
319 helpers::StringToContentSetting(content_setting_string
, &setting
);
322 SetExtensionContentSetting(extension_id
,
325 content_settings_type
,
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
,
346 ContentSettingsStore::Observer
,
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
)
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
)
374 return entries_
.end();
377 } // namespace extensions