OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/content_settings/pref_content_settings_provider.h" | 5 #include "chrome/browser/content_settings/pref_content_settings_provider.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
| 8 #include <vector> |
| 9 #include <utility> |
8 | 10 |
9 #include "base/command_line.h" | 11 #include "base/command_line.h" |
10 #include "chrome/browser/browser_thread.h" | 12 #include "chrome/browser/browser_thread.h" |
11 #include "chrome/browser/content_settings/content_settings_details.h" | 13 #include "chrome/browser/content_settings/content_settings_details.h" |
12 #include "chrome/browser/content_settings/content_settings_pattern.h" | 14 #include "chrome/browser/content_settings/content_settings_pattern.h" |
13 #include "chrome/browser/prefs/pref_service.h" | 15 #include "chrome/browser/prefs/pref_service.h" |
14 #include "chrome/browser/prefs/scoped_pref_update.h" | 16 #include "chrome/browser/prefs/scoped_pref_update.h" |
15 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
16 #include "chrome/common/chrome_switches.h" | 18 #include "chrome/common/chrome_switches.h" |
| 19 #include "chrome/common/content_settings.h" |
17 #include "chrome/common/notification_details.h" | 20 #include "chrome/common/notification_details.h" |
18 #include "chrome/common/notification_service.h" | 21 #include "chrome/common/notification_service.h" |
19 #include "chrome/common/notification_source.h" | 22 #include "chrome/common/notification_source.h" |
20 #include "chrome/common/pref_names.h" | 23 #include "chrome/common/pref_names.h" |
| 24 #include "googleurl/src/gurl.h" |
| 25 #include "net/base/net_util.h" |
21 | 26 |
22 namespace { | 27 namespace { |
23 | 28 |
| 29 // The preference keys where resource identifiers are stored for |
| 30 // ContentSettingsType values that support resource identifiers. |
| 31 const char* kResourceTypeNames[CONTENT_SETTINGS_NUM_TYPES] = { |
| 32 NULL, |
| 33 NULL, |
| 34 NULL, |
| 35 "per_plugin", |
| 36 NULL, |
| 37 NULL, // Not used for Geolocation |
| 38 NULL, // Not used for Notifications |
| 39 }; |
| 40 |
24 // The default setting for each content type. | 41 // The default setting for each content type. |
25 const ContentSetting kDefaultSettings[CONTENT_SETTINGS_NUM_TYPES] = { | 42 const ContentSetting kDefaultSettings[CONTENT_SETTINGS_NUM_TYPES] = { |
26 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_COOKIES | 43 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_COOKIES |
27 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_IMAGES | 44 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_IMAGES |
28 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_JAVASCRIPT | 45 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_JAVASCRIPT |
29 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_PLUGINS | 46 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_PLUGINS |
30 CONTENT_SETTING_BLOCK, // CONTENT_SETTINGS_TYPE_POPUPS | 47 CONTENT_SETTING_BLOCK, // CONTENT_SETTINGS_TYPE_POPUPS |
31 CONTENT_SETTING_ASK, // Not used for Geolocation | 48 CONTENT_SETTING_ASK, // Not used for Geolocation |
32 CONTENT_SETTING_ASK, // Not used for Notifications | 49 CONTENT_SETTING_ASK, // Not used for Notifications |
33 }; | 50 }; |
34 | 51 |
35 // The names of the ContentSettingsType values, for use with dictionary prefs. | 52 // The names of the ContentSettingsType values, for use with dictionary prefs. |
36 const char* kTypeNames[CONTENT_SETTINGS_NUM_TYPES] = { | 53 const char* kTypeNames[CONTENT_SETTINGS_NUM_TYPES] = { |
37 "cookies", | 54 "cookies", |
38 "images", | 55 "images", |
39 "javascript", | 56 "javascript", |
40 "plugins", | 57 "plugins", |
41 "popups", | 58 "popups", |
42 NULL, // Not used for Geolocation | 59 NULL, // Not used for Geolocation |
43 NULL, // Not used for Notifications | 60 NULL, // Not used for Notifications |
44 }; | 61 }; |
45 | 62 |
| 63 // True if a given content settings type requires additional resource |
| 64 // identifiers. |
| 65 const bool kRequiresResourceIdentifier[CONTENT_SETTINGS_NUM_TYPES] = { |
| 66 false, // CONTENT_SETTINGS_TYPE_COOKIES |
| 67 false, // CONTENT_SETTINGS_TYPE_IMAGES |
| 68 false, // CONTET_SETTINGS_TYPE_JAVASCRIPT |
| 69 true, // CONTENT_SETTINGS_TYPE_PLUGINS |
| 70 false, // CONTENT_SETTINGS_TYPE_POPUPS |
| 71 false, // Not used for Geolocation |
| 72 false, // Not used for Notifications |
| 73 }; |
46 | 74 |
47 // Map ASK for the plugins content type to BLOCK if click-to-play is | 75 // Map ASK for the plugins content type to BLOCK if click-to-play is |
48 // not enabled. | 76 // not enabled. |
49 ContentSetting ClickToPlayFixup(ContentSettingsType content_type, | 77 ContentSetting ClickToPlayFixup(ContentSettingsType content_type, |
50 ContentSetting setting) { | 78 ContentSetting setting) { |
51 if (setting == CONTENT_SETTING_ASK && | 79 if (setting == CONTENT_SETTING_ASK && |
52 content_type == CONTENT_SETTINGS_TYPE_PLUGINS && | 80 content_type == CONTENT_SETTINGS_TYPE_PLUGINS && |
53 !CommandLine::ForCurrentProcess()->HasSwitch( | 81 !CommandLine::ForCurrentProcess()->HasSwitch( |
54 switches::kEnableClickToPlay)) { | 82 switches::kEnableClickToPlay)) { |
55 return CONTENT_SETTING_BLOCK; | 83 return CONTENT_SETTING_BLOCK; |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 Source<HostContentSettingsMap>(profile_->GetHostContentSettingsMap()), | 282 Source<HostContentSettingsMap>(profile_->GetHostContentSettingsMap()), |
255 Details<const ContentSettingsDetails>(&details)); | 283 Details<const ContentSettingsDetails>(&details)); |
256 } | 284 } |
257 | 285 |
258 | 286 |
259 // static | 287 // static |
260 void PrefDefaultProvider::RegisterUserPrefs(PrefService* prefs) { | 288 void PrefDefaultProvider::RegisterUserPrefs(PrefService* prefs) { |
261 prefs->RegisterDictionaryPref(prefs::kDefaultContentSettings); | 289 prefs->RegisterDictionaryPref(prefs::kDefaultContentSettings); |
262 } | 290 } |
263 | 291 |
| 292 // //////////////////////////////////////////////////////////////////////////// |
| 293 // PrefProvider:: |
| 294 // |
| 295 |
| 296 // static |
| 297 void PrefProvider::RegisterUserPrefs(PrefService* prefs) { |
| 298 prefs->RegisterIntegerPref(prefs::kContentSettingsVersion, |
| 299 ContentSettingsPattern::kContentSettingsPatternVersion); |
| 300 prefs->RegisterDictionaryPref(prefs::kContentSettingsPatterns); |
| 301 |
| 302 // Obsolete prefs, for migration: |
| 303 prefs->RegisterListPref(prefs::kPopupWhitelistedHosts); |
| 304 prefs->RegisterDictionaryPref(prefs::kPerHostContentSettings); |
| 305 } |
| 306 |
| 307 PrefProvider::PrefProvider(Profile* profile) |
| 308 : profile_(profile), |
| 309 is_off_the_record_(profile_->IsOffTheRecord()), |
| 310 updating_preferences_(false) { |
| 311 initializing_ = true; |
| 312 PrefService* prefs = profile_->GetPrefs(); |
| 313 |
| 314 // Migrate obsolete preferences. |
| 315 MigrateObsoletePerhostPref(prefs); |
| 316 MigrateObsoletePopupsPref(prefs); |
| 317 |
| 318 // Verify preferences version. |
| 319 if (!prefs->HasPrefPath(prefs::kContentSettingsVersion)) { |
| 320 prefs->SetInteger(prefs::kContentSettingsVersion, |
| 321 ContentSettingsPattern::kContentSettingsPatternVersion); |
| 322 } |
| 323 if (prefs->GetInteger(prefs::kContentSettingsVersion) > |
| 324 ContentSettingsPattern::kContentSettingsPatternVersion) { |
| 325 LOG(ERROR) << "Unknown content settings version in preferences."; |
| 326 return; |
| 327 } |
| 328 |
| 329 // Read exceptions. |
| 330 ReadExceptions(false); |
| 331 |
| 332 pref_change_registrar_.Init(prefs); |
| 333 pref_change_registrar_.Add(prefs::kContentSettingsPatterns, this); |
| 334 |
| 335 notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED, |
| 336 Source<Profile>(profile_)); |
| 337 initializing_ = false; |
| 338 } |
| 339 |
| 340 bool PrefProvider::ContentSettingsTypeIsManaged( |
| 341 ContentSettingsType content_type) { |
| 342 return false; |
| 343 } |
| 344 |
| 345 ContentSetting PrefProvider::GetContentSetting( |
| 346 const GURL& requesting_url, |
| 347 const GURL& embedding_url, |
| 348 ContentSettingsType content_type, |
| 349 const ResourceIdentifier& resource_identifier) const { |
| 350 // Support for embedding_patterns is not implemented yet. |
| 351 DCHECK(requesting_url == embedding_url); |
| 352 |
| 353 if (!RequiresResourceIdentifier(content_type)) |
| 354 return GetNonDefaultContentSettings(requesting_url).settings[content_type]; |
| 355 |
| 356 if (RequiresResourceIdentifier(content_type) && resource_identifier.empty()) |
| 357 return CONTENT_SETTING_DEFAULT; |
| 358 |
| 359 if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 360 switches::kEnableResourceContentSettings)) { |
| 361 DCHECK(!resource_identifier.empty()); |
| 362 } |
| 363 |
| 364 base::AutoLock auto_lock(lock_); |
| 365 |
| 366 const std::string host(net::GetHostOrSpecFromURL(requesting_url)); |
| 367 ContentSettingsTypeResourceIdentifierPair |
| 368 requested_setting(content_type, resource_identifier); |
| 369 |
| 370 // Check for exact matches first. |
| 371 HostContentSettings::const_iterator i(host_content_settings_.find(host)); |
| 372 if (i != host_content_settings_.end() && |
| 373 i->second.content_settings_for_resources.find(requested_setting) != |
| 374 i->second.content_settings_for_resources.end()) { |
| 375 return i->second.content_settings_for_resources.find( |
| 376 requested_setting)->second; |
| 377 } |
| 378 |
| 379 // If this map is not for an off-the-record profile, these searches will never |
| 380 // match. The additional off-the-record exceptions always overwrite the |
| 381 // regular ones. |
| 382 i = off_the_record_settings_.find(host); |
| 383 if (i != off_the_record_settings_.end() && |
| 384 i->second.content_settings_for_resources.find(requested_setting) != |
| 385 i->second.content_settings_for_resources.end()) { |
| 386 return i->second.content_settings_for_resources.find( |
| 387 requested_setting)->second; |
| 388 } |
| 389 |
| 390 // Match patterns starting with the most concrete pattern match. |
| 391 for (std::string key = |
| 392 std::string(ContentSettingsPattern::kDomainWildcard) + host; ; ) { |
| 393 HostContentSettings::const_iterator i(off_the_record_settings_.find(key)); |
| 394 if (i != off_the_record_settings_.end() && |
| 395 i->second.content_settings_for_resources.find(requested_setting) != |
| 396 i->second.content_settings_for_resources.end()) { |
| 397 return i->second.content_settings_for_resources.find( |
| 398 requested_setting)->second; |
| 399 } |
| 400 |
| 401 i = host_content_settings_.find(key); |
| 402 if (i != host_content_settings_.end() && |
| 403 i->second.content_settings_for_resources.find(requested_setting) != |
| 404 i->second.content_settings_for_resources.end()) { |
| 405 return i->second.content_settings_for_resources.find( |
| 406 requested_setting)->second; |
| 407 } |
| 408 |
| 409 const size_t next_dot = |
| 410 key.find('.', ContentSettingsPattern::kDomainWildcardLength); |
| 411 if (next_dot == std::string::npos) |
| 412 break; |
| 413 key.erase(ContentSettingsPattern::kDomainWildcardLength, |
| 414 next_dot - ContentSettingsPattern::kDomainWildcardLength + 1); |
| 415 } |
| 416 |
| 417 return CONTENT_SETTING_DEFAULT; |
| 418 } |
| 419 |
| 420 void PrefProvider::SetContentSetting( |
| 421 const ContentSettingsPattern& requesting_pattern, |
| 422 const ContentSettingsPattern& embedding_pattern, |
| 423 ContentSettingsType content_type, |
| 424 const ResourceIdentifier& resource_identifier, |
| 425 ContentSetting setting) { |
| 426 // Support for embedding_patterns is not implemented yet. |
| 427 DCHECK(requesting_pattern == embedding_pattern); |
| 428 |
| 429 DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation. |
| 430 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 431 DCHECK_NE(RequiresResourceIdentifier(content_type), |
| 432 resource_identifier.empty()); |
| 433 DCHECK(content_type != CONTENT_SETTINGS_TYPE_PLUGINS || |
| 434 setting != CONTENT_SETTING_ASK || |
| 435 CommandLine::ForCurrentProcess()->HasSwitch( |
| 436 switches::kEnableClickToPlay)); |
| 437 |
| 438 const ContentSettingsPattern pattern( |
| 439 requesting_pattern.CanonicalizePattern()); |
| 440 |
| 441 bool early_exit = false; |
| 442 std::string pattern_str(pattern.AsString()); |
| 443 PrefService* prefs = NULL; |
| 444 DictionaryValue* all_settings_dictionary = NULL; |
| 445 HostContentSettings* map_to_modify = &off_the_record_settings_; |
| 446 if (!is_off_the_record_) { |
| 447 prefs = profile_->GetPrefs(); |
| 448 all_settings_dictionary = |
| 449 prefs->GetMutableDictionary(prefs::kContentSettingsPatterns); |
| 450 map_to_modify = &host_content_settings_; |
| 451 } |
| 452 |
| 453 { |
| 454 base::AutoLock auto_lock(lock_); |
| 455 if (!map_to_modify->count(pattern_str)) |
| 456 (*map_to_modify)[pattern_str].content_settings = ContentSettings(); |
| 457 HostContentSettings::iterator i( |
| 458 map_to_modify->find(pattern_str)); |
| 459 ContentSettings& settings = i->second.content_settings; |
| 460 if (RequiresResourceIdentifier(content_type)) { |
| 461 settings.settings[content_type] = CONTENT_SETTING_DEFAULT; |
| 462 if (setting != CONTENT_SETTING_DEFAULT) { |
| 463 i->second.content_settings_for_resources[ |
| 464 ContentSettingsTypeResourceIdentifierPair(content_type, |
| 465 resource_identifier)] = setting; |
| 466 } else { |
| 467 i->second.content_settings_for_resources.erase( |
| 468 ContentSettingsTypeResourceIdentifierPair(content_type, |
| 469 resource_identifier)); |
| 470 } |
| 471 } else { |
| 472 settings.settings[content_type] = setting; |
| 473 } |
| 474 if (AllDefault(i->second)) { |
| 475 map_to_modify->erase(i); |
| 476 if (all_settings_dictionary) |
| 477 all_settings_dictionary->RemoveWithoutPathExpansion(pattern_str, NULL); |
| 478 |
| 479 // We can't just return because |NotifyObservers()| needs to be called, |
| 480 // without |lock_| being held. |
| 481 early_exit = true; |
| 482 } |
| 483 } |
| 484 |
| 485 if (!early_exit && all_settings_dictionary) { |
| 486 DictionaryValue* host_settings_dictionary = NULL; |
| 487 bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion( |
| 488 pattern_str, &host_settings_dictionary); |
| 489 if (!found) { |
| 490 host_settings_dictionary = new DictionaryValue; |
| 491 all_settings_dictionary->SetWithoutPathExpansion( |
| 492 pattern_str, host_settings_dictionary); |
| 493 DCHECK_NE(setting, CONTENT_SETTING_DEFAULT); |
| 494 } |
| 495 if (RequiresResourceIdentifier(content_type)) { |
| 496 std::string dictionary_path(kResourceTypeNames[content_type]); |
| 497 DictionaryValue* resource_dictionary = NULL; |
| 498 found = host_settings_dictionary->GetDictionary( |
| 499 dictionary_path, &resource_dictionary); |
| 500 if (!found) { |
| 501 resource_dictionary = new DictionaryValue; |
| 502 host_settings_dictionary->Set(dictionary_path, resource_dictionary); |
| 503 } |
| 504 if (setting == CONTENT_SETTING_DEFAULT) { |
| 505 resource_dictionary->RemoveWithoutPathExpansion(resource_identifier, |
| 506 NULL); |
| 507 } else { |
| 508 resource_dictionary->SetWithoutPathExpansion( |
| 509 resource_identifier, Value::CreateIntegerValue(setting)); |
| 510 } |
| 511 } else { |
| 512 std::string dictionary_path(kTypeNames[content_type]); |
| 513 if (setting == CONTENT_SETTING_DEFAULT) { |
| 514 host_settings_dictionary->RemoveWithoutPathExpansion(dictionary_path, |
| 515 NULL); |
| 516 } else { |
| 517 host_settings_dictionary->SetWithoutPathExpansion( |
| 518 dictionary_path, Value::CreateIntegerValue(setting)); |
| 519 } |
| 520 } |
| 521 } |
| 522 |
| 523 updating_preferences_ = true; |
| 524 if (!is_off_the_record_) |
| 525 ScopedPrefUpdate update(prefs, prefs::kContentSettingsPatterns); |
| 526 updating_preferences_ = false; |
| 527 |
| 528 NotifyObservers(ContentSettingsDetails(pattern, content_type, "")); |
| 529 } |
| 530 |
| 531 void PrefProvider::GetAllContentSettingsRules( |
| 532 ContentSettingsType content_type, |
| 533 const ResourceIdentifier& resource_identifier, |
| 534 Rules* content_setting_rules) const { |
| 535 DCHECK(RequiresResourceIdentifier(content_type) != |
| 536 resource_identifier.empty()); |
| 537 DCHECK(content_setting_rules); |
| 538 content_setting_rules->clear(); |
| 539 |
| 540 const HostContentSettings* map_to_return = |
| 541 is_off_the_record_ ? &off_the_record_settings_ : &host_content_settings_; |
| 542 ContentSettingsTypeResourceIdentifierPair requested_setting( |
| 543 content_type, resource_identifier); |
| 544 |
| 545 base::AutoLock auto_lock(lock_); |
| 546 for (HostContentSettings::const_iterator i(map_to_return->begin()); |
| 547 i != map_to_return->end(); ++i) { |
| 548 ContentSetting setting; |
| 549 if (RequiresResourceIdentifier(content_type)) { |
| 550 if (i->second.content_settings_for_resources.find(requested_setting) != |
| 551 i->second.content_settings_for_resources.end()) { |
| 552 setting = i->second.content_settings_for_resources.find( |
| 553 requested_setting)->second; |
| 554 } else { |
| 555 setting = CONTENT_SETTING_DEFAULT; |
| 556 } |
| 557 } else { |
| 558 setting = i->second.content_settings.settings[content_type]; |
| 559 } |
| 560 if (setting != CONTENT_SETTING_DEFAULT) { |
| 561 // Use of push_back() relies on the map iterator traversing in order of |
| 562 // ascending keys. |
| 563 content_setting_rules->push_back(Rule(ContentSettingsPattern(i->first), |
| 564 ContentSettingsPattern(i->first), |
| 565 setting)); |
| 566 } |
| 567 } |
| 568 } |
| 569 |
| 570 void PrefProvider::ResetToDefaults() { |
| 571 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 572 |
| 573 { |
| 574 base::AutoLock auto_lock(lock_); |
| 575 host_content_settings_.clear(); |
| 576 off_the_record_settings_.clear(); |
| 577 } |
| 578 |
| 579 if (!is_off_the_record_) { |
| 580 PrefService* prefs = profile_->GetPrefs(); |
| 581 updating_preferences_ = true; |
| 582 prefs->ClearPref(prefs::kContentSettingsPatterns); |
| 583 updating_preferences_ = false; |
| 584 } |
| 585 } |
| 586 |
| 587 void PrefProvider::ClearAllContentSettingsRules( |
| 588 ContentSettingsType content_type) { |
| 589 DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation. |
| 590 |
| 591 PrefService* prefs = NULL; |
| 592 DictionaryValue* all_settings_dictionary = NULL; |
| 593 HostContentSettings* map_to_modify = &off_the_record_settings_; |
| 594 |
| 595 if (!is_off_the_record_) { |
| 596 prefs = profile_->GetPrefs(); |
| 597 all_settings_dictionary = |
| 598 prefs->GetMutableDictionary(prefs::kContentSettingsPatterns); |
| 599 map_to_modify = &host_content_settings_; |
| 600 } |
| 601 |
| 602 { |
| 603 base::AutoLock auto_lock(lock_); |
| 604 for (HostContentSettings::iterator i(map_to_modify->begin()); |
| 605 i != map_to_modify->end(); ) { |
| 606 if (RequiresResourceIdentifier(content_type) || |
| 607 i->second.content_settings.settings[content_type] != |
| 608 CONTENT_SETTING_DEFAULT) { |
| 609 if (RequiresResourceIdentifier(content_type)) |
| 610 i->second.content_settings_for_resources.clear(); |
| 611 i->second.content_settings.settings[content_type] = |
| 612 CONTENT_SETTING_DEFAULT; |
| 613 std::string host(i->first); |
| 614 if (AllDefault(i->second)) { |
| 615 if (all_settings_dictionary) |
| 616 all_settings_dictionary->RemoveWithoutPathExpansion(host, NULL); |
| 617 map_to_modify->erase(i++); |
| 618 } else if (all_settings_dictionary) { |
| 619 DictionaryValue* host_settings_dictionary; |
| 620 bool found = |
| 621 all_settings_dictionary->GetDictionaryWithoutPathExpansion( |
| 622 host, &host_settings_dictionary); |
| 623 DCHECK(found); |
| 624 host_settings_dictionary->RemoveWithoutPathExpansion( |
| 625 kTypeNames[content_type], NULL); |
| 626 ++i; |
| 627 } |
| 628 } else { |
| 629 ++i; |
| 630 } |
| 631 } |
| 632 } |
| 633 |
| 634 updating_preferences_ = true; |
| 635 if (!is_off_the_record_) |
| 636 ScopedPrefUpdate update(prefs, prefs::kContentSettingsPatterns); |
| 637 updating_preferences_ = false; |
| 638 |
| 639 NotifyObservers( |
| 640 ContentSettingsDetails(ContentSettingsPattern(), content_type, "")); |
| 641 } |
| 642 |
| 643 void PrefProvider::Observe( |
| 644 NotificationType type, |
| 645 const NotificationSource& source, |
| 646 const NotificationDetails& details) { |
| 647 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 648 |
| 649 if (type == NotificationType::PREF_CHANGED) { |
| 650 DCHECK_EQ(profile_->GetPrefs(), Source<PrefService>(source).ptr()); |
| 651 if (updating_preferences_) |
| 652 return; |
| 653 |
| 654 std::string* name = Details<std::string>(details).ptr(); |
| 655 if (*name == prefs::kContentSettingsPatterns) { |
| 656 ReadExceptions(true); |
| 657 } else { |
| 658 NOTREACHED() << "Unexpected preference observed"; |
| 659 return; |
| 660 } |
| 661 |
| 662 if (!is_off_the_record_) { |
| 663 NotifyObservers(ContentSettingsDetails(ContentSettingsPattern(), |
| 664 CONTENT_SETTINGS_TYPE_DEFAULT, |
| 665 "")); |
| 666 } |
| 667 } else if (type == NotificationType::PROFILE_DESTROYED) { |
| 668 DCHECK_EQ(profile_, Source<Profile>(source).ptr()); |
| 669 UnregisterObservers(); |
| 670 } else { |
| 671 NOTREACHED() << "Unexpected notification"; |
| 672 } |
| 673 } |
| 674 |
| 675 PrefProvider::~PrefProvider() { |
| 676 UnregisterObservers(); |
| 677 } |
| 678 |
| 679 // //////////////////////////////////////////////////////////////////////////// |
| 680 // Private |
| 681 |
| 682 bool PrefProvider::RequiresResourceIdentifier( |
| 683 ContentSettingsType content_type) const { |
| 684 if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 685 switches::kEnableResourceContentSettings)) { |
| 686 return kRequiresResourceIdentifier[content_type]; |
| 687 } else { |
| 688 return false; |
| 689 } |
| 690 } |
| 691 |
| 692 bool PrefProvider::AllDefault( |
| 693 const ExtendedContentSettings& settings) const { |
| 694 for (size_t i = 0; i < arraysize(settings.content_settings.settings); ++i) { |
| 695 if (settings.content_settings.settings[i] != CONTENT_SETTING_DEFAULT) |
| 696 return false; |
| 697 } |
| 698 return settings.content_settings_for_resources.empty(); |
| 699 } |
| 700 |
| 701 void PrefProvider::ReadExceptions(bool overwrite) { |
| 702 base::AutoLock lock(lock_); |
| 703 |
| 704 PrefService* prefs = profile_->GetPrefs(); |
| 705 DictionaryValue* all_settings_dictionary = |
| 706 prefs->GetMutableDictionary(prefs::kContentSettingsPatterns); |
| 707 |
| 708 if (overwrite) |
| 709 host_content_settings_.clear(); |
| 710 |
| 711 // Careful: The returned value could be NULL if the pref has never been set. |
| 712 if (all_settings_dictionary != NULL) { |
| 713 // Convert all Unicode patterns into punycode form, then read. |
| 714 CanonicalizeContentSettingsExceptions(all_settings_dictionary); |
| 715 |
| 716 for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys()); |
| 717 i != all_settings_dictionary->end_keys(); ++i) { |
| 718 const std::string& pattern(*i); |
| 719 if (!ContentSettingsPattern(pattern).IsValid()) |
| 720 LOG(WARNING) << "Invalid pattern stored in content settings"; |
| 721 DictionaryValue* pattern_settings_dictionary = NULL; |
| 722 bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion( |
| 723 pattern, &pattern_settings_dictionary); |
| 724 DCHECK(found); |
| 725 ContentSettings settings; |
| 726 GetSettingsFromDictionary(pattern_settings_dictionary, &settings); |
| 727 host_content_settings_[pattern].content_settings = settings; |
| 728 GetResourceSettingsFromDictionary( |
| 729 pattern_settings_dictionary, |
| 730 &host_content_settings_[pattern].content_settings_for_resources); |
| 731 } |
| 732 } |
| 733 } |
| 734 |
| 735 void PrefProvider::CanonicalizeContentSettingsExceptions( |
| 736 DictionaryValue* all_settings_dictionary) { |
| 737 DCHECK(all_settings_dictionary); |
| 738 |
| 739 std::vector<std::string> remove_items; |
| 740 std::vector<std::pair<std::string, std::string> > move_items; |
| 741 for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys()); |
| 742 i != all_settings_dictionary->end_keys(); ++i) { |
| 743 const std::string& pattern(*i); |
| 744 const std::string canonicalized_pattern = |
| 745 ContentSettingsPattern(pattern).CanonicalizePattern(); |
| 746 |
| 747 if (canonicalized_pattern.empty() || canonicalized_pattern == pattern) |
| 748 continue; |
| 749 |
| 750 // Clear old pattern if prefs already have canonicalized pattern. |
| 751 DictionaryValue* new_pattern_settings_dictionary = NULL; |
| 752 if (all_settings_dictionary->GetDictionaryWithoutPathExpansion( |
| 753 canonicalized_pattern, &new_pattern_settings_dictionary)) { |
| 754 remove_items.push_back(pattern); |
| 755 continue; |
| 756 } |
| 757 |
| 758 // Move old pattern to canonicalized pattern. |
| 759 DictionaryValue* old_pattern_settings_dictionary = NULL; |
| 760 if (all_settings_dictionary->GetDictionaryWithoutPathExpansion( |
| 761 pattern, &old_pattern_settings_dictionary)) { |
| 762 move_items.push_back(std::make_pair(pattern, canonicalized_pattern)); |
| 763 } |
| 764 } |
| 765 |
| 766 for (size_t i = 0; i < remove_items.size(); ++i) { |
| 767 all_settings_dictionary->RemoveWithoutPathExpansion(remove_items[i], NULL); |
| 768 } |
| 769 |
| 770 for (size_t i = 0; i < move_items.size(); ++i) { |
| 771 Value* pattern_settings_dictionary = NULL; |
| 772 all_settings_dictionary->RemoveWithoutPathExpansion( |
| 773 move_items[i].first, &pattern_settings_dictionary); |
| 774 all_settings_dictionary->SetWithoutPathExpansion( |
| 775 move_items[i].second, pattern_settings_dictionary); |
| 776 } |
| 777 } |
| 778 |
| 779 void PrefProvider::GetSettingsFromDictionary( |
| 780 const DictionaryValue* dictionary, |
| 781 ContentSettings* settings) { |
| 782 for (DictionaryValue::key_iterator i(dictionary->begin_keys()); |
| 783 i != dictionary->end_keys(); ++i) { |
| 784 const std::string& content_type(*i); |
| 785 for (size_t type = 0; type < arraysize(kTypeNames); ++type) { |
| 786 if ((kTypeNames[type] != NULL) && (kTypeNames[type] == content_type)) { |
| 787 int setting = CONTENT_SETTING_DEFAULT; |
| 788 bool found = dictionary->GetIntegerWithoutPathExpansion(content_type, |
| 789 &setting); |
| 790 DCHECK(found); |
| 791 settings->settings[type] = IntToContentSetting(setting); |
| 792 break; |
| 793 } |
| 794 } |
| 795 } |
| 796 // Migrate obsolete cookie prompt mode. |
| 797 if (settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] == |
| 798 CONTENT_SETTING_ASK) |
| 799 settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] = CONTENT_SETTING_BLOCK; |
| 800 |
| 801 settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS] = |
| 802 ClickToPlayFixup(CONTENT_SETTINGS_TYPE_PLUGINS, |
| 803 settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS]); |
| 804 } |
| 805 |
| 806 void PrefProvider::GetResourceSettingsFromDictionary( |
| 807 const DictionaryValue* dictionary, |
| 808 ResourceContentSettings* settings) { |
| 809 for (DictionaryValue::key_iterator i(dictionary->begin_keys()); |
| 810 i != dictionary->end_keys(); ++i) { |
| 811 const std::string& content_type(*i); |
| 812 for (size_t type = 0; type < arraysize(kResourceTypeNames); ++type) { |
| 813 if ((kResourceTypeNames[type] != NULL) && |
| 814 (kResourceTypeNames[type] == content_type)) { |
| 815 DictionaryValue* resource_dictionary = NULL; |
| 816 bool found = dictionary->GetDictionary(content_type, |
| 817 &resource_dictionary); |
| 818 DCHECK(found); |
| 819 for (DictionaryValue::key_iterator j(resource_dictionary->begin_keys()); |
| 820 j != resource_dictionary->end_keys(); ++j) { |
| 821 const std::string& resource_identifier(*j); |
| 822 int setting = CONTENT_SETTING_DEFAULT; |
| 823 bool found = resource_dictionary->GetIntegerWithoutPathExpansion( |
| 824 resource_identifier, &setting); |
| 825 DCHECK(found); |
| 826 (*settings)[ContentSettingsTypeResourceIdentifierPair( |
| 827 ContentSettingsType(type), resource_identifier)] = |
| 828 ClickToPlayFixup(ContentSettingsType(type), |
| 829 ContentSetting(setting)); |
| 830 } |
| 831 |
| 832 break; |
| 833 } |
| 834 } |
| 835 } |
| 836 } |
| 837 |
| 838 void PrefProvider::NotifyObservers( |
| 839 const ContentSettingsDetails& details) { |
| 840 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 841 if (initializing_ || profile_ == NULL) |
| 842 return; |
| 843 NotificationService::current()->Notify( |
| 844 NotificationType::CONTENT_SETTINGS_CHANGED, |
| 845 Source<HostContentSettingsMap>( |
| 846 profile_->GetHostContentSettingsMap()), |
| 847 Details<const ContentSettingsDetails>(&details)); |
| 848 } |
| 849 |
| 850 void PrefProvider::UnregisterObservers() { |
| 851 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 852 if (!profile_) |
| 853 return; |
| 854 pref_change_registrar_.RemoveAll(); |
| 855 notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED, |
| 856 Source<Profile>(profile_)); |
| 857 profile_ = NULL; |
| 858 } |
| 859 |
| 860 void PrefProvider::MigrateObsoletePerhostPref(PrefService* prefs) { |
| 861 if (prefs->HasPrefPath(prefs::kPerHostContentSettings)) { |
| 862 const DictionaryValue* all_settings_dictionary = |
| 863 prefs->GetDictionary(prefs::kPerHostContentSettings); |
| 864 for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys()); |
| 865 i != all_settings_dictionary->end_keys(); ++i) { |
| 866 const std::string& host(*i); |
| 867 ContentSettingsPattern pattern( |
| 868 std::string(ContentSettingsPattern::kDomainWildcard) + host); |
| 869 DictionaryValue* host_settings_dictionary = NULL; |
| 870 bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion( |
| 871 host, &host_settings_dictionary); |
| 872 DCHECK(found); |
| 873 ContentSettings settings; |
| 874 GetSettingsFromDictionary(host_settings_dictionary, &settings); |
| 875 for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) { |
| 876 if (settings.settings[j] != CONTENT_SETTING_DEFAULT && |
| 877 !RequiresResourceIdentifier(ContentSettingsType(j))) { |
| 878 SetContentSetting( |
| 879 pattern, |
| 880 pattern, |
| 881 ContentSettingsType(j), |
| 882 "", |
| 883 settings.settings[j]); |
| 884 } |
| 885 } |
| 886 } |
| 887 prefs->ClearPref(prefs::kPerHostContentSettings); |
| 888 } |
| 889 } |
| 890 |
| 891 void PrefProvider::MigrateObsoletePopupsPref(PrefService* prefs) { |
| 892 if (prefs->HasPrefPath(prefs::kPopupWhitelistedHosts)) { |
| 893 const ListValue* whitelist_pref = |
| 894 prefs->GetList(prefs::kPopupWhitelistedHosts); |
| 895 for (ListValue::const_iterator i(whitelist_pref->begin()); |
| 896 i != whitelist_pref->end(); ++i) { |
| 897 std::string host; |
| 898 (*i)->GetAsString(&host); |
| 899 SetContentSetting(ContentSettingsPattern(host), |
| 900 ContentSettingsPattern(host), |
| 901 CONTENT_SETTINGS_TYPE_POPUPS, |
| 902 "", |
| 903 CONTENT_SETTING_ALLOW); |
| 904 } |
| 905 prefs->ClearPref(prefs::kPopupWhitelistedHosts); |
| 906 } |
| 907 } |
| 908 |
| 909 // //////////////////////////////////////////////////////////////////////////// |
| 910 // LEGACY TBR |
| 911 // |
| 912 |
| 913 ContentSettings PrefProvider::GetNonDefaultContentSettings( |
| 914 const GURL& url) const { |
| 915 base::AutoLock auto_lock(lock_); |
| 916 |
| 917 const std::string host(net::GetHostOrSpecFromURL(url)); |
| 918 ContentSettings output; |
| 919 for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) |
| 920 output.settings[j] = CONTENT_SETTING_DEFAULT; |
| 921 |
| 922 // Check for exact matches first. |
| 923 HostContentSettings::const_iterator i(host_content_settings_.find(host)); |
| 924 if (i != host_content_settings_.end()) |
| 925 output = i->second.content_settings; |
| 926 |
| 927 // If this map is not for an off-the-record profile, these searches will never |
| 928 // match. The additional off-the-record exceptions always overwrite the |
| 929 // regular ones. |
| 930 i = off_the_record_settings_.find(host); |
| 931 if (i != off_the_record_settings_.end()) { |
| 932 for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) |
| 933 if (i->second.content_settings.settings[j] != CONTENT_SETTING_DEFAULT) |
| 934 output.settings[j] = i->second.content_settings.settings[j]; |
| 935 } |
| 936 |
| 937 // Match patterns starting with the most concrete pattern match. |
| 938 for (std::string key = |
| 939 std::string(ContentSettingsPattern::kDomainWildcard) + host; ; ) { |
| 940 HostContentSettings::const_iterator i(off_the_record_settings_.find(key)); |
| 941 if (i != off_the_record_settings_.end()) { |
| 942 for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) { |
| 943 if (output.settings[j] == CONTENT_SETTING_DEFAULT) |
| 944 output.settings[j] = i->second.content_settings.settings[j]; |
| 945 } |
| 946 } |
| 947 i = host_content_settings_.find(key); |
| 948 if (i != host_content_settings_.end()) { |
| 949 for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) { |
| 950 if (output.settings[j] == CONTENT_SETTING_DEFAULT) |
| 951 output.settings[j] = i->second.content_settings.settings[j]; |
| 952 } |
| 953 } |
| 954 const size_t next_dot = |
| 955 key.find('.', ContentSettingsPattern::kDomainWildcardLength); |
| 956 if (next_dot == std::string::npos) |
| 957 break; |
| 958 key.erase(ContentSettingsPattern::kDomainWildcardLength, |
| 959 next_dot - ContentSettingsPattern::kDomainWildcardLength + 1); |
| 960 } |
| 961 |
| 962 return output; |
| 963 } |
| 964 |
264 } // namespace content_settings | 965 } // namespace content_settings |
OLD | NEW |