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