• 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/content_settings/content_settings_store.h"
6 
7 #include <set>
8 
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_utils.h"
17 #include "chrome/browser/extensions/api/content_settings/content_settings_api_constants.h"
18 #include "chrome/browser/extensions/api/content_settings/content_settings_helpers.h"
19 #include "components/content_settings/core/browser/content_settings_origin_identifier_value_map.h"
20 #include "components/content_settings/core/browser/content_settings_rule.h"
21 #include "content/public/browser/browser_thread.h"
22 
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;
30 
31 namespace extensions {
32 
33 namespace helpers = content_settings_helpers;
34 namespace keys = content_settings_api_constants;
35 
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;
47 };
48 
ContentSettingsStore()49 ContentSettingsStore::ContentSettingsStore() {
50   DCHECK(OnCorrectThread());
51 }
52 
~ContentSettingsStore()53 ContentSettingsStore::~ContentSettingsStore() {
54   STLDeleteValues(&entries_);
55 }
56 
GetRuleIterator(ContentSettingsType type,const content_settings::ResourceIdentifier & identifier,bool incognito) const57 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;
65 
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_));
69 
70   for (entry = entries_.rbegin(); entry != entries_.rend(); ++entry) {
71     if (!entry->second->enabled)
72       continue;
73 
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));
88     }
89   }
90   return new ConcatenationIterator(&iterators, auto_lock.release());
91 }
92 
SetExtensionContentSetting(const std::string & ext_id,const ContentSettingsPattern & primary_pattern,const ContentSettingsPattern & secondary_pattern,ContentSettingsType type,const content_settings::ResourceIdentifier & identifier,ContentSetting setting,ExtensionPrefsScope scope)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) {
101   {
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));
109     }
110   }
111 
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);
118 }
119 
RegisterExtension(const std::string & ext_id,const base::Time & install_time,bool is_enabled)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));
132   }
133 
134   entry->id = ext_id;
135   entry->enabled = is_enabled;
136 }
137 
UnregisterExtension(const std::string & ext_id)138 void ContentSettingsStore::UnregisterExtension(
139     const std::string& ext_id) {
140   bool notify = false;
141   bool notify_incognito = false;
142   {
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();
150 
151     delete i->second;
152     entries_.erase(i);
153   }
154   if (notify)
155     NotifyOfContentSettingChanged(ext_id, false);
156   if (notify_incognito)
157     NotifyOfContentSettingChanged(ext_id, true);
158 }
159 
SetExtensionState(const std::string & ext_id,bool is_enabled)160 void ContentSettingsStore::SetExtensionState(
161     const std::string& ext_id, bool is_enabled) {
162   bool notify = false;
163   bool notify_incognito = false;
164   {
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();
172 
173     i->second->enabled = is_enabled;
174   }
175   if (notify)
176     NotifyOfContentSettingChanged(ext_id, false);
177   if (notify_incognito)
178     NotifyOfContentSettingChanged(ext_id, true);
179 }
180 
GetValueMap(const std::string & ext_id,ExtensionPrefsScope scope)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);
197     }
198   }
199   return NULL;
200 }
201 
GetValueMap(const std::string & ext_id,ExtensionPrefsScope scope) const202 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;
208 
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);
220   }
221 
222   NOTREACHED();
223   return NULL;
224 }
225 
ClearContentSettingsForExtension(const std::string & ext_id,ExtensionPrefsScope scope)226 void ContentSettingsStore::ClearContentSettingsForExtension(
227     const std::string& ext_id,
228     ExtensionPrefsScope scope) {
229   bool notify = false;
230   {
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;
237     }
238     notify = !map->empty();
239     map->clear();
240   }
241   if (notify) {
242     NotifyOfContentSettingChanged(ext_id, scope != kExtensionPrefsScopeRegular);
243   }
244 }
245 
GetSettingsForExtension(const std::string & extension_id,ExtensionPrefsScope scope) const246 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);
278     }
279   }
280   return settings;
281 }
282 
SetExtensionContentSettingFromList(const std::string & extension_id,const base::ListValue * list,ExtensionPrefsScope scope)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;
292     }
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());
299 
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());
305 
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);
311 
312     std::string resource_identifier;
313     dict->GetString(keys::kResourceIdentifierKey, &resource_identifier);
314 
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);
321 
322     SetExtensionContentSetting(extension_id,
323                                primary_pattern,
324                                secondary_pattern,
325                                content_settings_type,
326                                resource_identifier,
327                                setting,
328                                scope);
329   }
330 }
331 
AddObserver(Observer * observer)332 void ContentSettingsStore::AddObserver(Observer* observer) {
333   DCHECK(OnCorrectThread());
334   observers_.AddObserver(observer);
335 }
336 
RemoveObserver(Observer * observer)337 void ContentSettingsStore::RemoveObserver(Observer* observer) {
338   DCHECK(OnCorrectThread());
339   observers_.RemoveObserver(observer);
340 }
341 
NotifyOfContentSettingChanged(const std::string & extension_id,bool incognito)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));
349 }
350 
OnCorrectThread()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);
355 }
356 
357 ContentSettingsStore::ExtensionEntryMap::iterator
FindEntry(const std::string & ext_id)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;
363   }
364   return entries_.end();
365 }
366 
367 ContentSettingsStore::ExtensionEntryMap::const_iterator
FindEntry(const std::string & ext_id) const368 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;
373   }
374   return entries_.end();
375 }
376 
377 }  // namespace extensions
378