// 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/content_settings_base_provider.h" #include "base/command_line.h" #include "base/logging.h" #include "chrome/common/chrome_switches.h" #include "googleurl/src/gurl.h" #include "net/base/net_util.h" namespace { // 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 }; } // namespace namespace content_settings { ExtendedContentSettings::ExtendedContentSettings() {} ExtendedContentSettings::ExtendedContentSettings( const ExtendedContentSettings& rhs) : content_settings(rhs.content_settings), content_settings_for_resources(rhs.content_settings_for_resources) { } ExtendedContentSettings::~ExtendedContentSettings() {} BaseProvider::BaseProvider(bool is_incognito) : is_incognito_(is_incognito) { } BaseProvider::~BaseProvider() {} bool BaseProvider::RequiresResourceIdentifier( ContentSettingsType content_type) const { if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableResourceContentSettings)) { return kRequiresResourceIdentifier[content_type]; } else { return false; } } bool BaseProvider::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(); } ContentSetting BaseProvider::GetContentSetting( const GURL& requesting_url, const GURL& embedding_url, ContentSettingsType content_type, const ResourceIdentifier& resource_identifier) const { // Support for embedding_patterns is not implemented yet. DCHECK(requesting_url == embedding_url); if (!RequiresResourceIdentifier(content_type) || (RequiresResourceIdentifier(content_type) && resource_identifier.empty())) return GetNonDefaultContentSettings(requesting_url).settings[content_type]; // Resolve content settings with resource identifier. // 1. Check for pattern that exactly match the url/host // 1.1 In the content-settings-map // 1.2 In the incognito content-settings-map // 3. Shorten the url subdomain by subdomain and try to find a pattern in // 3.1 OTR content-settings-map // 3.2 content-settings-map base::AutoLock auto_lock(lock_); const std::string host(net::GetHostOrSpecFromURL(requesting_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 incognito profile, these searches will never // match. The additional incognito exceptions always overwrite the // regular ones. i = incognito_settings_.find(host); if (i != incognito_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(ContentSettingsPattern::kDomainWildcard) + host; ; ) { HostContentSettings::const_iterator i(incognito_settings_.find(key)); if (i != incognito_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('.', ContentSettingsPattern::kDomainWildcardLength); if (next_dot == std::string::npos) break; key.erase(ContentSettingsPattern::kDomainWildcardLength, next_dot - ContentSettingsPattern::kDomainWildcardLength + 1); } return CONTENT_SETTING_DEFAULT; } void BaseProvider::GetAllContentSettingsRules( ContentSettingsType content_type, const ResourceIdentifier& resource_identifier, Rules* content_setting_rules) const { DCHECK(content_setting_rules); content_setting_rules->clear(); const HostContentSettings* map_to_return = is_incognito_ ? &incognito_settings_ : &host_content_settings_; ContentSettingsTypeResourceIdentifierPair requested_setting( content_type, resource_identifier); base::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. content_setting_rules->push_back(Rule(ContentSettingsPattern(i->first), ContentSettingsPattern(i->first), setting)); } } } ContentSettings BaseProvider::GetNonDefaultContentSettings( const GURL& url) const { base::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 incognito profile, these searches will never // match. The additional incognito exceptions always overwrite the // regular ones. i = incognito_settings_.find(host); if (i != incognito_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(ContentSettingsPattern::kDomainWildcard) + host; ; ) { HostContentSettings::const_iterator i(incognito_settings_.find(key)); if (i != incognito_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('.', ContentSettingsPattern::kDomainWildcardLength); if (next_dot == std::string::npos) break; key.erase(ContentSettingsPattern::kDomainWildcardLength, next_dot - ContentSettingsPattern::kDomainWildcardLength + 1); } return output; } void BaseProvider::UpdateContentSettingsMap( const ContentSettingsPattern& requesting_pattern, const ContentSettingsPattern& embedding_pattern, ContentSettingsType content_type, const ResourceIdentifier& resource_identifier, ContentSetting content_setting) { std::string pattern_str(requesting_pattern.CanonicalizePattern()); HostContentSettings* content_settings_map = host_content_settings(); ExtendedContentSettings& extended_settings = (*content_settings_map)[pattern_str]; extended_settings.content_settings.settings[content_type] = content_setting; } // static ContentSetting BaseProvider::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 content_settings