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