1 // Copyright (c) 2012 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 #include "chrome/browser/content_settings/host_content_settings_map.h" 6 7 #include <utility> 8 9 #include "base/basictypes.h" 10 #include "base/command_line.h" 11 #include "base/prefs/pref_service.h" 12 #include "base/stl_util.h" 13 #include "base/strings/string_util.h" 14 #include "base/strings/utf_string_conversions.h" 15 #include "chrome/browser/chrome_notification_types.h" 16 #include "chrome/browser/content_settings/content_settings_custom_extension_provider.h" 17 #include "chrome/browser/content_settings/content_settings_default_provider.h" 18 #include "chrome/browser/content_settings/content_settings_details.h" 19 #include "chrome/browser/content_settings/content_settings_internal_extension_provider.h" 20 #include "chrome/browser/content_settings/content_settings_observable_provider.h" 21 #include "chrome/browser/content_settings/content_settings_policy_provider.h" 22 #include "chrome/browser/content_settings/content_settings_pref_provider.h" 23 #include "chrome/browser/content_settings/content_settings_provider.h" 24 #include "chrome/browser/content_settings/content_settings_rule.h" 25 #include "chrome/browser/content_settings/content_settings_utils.h" 26 #include "chrome/browser/extensions/extension_service.h" 27 #include "chrome/common/chrome_switches.h" 28 #include "chrome/common/content_settings_pattern.h" 29 #include "chrome/common/pref_names.h" 30 #include "chrome/common/url_constants.h" 31 #include "components/user_prefs/pref_registry_syncable.h" 32 #include "content/public/browser/browser_thread.h" 33 #include "content/public/browser/notification_service.h" 34 #include "content/public/browser/notification_source.h" 35 #include "content/public/browser/user_metrics.h" 36 #include "content/public/common/content_switches.h" 37 #include "extensions/common/constants.h" 38 #include "net/base/net_errors.h" 39 #include "net/base/static_cookie_policy.h" 40 #include "url/gurl.h" 41 42 using content::BrowserThread; 43 using content::UserMetricsAction; 44 45 namespace { 46 47 typedef std::vector<content_settings::Rule> Rules; 48 49 typedef std::pair<std::string, std::string> StringPair; 50 51 const char* kProviderNames[] = { 52 "platform_app", 53 "policy", 54 "extension", 55 "preference", 56 "default" 57 }; 58 59 content_settings::SettingSource kProviderSourceMap[] = { 60 content_settings::SETTING_SOURCE_EXTENSION, 61 content_settings::SETTING_SOURCE_POLICY, 62 content_settings::SETTING_SOURCE_EXTENSION, 63 content_settings::SETTING_SOURCE_USER, 64 content_settings::SETTING_SOURCE_USER, 65 }; 66 COMPILE_ASSERT(arraysize(kProviderSourceMap) == 67 HostContentSettingsMap::NUM_PROVIDER_TYPES, 68 kProviderSourceMap_has_incorrect_size); 69 70 // Returns true if the |content_type| supports a resource identifier. 71 // Resource identifiers are supported (but not required) for plug-ins. 72 bool SupportsResourceIdentifier(ContentSettingsType content_type) { 73 return content_type == CONTENT_SETTINGS_TYPE_PLUGINS; 74 } 75 76 } // namespace 77 78 HostContentSettingsMap::HostContentSettingsMap( 79 PrefService* prefs, 80 bool incognito) : 81 #ifndef NDEBUG 82 used_from_thread_id_(base::PlatformThread::CurrentId()), 83 #endif 84 prefs_(prefs), 85 is_off_the_record_(incognito) { 86 content_settings::ObservableProvider* policy_provider = 87 new content_settings::PolicyProvider(prefs_); 88 policy_provider->AddObserver(this); 89 content_settings_providers_[POLICY_PROVIDER] = policy_provider; 90 91 content_settings::ObservableProvider* pref_provider = 92 new content_settings::PrefProvider(prefs_, is_off_the_record_); 93 pref_provider->AddObserver(this); 94 content_settings_providers_[PREF_PROVIDER] = pref_provider; 95 96 content_settings::ObservableProvider* default_provider = 97 new content_settings::DefaultProvider(prefs_, is_off_the_record_); 98 default_provider->AddObserver(this); 99 content_settings_providers_[DEFAULT_PROVIDER] = default_provider; 100 101 if (!is_off_the_record_) { 102 // Migrate obsolete preferences. 103 MigrateObsoleteClearOnExitPref(); 104 } 105 } 106 107 #if defined(ENABLE_EXTENSIONS) 108 void HostContentSettingsMap::RegisterExtensionService( 109 ExtensionService* extension_service) { 110 DCHECK(extension_service); 111 DCHECK(!content_settings_providers_[INTERNAL_EXTENSION_PROVIDER]); 112 DCHECK(!content_settings_providers_[CUSTOM_EXTENSION_PROVIDER]); 113 114 content_settings::InternalExtensionProvider* internal_extension_provider = 115 new content_settings::InternalExtensionProvider(extension_service); 116 internal_extension_provider->AddObserver(this); 117 content_settings_providers_[INTERNAL_EXTENSION_PROVIDER] = 118 internal_extension_provider; 119 120 content_settings::ObservableProvider* custom_extension_provider = 121 new content_settings::CustomExtensionProvider( 122 extension_service->GetContentSettingsStore(), 123 is_off_the_record_); 124 custom_extension_provider->AddObserver(this); 125 content_settings_providers_[CUSTOM_EXTENSION_PROVIDER] = 126 custom_extension_provider; 127 128 #ifndef NDEBUG 129 DCHECK(used_from_thread_id_ != base::kInvalidThreadId) 130 << "Used from multiple threads before initialization complete."; 131 #endif 132 133 OnContentSettingChanged(ContentSettingsPattern(), 134 ContentSettingsPattern(), 135 CONTENT_SETTINGS_TYPE_DEFAULT, 136 std::string()); 137 } 138 #endif 139 140 // static 141 void HostContentSettingsMap::RegisterProfilePrefs( 142 user_prefs::PrefRegistrySyncable* registry) { 143 registry->RegisterIntegerPref( 144 prefs::kContentSettingsWindowLastTabIndex, 145 0, 146 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 147 registry->RegisterIntegerPref( 148 prefs::kContentSettingsDefaultWhitelistVersion, 149 0, 150 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); 151 registry->RegisterBooleanPref( 152 prefs::kContentSettingsClearOnExitMigrated, 153 false, 154 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); 155 156 // Register the prefs for the content settings providers. 157 content_settings::DefaultProvider::RegisterProfilePrefs(registry); 158 content_settings::PrefProvider::RegisterProfilePrefs(registry); 159 content_settings::PolicyProvider::RegisterProfilePrefs(registry); 160 } 161 162 ContentSetting HostContentSettingsMap::GetDefaultContentSettingFromProvider( 163 ContentSettingsType content_type, 164 content_settings::ProviderInterface* provider) const { 165 scoped_ptr<content_settings::RuleIterator> rule_iterator( 166 provider->GetRuleIterator(content_type, std::string(), false)); 167 168 ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard(); 169 while (rule_iterator->HasNext()) { 170 content_settings::Rule rule = rule_iterator->Next(); 171 if (rule.primary_pattern == wildcard && 172 rule.secondary_pattern == wildcard) { 173 return content_settings::ValueToContentSetting(rule.value.get()); 174 } 175 } 176 return CONTENT_SETTING_DEFAULT; 177 } 178 179 ContentSetting HostContentSettingsMap::GetDefaultContentSetting( 180 ContentSettingsType content_type, 181 std::string* provider_id) const { 182 UsedContentSettingsProviders(); 183 184 // Iterate through the list of providers and return the first non-NULL value 185 // that matches |primary_url| and |secondary_url|. 186 for (ConstProviderIterator provider = content_settings_providers_.begin(); 187 provider != content_settings_providers_.end(); 188 ++provider) { 189 if (provider->first == PREF_PROVIDER) 190 continue; 191 ContentSetting default_setting = 192 GetDefaultContentSettingFromProvider(content_type, provider->second); 193 if (default_setting != CONTENT_SETTING_DEFAULT) { 194 if (provider_id) 195 *provider_id = kProviderNames[provider->first]; 196 return default_setting; 197 } 198 } 199 200 // The method GetDefaultContentSetting always has to return an explicit 201 // value that is to be used as default. We here rely on the 202 // DefaultProvider to always provide a value. 203 NOTREACHED(); 204 return CONTENT_SETTING_DEFAULT; 205 } 206 207 ContentSetting HostContentSettingsMap::GetContentSetting( 208 const GURL& primary_url, 209 const GURL& secondary_url, 210 ContentSettingsType content_type, 211 const std::string& resource_identifier) const { 212 DCHECK(!ContentTypeHasCompoundValue(content_type)); 213 scoped_ptr<base::Value> value(GetWebsiteSetting( 214 primary_url, secondary_url, content_type, resource_identifier, NULL)); 215 return content_settings::ValueToContentSetting(value.get()); 216 } 217 218 void HostContentSettingsMap::GetSettingsForOneType( 219 ContentSettingsType content_type, 220 const std::string& resource_identifier, 221 ContentSettingsForOneType* settings) const { 222 DCHECK(SupportsResourceIdentifier(content_type) || 223 resource_identifier.empty()); 224 DCHECK(settings); 225 UsedContentSettingsProviders(); 226 227 settings->clear(); 228 for (ConstProviderIterator provider = content_settings_providers_.begin(); 229 provider != content_settings_providers_.end(); 230 ++provider) { 231 // For each provider, iterate first the incognito-specific rules, then the 232 // normal rules. 233 if (is_off_the_record_) { 234 AddSettingsForOneType(provider->second, 235 provider->first, 236 content_type, 237 resource_identifier, 238 settings, 239 true); 240 } 241 AddSettingsForOneType(provider->second, 242 provider->first, 243 content_type, 244 resource_identifier, 245 settings, 246 false); 247 } 248 } 249 250 void HostContentSettingsMap::SetDefaultContentSetting( 251 ContentSettingsType content_type, 252 ContentSetting setting) { 253 DCHECK(IsSettingAllowedForType(prefs_, setting, content_type)); 254 255 base::Value* value = NULL; 256 if (setting != CONTENT_SETTING_DEFAULT) 257 value = Value::CreateIntegerValue(setting); 258 SetWebsiteSetting( 259 ContentSettingsPattern::Wildcard(), 260 ContentSettingsPattern::Wildcard(), 261 content_type, 262 std::string(), 263 value); 264 } 265 266 void HostContentSettingsMap::SetWebsiteSetting( 267 const ContentSettingsPattern& primary_pattern, 268 const ContentSettingsPattern& secondary_pattern, 269 ContentSettingsType content_type, 270 const std::string& resource_identifier, 271 base::Value* value) { 272 DCHECK(IsValueAllowedForType(prefs_, value, content_type)); 273 DCHECK(SupportsResourceIdentifier(content_type) || 274 resource_identifier.empty()); 275 UsedContentSettingsProviders(); 276 277 for (ProviderIterator provider = content_settings_providers_.begin(); 278 provider != content_settings_providers_.end(); 279 ++provider) { 280 if (provider->second->SetWebsiteSetting(primary_pattern, 281 secondary_pattern, 282 content_type, 283 resource_identifier, 284 value)) { 285 return; 286 } 287 } 288 NOTREACHED(); 289 } 290 291 void HostContentSettingsMap::SetContentSetting( 292 const ContentSettingsPattern& primary_pattern, 293 const ContentSettingsPattern& secondary_pattern, 294 ContentSettingsType content_type, 295 const std::string& resource_identifier, 296 ContentSetting setting) { 297 DCHECK(!ContentTypeHasCompoundValue(content_type)); 298 base::Value* value = NULL; 299 if (setting != CONTENT_SETTING_DEFAULT) 300 value = Value::CreateIntegerValue(setting); 301 SetWebsiteSetting(primary_pattern, 302 secondary_pattern, 303 content_type, 304 resource_identifier, 305 value); 306 } 307 308 void HostContentSettingsMap::AddExceptionForURL( 309 const GURL& primary_url, 310 const GURL& secondary_url, 311 ContentSettingsType content_type, 312 const std::string& resource_identifier, 313 ContentSetting setting) { 314 // TODO(markusheintz): Until the UI supports pattern pairs, both urls must 315 // match. 316 DCHECK(primary_url == secondary_url); 317 DCHECK(!ContentTypeHasCompoundValue(content_type)); 318 319 // Make sure there is no entry that would override the pattern we are about 320 // to insert for exactly this URL. 321 SetContentSetting(ContentSettingsPattern::FromURLNoWildcard(primary_url), 322 ContentSettingsPattern::Wildcard(), 323 content_type, 324 resource_identifier, 325 CONTENT_SETTING_DEFAULT); 326 327 SetContentSetting(ContentSettingsPattern::FromURL(primary_url), 328 ContentSettingsPattern::Wildcard(), 329 content_type, 330 resource_identifier, 331 setting); 332 } 333 334 void HostContentSettingsMap::ClearSettingsForOneType( 335 ContentSettingsType content_type) { 336 UsedContentSettingsProviders(); 337 for (ProviderIterator provider = content_settings_providers_.begin(); 338 provider != content_settings_providers_.end(); 339 ++provider) { 340 provider->second->ClearAllContentSettingsRules(content_type); 341 } 342 } 343 344 bool HostContentSettingsMap::IsValueAllowedForType( 345 PrefService* prefs, const base::Value* value, ContentSettingsType type) { 346 return ContentTypeHasCompoundValue(type) || IsSettingAllowedForType( 347 prefs, content_settings::ValueToContentSetting(value), type); 348 } 349 350 // static 351 bool HostContentSettingsMap::IsSettingAllowedForType( 352 PrefService* prefs, 353 ContentSetting setting, 354 ContentSettingsType content_type) { 355 // We don't yet support stored content settings for mixed scripting. 356 if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) 357 return false; 358 359 // BLOCK semantics are not implemented for fullscreen. 360 if (content_type == CONTENT_SETTINGS_TYPE_FULLSCREEN && 361 setting == CONTENT_SETTING_BLOCK) { 362 return false; 363 } 364 365 // We don't support ALLOW for media default setting. 366 if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM && 367 setting == CONTENT_SETTING_ALLOW) { 368 return false; 369 } 370 371 // DEFAULT, ALLOW and BLOCK are always allowed. 372 if (setting == CONTENT_SETTING_DEFAULT || 373 setting == CONTENT_SETTING_ALLOW || 374 setting == CONTENT_SETTING_BLOCK) { 375 return true; 376 } 377 switch (content_type) { 378 case CONTENT_SETTINGS_TYPE_COOKIES: 379 return setting == CONTENT_SETTING_SESSION_ONLY; 380 case CONTENT_SETTINGS_TYPE_PLUGINS: 381 case CONTENT_SETTINGS_TYPE_GEOLOCATION: 382 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: 383 case CONTENT_SETTINGS_TYPE_MOUSELOCK: 384 case CONTENT_SETTINGS_TYPE_MEDIASTREAM: 385 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC: 386 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA: 387 case CONTENT_SETTINGS_TYPE_PPAPI_BROKER: 388 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS: 389 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX: 390 return setting == CONTENT_SETTING_ASK; 391 default: 392 return false; 393 } 394 } 395 396 // static 397 bool HostContentSettingsMap::ContentTypeHasCompoundValue( 398 ContentSettingsType type) { 399 // Values for content type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE and 400 // CONTENT_SETTINGS_TYPE_MEDIASTREAM are of type dictionary/map. Compound 401 // types like dictionaries can't be mapped to the type |ContentSetting|. 402 return (type == CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE || 403 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM); 404 } 405 406 void HostContentSettingsMap::OnContentSettingChanged( 407 const ContentSettingsPattern& primary_pattern, 408 const ContentSettingsPattern& secondary_pattern, 409 ContentSettingsType content_type, 410 std::string resource_identifier) { 411 const ContentSettingsDetails details(primary_pattern, 412 secondary_pattern, 413 content_type, 414 resource_identifier); 415 content::NotificationService::current()->Notify( 416 chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED, 417 content::Source<HostContentSettingsMap>(this), 418 content::Details<const ContentSettingsDetails>(&details)); 419 } 420 421 HostContentSettingsMap::~HostContentSettingsMap() { 422 DCHECK(!prefs_); 423 STLDeleteValues(&content_settings_providers_); 424 } 425 426 void HostContentSettingsMap::ShutdownOnUIThread() { 427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 428 DCHECK(prefs_); 429 prefs_ = NULL; 430 for (ProviderIterator it = content_settings_providers_.begin(); 431 it != content_settings_providers_.end(); 432 ++it) { 433 it->second->ShutdownOnUIThread(); 434 } 435 } 436 437 void HostContentSettingsMap::MigrateObsoleteClearOnExitPref() { 438 // Don't migrate more than once. 439 if (prefs_->HasPrefPath(prefs::kContentSettingsClearOnExitMigrated) && 440 prefs_->GetBoolean(prefs::kContentSettingsClearOnExitMigrated)) { 441 return; 442 } 443 444 if (!prefs_->GetBoolean(prefs::kClearSiteDataOnExit)) { 445 // Nothing to be done 446 prefs_->SetBoolean(prefs::kContentSettingsClearOnExitMigrated, true); 447 return; 448 } 449 450 // Change the default cookie settings: 451 // old new 452 // ---------------- ---------------- 453 // ALLOW SESSION_ONLY 454 // SESSION_ONLY SESSION_ONLY 455 // BLOCK BLOCK 456 ContentSetting default_setting = GetDefaultContentSettingFromProvider( 457 CONTENT_SETTINGS_TYPE_COOKIES, 458 content_settings_providers_[DEFAULT_PROVIDER]); 459 if (default_setting == CONTENT_SETTING_ALLOW) { 460 SetDefaultContentSetting( 461 CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_SESSION_ONLY); 462 } 463 464 // Change the exceptions using the same rules. 465 ContentSettingsForOneType exceptions; 466 AddSettingsForOneType(content_settings_providers_[PREF_PROVIDER], 467 PREF_PROVIDER, 468 CONTENT_SETTINGS_TYPE_COOKIES, 469 std::string(), 470 &exceptions, 471 false); 472 for (ContentSettingsForOneType::iterator it = exceptions.begin(); 473 it != exceptions.end(); ++it) { 474 if (it->setting != CONTENT_SETTING_ALLOW) 475 continue; 476 SetWebsiteSetting(it->primary_pattern, 477 it->secondary_pattern, 478 CONTENT_SETTINGS_TYPE_COOKIES, 479 std::string(), 480 Value::CreateIntegerValue(CONTENT_SETTING_SESSION_ONLY)); 481 } 482 483 prefs_->SetBoolean(prefs::kContentSettingsClearOnExitMigrated, true); 484 } 485 486 void HostContentSettingsMap::AddSettingsForOneType( 487 const content_settings::ProviderInterface* provider, 488 ProviderType provider_type, 489 ContentSettingsType content_type, 490 const std::string& resource_identifier, 491 ContentSettingsForOneType* settings, 492 bool incognito) const { 493 scoped_ptr<content_settings::RuleIterator> rule_iterator( 494 provider->GetRuleIterator(content_type, 495 resource_identifier, 496 incognito)); 497 while (rule_iterator->HasNext()) { 498 const content_settings::Rule& rule = rule_iterator->Next(); 499 ContentSetting setting_value = CONTENT_SETTING_DEFAULT; 500 // TODO(bauerb): Return rules as a list of values, not content settings. 501 // Handle the case using compound values for its exceptions and arbitrary 502 // values for its default setting. Here we assume all the exceptions 503 // are granted as |CONTENT_SETTING_ALLOW|. 504 if (ContentTypeHasCompoundValue(content_type) && 505 rule.value.get() && 506 rule.primary_pattern != ContentSettingsPattern::Wildcard()) { 507 setting_value = CONTENT_SETTING_ALLOW; 508 } else { 509 setting_value = content_settings::ValueToContentSetting(rule.value.get()); 510 } 511 settings->push_back(ContentSettingPatternSource( 512 rule.primary_pattern, rule.secondary_pattern, 513 setting_value, 514 kProviderNames[provider_type], 515 incognito)); 516 } 517 } 518 519 void HostContentSettingsMap::UsedContentSettingsProviders() const { 520 #ifndef NDEBUG 521 if (used_from_thread_id_ == base::kInvalidThreadId) 522 return; 523 524 if (base::PlatformThread::CurrentId() != used_from_thread_id_) 525 used_from_thread_id_ = base::kInvalidThreadId; 526 #endif 527 } 528 529 bool HostContentSettingsMap::ShouldAllowAllContent( 530 const GURL& primary_url, 531 const GURL& secondary_url, 532 ContentSettingsType content_type) { 533 if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS || 534 content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION || 535 content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) { 536 return false; 537 } 538 if (secondary_url.SchemeIs(chrome::kChromeUIScheme) && 539 content_type == CONTENT_SETTINGS_TYPE_COOKIES && 540 primary_url.SchemeIsSecure()) { 541 return true; 542 } 543 if (primary_url.SchemeIs(extensions::kExtensionScheme)) { 544 return content_type != CONTENT_SETTINGS_TYPE_PLUGINS && 545 (content_type != CONTENT_SETTINGS_TYPE_COOKIES || 546 secondary_url.SchemeIs(extensions::kExtensionScheme)); 547 } 548 return primary_url.SchemeIs(chrome::kChromeDevToolsScheme) || 549 primary_url.SchemeIs(chrome::kChromeInternalScheme) || 550 primary_url.SchemeIs(chrome::kChromeUIScheme); 551 } 552 553 base::Value* HostContentSettingsMap::GetWebsiteSetting( 554 const GURL& primary_url, 555 const GURL& secondary_url, 556 ContentSettingsType content_type, 557 const std::string& resource_identifier, 558 content_settings::SettingInfo* info) const { 559 DCHECK(SupportsResourceIdentifier(content_type) || 560 resource_identifier.empty()); 561 562 // Check if the scheme of the requesting url is whitelisted. 563 if (ShouldAllowAllContent(primary_url, secondary_url, content_type)) { 564 if (info) { 565 info->source = content_settings::SETTING_SOURCE_WHITELIST; 566 info->primary_pattern = ContentSettingsPattern::Wildcard(); 567 info->secondary_pattern = ContentSettingsPattern::Wildcard(); 568 } 569 return Value::CreateIntegerValue(CONTENT_SETTING_ALLOW); 570 } 571 572 ContentSettingsPattern* primary_pattern = NULL; 573 ContentSettingsPattern* secondary_pattern = NULL; 574 if (info) { 575 primary_pattern = &info->primary_pattern; 576 secondary_pattern = &info->secondary_pattern; 577 } 578 579 // The list of |content_settings_providers_| is ordered according to their 580 // precedence. 581 for (ConstProviderIterator provider = content_settings_providers_.begin(); 582 provider != content_settings_providers_.end(); 583 ++provider) { 584 base::Value* value = content_settings::GetContentSettingValueAndPatterns( 585 provider->second, primary_url, secondary_url, content_type, 586 resource_identifier, is_off_the_record_, 587 primary_pattern, secondary_pattern); 588 if (value) { 589 if (info) 590 info->source = kProviderSourceMap[provider->first]; 591 return value; 592 } 593 } 594 595 if (info) { 596 info->source = content_settings::SETTING_SOURCE_NONE; 597 info->primary_pattern = ContentSettingsPattern(); 598 info->secondary_pattern = ContentSettingsPattern(); 599 } 600 return NULL; 601 } 602 603 // static 604 HostContentSettingsMap::ProviderType 605 HostContentSettingsMap::GetProviderTypeFromSource( 606 const std::string& source) { 607 for (size_t i = 0; i < arraysize(kProviderNames); ++i) { 608 if (source == kProviderNames[i]) 609 return static_cast<ProviderType>(i); 610 } 611 612 NOTREACHED(); 613 return DEFAULT_PROVIDER; 614 } 615