OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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/extension_content_settings_store.h" | |
6 | |
7 #include <set> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "base/memory/scoped_vector.h" | |
12 #include "base/stl_util.h" | |
13 #include "base/values.h" | |
14 #include "chrome/browser/content_settings/content_settings_origin_identifier_val
ue_map.h" | |
15 #include "chrome/browser/content_settings/content_settings_rule.h" | |
16 #include "chrome/browser/content_settings/content_settings_utils.h" | |
17 #include "chrome/browser/extensions/extension_content_settings_api_constants.h" | |
18 #include "chrome/browser/extensions/extension_content_settings_helpers.h" | |
19 #include "content/public/browser/browser_thread.h" | |
20 | |
21 namespace helpers = extension_content_settings_helpers; | |
22 namespace keys = extension_content_settings_api_constants; | |
23 | |
24 using content::BrowserThread; | |
25 using content_settings::ConcatenationIterator; | |
26 using content_settings::Rule; | |
27 using content_settings::RuleIterator; | |
28 using content_settings::OriginIdentifierValueMap; | |
29 using content_settings::ResourceIdentifier; | |
30 using content_settings::ValueToContentSetting; | |
31 | |
32 struct ExtensionContentSettingsStore::ExtensionEntry { | |
33 // Extension id | |
34 std::string id; | |
35 // Whether extension is enabled in the profile. | |
36 bool enabled; | |
37 // Content settings. | |
38 OriginIdentifierValueMap settings; | |
39 // Persistent incognito content settings. | |
40 OriginIdentifierValueMap incognito_persistent_settings; | |
41 // Session-only incognito content settings. | |
42 OriginIdentifierValueMap incognito_session_only_settings; | |
43 }; | |
44 | |
45 ExtensionContentSettingsStore::ExtensionContentSettingsStore() { | |
46 DCHECK(OnCorrectThread()); | |
47 } | |
48 | |
49 ExtensionContentSettingsStore::~ExtensionContentSettingsStore() { | |
50 STLDeleteValues(&entries_); | |
51 } | |
52 | |
53 RuleIterator* ExtensionContentSettingsStore::GetRuleIterator( | |
54 ContentSettingsType type, | |
55 const content_settings::ResourceIdentifier& identifier, | |
56 bool incognito) const { | |
57 ScopedVector<RuleIterator> iterators; | |
58 // Iterate the extensions based on install time (last installed extensions | |
59 // first). | |
60 ExtensionEntryMap::const_reverse_iterator entry; | |
61 | |
62 // The individual |RuleIterators| shouldn't lock; pass |lock_| to the | |
63 // |ConcatenationIterator| in a locked state. | |
64 scoped_ptr<base::AutoLock> auto_lock(new base::AutoLock(lock_)); | |
65 | |
66 for (entry = entries_.rbegin(); entry != entries_.rend(); ++entry) { | |
67 if (!entry->second->enabled) | |
68 continue; | |
69 | |
70 if (incognito) { | |
71 iterators.push_back( | |
72 entry->second->incognito_session_only_settings.GetRuleIterator( | |
73 type, | |
74 identifier, | |
75 NULL)); | |
76 iterators.push_back( | |
77 entry->second->incognito_persistent_settings.GetRuleIterator( | |
78 type, | |
79 identifier, | |
80 NULL)); | |
81 } else { | |
82 iterators.push_back( | |
83 entry->second->settings.GetRuleIterator(type, identifier, NULL)); | |
84 } | |
85 } | |
86 return new ConcatenationIterator(&iterators, auto_lock.release()); | |
87 } | |
88 | |
89 void ExtensionContentSettingsStore::SetExtensionContentSetting( | |
90 const std::string& ext_id, | |
91 const ContentSettingsPattern& primary_pattern, | |
92 const ContentSettingsPattern& secondary_pattern, | |
93 ContentSettingsType type, | |
94 const content_settings::ResourceIdentifier& identifier, | |
95 ContentSetting setting, | |
96 ExtensionPrefsScope scope) { | |
97 { | |
98 base::AutoLock lock(lock_); | |
99 OriginIdentifierValueMap* map = GetValueMap(ext_id, scope); | |
100 if (setting == CONTENT_SETTING_DEFAULT) { | |
101 map->DeleteValue(primary_pattern, secondary_pattern, type, identifier); | |
102 } else { | |
103 map->SetValue(primary_pattern, secondary_pattern, type, identifier, | |
104 base::Value::CreateIntegerValue(setting)); | |
105 } | |
106 } | |
107 | |
108 // Send notification that content settings changed. | |
109 // TODO(markusheintz): Notifications should only be sent if the set content | |
110 // setting is effective and not hidden by another setting of another | |
111 // extension installed more recently. | |
112 NotifyOfContentSettingChanged(ext_id, | |
113 scope != kExtensionPrefsScopeRegular); | |
114 } | |
115 | |
116 void ExtensionContentSettingsStore::RegisterExtension( | |
117 const std::string& ext_id, | |
118 const base::Time& install_time, | |
119 bool is_enabled) { | |
120 base::AutoLock lock(lock_); | |
121 ExtensionEntryMap::iterator i = FindEntry(ext_id); | |
122 if (i != entries_.end()) { | |
123 delete i->second; | |
124 entries_.erase(i); | |
125 } | |
126 | |
127 ExtensionEntry* entry = new ExtensionEntry; | |
128 entry->id = ext_id; | |
129 entry->enabled = is_enabled; | |
130 entries_.insert(std::make_pair(install_time, entry)); | |
131 } | |
132 | |
133 void ExtensionContentSettingsStore::UnregisterExtension( | |
134 const std::string& ext_id) { | |
135 bool notify = false; | |
136 bool notify_incognito = false; | |
137 { | |
138 base::AutoLock lock(lock_); | |
139 ExtensionEntryMap::iterator i = FindEntry(ext_id); | |
140 if (i == entries_.end()) | |
141 return; | |
142 notify = !i->second->settings.empty(); | |
143 notify_incognito = !i->second->incognito_persistent_settings.empty() || | |
144 !i->second->incognito_session_only_settings.empty(); | |
145 | |
146 delete i->second; | |
147 entries_.erase(i); | |
148 } | |
149 if (notify) | |
150 NotifyOfContentSettingChanged(ext_id, false); | |
151 if (notify_incognito) | |
152 NotifyOfContentSettingChanged(ext_id, true); | |
153 } | |
154 | |
155 void ExtensionContentSettingsStore::SetExtensionState( | |
156 const std::string& ext_id, bool is_enabled) { | |
157 bool notify = false; | |
158 bool notify_incognito = false; | |
159 { | |
160 base::AutoLock lock(lock_); | |
161 ExtensionEntryMap::const_iterator i = FindEntry(ext_id); | |
162 if (i == entries_.end()) | |
163 return; | |
164 notify = !i->second->settings.empty(); | |
165 notify_incognito = !i->second->incognito_persistent_settings.empty() || | |
166 !i->second->incognito_session_only_settings.empty(); | |
167 | |
168 i->second->enabled = is_enabled; | |
169 } | |
170 if (notify) | |
171 NotifyOfContentSettingChanged(ext_id, false); | |
172 if (notify_incognito) | |
173 NotifyOfContentSettingChanged(ext_id, true); | |
174 } | |
175 | |
176 OriginIdentifierValueMap* ExtensionContentSettingsStore::GetValueMap( | |
177 const std::string& ext_id, | |
178 ExtensionPrefsScope scope) { | |
179 ExtensionEntryMap::const_iterator i = FindEntry(ext_id); | |
180 if (i != entries_.end()) { | |
181 switch (scope) { | |
182 case kExtensionPrefsScopeRegular: | |
183 return &(i->second->settings); | |
184 case kExtensionPrefsScopeIncognitoPersistent: | |
185 return &(i->second->incognito_persistent_settings); | |
186 case kExtensionPrefsScopeIncognitoSessionOnly: | |
187 return &(i->second->incognito_session_only_settings); | |
188 } | |
189 } | |
190 return NULL; | |
191 } | |
192 | |
193 const OriginIdentifierValueMap* ExtensionContentSettingsStore::GetValueMap( | |
194 const std::string& ext_id, | |
195 ExtensionPrefsScope scope) const { | |
196 ExtensionEntryMap::const_iterator i = FindEntry(ext_id); | |
197 if (i != entries_.end()) { | |
198 switch (scope) { | |
199 case kExtensionPrefsScopeRegular: | |
200 return &(i->second->settings); | |
201 case kExtensionPrefsScopeIncognitoPersistent: | |
202 return &(i->second->incognito_persistent_settings); | |
203 case kExtensionPrefsScopeIncognitoSessionOnly: | |
204 return &(i->second->incognito_session_only_settings); | |
205 } | |
206 } | |
207 return NULL; | |
208 } | |
209 | |
210 void ExtensionContentSettingsStore::ClearContentSettingsForExtension( | |
211 const std::string& ext_id, | |
212 ExtensionPrefsScope scope) { | |
213 bool notify = false; | |
214 { | |
215 base::AutoLock lock(lock_); | |
216 OriginIdentifierValueMap* map = GetValueMap(ext_id, scope); | |
217 notify = !map->empty(); | |
218 map->clear(); | |
219 } | |
220 if (notify) { | |
221 NotifyOfContentSettingChanged(ext_id, scope != kExtensionPrefsScopeRegular); | |
222 } | |
223 } | |
224 | |
225 base::ListValue* ExtensionContentSettingsStore::GetSettingsForExtension( | |
226 const std::string& extension_id, | |
227 ExtensionPrefsScope scope) const { | |
228 base::AutoLock lock(lock_); | |
229 const OriginIdentifierValueMap* map = GetValueMap(extension_id, scope); | |
230 if (!map) | |
231 return NULL; | |
232 base::ListValue* settings = new base::ListValue(); | |
233 OriginIdentifierValueMap::EntryMap::const_iterator it; | |
234 for (it = map->begin(); it != map->end(); ++it) { | |
235 scoped_ptr<RuleIterator> rule_iterator( | |
236 map->GetRuleIterator(it->first.content_type, | |
237 it->first.resource_identifier, | |
238 NULL)); // We already hold the lock. | |
239 while (rule_iterator->HasNext()) { | |
240 const Rule& rule = rule_iterator->Next(); | |
241 base::DictionaryValue* setting_dict = new base::DictionaryValue(); | |
242 setting_dict->SetString(keys::kPrimaryPatternKey, | |
243 rule.primary_pattern.ToString()); | |
244 setting_dict->SetString(keys::kSecondaryPatternKey, | |
245 rule.secondary_pattern.ToString()); | |
246 setting_dict->SetString( | |
247 keys::kContentSettingsTypeKey, | |
248 helpers::ContentSettingsTypeToString(it->first.content_type)); | |
249 setting_dict->SetString(keys::kResourceIdentifierKey, | |
250 it->first.resource_identifier); | |
251 ContentSetting content_setting = ValueToContentSetting(rule.value.get()); | |
252 DCHECK_NE(CONTENT_SETTING_DEFAULT, content_setting); | |
253 setting_dict->SetString( | |
254 keys::kContentSettingKey, | |
255 helpers::ContentSettingToString(content_setting)); | |
256 settings->Append(setting_dict); | |
257 } | |
258 } | |
259 return settings; | |
260 } | |
261 | |
262 void ExtensionContentSettingsStore::SetExtensionContentSettingsFromList( | |
263 const std::string& extension_id, | |
264 const base::ListValue* list, | |
265 ExtensionPrefsScope scope) { | |
266 for (base::ListValue::const_iterator it = list->begin(); | |
267 it != list->end(); ++it) { | |
268 if ((*it)->GetType() != Value::TYPE_DICTIONARY) { | |
269 NOTREACHED(); | |
270 continue; | |
271 } | |
272 base::DictionaryValue* dict = static_cast<base::DictionaryValue*>(*it); | |
273 std::string primary_pattern_str; | |
274 dict->GetString(keys::kPrimaryPatternKey, &primary_pattern_str); | |
275 ContentSettingsPattern primary_pattern = | |
276 ContentSettingsPattern::FromString(primary_pattern_str); | |
277 DCHECK(primary_pattern.IsValid()); | |
278 | |
279 std::string secondary_pattern_str; | |
280 dict->GetString(keys::kSecondaryPatternKey, &secondary_pattern_str); | |
281 ContentSettingsPattern secondary_pattern = | |
282 ContentSettingsPattern::FromString(secondary_pattern_str); | |
283 DCHECK(secondary_pattern.IsValid()); | |
284 | |
285 std::string content_settings_type_str; | |
286 dict->GetString(keys::kContentSettingsTypeKey, &content_settings_type_str); | |
287 ContentSettingsType content_settings_type = | |
288 helpers::StringToContentSettingsType(content_settings_type_str); | |
289 DCHECK_NE(CONTENT_SETTINGS_TYPE_DEFAULT, content_settings_type); | |
290 | |
291 std::string resource_identifier; | |
292 dict->GetString(keys::kResourceIdentifierKey, &resource_identifier); | |
293 | |
294 std::string content_setting_string; | |
295 dict->GetString(keys::kContentSettingKey, &content_setting_string); | |
296 ContentSetting setting = CONTENT_SETTING_DEFAULT; | |
297 bool result = | |
298 helpers::StringToContentSetting(content_setting_string, &setting); | |
299 DCHECK(result); | |
300 | |
301 SetExtensionContentSetting(extension_id, | |
302 primary_pattern, | |
303 secondary_pattern, | |
304 content_settings_type, | |
305 resource_identifier, | |
306 setting, | |
307 scope); | |
308 } | |
309 } | |
310 | |
311 void ExtensionContentSettingsStore::AddObserver(Observer* observer) { | |
312 DCHECK(OnCorrectThread()); | |
313 observers_.AddObserver(observer); | |
314 } | |
315 | |
316 void ExtensionContentSettingsStore::RemoveObserver(Observer* observer) { | |
317 DCHECK(OnCorrectThread()); | |
318 observers_.RemoveObserver(observer); | |
319 } | |
320 | |
321 void ExtensionContentSettingsStore::NotifyOfContentSettingChanged( | |
322 const std::string& extension_id, | |
323 bool incognito) { | |
324 FOR_EACH_OBSERVER( | |
325 ExtensionContentSettingsStore::Observer, | |
326 observers_, | |
327 OnContentSettingChanged(extension_id, incognito)); | |
328 } | |
329 | |
330 bool ExtensionContentSettingsStore::OnCorrectThread() { | |
331 // If there is no UI thread, we're most likely in a unit test. | |
332 return !BrowserThread::IsWellKnownThread(BrowserThread::UI) || | |
333 BrowserThread::CurrentlyOn(BrowserThread::UI); | |
334 } | |
335 | |
336 ExtensionContentSettingsStore::ExtensionEntryMap::iterator | |
337 ExtensionContentSettingsStore::FindEntry(const std::string& ext_id) { | |
338 ExtensionEntryMap::iterator i; | |
339 for (i = entries_.begin(); i != entries_.end(); ++i) { | |
340 if (i->second->id == ext_id) | |
341 return i; | |
342 } | |
343 return entries_.end(); | |
344 } | |
345 | |
346 ExtensionContentSettingsStore::ExtensionEntryMap::const_iterator | |
347 ExtensionContentSettingsStore::FindEntry(const std::string& ext_id) const { | |
348 ExtensionEntryMap::const_iterator i; | |
349 for (i = entries_.begin(); i != entries_.end(); ++i) { | |
350 if (i->second->id == ext_id) | |
351 return i; | |
352 } | |
353 return entries_.end(); | |
354 } | |
OLD | NEW |