diff options
-rw-r--r-- | chrome/browser/content_exceptions_table_model.cc | 10 | ||||
-rw-r--r-- | chrome/browser/host_content_settings_map.cc | 187 | ||||
-rw-r--r-- | chrome/browser/host_content_settings_map.h | 15 | ||||
-rw-r--r-- | chrome/browser/host_content_settings_map_unittest.cc | 123 |
4 files changed, 281 insertions, 54 deletions
diff --git a/chrome/browser/content_exceptions_table_model.cc b/chrome/browser/content_exceptions_table_model.cc index 53801ef..84e8c2d 100644 --- a/chrome/browser/content_exceptions_table_model.cc +++ b/chrome/browser/content_exceptions_table_model.cc @@ -30,7 +30,7 @@ ContentExceptionsTableModel::ContentExceptionsTableModel( ContentExceptionsTableModel::~ContentExceptionsTableModel() {} void ContentExceptionsTableModel::AddException( - const HostContentSettingsMap::Pattern& pattern, + const HostContentSettingsMap::Pattern& original_pattern, ContentSetting setting, bool is_off_the_record) { DCHECK(!is_off_the_record || off_the_record_map_); @@ -38,6 +38,9 @@ void ContentExceptionsTableModel::AddException( int insert_position = is_off_the_record ? RowCount() : static_cast<int>(entries_.size()); + const HostContentSettingsMap::Pattern pattern( + original_pattern.CanonicalizePattern()); + entries(is_off_the_record).push_back( HostContentSettingsMap::PatternSettingPair(pattern, setting)); map(is_off_the_record)->SetContentSetting(pattern, @@ -74,13 +77,16 @@ void ContentExceptionsTableModel::RemoveAll() { } int ContentExceptionsTableModel::IndexOfExceptionByPattern( - const HostContentSettingsMap::Pattern& pattern, + const HostContentSettingsMap::Pattern& original_pattern, bool is_off_the_record) { DCHECK(!is_off_the_record || off_the_record_map_); int offset = is_off_the_record ? static_cast<int>(entries_.size()) : 0; + const HostContentSettingsMap::Pattern pattern( + original_pattern.CanonicalizePattern()); + // This is called on every key type in the editor. Move to a map if we end up // with lots of exceptions. for (size_t i = 0; i < entries(is_off_the_record).size(); ++i) { diff --git a/chrome/browser/host_content_settings_map.cc b/chrome/browser/host_content_settings_map.cc index e20f725..5e2a78c 100644 --- a/chrome/browser/host_content_settings_map.cc +++ b/chrome/browser/host_content_settings_map.cc @@ -145,6 +145,26 @@ bool HostContentSettingsMap::Pattern::Matches(const GURL& url) const { (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), @@ -152,58 +172,11 @@ HostContentSettingsMap::HostContentSettingsMap(Profile* profile) updating_preferences_(false) { PrefService* prefs = profile_->GetPrefs(); - // Migrate obsolete cookie pref. - 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); - } - } + MigrateObsoleteCookiePref(prefs); - // Migrate obsolete popups pref. - 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); - } + MigrateObsoletePopupsPref(prefs); - // Migrate obsolete per-host pref. - 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); - } + MigrateObsoletePerhostPref(prefs); // Read global defaults. DCHECK_EQ(arraysize(kTypeNames), @@ -484,7 +457,7 @@ void HostContentSettingsMap::SetDefaultContentSetting( } void HostContentSettingsMap::SetContentSetting( - const Pattern& pattern, + const Pattern& original_pattern, ContentSettingsType content_type, const std::string& resource_identifier, ContentSetting setting) { @@ -493,6 +466,8 @@ void HostContentSettingsMap::SetContentSetting( DCHECK_NE(RequiresResourceIdentifier(content_type), resource_identifier.empty()); + const Pattern pattern(original_pattern.CanonicalizePattern()); + bool early_exit = false; std::string pattern_str(pattern.AsString()); PrefService* prefs = NULL; @@ -861,8 +836,10 @@ 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, @@ -873,12 +850,17 @@ void HostContentSettingsMap::ReadDefaultSettings(bool overwrite) { void HostContentSettingsMap::ReadExceptions(bool overwrite) { PrefService* prefs = profile_->GetPrefs(); - const DictionaryValue* all_settings_dictionary = + 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); @@ -915,3 +897,104 @@ void HostContentSettingsMap::UnregisterObservers() { 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); + } +} + diff --git a/chrome/browser/host_content_settings_map.h b/chrome/browser/host_content_settings_map.h index f6021a9..24518bf 100644 --- a/chrome/browser/host_content_settings_map.h +++ b/chrome/browser/host_content_settings_map.h @@ -63,6 +63,10 @@ class HostContentSettingsMap return pattern_ == other.pattern_; } + // Canonicalizes the pattern so that it's ASCII only, either + // in original or punycode form. + std::string CanonicalizePattern() const; + private: std::string pattern_; }; @@ -281,6 +285,17 @@ class HostContentSettingsMap void UnregisterObservers(); + // Various migration methods (old cookie, popup and per-host data gets + // migrated to the new format). + void MigrateObsoleteCookiePref(PrefService* prefs); + void MigrateObsoletePopupsPref(PrefService* prefs); + void MigrateObsoletePerhostPref(PrefService* prefs); + + // Converts all exceptions that have non-canonicalized pattern into + // canonicalized pattern. If such pattern already exists, we just remove the + // old exception. + void CanonicalizeContentSettingsExceptions(DictionaryValue* settings); + // The profile we're associated with. Profile* profile_; diff --git a/chrome/browser/host_content_settings_map_unittest.cc b/chrome/browser/host_content_settings_map_unittest.cc index 5bf5894..ea829d4 100644 --- a/chrome/browser/host_content_settings_map_unittest.cc +++ b/chrome/browser/host_content_settings_map_unittest.cc @@ -15,6 +15,7 @@ #include "chrome/common/url_constants.h" #include "chrome/test/testing_profile.h" #include "googleurl/src/gurl.h" +#include "net/base/static_cookie_policy.h" #include "testing/gtest/include/gtest/gtest.h" @@ -248,6 +249,40 @@ TEST_F(HostContentSettingsMapTest, PatternSupport) { GURL("http://example.org/"))); } +TEST_F(HostContentSettingsMapTest, CanonicalizePattern) { + // Basic patterns. + EXPECT_STREQ("[*.]ikea.com", HostContentSettingsMap::Pattern("[*.]ikea.com") + .CanonicalizePattern().c_str()); + EXPECT_STREQ("example.com", HostContentSettingsMap::Pattern("example.com") + .CanonicalizePattern().c_str()); + EXPECT_STREQ("192.168.1.1", HostContentSettingsMap::Pattern("192.168.1.1") + .CanonicalizePattern().c_str()); + EXPECT_STREQ("[::1]", HostContentSettingsMap::Pattern("[::1]") + .CanonicalizePattern().c_str()); + // IsValid returns false for file:/// patterns. + EXPECT_STREQ("", HostContentSettingsMap::Pattern( + "file:///temp/file.html").CanonicalizePattern().c_str()); + + // UTF-8 patterns. + EXPECT_STREQ("[*.]xn--ira-ppa.com", HostContentSettingsMap::Pattern( + "[*.]\xC4\x87ira.com").CanonicalizePattern().c_str()); + EXPECT_STREQ("xn--ira-ppa.com", HostContentSettingsMap::Pattern( + "\xC4\x87ira.com").CanonicalizePattern().c_str()); + // IsValid returns false for file:/// patterns. + EXPECT_STREQ("", HostContentSettingsMap::Pattern( + "file:///\xC4\x87ira.html").CanonicalizePattern().c_str()); + + // Invalid patterns. + EXPECT_STREQ("", HostContentSettingsMap::Pattern( + "*example.com").CanonicalizePattern().c_str()); + EXPECT_STREQ("", HostContentSettingsMap::Pattern( + "example.*").CanonicalizePattern().c_str()); + EXPECT_STREQ("", HostContentSettingsMap::Pattern( + "*\xC4\x87ira.com").CanonicalizePattern().c_str()); + EXPECT_STREQ("", HostContentSettingsMap::Pattern( + "\xC4\x87ira.*").CanonicalizePattern().c_str()); +} + TEST_F(HostContentSettingsMapTest, Observer) { TestingProfile profile; HostContentSettingsMap* host_content_settings_map = @@ -529,6 +564,94 @@ TEST_F(HostContentSettingsMapTest, OffTheRecord) { host, CONTENT_SETTINGS_TYPE_IMAGES, "")); } +TEST_F(HostContentSettingsMapTest, MigrateObsoletePrefs) { + // This feature is currently behind a flag. + CommandLine cl(*CommandLine::ForCurrentProcess()); + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableResourceContentSettings); + + TestingProfile profile; + PrefService* prefs = profile.GetPrefs(); + + // Set obsolete data. + prefs->SetInteger(prefs::kCookieBehavior, + net::StaticCookiePolicy::BLOCK_ALL_COOKIES); + + ListValue popup_hosts; + popup_hosts.Append(new StringValue("[*.]example.com")); + prefs->Set(prefs::kPopupWhitelistedHosts, popup_hosts); + + HostContentSettingsMap* host_content_settings_map = + profile.GetHostContentSettingsMap(); + + EXPECT_EQ(CONTENT_SETTING_BLOCK, + host_content_settings_map->GetDefaultContentSetting( + CONTENT_SETTINGS_TYPE_COOKIES)); + + GURL host("http://example.com"); + EXPECT_EQ(CONTENT_SETTING_ALLOW, + host_content_settings_map->GetContentSetting( + host, CONTENT_SETTINGS_TYPE_POPUPS, "")); + *CommandLine::ForCurrentProcess() = cl; +} + +// For a single Unicode encoded pattern, check if it gets converted to punycode +// and old pattern gets deleted. +TEST_F(HostContentSettingsMapTest, CanonicalizeExceptionsUnicodeOnly) { + TestingProfile profile; + PrefService* prefs = profile.GetPrefs(); + + // Set utf-8 data. + DictionaryValue* all_settings_dictionary = + prefs->GetMutableDictionary(prefs::kContentSettingsPatterns); + ASSERT_TRUE(NULL != all_settings_dictionary); + + DictionaryValue* dummy_payload = new DictionaryValue; + dummy_payload->SetInteger("images", CONTENT_SETTING_ALLOW); + all_settings_dictionary->SetWithoutPathExpansion("[*.]\xC4\x87ira.com", + dummy_payload); + + profile.GetHostContentSettingsMap(); + + DictionaryValue* result = NULL; + EXPECT_FALSE(all_settings_dictionary->GetDictionaryWithoutPathExpansion( + "[*.]\xC4\x87ira.com", &result)); + EXPECT_TRUE(all_settings_dictionary->GetDictionaryWithoutPathExpansion( + "[*.]xn--ira-ppa.com", &result)); +} + +// If both Unicode and its punycode pattern exist, make sure we don't touch the +// settings for the punycode, and that Unicode pattern gets deleted. +TEST_F(HostContentSettingsMapTest, CanonicalizeExceptionsUnicodeAndPunycode) { + // This feature is currently behind a flag. + CommandLine cl(*CommandLine::ForCurrentProcess()); + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableResourceContentSettings); + + TestingProfile profile; + + scoped_ptr<Value> value(base::JSONReader::Read( + "{\"[*.]\\xC4\\x87ira.com\":{\"per_plugin\":{\"pluginx\":2}}}", false)); + profile.GetPrefs()->Set(prefs::kContentSettingsPatterns, *value); + + // Set punycode equivalent, with different setting. + scoped_ptr<Value> puny_value(base::JSONReader::Read( + "{\"[*.]xn--ira-ppa.com\":{\"per_plugin\":{\"pluginy\":2}}}", false)); + profile.GetPrefs()->Set(prefs::kContentSettingsPatterns, *puny_value); + + // Initialize the content map. + profile.GetHostContentSettingsMap(); + + const DictionaryValue* content_setting_prefs = + profile.GetPrefs()->GetDictionary(prefs::kContentSettingsPatterns); + std::string prefs_as_json; + base::JSONWriter::Write(content_setting_prefs, false, &prefs_as_json); + EXPECT_STREQ("{\"[*.]xn--ira-ppa.com\":{\"per_plugin\":{\"pluginy\":2}}}", + prefs_as_json.c_str()); + + *CommandLine::ForCurrentProcess() = cl; +} + TEST_F(HostContentSettingsMapTest, NonDefaultSettings) { TestingProfile profile; HostContentSettingsMap* host_content_settings_map = |