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/content_settings/host_content_settings_map.h"
6
7#include "base/command_line.h"
8#include "base/string_util.h"
9#include "base/utf_string_conversions.h"
10#include "chrome/browser/content_settings/content_settings_details.h"
11#include "chrome/browser/content_settings/content_settings_policy_provider.h"
12#include "chrome/browser/content_settings/content_settings_pref_provider.h"
13#include "chrome/browser/content_settings/content_settings_provider.h"
14#include "chrome/browser/metrics/user_metrics.h"
15#include "chrome/browser/prefs/pref_service.h"
16#include "chrome/browser/prefs/scoped_user_pref_update.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/common/chrome_switches.h"
19#include "chrome/common/pref_names.h"
20#include "chrome/common/url_constants.h"
21#include "content/browser/browser_thread.h"
22#include "content/common/notification_service.h"
23#include "content/common/notification_source.h"
24#include "content/common/notification_type.h"
25#include "googleurl/src/gurl.h"
26#include "net/base/net_util.h"
27#include "net/base/static_cookie_policy.h"
28
29namespace {
30
31// Returns true if we should allow all content types for this URL.  This is
32// true for various internal objects like chrome:// URLs, so UI and other
33// things users think of as "not webpages" don't break.
34static bool ShouldAllowAllContent(const GURL& url) {
35  return url.SchemeIs(chrome::kChromeDevToolsScheme) ||
36         url.SchemeIs(chrome::kChromeInternalScheme) ||
37         url.SchemeIs(chrome::kChromeUIScheme) ||
38         url.SchemeIs(chrome::kExtensionScheme) ||
39         url.SchemeIs(chrome::kUserScriptScheme);
40}
41
42typedef linked_ptr<content_settings::DefaultProviderInterface>
43    DefaultContentSettingsProviderPtr;
44typedef std::vector<DefaultContentSettingsProviderPtr>::iterator
45    DefaultProviderIterator;
46typedef std::vector<DefaultContentSettingsProviderPtr>::const_iterator
47    ConstDefaultProviderIterator;
48
49typedef linked_ptr<content_settings::ProviderInterface> ProviderPtr;
50typedef std::vector<ProviderPtr>::iterator ProviderIterator;
51typedef std::vector<ProviderPtr>::const_iterator ConstProviderIterator;
52
53typedef content_settings::ProviderInterface::Rules Rules;
54typedef content_settings::ProviderInterface::Rules::iterator
55    rules_iterator;
56typedef content_settings::ProviderInterface::Rules::const_iterator
57    const_rules_iterator;
58
59}  // namespace
60
61HostContentSettingsMap::HostContentSettingsMap(Profile* profile)
62    : profile_(profile),
63      is_off_the_record_(profile_->IsOffTheRecord()),
64      updating_preferences_(false),
65      block_third_party_cookies_(false),
66      is_block_third_party_cookies_managed_(false) {
67  // The order in which the default content settings providers are created is
68  // critical, as providers that are further down in the list (i.e. added later)
69  // override providers further up.
70  default_content_settings_providers_.push_back(
71      DefaultContentSettingsProviderPtr(
72          new content_settings::PrefDefaultProvider(profile)));
73  default_content_settings_providers_.push_back(
74      DefaultContentSettingsProviderPtr(
75          new content_settings::PolicyDefaultProvider(profile)));
76
77  PrefService* prefs = profile_->GetPrefs();
78
79  // TODO(markusheintz): Discuss whether it is sensible to move migration code
80  // to PrefContentSettingsProvider.
81  MigrateObsoleteCookiePref(prefs);
82
83  // Read misc. global settings.
84  block_third_party_cookies_ =
85      prefs->GetBoolean(prefs::kBlockThirdPartyCookies);
86  if (block_third_party_cookies_) {
87    UserMetrics::RecordAction(
88        UserMetricsAction("ThirdPartyCookieBlockingEnabled"));
89  } else {
90    UserMetrics::RecordAction(
91        UserMetricsAction("ThirdPartyCookieBlockingDisabled"));
92  }
93  is_block_third_party_cookies_managed_ =
94      prefs->IsManagedPreference(prefs::kBlockThirdPartyCookies);
95  block_nonsandboxed_plugins_ =
96      prefs->GetBoolean(prefs::kBlockNonsandboxedPlugins);
97
98  // User defined non default content settings are provided by the PrefProvider.
99  // The order in which the content settings providers are created is critical,
100  // as providers that are further up in the list (i.e. added earlier) override
101  // providers further down.
102  content_settings_providers_.push_back(
103      make_linked_ptr(new content_settings::PolicyProvider(profile)));
104  content_settings_providers_.push_back(
105      make_linked_ptr(new content_settings::PrefProvider(profile)));
106
107  pref_change_registrar_.Init(prefs);
108  pref_change_registrar_.Add(prefs::kBlockThirdPartyCookies, this);
109  pref_change_registrar_.Add(prefs::kBlockNonsandboxedPlugins, this);
110  notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
111                              Source<Profile>(profile_));
112}
113
114// static
115void HostContentSettingsMap::RegisterUserPrefs(PrefService* prefs) {
116  prefs->RegisterBooleanPref(prefs::kBlockThirdPartyCookies, false);
117  prefs->RegisterBooleanPref(prefs::kBlockNonsandboxedPlugins, false);
118  prefs->RegisterIntegerPref(prefs::kContentSettingsWindowLastTabIndex, 0);
119
120  // Obsolete prefs, for migration:
121  prefs->RegisterIntegerPref(prefs::kCookieBehavior,
122                             net::StaticCookiePolicy::ALLOW_ALL_COOKIES);
123
124  // Register the prefs for the content settings providers.
125  content_settings::PrefDefaultProvider::RegisterUserPrefs(prefs);
126  content_settings::PolicyDefaultProvider::RegisterUserPrefs(prefs);
127  content_settings::PrefProvider::RegisterUserPrefs(prefs);
128  content_settings::PolicyProvider::RegisterUserPrefs(prefs);
129}
130
131ContentSetting HostContentSettingsMap::GetDefaultContentSetting(
132    ContentSettingsType content_type) const {
133  ContentSetting setting = CONTENT_SETTING_DEFAULT;
134  for (ConstDefaultProviderIterator provider =
135           default_content_settings_providers_.begin();
136       provider != default_content_settings_providers_.end(); ++provider) {
137    ContentSetting provided_setting =
138        (*provider)->ProvideDefaultSetting(content_type);
139    if (provided_setting != CONTENT_SETTING_DEFAULT)
140      setting = provided_setting;
141  }
142  // The method GetDefaultContentSetting always has to return an explicit
143  // value that is to be used as default. We here rely on the
144  // PrefContentSettingProvider to always provide a value.
145  CHECK_NE(CONTENT_SETTING_DEFAULT, setting);
146  return setting;
147}
148
149ContentSetting HostContentSettingsMap::GetContentSetting(
150    const GURL& url,
151    ContentSettingsType content_type,
152    const std::string& resource_identifier) const {
153  ContentSetting setting = GetNonDefaultContentSetting(url,
154                                                       content_type,
155                                                       resource_identifier);
156  if (setting == CONTENT_SETTING_DEFAULT)
157    return GetDefaultContentSetting(content_type);
158  return setting;
159}
160
161ContentSetting HostContentSettingsMap::GetNonDefaultContentSetting(
162    const GURL& url,
163    ContentSettingsType content_type,
164    const std::string& resource_identifier) const {
165  if (ShouldAllowAllContent(url))
166    return CONTENT_SETTING_ALLOW;
167
168  // Iterate through the list of providers and break when the first non default
169  // setting is found.
170  ContentSetting provided_setting(CONTENT_SETTING_DEFAULT);
171  for (ConstProviderIterator provider = content_settings_providers_.begin();
172       provider != content_settings_providers_.end();
173       ++provider) {
174    provided_setting = (*provider)->GetContentSetting(
175        url, url, content_type, resource_identifier);
176    bool isManaged = (*provider)->ContentSettingsTypeIsManaged(content_type);
177    if (provided_setting != CONTENT_SETTING_DEFAULT || isManaged)
178      return provided_setting;
179  }
180  return provided_setting;
181}
182
183ContentSettings HostContentSettingsMap::GetContentSettings(
184    const GURL& url) const {
185  ContentSettings output = GetNonDefaultContentSettings(url);
186
187  // If we require a resource identifier, set the content settings to default,
188  // otherwise make the defaults explicit.
189  for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) {
190    // A managed default content setting has the highest priority and hence
191    // will overwrite any previously set value.
192    if (output.settings[j] == CONTENT_SETTING_DEFAULT &&
193        j != CONTENT_SETTINGS_TYPE_PLUGINS) {
194      output.settings[j] = GetDefaultContentSetting(ContentSettingsType(j));
195    }
196  }
197  return output;
198}
199
200ContentSettings HostContentSettingsMap::GetNonDefaultContentSettings(
201    const GURL& url) const {
202  if (ShouldAllowAllContent(url))
203      return ContentSettings(CONTENT_SETTING_ALLOW);
204
205  ContentSettings output(CONTENT_SETTING_DEFAULT);
206  for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) {
207    output.settings[j] = GetNonDefaultContentSetting(
208        url, ContentSettingsType(j) , "");
209  }
210  return output;
211}
212
213void HostContentSettingsMap::GetSettingsForOneType(
214    ContentSettingsType content_type,
215    const std::string& resource_identifier,
216    SettingsForOneType* settings) const {
217  DCHECK(settings);
218  settings->clear();
219
220  // Collect content_settings::Rules for the given content_type and
221  // resource_identifier from the content settings providers.
222  Rules content_settings_rules;
223  for (ConstProviderIterator provider = content_settings_providers_.begin();
224       provider != content_settings_providers_.end();
225       ++provider) {
226    // TODO(markusheintz): Only the rules that are applied should be collected.
227    // Merge rules.
228    // TODO(markusheintz): GetAllContentSettingsRules should maybe not clear the
229    // passed vector in case rule sets are just unified.
230    Rules rules;
231    (*provider)->GetAllContentSettingsRules(
232        content_type, resource_identifier, &rules);
233    content_settings_rules.insert(content_settings_rules.end(),
234                                  rules.begin(),
235                                  rules.end());
236  }
237
238  // convert Rules to SettingsForOneType
239  for (const_rules_iterator rule_iterator =
240           content_settings_rules.begin();
241       rule_iterator != content_settings_rules.end();
242       ++rule_iterator) {
243    settings->push_back(std::make_pair(ContentSettingsPattern(
244        rule_iterator->requesting_url_pattern),
245        rule_iterator->content_setting));
246  }
247}
248
249void HostContentSettingsMap::SetDefaultContentSetting(
250    ContentSettingsType content_type,
251    ContentSetting setting) {
252  for (DefaultProviderIterator provider =
253           default_content_settings_providers_.begin();
254       provider != default_content_settings_providers_.end(); ++provider) {
255    (*provider)->UpdateDefaultSetting(content_type, setting);
256  }
257}
258
259void HostContentSettingsMap::SetContentSetting(
260    const ContentSettingsPattern& pattern,
261    ContentSettingsType content_type,
262    const std::string& resource_identifier,
263    ContentSetting setting) {
264  for (ProviderIterator provider = content_settings_providers_.begin();
265       provider != content_settings_providers_.end();
266       ++provider) {
267    (*provider)->SetContentSetting(
268        pattern, pattern, content_type, resource_identifier, setting);
269  }
270}
271
272void HostContentSettingsMap::AddExceptionForURL(
273    const GURL& url,
274    ContentSettingsType content_type,
275    const std::string& resource_identifier,
276    ContentSetting setting) {
277  // Make sure there is no entry that would override the pattern we are about
278  // to insert for exactly this URL.
279  SetContentSetting(ContentSettingsPattern::FromURLNoWildcard(url),
280                    content_type,
281                    resource_identifier,
282                    CONTENT_SETTING_DEFAULT);
283  SetContentSetting(ContentSettingsPattern::FromURL(url),
284                    content_type,
285                    resource_identifier,
286                    setting);
287}
288
289void HostContentSettingsMap::ClearSettingsForOneType(
290    ContentSettingsType content_type) {
291  for (ProviderIterator provider = content_settings_providers_.begin();
292       provider != content_settings_providers_.end();
293       ++provider) {
294    (*provider)->ClearAllContentSettingsRules(content_type);
295  }
296}
297
298void HostContentSettingsMap::SetBlockThirdPartyCookies(bool block) {
299  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
300
301  // This setting may not be directly modified for OTR sessions.  Instead, it
302  // is synced to the main profile's setting.
303  if (is_off_the_record_) {
304    NOTREACHED();
305    return;
306  }
307
308  PrefService* prefs = profile_->GetPrefs();
309  // If the preference block-third-party-cookies is managed then do not allow to
310  // change it.
311  if (prefs->IsManagedPreference(prefs::kBlockThirdPartyCookies)) {
312    NOTREACHED();
313    return;
314  }
315
316  {
317    base::AutoLock auto_lock(lock_);
318    block_third_party_cookies_ = block;
319  }
320
321  if (block)
322    prefs->SetBoolean(prefs::kBlockThirdPartyCookies, true);
323  else
324    prefs->ClearPref(prefs::kBlockThirdPartyCookies);
325}
326
327void HostContentSettingsMap::SetBlockNonsandboxedPlugins(bool block) {
328  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
329
330  // This setting may not be directly modified for OTR sessions.  Instead, it
331  // is synced to the main profile's setting.
332  if (is_off_the_record_) {
333    NOTREACHED();
334    return;
335  }
336
337  {
338    base::AutoLock auto_lock(lock_);
339    block_nonsandboxed_plugins_ = block;
340  }
341
342  PrefService* prefs = profile_->GetPrefs();
343  if (block) {
344    UserMetrics::RecordAction(
345        UserMetricsAction("BlockNonsandboxedPlugins_Enable"));
346    prefs->SetBoolean(prefs::kBlockNonsandboxedPlugins, true);
347  } else {
348    UserMetrics::RecordAction(
349        UserMetricsAction("BlockNonsandboxedPlugins_Disable"));
350    prefs->ClearPref(prefs::kBlockNonsandboxedPlugins);
351  }
352}
353
354void HostContentSettingsMap::ResetToDefaults() {
355  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
356
357  {
358    base::AutoLock auto_lock(lock_);
359    for (DefaultProviderIterator provider =
360             default_content_settings_providers_.begin();
361         provider != default_content_settings_providers_.end(); ++provider) {
362      (*provider)->ResetToDefaults();
363    }
364
365    for (ProviderIterator provider = content_settings_providers_.begin();
366         provider != content_settings_providers_.end();
367         ++provider) {
368      (*provider)->ResetToDefaults();
369    }
370
371    // Don't reset block third party cookies if they are managed.
372    if (!IsBlockThirdPartyCookiesManaged())
373      block_third_party_cookies_ = false;
374    block_nonsandboxed_plugins_ = false;
375  }
376
377  if (!is_off_the_record_) {
378    PrefService* prefs = profile_->GetPrefs();
379    updating_preferences_ = true;
380    // If the block third party cookies preference is managed we still must
381    // clear it in order to restore the default value for later when the
382    // preference is not managed anymore.
383    prefs->ClearPref(prefs::kBlockThirdPartyCookies);
384    prefs->ClearPref(prefs::kBlockNonsandboxedPlugins);
385    updating_preferences_ = false;
386    NotifyObservers(ContentSettingsDetails(ContentSettingsPattern(),
387                                           CONTENT_SETTINGS_TYPE_DEFAULT,
388                                           ""));
389  }
390}
391
392void HostContentSettingsMap::Observe(NotificationType type,
393                                     const NotificationSource& source,
394                                     const NotificationDetails& details) {
395  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
396
397  if (type == NotificationType::PREF_CHANGED) {
398    DCHECK_EQ(profile_->GetPrefs(), Source<PrefService>(source).ptr());
399    if (updating_preferences_)
400      return;
401
402    std::string* name = Details<std::string>(details).ptr();
403    if (*name == prefs::kBlockThirdPartyCookies) {
404      base::AutoLock auto_lock(lock_);
405      block_third_party_cookies_ = profile_->GetPrefs()->GetBoolean(
406          prefs::kBlockThirdPartyCookies);
407      is_block_third_party_cookies_managed_ =
408          profile_->GetPrefs()->IsManagedPreference(
409              prefs::kBlockThirdPartyCookies);
410    } else if (*name == prefs::kBlockNonsandboxedPlugins) {
411      base::AutoLock auto_lock(lock_);
412      block_nonsandboxed_plugins_ = profile_->GetPrefs()->GetBoolean(
413          prefs::kBlockNonsandboxedPlugins);
414    } else {
415      NOTREACHED() << "Unexpected preference observed";
416      return;
417    }
418
419    if (!is_off_the_record_) {
420      NotifyObservers(ContentSettingsDetails(ContentSettingsPattern(),
421                                             CONTENT_SETTINGS_TYPE_DEFAULT,
422                                             ""));
423    }
424  } else if (type == NotificationType::PROFILE_DESTROYED) {
425    DCHECK_EQ(profile_, Source<Profile>(source).ptr());
426    UnregisterObservers();
427  } else {
428    NOTREACHED() << "Unexpected notification";
429  }
430}
431
432HostContentSettingsMap::~HostContentSettingsMap() {
433  UnregisterObservers();
434}
435
436bool HostContentSettingsMap::IsDefaultContentSettingManaged(
437    ContentSettingsType content_type) const {
438  for (ConstDefaultProviderIterator provider =
439           default_content_settings_providers_.begin();
440       provider != default_content_settings_providers_.end(); ++provider) {
441    if ((*provider)->DefaultSettingIsManaged(content_type))
442      return true;
443  }
444  return false;
445}
446
447void HostContentSettingsMap::NotifyObservers(
448    const ContentSettingsDetails& details) {
449  NotificationService::current()->Notify(
450      NotificationType::CONTENT_SETTINGS_CHANGED,
451      Source<HostContentSettingsMap>(this),
452      Details<const ContentSettingsDetails>(&details));
453}
454
455void HostContentSettingsMap::UnregisterObservers() {
456  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
457  if (!profile_)
458    return;
459  pref_change_registrar_.RemoveAll();
460  notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED,
461                                 Source<Profile>(profile_));
462  profile_ = NULL;
463}
464
465void HostContentSettingsMap::MigrateObsoleteCookiePref(PrefService* prefs) {
466  if (prefs->HasPrefPath(prefs::kCookieBehavior)) {
467    int cookie_behavior = prefs->GetInteger(prefs::kCookieBehavior);
468    prefs->ClearPref(prefs::kCookieBehavior);
469    if (!prefs->HasPrefPath(prefs::kDefaultContentSettings)) {
470        SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES,
471            (cookie_behavior == net::StaticCookiePolicy::BLOCK_ALL_COOKIES) ?
472                CONTENT_SETTING_BLOCK : CONTENT_SETTING_ALLOW);
473    }
474    if (!prefs->HasPrefPath(prefs::kBlockThirdPartyCookies)) {
475      SetBlockThirdPartyCookies(cookie_behavior ==
476          net::StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES);
477    }
478  }
479}
480