Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / components / content_settings / core / browser / content_settings_default_provider.cc
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 "components/content_settings/core/browser/content_settings_default_provider.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/auto_reset.h"
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/metrics/histogram.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/prefs/scoped_user_pref_update.h"
17 #include "components/content_settings/core/browser/content_settings_rule.h"
18 #include "components/content_settings/core/browser/content_settings_utils.h"
19 #include "components/content_settings/core/common/content_settings.h"
20 #include "components/content_settings/core/common/content_settings_pattern.h"
21 #include "components/content_settings/core/common/pref_names.h"
22 #include "components/pref_registry/pref_registry_syncable.h"
23 #include "url/gurl.h"
24
25 namespace {
26
27 // The default setting for each content type.
28 const ContentSetting kDefaultSettings[] = {
29   CONTENT_SETTING_ALLOW,    // CONTENT_SETTINGS_TYPE_COOKIES
30   CONTENT_SETTING_ALLOW,    // CONTENT_SETTINGS_TYPE_IMAGES
31   CONTENT_SETTING_ALLOW,    // CONTENT_SETTINGS_TYPE_JAVASCRIPT
32   CONTENT_SETTING_ALLOW,    // CONTENT_SETTINGS_TYPE_PLUGINS
33   CONTENT_SETTING_BLOCK,    // CONTENT_SETTINGS_TYPE_POPUPS
34   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_GEOLOCATION
35   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_NOTIFICATIONS
36   CONTENT_SETTING_DEFAULT,  // CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE
37   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_FULLSCREEN
38   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_MOUSELOCK
39   CONTENT_SETTING_DEFAULT,  // CONTENT_SETTINGS_TYPE_MIXEDSCRIPT
40   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_MEDIASTREAM
41   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
42   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
43   CONTENT_SETTING_DEFAULT,  // CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS
44   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_PPAPI_BROKER
45   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
46   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_MIDI_SYSEX
47   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_PUSH_MESSAGING
48   CONTENT_SETTING_ALLOW,    // CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS
49 #if defined(OS_WIN)
50   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP
51 #elif defined(OS_ANDROID) || defined(OS_CHROMEOS)
52   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER
53 #endif
54 #if defined(OS_ANDROID)
55   CONTENT_SETTING_DEFAULT,  // CONTENT_SETTINGS_TYPE_APP_BANNER
56 #endif
57 };
58 COMPILE_ASSERT(arraysize(kDefaultSettings) == CONTENT_SETTINGS_NUM_TYPES,
59                default_settings_incorrect_size);
60
61 }  // namespace
62
63 namespace content_settings {
64
65 namespace {
66
67 class DefaultRuleIterator : public RuleIterator {
68  public:
69   explicit DefaultRuleIterator(const base::Value* value) {
70     if (value)
71       value_.reset(value->DeepCopy());
72   }
73
74   bool HasNext() const override { return value_.get() != NULL; }
75
76   Rule Next() override {
77     DCHECK(value_.get());
78     return Rule(ContentSettingsPattern::Wildcard(),
79                 ContentSettingsPattern::Wildcard(),
80                 value_.release());
81   }
82
83  private:
84   scoped_ptr<base::Value> value_;
85 };
86
87 }  // namespace
88
89 // static
90 void DefaultProvider::RegisterProfilePrefs(
91     user_prefs::PrefRegistrySyncable* registry) {
92   // The registration of the preference prefs::kDefaultContentSettings should
93   // also include the default values for default content settings. This allows
94   // functional tests to get default content settings by reading the preference
95   // prefs::kDefaultContentSettings via pyauto.
96   // TODO(markusheintz): Write pyauto hooks for the content settings map as
97   // content settings should be read from the host content settings map.
98   base::DictionaryValue* default_content_settings = new base::DictionaryValue();
99   registry->RegisterDictionaryPref(
100       prefs::kDefaultContentSettings,
101       default_content_settings,
102       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
103 }
104
105 DefaultProvider::DefaultProvider(PrefService* prefs, bool incognito)
106     : prefs_(prefs),
107       is_incognito_(incognito),
108       updating_preferences_(false) {
109   DCHECK(prefs_);
110
111   // Read global defaults.
112   ReadDefaultSettings(true);
113
114   UMA_HISTOGRAM_ENUMERATION(
115       "ContentSettings.DefaultCookiesSetting",
116       ValueToContentSetting(
117           default_settings_[CONTENT_SETTINGS_TYPE_COOKIES].get()),
118       CONTENT_SETTING_NUM_SETTINGS);
119   UMA_HISTOGRAM_ENUMERATION(
120       "ContentSettings.DefaultImagesSetting",
121       ValueToContentSetting(
122           default_settings_[CONTENT_SETTINGS_TYPE_IMAGES].get()),
123       CONTENT_SETTING_NUM_SETTINGS);
124   UMA_HISTOGRAM_ENUMERATION(
125       "ContentSettings.DefaultJavaScriptSetting",
126       ValueToContentSetting(
127           default_settings_[CONTENT_SETTINGS_TYPE_JAVASCRIPT].get()),
128       CONTENT_SETTING_NUM_SETTINGS);
129   UMA_HISTOGRAM_ENUMERATION(
130       "ContentSettings.DefaultPluginsSetting",
131       ValueToContentSetting(
132           default_settings_[CONTENT_SETTINGS_TYPE_PLUGINS].get()),
133       CONTENT_SETTING_NUM_SETTINGS);
134   UMA_HISTOGRAM_ENUMERATION(
135       "ContentSettings.DefaultPopupsSetting",
136       ValueToContentSetting(
137           default_settings_[CONTENT_SETTINGS_TYPE_POPUPS].get()),
138       CONTENT_SETTING_NUM_SETTINGS);
139   UMA_HISTOGRAM_ENUMERATION(
140       "ContentSettings.DefaultLocationSetting",
141       ValueToContentSetting(
142           default_settings_[CONTENT_SETTINGS_TYPE_GEOLOCATION].get()),
143       CONTENT_SETTING_NUM_SETTINGS);
144   UMA_HISTOGRAM_ENUMERATION(
145       "ContentSettings.DefaultNotificationsSetting",
146       ValueToContentSetting(
147           default_settings_[CONTENT_SETTINGS_TYPE_NOTIFICATIONS].get()),
148       CONTENT_SETTING_NUM_SETTINGS);
149   UMA_HISTOGRAM_ENUMERATION(
150       "ContentSettings.DefaultMouseCursorSetting",
151       ValueToContentSetting(
152           default_settings_[CONTENT_SETTINGS_TYPE_MOUSELOCK].get()),
153       CONTENT_SETTING_NUM_SETTINGS);
154   UMA_HISTOGRAM_ENUMERATION(
155       "ContentSettings.DefaultMediaStreamSetting",
156       ValueToContentSetting(
157           default_settings_[CONTENT_SETTINGS_TYPE_MEDIASTREAM].get()),
158       CONTENT_SETTING_NUM_SETTINGS);
159   UMA_HISTOGRAM_ENUMERATION(
160       "ContentSettings.DefaultMIDISysExSetting",
161       ValueToContentSetting(
162           default_settings_[CONTENT_SETTINGS_TYPE_MIDI_SYSEX].get()),
163       CONTENT_SETTING_NUM_SETTINGS);
164   UMA_HISTOGRAM_ENUMERATION(
165       "ContentSettings.DefaultPushMessagingSetting",
166       ValueToContentSetting(
167           default_settings_[CONTENT_SETTINGS_TYPE_PUSH_MESSAGING].get()),
168       CONTENT_SETTING_NUM_SETTINGS);
169
170   pref_change_registrar_.Init(prefs_);
171   PrefChangeRegistrar::NamedChangeCallback callback = base::Bind(
172       &DefaultProvider::OnPreferenceChanged, base::Unretained(this));
173   pref_change_registrar_.Add(prefs::kDefaultContentSettings, callback);
174 }
175
176 DefaultProvider::~DefaultProvider() {
177 }
178
179 bool DefaultProvider::SetWebsiteSetting(
180     const ContentSettingsPattern& primary_pattern,
181     const ContentSettingsPattern& secondary_pattern,
182     ContentSettingsType content_type,
183     const ResourceIdentifier& resource_identifier,
184     base::Value* in_value) {
185   DCHECK(CalledOnValidThread());
186   DCHECK(prefs_);
187
188   // Ignore non default settings
189   if (primary_pattern != ContentSettingsPattern::Wildcard() ||
190       secondary_pattern != ContentSettingsPattern::Wildcard()) {
191     return false;
192   }
193
194   // The default settings may not be directly modified for OTR sessions.
195   // Instead, they are synced to the main profile's setting.
196   if (is_incognito_)
197     return false;
198
199   // Put |in_value| in a scoped pointer to ensure that it gets cleaned up
200   // properly if we don't pass on the ownership.
201   scoped_ptr<base::Value> value(in_value);
202   {
203     base::AutoReset<bool> auto_reset(&updating_preferences_, true);
204
205     // |DefaultProvider| should not send any notifications when holding
206     // |lock_|. |DictionaryPrefUpdate| destructor and
207     // |PrefService::SetInteger()| send out notifications. As a response, the
208     // upper layers may call |GetAllContentSettingRules| which acquires |lock_|
209     // again.
210     DictionaryPrefUpdate update(prefs_, prefs::kDefaultContentSettings);
211     base::DictionaryValue* default_settings_dictionary = update.Get();
212     base::AutoLock lock(lock_);
213     if (value.get() == NULL ||
214         ValueToContentSetting(value.get()) == kDefaultSettings[content_type]) {
215       // If |value| is NULL we need to reset the default setting the the
216       // hardcoded default.
217       default_settings_[content_type].reset(
218           new base::FundamentalValue(kDefaultSettings[content_type]));
219
220       // Remove the corresponding pref entry since the hardcoded default value
221       // is used.
222       default_settings_dictionary->RemoveWithoutPathExpansion(
223           GetTypeName(content_type), NULL);
224     } else {
225       default_settings_[content_type].reset(value->DeepCopy());
226       // Transfer ownership of |value| to the |default_settings_dictionary|.
227       default_settings_dictionary->SetWithoutPathExpansion(
228           GetTypeName(content_type), value.release());
229     }
230   }
231
232   NotifyObservers(ContentSettingsPattern(),
233                   ContentSettingsPattern(),
234                   content_type,
235                   std::string());
236
237   return true;
238 }
239
240 RuleIterator* DefaultProvider::GetRuleIterator(
241     ContentSettingsType content_type,
242     const ResourceIdentifier& resource_identifier,
243     bool incognito) const {
244   base::AutoLock lock(lock_);
245   if (resource_identifier.empty()) {
246     ValueMap::const_iterator it(default_settings_.find(content_type));
247     if (it != default_settings_.end()) {
248       return new DefaultRuleIterator(it->second.get());
249     }
250     NOTREACHED();
251   }
252   return new EmptyRuleIterator();
253 }
254
255 void DefaultProvider::ClearAllContentSettingsRules(
256     ContentSettingsType content_type) {
257   // TODO(markusheintz): This method is only called when the
258   // |DesktopNotificationService| calls |ClearAllSettingsForType| method on the
259   // |HostContentSettingsMap|. Don't implement this method yet, otherwise the
260   // default notification settings will be cleared as well.
261 }
262
263 void DefaultProvider::ShutdownOnUIThread() {
264   DCHECK(CalledOnValidThread());
265   DCHECK(prefs_);
266   RemoveAllObservers();
267   pref_change_registrar_.RemoveAll();
268   prefs_ = NULL;
269 }
270
271 void DefaultProvider::OnPreferenceChanged(const std::string& name) {
272   DCHECK(CalledOnValidThread());
273   if (updating_preferences_)
274     return;
275
276   if (name == prefs::kDefaultContentSettings) {
277     ReadDefaultSettings(true);
278   } else {
279     NOTREACHED() << "Unexpected preference observed";
280     return;
281   }
282
283   NotifyObservers(ContentSettingsPattern(),
284                   ContentSettingsPattern(),
285                   CONTENT_SETTINGS_TYPE_DEFAULT,
286                   std::string());
287 }
288
289 void DefaultProvider::ReadDefaultSettings(bool overwrite) {
290   base::AutoLock lock(lock_);
291   const base::DictionaryValue* default_settings_dictionary =
292       prefs_->GetDictionary(prefs::kDefaultContentSettings);
293
294   if (overwrite)
295     default_settings_.clear();
296
297   // Careful: The returned value could be NULL if the pref has never been set.
298   if (default_settings_dictionary)
299     GetSettingsFromDictionary(default_settings_dictionary);
300
301   ForceDefaultsToBeExplicit();
302 }
303
304 void DefaultProvider::ForceDefaultsToBeExplicit() {
305   for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
306     ContentSettingsType type = ContentSettingsType(i);
307     if (!default_settings_[type].get() &&
308         kDefaultSettings[i] != CONTENT_SETTING_DEFAULT) {
309       default_settings_[type].reset(
310           new base::FundamentalValue(kDefaultSettings[i]));
311     }
312   }
313 }
314
315 void DefaultProvider::GetSettingsFromDictionary(
316     const base::DictionaryValue* dictionary) {
317   for (base::DictionaryValue::Iterator i(*dictionary);
318        !i.IsAtEnd(); i.Advance()) {
319     const std::string& content_type(i.key());
320     for (size_t type = 0; type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
321       if (content_type == GetTypeName(ContentSettingsType(type))) {
322         int int_value = CONTENT_SETTING_DEFAULT;
323         bool is_integer = i.value().GetAsInteger(&int_value);
324         DCHECK(is_integer);
325         default_settings_[ContentSettingsType(type)].reset(
326             new base::FundamentalValue(int_value));
327         break;
328       }
329     }
330   }
331   // Migrate obsolete cookie prompt mode.
332   if (ValueToContentSetting(
333           default_settings_[CONTENT_SETTINGS_TYPE_COOKIES].get()) ==
334               CONTENT_SETTING_ASK) {
335     default_settings_[CONTENT_SETTINGS_TYPE_COOKIES].reset(
336         new base::FundamentalValue(CONTENT_SETTING_BLOCK));
337   }
338 }
339
340 }  // namespace content_settings