1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 6 #include "chrome/browser/content_settings/content_settings_base_provider.h" 7 8 #include "base/command_line.h" 9 #include "base/logging.h" 10 #include "chrome/common/chrome_switches.h" 11 #include "googleurl/src/gurl.h" 12 #include "net/base/net_util.h" 13 14 namespace { 15 16 // True if a given content settings type requires additional resource 17 // identifiers. 18 const bool kRequiresResourceIdentifier[CONTENT_SETTINGS_NUM_TYPES] = { 19 false, // CONTENT_SETTINGS_TYPE_COOKIES 20 false, // CONTENT_SETTINGS_TYPE_IMAGES 21 false, // CONTENT_SETTINGS_TYPE_JAVASCRIPT 22 true, // CONTENT_SETTINGS_TYPE_PLUGINS 23 false, // CONTENT_SETTINGS_TYPE_POPUPS 24 false, // Not used for Geolocation 25 false, // Not used for Notifications 26 }; 27 28 } // namespace 29 30 namespace content_settings { 31 32 ExtendedContentSettings::ExtendedContentSettings() {} 33 34 ExtendedContentSettings::ExtendedContentSettings( 35 const ExtendedContentSettings& rhs) 36 : content_settings(rhs.content_settings), 37 content_settings_for_resources(rhs.content_settings_for_resources) { 38 } 39 40 ExtendedContentSettings::~ExtendedContentSettings() {} 41 42 BaseProvider::BaseProvider(bool is_incognito) 43 : is_incognito_(is_incognito) { 44 } 45 46 BaseProvider::~BaseProvider() {} 47 48 bool BaseProvider::RequiresResourceIdentifier( 49 ContentSettingsType content_type) const { 50 if (CommandLine::ForCurrentProcess()->HasSwitch( 51 switches::kEnableResourceContentSettings)) { 52 return kRequiresResourceIdentifier[content_type]; 53 } else { 54 return false; 55 } 56 } 57 58 bool BaseProvider::AllDefault( 59 const ExtendedContentSettings& settings) const { 60 for (size_t i = 0; i < arraysize(settings.content_settings.settings); ++i) { 61 if (settings.content_settings.settings[i] != CONTENT_SETTING_DEFAULT) 62 return false; 63 } 64 return settings.content_settings_for_resources.empty(); 65 } 66 67 ContentSetting BaseProvider::GetContentSetting( 68 const GURL& requesting_url, 69 const GURL& embedding_url, 70 ContentSettingsType content_type, 71 const ResourceIdentifier& resource_identifier) const { 72 // Support for embedding_patterns is not implemented yet. 73 DCHECK(requesting_url == embedding_url); 74 75 if (!RequiresResourceIdentifier(content_type) || 76 (RequiresResourceIdentifier(content_type) && resource_identifier.empty())) 77 return GetNonDefaultContentSettings(requesting_url).settings[content_type]; 78 79 // Resolve content settings with resource identifier. 80 // 1. Check for pattern that exactly match the url/host 81 // 1.1 In the content-settings-map 82 // 1.2 In the incognito content-settings-map 83 // 3. Shorten the url subdomain by subdomain and try to find a pattern in 84 // 3.1 OTR content-settings-map 85 // 3.2 content-settings-map 86 base::AutoLock auto_lock(lock_); 87 const std::string host(net::GetHostOrSpecFromURL(requesting_url)); 88 ContentSettingsTypeResourceIdentifierPair 89 requested_setting(content_type, resource_identifier); 90 91 // Check for exact matches first. 92 HostContentSettings::const_iterator i(host_content_settings_.find(host)); 93 if (i != host_content_settings_.end() && 94 i->second.content_settings_for_resources.find(requested_setting) != 95 i->second.content_settings_for_resources.end()) { 96 return i->second.content_settings_for_resources.find( 97 requested_setting)->second; 98 } 99 100 // If this map is not for an incognito profile, these searches will never 101 // match. The additional incognito exceptions always overwrite the 102 // regular ones. 103 i = incognito_settings_.find(host); 104 if (i != incognito_settings_.end() && 105 i->second.content_settings_for_resources.find(requested_setting) != 106 i->second.content_settings_for_resources.end()) { 107 return i->second.content_settings_for_resources.find( 108 requested_setting)->second; 109 } 110 111 // Match patterns starting with the most concrete pattern match. 112 for (std::string key = 113 std::string(ContentSettingsPattern::kDomainWildcard) + host; ; ) { 114 HostContentSettings::const_iterator i(incognito_settings_.find(key)); 115 if (i != incognito_settings_.end() && 116 i->second.content_settings_for_resources.find(requested_setting) != 117 i->second.content_settings_for_resources.end()) { 118 return i->second.content_settings_for_resources.find( 119 requested_setting)->second; 120 } 121 122 i = host_content_settings_.find(key); 123 if (i != host_content_settings_.end() && 124 i->second.content_settings_for_resources.find(requested_setting) != 125 i->second.content_settings_for_resources.end()) { 126 return i->second.content_settings_for_resources.find( 127 requested_setting)->second; 128 } 129 130 const size_t next_dot = 131 key.find('.', ContentSettingsPattern::kDomainWildcardLength); 132 if (next_dot == std::string::npos) 133 break; 134 key.erase(ContentSettingsPattern::kDomainWildcardLength, 135 next_dot - ContentSettingsPattern::kDomainWildcardLength + 1); 136 } 137 138 return CONTENT_SETTING_DEFAULT; 139 } 140 141 void BaseProvider::GetAllContentSettingsRules( 142 ContentSettingsType content_type, 143 const ResourceIdentifier& resource_identifier, 144 Rules* content_setting_rules) const { 145 DCHECK(content_setting_rules); 146 content_setting_rules->clear(); 147 148 const HostContentSettings* map_to_return = 149 is_incognito_ ? &incognito_settings_ : &host_content_settings_; 150 ContentSettingsTypeResourceIdentifierPair requested_setting( 151 content_type, resource_identifier); 152 153 base::AutoLock auto_lock(lock_); 154 for (HostContentSettings::const_iterator i(map_to_return->begin()); 155 i != map_to_return->end(); ++i) { 156 ContentSetting setting; 157 if (RequiresResourceIdentifier(content_type)) { 158 if (i->second.content_settings_for_resources.find(requested_setting) != 159 i->second.content_settings_for_resources.end()) { 160 setting = i->second.content_settings_for_resources.find( 161 requested_setting)->second; 162 } else { 163 setting = CONTENT_SETTING_DEFAULT; 164 } 165 } else { 166 setting = i->second.content_settings.settings[content_type]; 167 } 168 if (setting != CONTENT_SETTING_DEFAULT) { 169 // Use of push_back() relies on the map iterator traversing in order of 170 // ascending keys. 171 content_setting_rules->push_back(Rule(ContentSettingsPattern(i->first), 172 ContentSettingsPattern(i->first), 173 setting)); 174 } 175 } 176 } 177 178 ContentSettings BaseProvider::GetNonDefaultContentSettings( 179 const GURL& url) const { 180 base::AutoLock auto_lock(lock_); 181 182 const std::string host(net::GetHostOrSpecFromURL(url)); 183 ContentSettings output; 184 for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) 185 output.settings[j] = CONTENT_SETTING_DEFAULT; 186 187 // Check for exact matches first. 188 HostContentSettings::const_iterator i(host_content_settings_.find(host)); 189 if (i != host_content_settings_.end()) 190 output = i->second.content_settings; 191 192 // If this map is not for an incognito profile, these searches will never 193 // match. The additional incognito exceptions always overwrite the 194 // regular ones. 195 i = incognito_settings_.find(host); 196 if (i != incognito_settings_.end()) { 197 for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) 198 if (i->second.content_settings.settings[j] != CONTENT_SETTING_DEFAULT) 199 output.settings[j] = i->second.content_settings.settings[j]; 200 } 201 202 // Match patterns starting with the most concrete pattern match. 203 for (std::string key = 204 std::string(ContentSettingsPattern::kDomainWildcard) + host; ; ) { 205 HostContentSettings::const_iterator i(incognito_settings_.find(key)); 206 if (i != incognito_settings_.end()) { 207 for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) { 208 if (output.settings[j] == CONTENT_SETTING_DEFAULT) 209 output.settings[j] = i->second.content_settings.settings[j]; 210 } 211 } 212 i = host_content_settings_.find(key); 213 if (i != host_content_settings_.end()) { 214 for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) { 215 if (output.settings[j] == CONTENT_SETTING_DEFAULT) 216 output.settings[j] = i->second.content_settings.settings[j]; 217 } 218 } 219 const size_t next_dot = 220 key.find('.', ContentSettingsPattern::kDomainWildcardLength); 221 if (next_dot == std::string::npos) 222 break; 223 key.erase(ContentSettingsPattern::kDomainWildcardLength, 224 next_dot - ContentSettingsPattern::kDomainWildcardLength + 1); 225 } 226 227 return output; 228 } 229 230 void BaseProvider::UpdateContentSettingsMap( 231 const ContentSettingsPattern& requesting_pattern, 232 const ContentSettingsPattern& embedding_pattern, 233 ContentSettingsType content_type, 234 const ResourceIdentifier& resource_identifier, 235 ContentSetting content_setting) { 236 std::string pattern_str(requesting_pattern.CanonicalizePattern()); 237 HostContentSettings* content_settings_map = host_content_settings(); 238 ExtendedContentSettings& extended_settings = 239 (*content_settings_map)[pattern_str]; 240 extended_settings.content_settings.settings[content_type] = content_setting; 241 } 242 243 // static 244 ContentSetting BaseProvider::ClickToPlayFixup(ContentSettingsType content_type, 245 ContentSetting setting) { 246 if (setting == CONTENT_SETTING_ASK && 247 content_type == CONTENT_SETTINGS_TYPE_PLUGINS && 248 !CommandLine::ForCurrentProcess()->HasSwitch( 249 switches::kEnableClickToPlay)) { 250 return CONTENT_SETTING_BLOCK; 251 } 252 return setting; 253 } 254 255 } // namespace content_settings 256