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/cookie_settings.h"
6
7#include "base/command_line.h"
8#include "base/prefs/pref_service.h"
9#include "chrome/browser/chrome_notification_types.h"
10#include "chrome/browser/content_settings/content_settings_utils.h"
11#include "chrome/browser/content_settings/host_content_settings_map.h"
12#include "chrome/browser/profiles/incognito_helpers.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/common/chrome_switches.h"
15#include "chrome/common/content_settings_pattern.h"
16#include "chrome/common/pref_names.h"
17#include "components/keyed_service/content/browser_context_dependency_manager.h"
18#include "components/keyed_service/core/keyed_service.h"
19#include "components/pref_registry/pref_registry_syncable.h"
20#include "content/public/browser/browser_thread.h"
21#include "content/public/browser/notification_service.h"
22#include "content/public/browser/notification_source.h"
23#include "content/public/browser/user_metrics.h"
24#include "extensions/common/constants.h"
25#include "net/base/net_errors.h"
26#include "net/base/static_cookie_policy.h"
27#include "url/gurl.h"
28
29using base::UserMetricsAction;
30using content::BrowserThread;
31
32namespace {
33
34bool IsValidSetting(ContentSetting setting) {
35  return (setting == CONTENT_SETTING_ALLOW ||
36          setting == CONTENT_SETTING_SESSION_ONLY ||
37          setting == CONTENT_SETTING_BLOCK);
38}
39
40bool IsAllowed(ContentSetting setting) {
41  DCHECK(IsValidSetting(setting));
42  return (setting == CONTENT_SETTING_ALLOW ||
43          setting == CONTENT_SETTING_SESSION_ONLY);
44}
45
46}  // namespace
47
48// static
49scoped_refptr<CookieSettings> CookieSettings::Factory::GetForProfile(
50    Profile* profile) {
51  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
52  return static_cast<CookieSettings*>(
53      GetInstance()->GetServiceForBrowserContext(profile, true).get());
54}
55
56// static
57CookieSettings::Factory* CookieSettings::Factory::GetInstance() {
58  return Singleton<CookieSettings::Factory>::get();
59}
60
61CookieSettings::Factory::Factory()
62    : RefcountedBrowserContextKeyedServiceFactory(
63        "CookieSettings",
64        BrowserContextDependencyManager::GetInstance()) {
65}
66
67CookieSettings::Factory::~Factory() {}
68
69void CookieSettings::Factory::RegisterProfilePrefs(
70    user_prefs::PrefRegistrySyncable* registry) {
71  registry->RegisterBooleanPref(
72      prefs::kBlockThirdPartyCookies,
73      false,
74      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
75}
76
77content::BrowserContext* CookieSettings::Factory::GetBrowserContextToUse(
78    content::BrowserContext* context) const {
79  return chrome::GetBrowserContextRedirectedInIncognito(context);
80}
81
82scoped_refptr<RefcountedBrowserContextKeyedService>
83CookieSettings::Factory::BuildServiceInstanceFor(
84    content::BrowserContext* context) const {
85  Profile* profile = static_cast<Profile*>(context);
86  return new CookieSettings(profile->GetHostContentSettingsMap(),
87                            profile->GetPrefs());
88}
89
90CookieSettings::CookieSettings(
91    HostContentSettingsMap* host_content_settings_map,
92    PrefService* prefs)
93    : host_content_settings_map_(host_content_settings_map),
94      block_third_party_cookies_(
95          prefs->GetBoolean(prefs::kBlockThirdPartyCookies)) {
96  if (block_third_party_cookies_) {
97    content::RecordAction(
98        UserMetricsAction("ThirdPartyCookieBlockingEnabled"));
99  } else {
100    content::RecordAction(
101        UserMetricsAction("ThirdPartyCookieBlockingDisabled"));
102  }
103
104  pref_change_registrar_.Init(prefs);
105  pref_change_registrar_.Add(
106      prefs::kBlockThirdPartyCookies,
107      base::Bind(&CookieSettings::OnBlockThirdPartyCookiesChanged,
108                 base::Unretained(this)));
109}
110
111ContentSetting
112CookieSettings::GetDefaultCookieSetting(std::string* provider_id) const {
113  return host_content_settings_map_->GetDefaultContentSetting(
114      CONTENT_SETTINGS_TYPE_COOKIES, provider_id);
115}
116
117bool CookieSettings::IsReadingCookieAllowed(const GURL& url,
118                                            const GURL& first_party_url) const {
119  ContentSetting setting = GetCookieSetting(url, first_party_url, false, NULL);
120  return IsAllowed(setting);
121}
122
123bool CookieSettings::IsSettingCookieAllowed(const GURL& url,
124                                            const GURL& first_party_url) const {
125  ContentSetting setting = GetCookieSetting(url, first_party_url, true, NULL);
126  return IsAllowed(setting);
127}
128
129bool CookieSettings::IsCookieSessionOnly(const GURL& origin) const {
130  ContentSetting setting = GetCookieSetting(origin, origin, true, NULL);
131  DCHECK(IsValidSetting(setting));
132  return (setting == CONTENT_SETTING_SESSION_ONLY);
133}
134
135void CookieSettings::GetCookieSettings(
136    ContentSettingsForOneType* settings) const {
137  return host_content_settings_map_->GetSettingsForOneType(
138      CONTENT_SETTINGS_TYPE_COOKIES, std::string(), settings);
139}
140
141void CookieSettings::SetDefaultCookieSetting(ContentSetting setting) {
142  DCHECK(IsValidSetting(setting));
143  host_content_settings_map_->SetDefaultContentSetting(
144      CONTENT_SETTINGS_TYPE_COOKIES, setting);
145}
146
147void CookieSettings::SetCookieSetting(
148    const ContentSettingsPattern& primary_pattern,
149    const ContentSettingsPattern& secondary_pattern,
150    ContentSetting setting) {
151  DCHECK(IsValidSetting(setting));
152  if (setting == CONTENT_SETTING_SESSION_ONLY) {
153    DCHECK(secondary_pattern == ContentSettingsPattern::Wildcard());
154  }
155  host_content_settings_map_->SetContentSetting(primary_pattern,
156                                                secondary_pattern,
157                                                CONTENT_SETTINGS_TYPE_COOKIES,
158                                                std::string(),
159                                                setting);
160}
161
162void CookieSettings::ResetCookieSetting(
163    const ContentSettingsPattern& primary_pattern,
164    const ContentSettingsPattern& secondary_pattern) {
165  host_content_settings_map_->SetContentSetting(primary_pattern,
166                                                secondary_pattern,
167                                                CONTENT_SETTINGS_TYPE_COOKIES,
168                                                std::string(),
169                                                CONTENT_SETTING_DEFAULT);
170}
171
172void CookieSettings::ShutdownOnUIThread() {
173  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
174  pref_change_registrar_.RemoveAll();
175}
176
177ContentSetting CookieSettings::GetCookieSetting(
178    const GURL& url,
179    const GURL& first_party_url,
180    bool setting_cookie,
181    content_settings::SettingSource* source) const {
182  if (HostContentSettingsMap::ShouldAllowAllContent(
183        url, first_party_url, CONTENT_SETTINGS_TYPE_COOKIES))
184    return CONTENT_SETTING_ALLOW;
185
186  // First get any host-specific settings.
187  content_settings::SettingInfo info;
188  scoped_ptr<base::Value> value(host_content_settings_map_->GetWebsiteSetting(
189      url,
190      first_party_url,
191      CONTENT_SETTINGS_TYPE_COOKIES,
192      std::string(),
193      &info));
194  if (source)
195    *source = info.source;
196
197  // If no explicit exception has been made and third-party cookies are blocked
198  // by default, apply that rule.
199  if (info.primary_pattern.MatchesAllHosts() &&
200      info.secondary_pattern.MatchesAllHosts() &&
201      ShouldBlockThirdPartyCookies() &&
202      !first_party_url.SchemeIs(extensions::kExtensionScheme)) {
203    net::StaticCookiePolicy policy(
204        net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES);
205    int rv;
206    if (setting_cookie)
207      rv = policy.CanSetCookie(url, first_party_url);
208    else
209      rv = policy.CanGetCookies(url, first_party_url);
210    DCHECK_NE(net::ERR_IO_PENDING, rv);
211    if (rv != net::OK)
212      return CONTENT_SETTING_BLOCK;
213  }
214
215  // We should always have a value, at least from the default provider.
216  DCHECK(value.get());
217  return content_settings::ValueToContentSetting(value.get());
218}
219
220CookieSettings::~CookieSettings() {}
221
222void CookieSettings::OnBlockThirdPartyCookiesChanged() {
223  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
224
225  base::AutoLock auto_lock(lock_);
226  block_third_party_cookies_ = pref_change_registrar_.prefs()->GetBoolean(
227      prefs::kBlockThirdPartyCookies);
228}
229
230bool CookieSettings::ShouldBlockThirdPartyCookies() const {
231  base::AutoLock auto_lock(lock_);
232  return block_third_party_cookies_;
233}
234