// Copyright (c) 2012 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 "chrome/browser/content_settings/content_settings_utils.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/common/chrome_notification_types.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/content_settings_pattern.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/user_metrics.h" #include "googleurl/src/gurl.h" #include "net/base/net_errors.h" #include "net/base/static_cookie_policy.h" using content::BrowserThread; using content::UserMetricsAction; namespace { bool IsValidSetting(ContentSetting setting) { return (setting == CONTENT_SETTING_ALLOW || setting == CONTENT_SETTING_SESSION_ONLY || setting == CONTENT_SETTING_BLOCK); } bool IsAllowed(ContentSetting setting) { DCHECK(IsValidSetting(setting)); return (setting == CONTENT_SETTING_ALLOW || setting == CONTENT_SETTING_SESSION_ONLY); } } // namespace // static scoped_refptr CookieSettings::Factory::GetForProfile( Profile* profile) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); return static_cast( GetInstance()->GetServiceForProfile(profile, true).get()); } // static CookieSettings::Factory* CookieSettings::Factory::GetInstance() { return Singleton::get(); } CookieSettings::Factory::Factory() : RefcountedProfileKeyedServiceFactory( "CookieSettings", ProfileDependencyManager::GetInstance()) { } CookieSettings::Factory::~Factory() {} void CookieSettings::Factory::RegisterUserPrefs(PrefService* user_prefs) { user_prefs->RegisterBooleanPref(prefs::kBlockThirdPartyCookies, false, PrefService::SYNCABLE_PREF); } bool CookieSettings::Factory::ServiceRedirectedInIncognito() { return true; } scoped_refptr CookieSettings::Factory::BuildServiceInstanceFor(Profile* profile) const { return new CookieSettings(profile->GetHostContentSettingsMap(), profile->GetPrefs()); } 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_) { content::RecordAction( UserMetricsAction("ThirdPartyCookieBlockingEnabled")); } else { content::RecordAction( UserMetricsAction("ThirdPartyCookieBlockingDisabled")); } pref_change_registrar_.Init(prefs); pref_change_registrar_.Add(prefs::kBlockThirdPartyCookies, this); } ContentSetting CookieSettings::GetDefaultCookieSetting(std::string* provider_id) const { return host_content_settings_map_->GetDefaultContentSetting( CONTENT_SETTINGS_TYPE_COOKIES, provider_id); } bool CookieSettings::IsReadingCookieAllowed(const GURL& url, const GURL& first_party_url) const { ContentSetting setting = GetCookieSetting(url, first_party_url, false, NULL); return IsAllowed(setting); } bool CookieSettings::IsSettingCookieAllowed(const GURL& url, const GURL& first_party_url) const { ContentSetting setting = GetCookieSetting(url, first_party_url, true, NULL); return IsAllowed(setting); } bool CookieSettings::IsCookieSessionOnly(const GURL& origin) const { ContentSetting setting = GetCookieSetting(origin, origin, true, NULL); DCHECK(IsValidSetting(setting)); return (setting == CONTENT_SETTING_SESSION_ONLY); } void CookieSettings::GetCookieSettings( ContentSettingsForOneType* settings) const { return host_content_settings_map_->GetSettingsForOneType( CONTENT_SETTINGS_TYPE_COOKIES, "", settings); } void CookieSettings::SetDefaultCookieSetting(ContentSetting setting) { DCHECK(IsValidSetting(setting)); host_content_settings_map_->SetDefaultContentSetting( CONTENT_SETTINGS_TYPE_COOKIES, setting); } void CookieSettings::SetCookieSetting( const ContentSettingsPattern& primary_pattern, const ContentSettingsPattern& secondary_pattern, ContentSetting setting) { DCHECK(IsValidSetting(setting)); if (setting == CONTENT_SETTING_SESSION_ONLY) { DCHECK(secondary_pattern == ContentSettingsPattern::Wildcard()); } host_content_settings_map_->SetContentSetting( primary_pattern, secondary_pattern, CONTENT_SETTINGS_TYPE_COOKIES, "", setting); } void CookieSettings::ResetCookieSetting( const ContentSettingsPattern& primary_pattern, const ContentSettingsPattern& secondary_pattern) { host_content_settings_map_->SetContentSetting( primary_pattern, secondary_pattern, CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_DEFAULT); } void CookieSettings::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (type == chrome::NOTIFICATION_PREF_CHANGED) { PrefService* prefs = content::Source(source).ptr(); std::string* name = content::Details(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::GetCookieSetting( const GURL& url, const GURL& first_party_url, bool setting_cookie, content_settings::SettingSource* source) const { if (HostContentSettingsMap::ShouldAllowAllContent( url, first_party_url, CONTENT_SETTINGS_TYPE_COOKIES)) return CONTENT_SETTING_ALLOW; // First get any host-specific settings. content_settings::SettingInfo info; scoped_ptr value( host_content_settings_map_->GetWebsiteSetting( url, first_party_url, CONTENT_SETTINGS_TYPE_COOKIES, "", &info)); if (source) *source = info.source; // If no explicit exception has been made and third-party cookies are blocked // by default, apply that rule. if (info.primary_pattern.MatchesAllHosts() && info.secondary_pattern.MatchesAllHosts() && ShouldBlockThirdPartyCookies() && !first_party_url.SchemeIs(chrome::kExtensionScheme)) { bool not_strict = CommandLine::ForCurrentProcess()->HasSwitch( switches::kOnlyBlockSettingThirdPartyCookies); net::StaticCookiePolicy policy(not_strict ? net::StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES : net::StaticCookiePolicy::BLOCK_ALL_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) return CONTENT_SETTING_BLOCK; } // We should always have a value, at least from the default provider. DCHECK(value.get()); return content_settings::ValueToContentSetting(value.get()); } CookieSettings::~CookieSettings() {} bool CookieSettings::ShouldBlockThirdPartyCookies() const { base::AutoLock auto_lock(lock_); return block_third_party_cookies_; }