| // Copyright (c) 2010 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/host_content_settings_map.h" |
| |
| #include "base/command_line.h" |
| #include "base/string_util.h" |
| #include "base/utf_string_conversions.h" |
| #include "chrome/browser/browser_thread.h" |
| #include "chrome/browser/metrics/user_metrics.h" |
| #include "chrome/browser/prefs/pref_service.h" |
| #include "chrome/browser/profile.h" |
| #include "chrome/browser/prefs/scoped_pref_update.h" |
| #include "chrome/common/notification_service.h" |
| #include "chrome/common/notification_source.h" |
| #include "chrome/common/notification_type.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/url_constants.h" |
| #include "googleurl/src/gurl.h" |
| #include "googleurl/src/url_canon.h" |
| #include "googleurl/src/url_parse.h" |
| #include "net/base/dns_util.h" |
| #include "net/base/net_util.h" |
| #include "net/base/static_cookie_policy.h" |
| |
| namespace { |
| // The version of the pattern format implemented. Version 1 includes the |
| // following patterns: |
| // - [*.]domain.tld (matches domain.tld and all sub-domains) |
| // - host (matches an exact hostname) |
| // - a.b.c.d (matches an exact IPv4 ip) |
| // - [a:b:c:d:e:f:g:h] (matches an exact IPv6 ip) |
| // - file:///tmp/test.html (a complete URL without a host) |
| // Version 2 adds a resource identifier for plugins. |
| // TODO(jochen): update once this feature is no longer behind a flag. |
| const int kContentSettingsPatternVersion = 1; |
| |
| // The format of a domain wildcard. |
| const char kDomainWildcard[] = "[*.]"; |
| |
| // The length of kDomainWildcard (without the trailing '\0') |
| const size_t kDomainWildcardLength = arraysize(kDomainWildcard) - 1; |
| |
| // Base pref path of the prefs that contain the managed default content |
| // settings values. |
| const std::string kManagedSettings = |
| "profile.managed_default_content_settings"; |
| |
| // The preference keys where resource identifiers are stored for |
| // ContentSettingsType values that support resource identifiers. |
| const char* kResourceTypeNames[CONTENT_SETTINGS_NUM_TYPES] = { |
| NULL, |
| NULL, |
| NULL, |
| "per_plugin", |
| NULL, |
| NULL, // Not used for Geolocation |
| NULL, // Not used for Notifications |
| }; |
| |
| // The names of the ContentSettingsType values, for use with dictionary prefs. |
| const char* kTypeNames[CONTENT_SETTINGS_NUM_TYPES] = { |
| "cookies", |
| "images", |
| "javascript", |
| "plugins", |
| "popups", |
| NULL, // Not used for Geolocation |
| NULL, // Not used for Notifications |
| }; |
| |
| // The preferences used to manage ContentSettingsTypes. |
| const char* kPrefToManageType[CONTENT_SETTINGS_NUM_TYPES] = { |
| prefs::kManagedDefaultCookiesSetting, |
| prefs::kManagedDefaultImagesSetting, |
| prefs::kManagedDefaultJavaScriptSetting, |
| prefs::kManagedDefaultPluginsSetting, |
| prefs::kManagedDefaultPopupsSetting, |
| NULL, // Not used for Geolocation |
| NULL, // Not used for Notifications |
| }; |
| |
| // The default setting for each content type. |
| const ContentSetting kDefaultSettings[CONTENT_SETTINGS_NUM_TYPES] = { |
| CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_COOKIES |
| CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_IMAGES |
| CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_JAVASCRIPT |
| CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_PLUGINS |
| CONTENT_SETTING_BLOCK, // CONTENT_SETTINGS_TYPE_POPUPS |
| CONTENT_SETTING_ASK, // Not used for Geolocation |
| CONTENT_SETTING_ASK, // Not used for Notifications |
| }; |
| |
| // True if a given content settings type requires additional resource |
| // identifiers. |
| const bool kRequiresResourceIdentifier[CONTENT_SETTINGS_NUM_TYPES] = { |
| false, // CONTENT_SETTINGS_TYPE_COOKIES |
| false, // CONTENT_SETTINGS_TYPE_IMAGES |
| false, // CONTENT_SETTINGS_TYPE_JAVASCRIPT |
| true, // CONTENT_SETTINGS_TYPE_PLUGINS |
| false, // CONTENT_SETTINGS_TYPE_POPUPS |
| false, // Not used for Geolocation |
| false, // Not used for Notifications |
| }; |
| |
| // Returns true if we should allow all content types for this URL. This is |
| // true for various internal objects like chrome:// URLs, so UI and other |
| // things users think of as "not webpages" don't break. |
| static bool ShouldAllowAllContent(const GURL& url) { |
| return url.SchemeIs(chrome::kChromeDevToolsScheme) || |
| url.SchemeIs(chrome::kChromeInternalScheme) || |
| url.SchemeIs(chrome::kChromeUIScheme) || |
| url.SchemeIs(chrome::kExtensionScheme) || |
| url.SchemeIs(chrome::kGearsScheme) || |
| url.SchemeIs(chrome::kUserScriptScheme); |
| } |
| |
| // Map ASK for the plugins content type to BLOCK if click-to-play is |
| // not enabled. |
| ContentSetting ClickToPlayFixup(ContentSettingsType content_type, |
| ContentSetting setting) { |
| if (setting == CONTENT_SETTING_ASK && |
| content_type == CONTENT_SETTINGS_TYPE_PLUGINS && |
| !CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableClickToPlay)) { |
| return CONTENT_SETTING_BLOCK; |
| } |
| return setting; |
| } |
| |
| } // namespace |
| |
| |
| struct HostContentSettingsMap::ExtendedContentSettings { |
| ContentSettings content_settings; |
| ResourceContentSettings content_settings_for_resources; |
| }; |
| |
| // static |
| HostContentSettingsMap::Pattern HostContentSettingsMap::Pattern::FromURL( |
| const GURL& url) { |
| return Pattern(!url.has_host() || url.HostIsIPAddress() ? |
| net::GetHostOrSpecFromURL(url) : |
| std::string(kDomainWildcard) + url.host()); |
| } |
| |
| // static |
| HostContentSettingsMap::Pattern |
| HostContentSettingsMap::Pattern::FromURLNoWildcard(const GURL& url) { |
| return Pattern(net::GetHostOrSpecFromURL(url)); |
| } |
| |
| bool HostContentSettingsMap::Pattern::IsValid() const { |
| if (pattern_.empty()) |
| return false; |
| |
| const std::string host(pattern_.length() > kDomainWildcardLength && |
| StartsWithASCII(pattern_, kDomainWildcard, false) ? |
| pattern_.substr(kDomainWildcardLength) : |
| pattern_); |
| url_canon::CanonHostInfo host_info; |
| return host.find('*') == std::string::npos && |
| !net::CanonicalizeHost(host, &host_info).empty(); |
| } |
| |
| bool HostContentSettingsMap::Pattern::Matches(const GURL& url) const { |
| if (!IsValid()) |
| return false; |
| |
| const std::string host(net::GetHostOrSpecFromURL(url)); |
| if (pattern_.length() < kDomainWildcardLength || |
| !StartsWithASCII(pattern_, kDomainWildcard, false)) |
| return pattern_ == host; |
| |
| const size_t match = |
| host.rfind(pattern_.substr(kDomainWildcardLength)); |
| |
| return (match != std::string::npos) && |
| (match == 0 || host[match - 1] == '.') && |
| (match + pattern_.length() - kDomainWildcardLength == host.length()); |
| } |
| |
| std::string HostContentSettingsMap::Pattern::CanonicalizePattern() const { |
| if (!IsValid()) { |
| return ""; |
| } |
| |
| bool starts_with_wildcard = pattern_.length() > kDomainWildcardLength && |
| StartsWithASCII(pattern_, kDomainWildcard, false); |
| |
| const std::string host(starts_with_wildcard ? |
| pattern_.substr(kDomainWildcardLength) : pattern_); |
| |
| std::string canonicalized_pattern = |
| starts_with_wildcard ? kDomainWildcard : ""; |
| |
| url_canon::CanonHostInfo host_info; |
| canonicalized_pattern += net::CanonicalizeHost(host, &host_info); |
| |
| return canonicalized_pattern; |
| } |
| |
| HostContentSettingsMap::HostContentSettingsMap(Profile* profile) |
| : profile_(profile), |
| block_third_party_cookies_(false), |
| is_off_the_record_(profile_->IsOffTheRecord()), |
| updating_preferences_(false) { |
| PrefService* prefs = profile_->GetPrefs(); |
| |
| MigrateObsoleteCookiePref(prefs); |
| |
| MigrateObsoletePopupsPref(prefs); |
| |
| MigrateObsoletePerhostPref(prefs); |
| |
| // Read global defaults. |
| DCHECK_EQ(arraysize(kTypeNames), |
| static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES)); |
| ReadDefaultSettings(false); |
| |
| // Read misc. global settings. |
| block_third_party_cookies_ = |
| prefs->GetBoolean(prefs::kBlockThirdPartyCookies); |
| block_nonsandboxed_plugins_ = |
| prefs->GetBoolean(prefs::kBlockNonsandboxedPlugins); |
| |
| // Verify preferences version. |
| if (!prefs->HasPrefPath(prefs::kContentSettingsVersion)) { |
| prefs->SetInteger(prefs::kContentSettingsVersion, |
| kContentSettingsPatternVersion); |
| } |
| if (prefs->GetInteger(prefs::kContentSettingsVersion) > |
| kContentSettingsPatternVersion) { |
| LOG(ERROR) << "Unknown content settings version in preferences."; |
| return; |
| } |
| |
| // Read exceptions. |
| ReadExceptions(false); |
| |
| pref_change_registrar_.Init(prefs); |
| pref_change_registrar_.Add(prefs::kDefaultContentSettings, this); |
| pref_change_registrar_.Add(prefs::kContentSettingsPatterns, this); |
| pref_change_registrar_.Add(prefs::kBlockThirdPartyCookies, this); |
| pref_change_registrar_.Add(prefs::kBlockNonsandboxedPlugins, this); |
| // The following preferences are only used to indicate if a |
| // default-content-setting is managed and to hold the managed default-setting |
| // value. If the value for any of the following perferences is set then the |
| // corresponding default-content-setting is managed. These preferences exist |
| // in parallel to the preference default-content-settings. If a |
| // default-content-settings-type is managed any user defined excpetions |
| // (patterns) for this type are ignored. |
| pref_change_registrar_.Add(prefs::kManagedDefaultCookiesSetting, this); |
| pref_change_registrar_.Add(prefs::kManagedDefaultImagesSetting, this); |
| pref_change_registrar_.Add(prefs::kManagedDefaultJavaScriptSetting, this); |
| pref_change_registrar_.Add(prefs::kManagedDefaultPluginsSetting, this); |
| pref_change_registrar_.Add(prefs::kManagedDefaultPopupsSetting, this); |
| notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED, |
| Source<Profile>(profile_)); |
| } |
| |
| // static |
| void HostContentSettingsMap::RegisterUserPrefs(PrefService* prefs) { |
| prefs->RegisterDictionaryPref(prefs::kDefaultContentSettings); |
| prefs->RegisterIntegerPref(prefs::kContentSettingsVersion, |
| kContentSettingsPatternVersion); |
| prefs->RegisterDictionaryPref(prefs::kContentSettingsPatterns); |
| prefs->RegisterBooleanPref(prefs::kBlockThirdPartyCookies, false); |
| prefs->RegisterBooleanPref(prefs::kBlockNonsandboxedPlugins, false); |
| prefs->RegisterIntegerPref(prefs::kContentSettingsWindowLastTabIndex, 0); |
| |
| // Preferences for default content setting policies. A policy is not set of |
| // the corresponding preferences below is set to CONTENT_SETTING_DEFAULT. |
| prefs->RegisterIntegerPref(prefs::kManagedDefaultCookiesSetting, |
| CONTENT_SETTING_DEFAULT); |
| prefs->RegisterIntegerPref(prefs::kManagedDefaultImagesSetting, |
| CONTENT_SETTING_DEFAULT); |
| prefs->RegisterIntegerPref(prefs::kManagedDefaultJavaScriptSetting, |
| CONTENT_SETTING_DEFAULT); |
| prefs->RegisterIntegerPref(prefs::kManagedDefaultPluginsSetting, |
| CONTENT_SETTING_DEFAULT); |
| prefs->RegisterIntegerPref(prefs::kManagedDefaultPopupsSetting, |
| CONTENT_SETTING_DEFAULT); |
| |
| // Obsolete prefs, for migration: |
| prefs->RegisterIntegerPref(prefs::kCookieBehavior, |
| net::StaticCookiePolicy::ALLOW_ALL_COOKIES); |
| prefs->RegisterListPref(prefs::kPopupWhitelistedHosts); |
| prefs->RegisterDictionaryPref(prefs::kPerHostContentSettings); |
| } |
| |
| ContentSetting HostContentSettingsMap::GetDefaultContentSetting( |
| ContentSettingsType content_type) const { |
| AutoLock auto_lock(lock_); |
| if (IsDefaultContentSettingManaged(content_type)) |
| return managed_default_content_settings_.settings[content_type]; |
| return default_content_settings_.settings[content_type]; |
| } |
| |
| ContentSetting HostContentSettingsMap::GetContentSetting( |
| const GURL& url, |
| ContentSettingsType content_type, |
| const std::string& resource_identifier) const { |
| ContentSetting setting = GetNonDefaultContentSetting(url, |
| content_type, |
| resource_identifier); |
| if (setting == CONTENT_SETTING_DEFAULT || |
| IsDefaultContentSettingManaged(content_type)) { |
| return GetDefaultContentSetting(content_type); |
| } |
| return setting; |
| } |
| |
| ContentSetting HostContentSettingsMap::GetNonDefaultContentSetting( |
| const GURL& url, |
| ContentSettingsType content_type, |
| const std::string& resource_identifier) const { |
| if (ShouldAllowAllContent(url)) |
| return CONTENT_SETTING_ALLOW; |
| |
| if (!RequiresResourceIdentifier(content_type)) |
| return GetNonDefaultContentSettings(url).settings[content_type]; |
| |
| if (CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableResourceContentSettings)) { |
| DCHECK(!resource_identifier.empty()); |
| } |
| |
| // Host content settings are ignored if the default_content_setting is |
| // managed. |
| if (IsDefaultContentSettingManaged(content_type)) { |
| return GetDefaultContentSetting(content_type); |
| } |
| |
| AutoLock auto_lock(lock_); |
| |
| const std::string host(net::GetHostOrSpecFromURL(url)); |
| ContentSettingsTypeResourceIdentifierPair |
| requested_setting(content_type, resource_identifier); |
| |
| // Check for exact matches first. |
| HostContentSettings::const_iterator i(host_content_settings_.find(host)); |
| if (i != host_content_settings_.end() && |
| i->second.content_settings_for_resources.find(requested_setting) != |
| i->second.content_settings_for_resources.end()) { |
| return i->second.content_settings_for_resources.find( |
| requested_setting)->second; |
| } |
| |
| // If this map is not for an off-the-record profile, these searches will never |
| // match. The additional off-the-record exceptions always overwrite the |
| // regular ones. |
| i = off_the_record_settings_.find(host); |
| if (i != off_the_record_settings_.end() && |
| i->second.content_settings_for_resources.find(requested_setting) != |
| i->second.content_settings_for_resources.end()) { |
| return i->second.content_settings_for_resources.find( |
| requested_setting)->second; |
| } |
| |
| // Match patterns starting with the most concrete pattern match. |
| for (std::string key = std::string(kDomainWildcard) + host; ; ) { |
| HostContentSettings::const_iterator i(off_the_record_settings_.find(key)); |
| if (i != off_the_record_settings_.end() && |
| i->second.content_settings_for_resources.find(requested_setting) != |
| i->second.content_settings_for_resources.end()) { |
| return i->second.content_settings_for_resources.find( |
| requested_setting)->second; |
| } |
| |
| i = host_content_settings_.find(key); |
| if (i != host_content_settings_.end() && |
| i->second.content_settings_for_resources.find(requested_setting) != |
| i->second.content_settings_for_resources.end()) { |
| return i->second.content_settings_for_resources.find( |
| requested_setting)->second; |
| } |
| |
| const size_t next_dot = key.find('.', kDomainWildcardLength); |
| if (next_dot == std::string::npos) |
| break; |
| key.erase(kDomainWildcardLength, next_dot - kDomainWildcardLength + 1); |
| } |
| |
| return CONTENT_SETTING_DEFAULT; |
| } |
| |
| ContentSettings HostContentSettingsMap::GetContentSettings( |
| const GURL& url) const { |
| ContentSettings output = GetNonDefaultContentSettings(url); |
| |
| AutoLock auto_lock(lock_); |
| |
| // If we require a resource identifier, set the content settings to default, |
| // otherwise make the defaults explicit. |
| for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) { |
| if (RequiresResourceIdentifier(ContentSettingsType(j))) { |
| output.settings[j] = CONTENT_SETTING_DEFAULT; |
| } else { |
| if (output.settings[j] == CONTENT_SETTING_DEFAULT) { |
| output.settings[j] = default_content_settings_.settings[j]; |
| } |
| // A managed default content setting has the highest priority and hence |
| // will overwrite any previously set value. |
| if (IsDefaultContentSettingManaged(ContentSettingsType(j))) { |
| output.settings[j] = |
| managed_default_content_settings_.settings[j]; |
| } |
| } |
| } |
| return output; |
| } |
| |
| ContentSettings HostContentSettingsMap::GetNonDefaultContentSettings( |
| const GURL& url) const { |
| if (ShouldAllowAllContent(url)) |
| return ContentSettings(CONTENT_SETTING_ALLOW); |
| |
| AutoLock auto_lock(lock_); |
| |
| const std::string host(net::GetHostOrSpecFromURL(url)); |
| ContentSettings output; |
| for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) |
| output.settings[j] = CONTENT_SETTING_DEFAULT; |
| |
| // Check for exact matches first. |
| HostContentSettings::const_iterator i(host_content_settings_.find(host)); |
| if (i != host_content_settings_.end()) |
| output = i->second.content_settings; |
| |
| // If this map is not for an off-the-record profile, these searches will never |
| // match. The additional off-the-record exceptions always overwrite the |
| // regular ones. |
| i = off_the_record_settings_.find(host); |
| if (i != off_the_record_settings_.end()) { |
| for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) |
| if (i->second.content_settings.settings[j] != CONTENT_SETTING_DEFAULT) |
| output.settings[j] = i->second.content_settings.settings[j]; |
| } |
| |
| // Match patterns starting with the most concrete pattern match. |
| for (std::string key = std::string(kDomainWildcard) + host; ; ) { |
| HostContentSettings::const_iterator i(off_the_record_settings_.find(key)); |
| if (i != off_the_record_settings_.end()) { |
| for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) { |
| if (output.settings[j] == CONTENT_SETTING_DEFAULT) |
| output.settings[j] = i->second.content_settings.settings[j]; |
| } |
| } |
| i = host_content_settings_.find(key); |
| if (i != host_content_settings_.end()) { |
| for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) { |
| if (output.settings[j] == CONTENT_SETTING_DEFAULT) |
| output.settings[j] = i->second.content_settings.settings[j]; |
| } |
| } |
| const size_t next_dot = key.find('.', kDomainWildcardLength); |
| if (next_dot == std::string::npos) |
| break; |
| key.erase(kDomainWildcardLength, next_dot - kDomainWildcardLength + 1); |
| } |
| |
| return output; |
| } |
| |
| void HostContentSettingsMap::GetSettingsForOneType( |
| ContentSettingsType content_type, |
| const std::string& resource_identifier, |
| SettingsForOneType* settings) const { |
| DCHECK(RequiresResourceIdentifier(content_type) != |
| resource_identifier.empty()); |
| DCHECK(settings); |
| settings->clear(); |
| |
| const HostContentSettings* map_to_return = |
| is_off_the_record_ ? &off_the_record_settings_ : &host_content_settings_; |
| ContentSettingsTypeResourceIdentifierPair |
| requested_setting(content_type, resource_identifier); |
| |
| AutoLock auto_lock(lock_); |
| for (HostContentSettings::const_iterator i(map_to_return->begin()); |
| i != map_to_return->end(); ++i) { |
| ContentSetting setting; |
| if (RequiresResourceIdentifier(content_type)) { |
| if (i->second.content_settings_for_resources.find(requested_setting) != |
| i->second.content_settings_for_resources.end()) |
| setting = i->second.content_settings_for_resources.find( |
| requested_setting)->second; |
| else |
| setting = CONTENT_SETTING_DEFAULT; |
| } else { |
| setting = i->second.content_settings.settings[content_type]; |
| } |
| if (setting != CONTENT_SETTING_DEFAULT) { |
| // Use of push_back() relies on the map iterator traversing in order of |
| // ascending keys. |
| settings->push_back(std::make_pair(Pattern(i->first), setting)); |
| } |
| } |
| } |
| |
| void HostContentSettingsMap::SetDefaultContentSetting( |
| ContentSettingsType content_type, |
| ContentSetting setting) { |
| DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation. |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK(content_type != CONTENT_SETTINGS_TYPE_PLUGINS || |
| setting != CONTENT_SETTING_ASK || |
| CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableClickToPlay)); |
| PrefService* prefs = profile_->GetPrefs(); |
| |
| // The default settings may not be directly modified for OTR sessions. |
| // Instead, they are synced to the main profile's setting. |
| if (is_off_the_record_) { |
| NOTREACHED(); |
| return; |
| } |
| |
| DictionaryValue* default_settings_dictionary = |
| prefs->GetMutableDictionary(prefs::kDefaultContentSettings); |
| std::string dictionary_path(kTypeNames[content_type]); |
| updating_preferences_ = true; |
| { |
| AutoLock auto_lock(lock_); |
| ScopedPrefUpdate update(prefs, prefs::kDefaultContentSettings); |
| if ((setting == CONTENT_SETTING_DEFAULT) || |
| (setting == kDefaultSettings[content_type])) { |
| default_content_settings_.settings[content_type] = |
| kDefaultSettings[content_type]; |
| default_settings_dictionary->RemoveWithoutPathExpansion(dictionary_path, |
| NULL); |
| } else { |
| default_content_settings_.settings[content_type] = setting; |
| default_settings_dictionary->SetWithoutPathExpansion( |
| dictionary_path, Value::CreateIntegerValue(setting)); |
| } |
| } |
| updating_preferences_ = false; |
| |
| NotifyObservers(ContentSettingsDetails(Pattern(), content_type, "")); |
| } |
| |
| void HostContentSettingsMap::SetContentSetting( |
| const Pattern& original_pattern, |
| ContentSettingsType content_type, |
| const std::string& resource_identifier, |
| ContentSetting setting) { |
| DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation. |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| DCHECK_NE(RequiresResourceIdentifier(content_type), |
| resource_identifier.empty()); |
| DCHECK(content_type != CONTENT_SETTINGS_TYPE_PLUGINS || |
| setting != CONTENT_SETTING_ASK || |
| CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableClickToPlay)); |
| |
| const Pattern pattern(original_pattern.CanonicalizePattern()); |
| |
| bool early_exit = false; |
| std::string pattern_str(pattern.AsString()); |
| PrefService* prefs = NULL; |
| DictionaryValue* all_settings_dictionary = NULL; |
| HostContentSettings* map_to_modify = &off_the_record_settings_; |
| if (!is_off_the_record_) { |
| prefs = profile_->GetPrefs(); |
| all_settings_dictionary = |
| prefs->GetMutableDictionary(prefs::kContentSettingsPatterns); |
| map_to_modify = &host_content_settings_; |
| } |
| |
| { |
| AutoLock auto_lock(lock_); |
| if (!map_to_modify->count(pattern_str)) |
| (*map_to_modify)[pattern_str].content_settings = ContentSettings(); |
| HostContentSettings::iterator |
| i(map_to_modify->find(pattern_str)); |
| ContentSettings& settings = i->second.content_settings; |
| if (RequiresResourceIdentifier(content_type)) { |
| settings.settings[content_type] = CONTENT_SETTING_DEFAULT; |
| if (setting != CONTENT_SETTING_DEFAULT) { |
| i->second.content_settings_for_resources[ |
| ContentSettingsTypeResourceIdentifierPair(content_type, |
| resource_identifier)] = setting; |
| } else { |
| i->second.content_settings_for_resources.erase( |
| ContentSettingsTypeResourceIdentifierPair(content_type, |
| resource_identifier)); |
| } |
| } else { |
| settings.settings[content_type] = setting; |
| } |
| if (AllDefault(i->second)) { |
| map_to_modify->erase(i); |
| if (all_settings_dictionary) |
| all_settings_dictionary->RemoveWithoutPathExpansion(pattern_str, NULL); |
| |
| // We can't just return because |NotifyObservers()| needs to be called, |
| // without |lock_| being held. |
| early_exit = true; |
| } |
| } |
| |
| if (!early_exit && all_settings_dictionary) { |
| DictionaryValue* host_settings_dictionary = NULL; |
| bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion( |
| pattern_str, &host_settings_dictionary); |
| if (!found) { |
| host_settings_dictionary = new DictionaryValue; |
| all_settings_dictionary->SetWithoutPathExpansion( |
| pattern_str, host_settings_dictionary); |
| DCHECK_NE(setting, CONTENT_SETTING_DEFAULT); |
| } |
| if (RequiresResourceIdentifier(content_type)) { |
| std::string dictionary_path(kResourceTypeNames[content_type]); |
| DictionaryValue* resource_dictionary = NULL; |
| found = host_settings_dictionary->GetDictionary( |
| dictionary_path, &resource_dictionary); |
| if (!found) { |
| resource_dictionary = new DictionaryValue; |
| host_settings_dictionary->Set(dictionary_path, resource_dictionary); |
| } |
| if (setting == CONTENT_SETTING_DEFAULT) { |
| resource_dictionary->RemoveWithoutPathExpansion(resource_identifier, |
| NULL); |
| } else { |
| resource_dictionary->SetWithoutPathExpansion( |
| resource_identifier, Value::CreateIntegerValue(setting)); |
| } |
| } else { |
| std::string dictionary_path(kTypeNames[content_type]); |
| if (setting == CONTENT_SETTING_DEFAULT) { |
| host_settings_dictionary->RemoveWithoutPathExpansion(dictionary_path, |
| NULL); |
| } else { |
| host_settings_dictionary->SetWithoutPathExpansion( |
| dictionary_path, Value::CreateIntegerValue(setting)); |
| } |
| } |
| } |
| |
| updating_preferences_ = true; |
| if (!is_off_the_record_) |
| ScopedPrefUpdate update(prefs, prefs::kContentSettingsPatterns); |
| updating_preferences_ = false; |
| |
| NotifyObservers(ContentSettingsDetails(pattern, content_type, "")); |
| } |
| |
| void HostContentSettingsMap::AddExceptionForURL( |
| const GURL& url, |
| ContentSettingsType content_type, |
| const std::string& resource_identifier, |
| ContentSetting setting) { |
| // Make sure there is no entry that would override the pattern we are about |
| // to insert for exactly this URL. |
| SetContentSetting(Pattern::FromURLNoWildcard(url), |
| content_type, |
| resource_identifier, |
| CONTENT_SETTING_DEFAULT); |
| SetContentSetting(Pattern::FromURL(url), |
| content_type, |
| resource_identifier, |
| setting); |
| } |
| |
| void HostContentSettingsMap::ClearSettingsForOneType( |
| ContentSettingsType content_type) { |
| DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation. |
| |
| PrefService* prefs = NULL; |
| DictionaryValue* all_settings_dictionary = NULL; |
| HostContentSettings* map_to_modify = &off_the_record_settings_; |
| |
| if (!is_off_the_record_) { |
| prefs = profile_->GetPrefs(); |
| all_settings_dictionary = |
| prefs->GetMutableDictionary(prefs::kContentSettingsPatterns); |
| map_to_modify = &host_content_settings_; |
| } |
| |
| { |
| AutoLock auto_lock(lock_); |
| for (HostContentSettings::iterator i(map_to_modify->begin()); |
| i != map_to_modify->end(); ) { |
| if (RequiresResourceIdentifier(content_type) || |
| i->second.content_settings.settings[content_type] != |
| CONTENT_SETTING_DEFAULT) { |
| if (RequiresResourceIdentifier(content_type)) |
| i->second.content_settings_for_resources.clear(); |
| i->second.content_settings.settings[content_type] = |
| CONTENT_SETTING_DEFAULT; |
| std::string host(i->first); |
| if (AllDefault(i->second)) { |
| if (all_settings_dictionary) |
| all_settings_dictionary-> |
| RemoveWithoutPathExpansion(host, NULL); |
| map_to_modify->erase(i++); |
| } else if (all_settings_dictionary) { |
| DictionaryValue* host_settings_dictionary; |
| bool found = |
| all_settings_dictionary->GetDictionaryWithoutPathExpansion( |
| host, &host_settings_dictionary); |
| DCHECK(found); |
| host_settings_dictionary->RemoveWithoutPathExpansion( |
| kTypeNames[content_type], NULL); |
| ++i; |
| } |
| } else { |
| ++i; |
| } |
| } |
| } |
| |
| updating_preferences_ = true; |
| if (!is_off_the_record_) |
| ScopedPrefUpdate update(prefs, prefs::kContentSettingsPatterns); |
| updating_preferences_ = false; |
| |
| NotifyObservers(ContentSettingsDetails(Pattern(), content_type, "")); |
| } |
| |
| bool HostContentSettingsMap::RequiresResourceIdentifier( |
| ContentSettingsType content_type) const { |
| if (CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableResourceContentSettings)) { |
| return kRequiresResourceIdentifier[content_type]; |
| } else { |
| return false; |
| } |
| } |
| |
| void HostContentSettingsMap::SetBlockThirdPartyCookies(bool block) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| // This setting may not be directly modified for OTR sessions. Instead, it |
| // is synced to the main profile's setting. |
| if (is_off_the_record_) { |
| NOTREACHED(); |
| return; |
| } |
| |
| PrefService* prefs = profile_->GetPrefs(); |
| // If the preference block-third-party-cookies is managed then do not allow to |
| // change it. |
| if (prefs->IsManagedPreference(prefs::kBlockThirdPartyCookies)) { |
| NOTREACHED(); |
| return; |
| } |
| |
| { |
| AutoLock auto_lock(lock_); |
| block_third_party_cookies_ = block; |
| } |
| |
| if (block) |
| prefs->SetBoolean(prefs::kBlockThirdPartyCookies, true); |
| else |
| prefs->ClearPref(prefs::kBlockThirdPartyCookies); |
| } |
| |
| void HostContentSettingsMap::SetBlockNonsandboxedPlugins(bool block) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| // This setting may not be directly modified for OTR sessions. Instead, it |
| // is synced to the main profile's setting. |
| if (is_off_the_record_) { |
| NOTREACHED(); |
| return; |
| } |
| |
| { |
| AutoLock auto_lock(lock_); |
| block_nonsandboxed_plugins_ = block; |
| } |
| |
| |
| PrefService* prefs = profile_->GetPrefs(); |
| if (block) { |
| UserMetrics::RecordAction( |
| UserMetricsAction("BlockNonsandboxedPlugins_Enable")); |
| prefs->SetBoolean(prefs::kBlockNonsandboxedPlugins, true); |
| } else { |
| UserMetrics::RecordAction( |
| UserMetricsAction("BlockNonsandboxedPlugins_Disable")); |
| prefs->ClearPref(prefs::kBlockNonsandboxedPlugins); |
| } |
| } |
| |
| void HostContentSettingsMap::ResetToDefaults() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| { |
| AutoLock auto_lock(lock_); |
| default_content_settings_ = ContentSettings(); |
| ForceDefaultsToBeExplicit(); |
| host_content_settings_.clear(); |
| off_the_record_settings_.clear(); |
| block_third_party_cookies_ = false; |
| block_nonsandboxed_plugins_ = false; |
| } |
| |
| if (!is_off_the_record_) { |
| PrefService* prefs = profile_->GetPrefs(); |
| updating_preferences_ = true; |
| prefs->ClearPref(prefs::kDefaultContentSettings); |
| prefs->ClearPref(prefs::kContentSettingsPatterns); |
| prefs->ClearPref(prefs::kBlockThirdPartyCookies); |
| prefs->ClearPref(prefs::kBlockNonsandboxedPlugins); |
| updating_preferences_ = false; |
| NotifyObservers( |
| ContentSettingsDetails(Pattern(), CONTENT_SETTINGS_TYPE_DEFAULT, "")); |
| } |
| } |
| |
| void HostContentSettingsMap::Observe(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| if (NotificationType::PREF_CHANGED == type) { |
| if (updating_preferences_) |
| return; |
| |
| std::string* name = Details<std::string>(details).ptr(); |
| if (prefs::kDefaultContentSettings == *name) { |
| ReadDefaultSettings(true); |
| } else if (prefs::kContentSettingsPatterns == *name) { |
| ReadExceptions(true); |
| } else if (prefs::kBlockThirdPartyCookies == *name) { |
| AutoLock auto_lock(lock_); |
| block_third_party_cookies_ = profile_->GetPrefs()->GetBoolean( |
| prefs::kBlockThirdPartyCookies); |
| } else if (prefs::kBlockNonsandboxedPlugins == *name) { |
| AutoLock auto_lock(lock_); |
| block_nonsandboxed_plugins_ = profile_->GetPrefs()->GetBoolean( |
| prefs::kBlockNonsandboxedPlugins); |
| } else if (prefs::kManagedDefaultCookiesSetting == *name) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES, |
| profile_->GetPrefs(), |
| &managed_default_content_settings_); |
| } else if (prefs::kManagedDefaultImagesSetting == *name) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_IMAGES, |
| profile_->GetPrefs(), |
| &managed_default_content_settings_); |
| } else if (prefs::kManagedDefaultJavaScriptSetting == *name) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT, |
| profile_->GetPrefs(), |
| &managed_default_content_settings_); |
| } else if (prefs::kManagedDefaultPluginsSetting == *name) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_PLUGINS, |
| profile_->GetPrefs(), |
| &managed_default_content_settings_); |
| } else if (prefs::kManagedDefaultPopupsSetting == *name) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_POPUPS, |
| profile_->GetPrefs(), |
| &managed_default_content_settings_); |
| } else { |
| NOTREACHED() << "Unexpected preference observed"; |
| return; |
| } |
| |
| if (!is_off_the_record_) { |
| NotifyObservers( |
| ContentSettingsDetails(Pattern(), CONTENT_SETTINGS_TYPE_DEFAULT, "")); |
| } |
| } else if (NotificationType::PROFILE_DESTROYED == type) { |
| UnregisterObservers(); |
| } else { |
| NOTREACHED() << "Unexpected notification"; |
| } |
| } |
| |
| HostContentSettingsMap::~HostContentSettingsMap() { |
| UnregisterObservers(); |
| } |
| |
| void HostContentSettingsMap::GetSettingsFromDictionary( |
| const DictionaryValue* dictionary, |
| ContentSettings* settings) { |
| for (DictionaryValue::key_iterator i(dictionary->begin_keys()); |
| i != dictionary->end_keys(); ++i) { |
| const std::string& content_type(*i); |
| for (size_t type = 0; type < arraysize(kTypeNames); ++type) { |
| if ((kTypeNames[type] != NULL) && (kTypeNames[type] == content_type)) { |
| int setting = CONTENT_SETTING_DEFAULT; |
| bool found = dictionary->GetIntegerWithoutPathExpansion(content_type, |
| &setting); |
| DCHECK(found); |
| settings->settings[type] = IntToContentSetting(setting); |
| break; |
| } |
| } |
| } |
| // Migrate obsolete cookie prompt mode. |
| if (settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] == |
| CONTENT_SETTING_ASK) |
| settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] = CONTENT_SETTING_BLOCK; |
| |
| settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS] = |
| ClickToPlayFixup(CONTENT_SETTINGS_TYPE_PLUGINS, |
| settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS]); |
| } |
| |
| void HostContentSettingsMap::GetResourceSettingsFromDictionary( |
| const DictionaryValue* dictionary, |
| ResourceContentSettings* settings) { |
| for (DictionaryValue::key_iterator i(dictionary->begin_keys()); |
| i != dictionary->end_keys(); ++i) { |
| const std::string& content_type(*i); |
| for (size_t type = 0; type < arraysize(kResourceTypeNames); ++type) { |
| if ((kResourceTypeNames[type] != NULL) && |
| (kResourceTypeNames[type] == content_type)) { |
| DictionaryValue* resource_dictionary = NULL; |
| bool found = dictionary->GetDictionary(content_type, |
| &resource_dictionary); |
| DCHECK(found); |
| for (DictionaryValue::key_iterator j(resource_dictionary->begin_keys()); |
| j != resource_dictionary->end_keys(); ++j) { |
| const std::string& resource_identifier(*j); |
| int setting = CONTENT_SETTING_DEFAULT; |
| bool found = resource_dictionary->GetIntegerWithoutPathExpansion( |
| resource_identifier, &setting); |
| DCHECK(found); |
| (*settings)[ContentSettingsTypeResourceIdentifierPair( |
| ContentSettingsType(type), resource_identifier)] = |
| ClickToPlayFixup(ContentSettingsType(type), |
| ContentSetting(setting)); |
| } |
| |
| break; |
| } |
| } |
| } |
| } |
| |
| void HostContentSettingsMap::ForceDefaultsToBeExplicit() { |
| DCHECK_EQ(arraysize(kDefaultSettings), |
| static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES)); |
| |
| for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { |
| if (default_content_settings_.settings[i] == CONTENT_SETTING_DEFAULT) |
| default_content_settings_.settings[i] = kDefaultSettings[i]; |
| } |
| } |
| |
| bool HostContentSettingsMap::AllDefault( |
| const ExtendedContentSettings& settings) const { |
| for (size_t i = 0; i < arraysize(settings.content_settings.settings); ++i) { |
| if (settings.content_settings.settings[i] != CONTENT_SETTING_DEFAULT) |
| return false; |
| } |
| return settings.content_settings_for_resources.empty(); |
| } |
| |
| void HostContentSettingsMap::ReadDefaultSettings(bool overwrite) { |
| PrefService* prefs = profile_->GetPrefs(); |
| const DictionaryValue* default_settings_dictionary = |
| prefs->GetDictionary(prefs::kDefaultContentSettings); |
| |
| if (overwrite) |
| default_content_settings_ = ContentSettings(); |
| |
| // Careful: The returned value could be NULL if the pref has never been set. |
| if (default_settings_dictionary != NULL) { |
| GetSettingsFromDictionary(default_settings_dictionary, |
| &default_content_settings_); |
| } |
| ForceDefaultsToBeExplicit(); |
| |
| // Read managed default content settings. |
| ReadManagedDefaultSettings(prefs, &managed_default_content_settings_); |
| } |
| |
| void HostContentSettingsMap::ReadManagedDefaultSettings ( |
| const PrefService* prefs, ContentSettings* settings) { |
| for (size_t type = 0; type < arraysize(kPrefToManageType); ++type) { |
| if (kPrefToManageType[type] == NULL) { |
| // TODO(markusheintz): Handle Geolocation and notification separately. |
| continue; |
| } |
| UpdateManagedDefaultSetting(ContentSettingsType(type), prefs, settings); |
| } |
| } |
| |
| void HostContentSettingsMap::UpdateManagedDefaultSetting( |
| ContentSettingsType type, |
| const PrefService* prefs, |
| ContentSettings* settings) { |
| // If a pref to manage a default-content-setting was not set (NOTICE: |
| // "HasPrefPath" returns false if no value was set for a registered pref) then |
| // the default value of the preference is used. The default value of a |
| // preference to manage a default-content-settings is |
| // CONTENT_SETTING_DEFAULT. This indicates that no managed value is set. If a |
| // pref was set, than it MUST be managed. |
| DCHECK(!prefs->HasPrefPath(kPrefToManageType[type]) || |
| prefs->IsManagedPreference(kPrefToManageType[type])); |
| AutoLock auto_lock(lock_); |
| settings->settings[type] = IntToContentSetting( |
| prefs->GetInteger(kPrefToManageType[type])); |
| } |
| |
| bool HostContentSettingsMap::IsDefaultContentSettingManaged( |
| ContentSettingsType content_type) const { |
| // All managed_default_content_settings_ are always set explicitly or |
| // initialized to CONTENT_SETTINGS_DEFAULT. Hence each content settings type |
| // that is set to CONTENT_SETTINGS_DEFAULT is not managed since it was not set |
| // explicitly. |
| return managed_default_content_settings_.settings[content_type] != |
| CONTENT_SETTING_DEFAULT; |
| } |
| |
| void HostContentSettingsMap::ReadExceptions(bool overwrite) { |
| PrefService* prefs = profile_->GetPrefs(); |
| DictionaryValue* all_settings_dictionary = |
| prefs->GetMutableDictionary(prefs::kContentSettingsPatterns); |
| |
| if (overwrite) |
| host_content_settings_.clear(); |
| |
| // Careful: The returned value could be NULL if the pref has never been set. |
| if (all_settings_dictionary != NULL) { |
| // Convert all Unicode patterns into punycode form, then read. |
| CanonicalizeContentSettingsExceptions(all_settings_dictionary); |
| |
| for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys()); |
| i != all_settings_dictionary->end_keys(); ++i) { |
| const std::string& pattern(*i); |
| if (!Pattern(pattern).IsValid()) |
| LOG(WARNING) << "Invalid pattern stored in content settings"; |
| DictionaryValue* pattern_settings_dictionary = NULL; |
| bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion( |
| pattern, &pattern_settings_dictionary); |
| DCHECK(found); |
| ContentSettings settings; |
| GetSettingsFromDictionary(pattern_settings_dictionary, &settings); |
| host_content_settings_[pattern].content_settings = settings; |
| GetResourceSettingsFromDictionary( |
| pattern_settings_dictionary, |
| &host_content_settings_[pattern].content_settings_for_resources); |
| } |
| } |
| } |
| |
| void HostContentSettingsMap::NotifyObservers( |
| const ContentSettingsDetails& details) { |
| NotificationService::current()->Notify( |
| NotificationType::CONTENT_SETTINGS_CHANGED, |
| Source<HostContentSettingsMap>(this), |
| Details<const ContentSettingsDetails>(&details)); |
| } |
| |
| void HostContentSettingsMap::UnregisterObservers() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| if (!profile_) |
| return; |
| pref_change_registrar_.RemoveAll(); |
| notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED, |
| Source<Profile>(profile_)); |
| profile_ = NULL; |
| } |
| |
| void HostContentSettingsMap::MigrateObsoleteCookiePref(PrefService* prefs) { |
| if (prefs->HasPrefPath(prefs::kCookieBehavior)) { |
| int cookie_behavior = prefs->GetInteger(prefs::kCookieBehavior); |
| prefs->ClearPref(prefs::kCookieBehavior); |
| if (!prefs->HasPrefPath(prefs::kDefaultContentSettings)) { |
| SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES, |
| (cookie_behavior == net::StaticCookiePolicy::BLOCK_ALL_COOKIES) ? |
| CONTENT_SETTING_BLOCK : CONTENT_SETTING_ALLOW); |
| } |
| if (!prefs->HasPrefPath(prefs::kBlockThirdPartyCookies)) { |
| SetBlockThirdPartyCookies(cookie_behavior == |
| net::StaticCookiePolicy::BLOCK_THIRD_PARTY_COOKIES); |
| } |
| } |
| } |
| |
| void HostContentSettingsMap::MigrateObsoletePopupsPref(PrefService* prefs) { |
| if (prefs->HasPrefPath(prefs::kPopupWhitelistedHosts)) { |
| const ListValue* whitelist_pref = |
| prefs->GetList(prefs::kPopupWhitelistedHosts); |
| for (ListValue::const_iterator i(whitelist_pref->begin()); |
| i != whitelist_pref->end(); ++i) { |
| std::string host; |
| (*i)->GetAsString(&host); |
| SetContentSetting(Pattern(host), CONTENT_SETTINGS_TYPE_POPUPS, "", |
| CONTENT_SETTING_ALLOW); |
| } |
| prefs->ClearPref(prefs::kPopupWhitelistedHosts); |
| } |
| } |
| |
| void HostContentSettingsMap::MigrateObsoletePerhostPref(PrefService* prefs) { |
| if (prefs->HasPrefPath(prefs::kPerHostContentSettings)) { |
| const DictionaryValue* all_settings_dictionary = |
| prefs->GetDictionary(prefs::kPerHostContentSettings); |
| for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys()); |
| i != all_settings_dictionary->end_keys(); ++i) { |
| const std::string& host(*i); |
| Pattern pattern(std::string(kDomainWildcard) + host); |
| DictionaryValue* host_settings_dictionary = NULL; |
| bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion( |
| host, &host_settings_dictionary); |
| DCHECK(found); |
| ContentSettings settings; |
| GetSettingsFromDictionary(host_settings_dictionary, &settings); |
| for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) { |
| if (settings.settings[j] != CONTENT_SETTING_DEFAULT && |
| !RequiresResourceIdentifier(ContentSettingsType(j))) |
| SetContentSetting( |
| pattern, ContentSettingsType(j), "", settings.settings[j]); |
| } |
| } |
| prefs->ClearPref(prefs::kPerHostContentSettings); |
| } |
| } |
| |
| void HostContentSettingsMap::CanonicalizeContentSettingsExceptions( |
| DictionaryValue* all_settings_dictionary) { |
| DCHECK(all_settings_dictionary); |
| |
| std::vector<std::string> remove_items; |
| std::vector<std::pair<std::string, std::string> > move_items; |
| for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys()); |
| i != all_settings_dictionary->end_keys(); ++i) { |
| const std::string& pattern(*i); |
| const std::string canonicalized_pattern = |
| Pattern(pattern).CanonicalizePattern(); |
| |
| if (canonicalized_pattern.empty() || canonicalized_pattern == pattern) |
| continue; |
| |
| // Clear old pattern if prefs already have canonicalized pattern. |
| DictionaryValue* new_pattern_settings_dictionary = NULL; |
| if (all_settings_dictionary->GetDictionaryWithoutPathExpansion( |
| canonicalized_pattern, &new_pattern_settings_dictionary)) { |
| remove_items.push_back(pattern); |
| continue; |
| } |
| |
| // Move old pattern to canonicalized pattern. |
| DictionaryValue* old_pattern_settings_dictionary = NULL; |
| if (all_settings_dictionary->GetDictionaryWithoutPathExpansion( |
| pattern, &old_pattern_settings_dictionary)) { |
| move_items.push_back(std::make_pair(pattern, canonicalized_pattern)); |
| } |
| } |
| |
| for (size_t i = 0; i < remove_items.size(); ++i) { |
| all_settings_dictionary->RemoveWithoutPathExpansion(remove_items[i], NULL); |
| } |
| |
| for (size_t i = 0; i < move_items.size(); ++i) { |
| Value* pattern_settings_dictionary = NULL; |
| all_settings_dictionary->RemoveWithoutPathExpansion( |
| move_items[i].first, &pattern_settings_dictionary); |
| all_settings_dictionary->SetWithoutPathExpansion( |
| move_items[i].second, pattern_settings_dictionary); |
| } |
| } |