Index: chrome/browser/content_settings/cookie_settings.cc |
diff --git a/chrome/browser/content_settings/cookie_settings.cc b/chrome/browser/content_settings/cookie_settings.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3e74143fd23740e63f89f3f83d153f02afe1aa88 |
--- /dev/null |
+++ b/chrome/browser/content_settings/cookie_settings.cc |
@@ -0,0 +1,342 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/content_settings/cookie_settings.h" |
+ |
+#include "base/command_line.h" |
+#include "base/memory/singleton.h" |
+#include "chrome/browser/content_settings/content_settings_pattern.h" |
+#include "chrome/browser/content_settings/host_content_settings_map.h" |
+#include "chrome/browser/prefs/pref_service.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/profiles/profile_dependency_manager.h" |
+#include "chrome/browser/profiles/profile_keyed_service.h" |
+#include "chrome/browser/profiles/profile_keyed_service_factory.h" |
+#include "chrome/common/chrome_notification_types.h" |
+#include "chrome/common/chrome_switches.h" |
+#include "chrome/common/pref_names.h" |
+#include "content/browser/browser_thread.h" |
+#include "content/browser/user_metrics.h" |
+#include "content/common/notification_service.h" |
+#include "content/common/notification_source.h" |
+#include "googleurl/src/gurl.h" |
+#include "net/base/net_errors.h" |
+#include "net/base/static_cookie_policy.h" |
+ |
+namespace { |
+ |
+// ProfileKeyedFactory is the owner of the ProfileKeyedServices. This wrapper |
+// class allows others to hold shared pointers to CookieSettings. |
+class CookieSettingsWrapper : public ProfileKeyedService { |
+ public: |
+ explicit CookieSettingsWrapper(scoped_refptr<CookieSettings> cookie_settings) |
+ : cookie_settings_(cookie_settings) {} |
+ virtual ~CookieSettingsWrapper() {} |
+ |
+ CookieSettings* cookie_settings() { return cookie_settings_.get(); } |
+ |
+ private: |
+ // ProfileKeyedService methods: |
+ virtual void Shutdown() OVERRIDE { |
+ cookie_settings_->ShutdownOnUIThread(); |
+ } |
+ |
+ scoped_refptr<CookieSettings> cookie_settings_; |
+}; |
+ |
+// Helper functions for converting cookie settings. |
+ |
+// Converts a single cookie content setting into a content setting pair for |
+// (cookies, permanent cookies). |
+void ConvertCookieSettingToSettingPair( |
+ ContentSetting setting, ContentSetting* cookies_allowed, |
+ ContentSetting* permanent_cookies_allowed) { |
+ *cookies_allowed = CONTENT_SETTING_BLOCK; |
+ *permanent_cookies_allowed = CONTENT_SETTING_ALLOW; |
+ if (setting == CONTENT_SETTING_ALLOW || |
+ setting == CONTENT_SETTING_SESSION_ONLY) |
+ *cookies_allowed = CONTENT_SETTING_ALLOW; |
+ if (setting == CONTENT_SETTING_SESSION_ONLY) |
+ *permanent_cookies_allowed = CONTENT_SETTING_BLOCK; |
+} |
+ |
+// Converts the content settings pair (cookies, permanent cookies) into a |
+// single content setting. |
+ContentSetting ConvertSettingPairToCookieSetting( |
+ ContentSetting cookies_allowed, ContentSetting permanent_cookies_allowed) { |
+ DCHECK(cookies_allowed == CONTENT_SETTING_ALLOW || |
+ cookies_allowed == CONTENT_SETTING_BLOCK); |
+ DCHECK(permanent_cookies_allowed == CONTENT_SETTING_ALLOW || |
+ permanent_cookies_allowed == CONTENT_SETTING_BLOCK); |
+ if (cookies_allowed == CONTENT_SETTING_BLOCK) |
+ return CONTENT_SETTING_BLOCK; |
+ if (permanent_cookies_allowed == CONTENT_SETTING_ALLOW) |
+ return CONTENT_SETTING_ALLOW; |
+ return CONTENT_SETTING_SESSION_ONLY; |
+} |
+ |
+} // namespace |
+ |
+class CookieSettings::Factory : public ProfileKeyedServiceFactory { |
+ public: |
+ static Factory* GetInstance(); |
+ |
+ CookieSettingsWrapper* GetWrapperForProfile(Profile* profile); |
+ |
+ private: |
+ friend struct DefaultSingletonTraits<Factory>; |
+ |
+ Factory(); |
+ virtual ~Factory() {} |
+ |
+ // PrefoileKeyedServiceFactory methods: |
Bernhard Bauer
2011/09/14 16:01:36
Nit: ProfileKeyedServiceFactory
|
+ virtual CookieSettingsWrapper* BuildServiceInstanceFor( |
+ Profile* profile) const OVERRIDE; |
+ virtual bool ServiceRedirectedInIncognito() OVERRIDE { return true; } |
+}; |
+ |
+// static |
+CookieSettings::Factory* CookieSettings::Factory::GetInstance() { |
+ return Singleton<CookieSettings::Factory>::get(); |
+} |
+ |
+CookieSettingsWrapper* CookieSettings::Factory::GetWrapperForProfile( |
+ Profile* profile) { |
+ return static_cast<CookieSettingsWrapper*>( |
+ GetServiceForProfile(profile,true)); |
+} |
+ |
+CookieSettings::Factory::Factory() |
+ : ProfileKeyedServiceFactory(ProfileDependencyManager::GetInstance()) { |
+} |
+ |
+CookieSettingsWrapper* CookieSettings::Factory::BuildServiceInstanceFor( |
+ Profile* profile) const { |
+ scoped_refptr<CookieSettings> cookie_settings = new CookieSettings( |
+ profile->GetHostContentSettingsMap(), |
+ profile->GetPrefs()); |
+ return new CookieSettingsWrapper(cookie_settings); |
+} |
+ |
+CookieSettings::CookieSettings( |
+ HostContentSettingsMap* host_content_settings_map, |
+ PrefService* prefs) |
+ : host_content_settings_map_(host_content_settings_map), |
+ block_third_party_cookies_( |
+ prefs->GetBoolean(prefs::kBlockThirdPartyCookies)) { |
+ if (block_third_party_cookies_) { |
+ UserMetrics::RecordAction( |
+ UserMetricsAction("ThirdPartyCookieBlockingEnabled")); |
+ } else { |
+ UserMetrics::RecordAction( |
+ UserMetricsAction("ThirdPartyCookieBlockingDisabled")); |
+ } |
+ |
+ pref_change_registrar_.Init(prefs); |
+ pref_change_registrar_.Add(prefs::kBlockThirdPartyCookies, this); |
+} |
+ |
+CookieSettings::~CookieSettings() { |
+} |
+ |
+// static |
+CookieSettings* CookieSettings::GetForProfile(Profile* profile) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ CookieSettings* cookie_settings = |
+ Factory::GetInstance()->GetWrapperForProfile(profile)->cookie_settings(); |
+ DCHECK(cookie_settings); |
+ return cookie_settings; |
+} |
+ |
+ContentSetting CookieSettings::GetDefaultCookieSetting() const { |
+ ContentSetting cookies_allowed = |
+ host_content_settings_map_->GetDefaultContentSetting( |
+ CONTENT_SETTINGS_TYPE_COOKIES); |
+ ContentSetting permanent_cookies_allowed = |
+ host_content_settings_map_->GetDefaultContentSetting( |
+ CONTENT_SETTINGS_TYPE_PERMANENT_COOKIES); |
+ return ConvertSettingPairToCookieSetting( |
+ cookies_allowed, permanent_cookies_allowed); |
+} |
+ |
+bool CookieSettings::IsReadingCookieAllowed(const GURL& url, |
+ const GURL& first_party_url) const { |
+ ContentSetting setting = GetCookieContentSetting( |
+ url, first_party_url, CONTENT_SETTINGS_TYPE_COOKIES, false); |
+ DCHECK(setting == CONTENT_SETTING_ALLOW || |
+ setting == CONTENT_SETTING_BLOCK); |
+ return setting == CONTENT_SETTING_ALLOW; |
+} |
+ |
+bool CookieSettings::IsSettingCookieAllowed(const GURL& url, |
+ const GURL& first_party_url) const { |
+ ContentSetting setting = GetCookieContentSetting( |
+ url, first_party_url, CONTENT_SETTINGS_TYPE_COOKIES, true); |
+ DCHECK(setting == CONTENT_SETTING_ALLOW || |
+ setting == CONTENT_SETTING_BLOCK); |
+ return setting == CONTENT_SETTING_ALLOW; |
+} |
+ |
+bool CookieSettings::IsCookieSessionOnly(const GURL& origin) const { |
+ ContentSetting setting = GetCookieContentSetting( |
+ origin, origin, CONTENT_SETTINGS_TYPE_PERMANENT_COOKIES, true); |
+ DCHECK(setting == CONTENT_SETTING_ALLOW || |
+ setting == CONTENT_SETTING_BLOCK); |
+ return (setting == CONTENT_SETTING_BLOCK); |
+} |
+ |
+void CookieSettings::GetCookieSettings( |
+ HostContentSettingsMap::SettingsForOneType* settings) const { |
+ DCHECK(settings); |
+ settings->clear(); |
+ |
+ // cookie_settings and permanent_cookie_settings will contain the same |
Bernhard Bauer
2011/09/14 16:01:36
Nit: Please add bars around |cookie_settings| and
|
+ // elements, since all exceptions are stored for both content types. |
+ HostContentSettingsMap::SettingsForOneType cookie_settings; |
+ host_content_settings_map_->GetSettingsForOneType( |
+ CONTENT_SETTINGS_TYPE_COOKIES, "", &cookie_settings); |
+ HostContentSettingsMap::SettingsForOneType permanent_cookie_settings; |
+ host_content_settings_map_->GetSettingsForOneType( |
+ CONTENT_SETTINGS_TYPE_PERMANENT_COOKIES, "", &permanent_cookie_settings); |
+ DCHECK(cookie_settings.size() == permanent_cookie_settings.size()); |
Bernhard Bauer
2011/09/14 16:01:36
If you use DCHECK_EQ(expected, actual) you get nic
|
+ |
+ HostContentSettingsMap::PatternSettingSourceTuple setting; |
+ setting.b = ContentSettingsPattern::Wildcard(); |
+ for (size_t i = 0; i < cookie_settings.size(); ++i) { |
+ DCHECK(cookie_settings[i].a == permanent_cookie_settings[i].a); |
+ setting.a = cookie_settings[i].a; |
+ setting.c = ConvertSettingPairToCookieSetting( |
+ cookie_settings[i].c, permanent_cookie_settings[i].c); |
+ settings->push_back(setting); |
+ } |
+} |
+ |
+void CookieSettings::SetDefaultCookieSetting(ContentSetting setting) { |
+ DCHECK(setting == CONTENT_SETTING_ALLOW || |
+ setting == CONTENT_SETTING_SESSION_ONLY || |
+ setting == CONTENT_SETTING_BLOCK); |
+ ContentSetting cookies_allowed; |
+ ContentSetting permanent_cookies_allowed; |
+ ConvertCookieSettingToSettingPair(setting, |
+ &cookies_allowed, |
+ &permanent_cookies_allowed); |
+ host_content_settings_map_->SetDefaultContentSetting( |
+ CONTENT_SETTINGS_TYPE_PERMANENT_COOKIES, permanent_cookies_allowed); |
+ host_content_settings_map_->SetDefaultContentSetting( |
+ CONTENT_SETTINGS_TYPE_COOKIES, cookies_allowed); |
+} |
+ |
+void CookieSettings::SetCookieSetting( |
+ const ContentSettingsPattern& primary_pattern, |
+ ContentSetting setting) { |
+ DCHECK(setting == CONTENT_SETTING_ALLOW || |
+ setting == CONTENT_SETTING_SESSION_ONLY || |
+ setting == CONTENT_SETTING_BLOCK); |
+ ContentSetting cookies_allowed; |
+ ContentSetting permanent_cookies_allowed; |
+ ConvertCookieSettingToSettingPair(setting, |
+ &cookies_allowed, |
+ &permanent_cookies_allowed); |
+ // Set CONTENT_SETTINGS_TYPE_PERMANENT_COOKIES first; when clients monitoring |
+ // CONTENT_SETTINGS_TYPE_COOKIES get a notification, we're already in a |
+ // consistent state. |
+ host_content_settings_map_->SetContentSetting( |
+ primary_pattern, ContentSettingsPattern::Wildcard(), |
+ CONTENT_SETTINGS_TYPE_PERMANENT_COOKIES, "", |
+ permanent_cookies_allowed); |
+ host_content_settings_map_->SetContentSetting( |
+ primary_pattern, ContentSettingsPattern::Wildcard(), |
+ CONTENT_SETTINGS_TYPE_COOKIES, "", |
+ cookies_allowed); |
+} |
+ |
+void CookieSettings::ResetCookieSetting( |
+ const ContentSettingsPattern& primary_pattern) { |
+ // Set CONTENT_SETTINGS_TYPE_PERMANENT_COOKIES first; when clients monitoring |
+ // CONTENT_SETTINGS_TYPE_COOKIES get a notification, we're already in a |
+ // consistent state. |
+ host_content_settings_map_->SetContentSetting( |
+ primary_pattern, ContentSettingsPattern::Wildcard(), |
+ CONTENT_SETTINGS_TYPE_PERMANENT_COOKIES, "", |
+ CONTENT_SETTING_DEFAULT); |
+ host_content_settings_map_->SetContentSetting( |
+ primary_pattern, ContentSettingsPattern::Wildcard(), |
+ CONTENT_SETTINGS_TYPE_COOKIES, "", |
+ CONTENT_SETTING_DEFAULT); |
+} |
+ |
+void CookieSettings::Observe(int type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ if (type == chrome::NOTIFICATION_PREF_CHANGED) { |
+ PrefService* prefs = Source<PrefService>(source).ptr(); |
+ |
+ std::string* name = Details<std::string>(details).ptr(); |
+ if (*name == prefs::kBlockThirdPartyCookies) { |
+ base::AutoLock auto_lock(lock_); |
+ block_third_party_cookies_ = prefs->GetBoolean( |
+ prefs::kBlockThirdPartyCookies); |
+ } else { |
+ NOTREACHED() << "Unexpected preference observed"; |
+ return; |
+ } |
+ } else { |
+ NOTREACHED() << "Unexpected notification"; |
+ } |
+} |
+ |
+void CookieSettings::ShutdownOnUIThread() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ pref_change_registrar_.RemoveAll(); |
+} |
+ |
+ContentSetting CookieSettings::GetCookieContentSetting( |
+ const GURL& url, |
+ const GURL& first_party_url, |
+ ContentSettingsType content_type, |
+ bool setting_cookie) const { |
+ if (HostContentSettingsMap::ShouldAllowAllContent( |
+ first_party_url, CONTENT_SETTINGS_TYPE_COOKIES)) |
+ return CONTENT_SETTING_ALLOW; |
+ |
+ // First get any host-specific settings. |
+ ContentSetting setting = |
+ host_content_settings_map_->GetNonDefaultContentSetting( |
+ url, first_party_url, content_type, ""); |
+ |
+ // Check if third-party cookie settings deny the cookie. This check makes |
+ // sense only for the CONTENT_SETTINGS_TYPE_COOKIES, since the session only |
+ // check is based on one url only. |
+ if (content_type == CONTENT_SETTINGS_TYPE_COOKIES && |
+ setting == CONTENT_SETTING_DEFAULT && |
+ ShouldBlockThirdPartyCookies()) { |
+ bool strict = CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kBlockReadingThirdPartyCookies); |
+ net::StaticCookiePolicy policy(strict ? |
+ net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES : |
+ net::StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES); |
+ int rv; |
+ if (setting_cookie) |
+ rv = policy.CanSetCookie(url, first_party_url); |
+ else |
+ rv = policy.CanGetCookies(url, first_party_url); |
+ DCHECK_NE(net::ERR_IO_PENDING, rv); |
+ if (rv != net::OK) |
+ setting = CONTENT_SETTING_BLOCK; |
+ } |
+ |
+ // If no other policy has changed the setting, use the default. |
+ if (setting == CONTENT_SETTING_DEFAULT) { |
+ setting = |
+ host_content_settings_map_->GetDefaultContentSetting(content_type); |
+ } |
+ return setting; |
+} |
+ |
+bool CookieSettings::ShouldBlockThirdPartyCookies() const { |
+ base::AutoLock auto_lock(lock_); |
+ return block_third_party_cookies_; |
+} |