OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/extensions/extension_updater.h" | 5 #include "chrome/browser/extensions/extension_updater.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <set> | 8 #include <set> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 int response_code, | 371 int response_code, |
372 const std::string& data) { | 372 const std::string& data) { |
373 // We want to try parsing the manifest, and if it indicates updates are | 373 // We want to try parsing the manifest, and if it indicates updates are |
374 // available, we want to fire off requests to fetch those updates. | 374 // available, we want to fire off requests to fetch those updates. |
375 if (status.status() == URLRequestStatus::SUCCESS && response_code == 200) { | 375 if (status.status() == URLRequestStatus::SUCCESS && response_code == 200) { |
376 scoped_refptr<SafeManifestParser> safe_parser = | 376 scoped_refptr<SafeManifestParser> safe_parser = |
377 new SafeManifestParser(data, current_manifest_fetch_.release(), this); | 377 new SafeManifestParser(data, current_manifest_fetch_.release(), this); |
378 safe_parser->Start(); | 378 safe_parser->Start(); |
379 } else { | 379 } else { |
380 // TODO(asargent) Do exponential backoff here. (http://crbug.com/12546). | 380 // TODO(asargent) Do exponential backoff here. (http://crbug.com/12546). |
381 LOG(INFO) << "Failed to fetch manifst '" << url.possibly_invalid_spec() << | 381 LOG(INFO) << "Failed to fetch manifest '" << url.possibly_invalid_spec() << |
382 "' response code:" << response_code; | 382 "' response code:" << response_code; |
383 } | 383 } |
384 manifest_fetcher_.reset(); | 384 manifest_fetcher_.reset(); |
385 current_manifest_fetch_.reset(); | 385 current_manifest_fetch_.reset(); |
386 | 386 |
387 // If we have any pending manifest requests, fire off the next one. | 387 // If we have any pending manifest requests, fire off the next one. |
388 if (!manifests_pending_.empty()) { | 388 if (!manifests_pending_.empty()) { |
389 ManifestFetchData* manifest_fetch = manifests_pending_.front(); | 389 ManifestFetchData* manifest_fetch = manifests_pending_.front(); |
390 manifests_pending_.pop_front(); | 390 manifests_pending_.pop_front(); |
391 StartUpdateCheck(manifest_fetch); | 391 StartUpdateCheck(manifest_fetch); |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 50); // 50 buckets seems to be the default. | 533 50); // 50 buckets seems to be the default. |
534 } | 534 } |
535 } | 535 } |
536 | 536 |
537 // Save the last check time, and schedule the next check. | 537 // Save the last check time, and schedule the next check. |
538 int64 now = Time::Now().ToInternalValue(); | 538 int64 now = Time::Now().ToInternalValue(); |
539 prefs_->SetInt64(kLastExtensionsUpdateCheck, now); | 539 prefs_->SetInt64(kLastExtensionsUpdateCheck, now); |
540 ScheduleNextCheck(TimeDelta::FromSeconds(frequency_seconds_)); | 540 ScheduleNextCheck(TimeDelta::FromSeconds(frequency_seconds_)); |
541 } | 541 } |
542 | 542 |
543 void ExtensionUpdater::CheckNow() { | 543 namespace { |
544 // List of data on fetches we're going to do. We limit the number of | |
545 // extensions grouped together in one batch to avoid running into the limits | |
546 // on the length of http GET requests, so there might be multiple | |
547 // ManifestFetchData* objects with the same base_url. | |
548 std::multimap<GURL, ManifestFetchData*> fetches; | |
549 | 544 |
550 int no_url_count = 0; | 545 struct URLStats { |
551 int google_url_count = 0; | 546 URLStats() |
552 int other_url_count = 0; | 547 : no_url_count(0), |
553 int theme_count = 0; | 548 google_url_count(0), |
| 549 other_url_count(0), |
| 550 theme_count(0) {} |
554 | 551 |
555 const ExtensionList* extensions = service_->extensions(); | 552 void ReportStats() const { |
556 for (ExtensionList::const_iterator iter = extensions->begin(); | 553 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtensions", |
557 iter != extensions->end(); ++iter) { | 554 google_url_count + other_url_count - |
558 Extension* extension = (*iter); | 555 theme_count); |
| 556 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckTheme", |
| 557 theme_count); |
| 558 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckGoogleUrl", |
| 559 google_url_count); |
| 560 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckOtherUrl", |
| 561 other_url_count); |
| 562 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckNoUrl", |
| 563 no_url_count); |
| 564 } |
559 | 565 |
| 566 int no_url_count, google_url_count, other_url_count, theme_count; |
| 567 }; |
| 568 |
| 569 class ManifestFetchesBuilder { |
| 570 public: |
| 571 explicit ManifestFetchesBuilder(ExtensionUpdateService* service) |
| 572 : service_(service) { |
| 573 DCHECK(service_); |
| 574 } |
| 575 |
| 576 void AddExtension(const Extension& extension) { |
| 577 AddExtensionData(extension.location(), |
| 578 extension.id(), |
| 579 *extension.version(), |
| 580 extension.converted_from_user_script(), |
| 581 extension.IsTheme(), |
| 582 extension.update_url()); |
| 583 } |
| 584 |
| 585 void AddPendingExtension(const std::string& id, |
| 586 const PendingExtensionInfo& info) { |
| 587 AddExtensionData(Extension::INTERNAL, id, info.version, |
| 588 false, info.is_theme, info.update_url); |
| 589 } |
| 590 |
| 591 const URLStats& url_stats() const { return url_stats_; } |
| 592 |
| 593 // Caller takes ownership of the returned ManifestFetchData |
| 594 // objects. Clears all counters. |
| 595 std::vector<ManifestFetchData*> GetFetches() { |
| 596 std::vector<ManifestFetchData*> fetches; |
| 597 fetches.reserve(fetches_.size()); |
| 598 for (std::multimap<GURL, ManifestFetchData*>::iterator it = |
| 599 fetches_.begin(); it != fetches_.end(); ++it) { |
| 600 fetches.push_back(it->second); |
| 601 } |
| 602 fetches_.clear(); |
| 603 url_stats_ = URLStats(); |
| 604 return fetches; |
| 605 } |
| 606 |
| 607 private: |
| 608 void AddExtensionData(Extension::Location location, |
| 609 const std::string& id, |
| 610 const Version& version, |
| 611 bool converted_from_user_script, |
| 612 bool is_theme, |
| 613 const GURL& update_url) { |
560 // Only internal and external extensions can be autoupdated. | 614 // Only internal and external extensions can be autoupdated. |
561 if (extension->location() != Extension::INTERNAL && | 615 if (location != Extension::INTERNAL && |
562 !Extension::IsExternalLocation(extension->location())) { | 616 !Extension::IsExternalLocation(location)) { |
563 continue; | 617 return; |
564 } | 618 } |
565 | 619 |
566 const GURL& update_url = extension->update_url(); | |
567 | |
568 // Collect histogram data and skip extensions with no update url. | 620 // Collect histogram data and skip extensions with no update url. |
569 if (update_url.DomainIs("google.com")) { | 621 if (update_url.DomainIs("google.com")) { |
570 google_url_count++; | 622 url_stats_.google_url_count++; |
571 } else if (update_url.is_empty() || extension->id().empty()) { | 623 } else if (update_url.is_empty() || id.empty()) { |
572 // TODO(asargent) when a default URL is added, make sure to update | 624 // TODO(asargent) when a default URL is added, make sure to update |
573 // the total histogram below. Also, make sure to skip extensions that | 625 // the total histogram below. Also, make sure to skip extensions that |
574 // are "converted_from_user_script". | 626 // are "converted_from_user_script". |
575 if (!extension->converted_from_user_script()) | 627 if (!converted_from_user_script) |
576 no_url_count++; | 628 url_stats_.no_url_count++; |
577 continue; | 629 return; |
578 } else { | 630 } else { |
579 other_url_count++; | 631 url_stats_.other_url_count++; |
580 } | 632 } |
581 if (extension->IsTheme()) | 633 if (is_theme) |
582 theme_count++; | 634 url_stats_.theme_count++; |
583 | 635 |
584 DCHECK(update_url.is_valid()); | 636 DCHECK(update_url.is_valid()); |
585 | 637 |
586 ManifestFetchData* fetch = NULL; | 638 ManifestFetchData* fetch = NULL; |
587 std::multimap<GURL, ManifestFetchData*>::iterator existing_iter = | 639 std::multimap<GURL, ManifestFetchData*>::iterator existing_iter = |
588 fetches.find(update_url); | 640 fetches_.find(update_url); |
589 | 641 |
590 // Find or create a ManifestFetchData to add this extension to. | 642 // Find or create a ManifestFetchData to add this extension to. |
591 std::string id = extension->id(); | 643 int ping_days = CalculatePingDays(id); |
592 std::string version = extension->VersionString(); | 644 while (existing_iter != fetches_.end()) { |
593 int ping_days = CalculatePingDays(extension->id()); | 645 if (existing_iter->second->AddExtension(id, version.GetString(), |
594 while (existing_iter != fetches.end()) { | 646 ping_days)) { |
595 if (existing_iter->second->AddExtension(id, version, ping_days)) { | |
596 fetch = existing_iter->second; | 647 fetch = existing_iter->second; |
597 break; | 648 break; |
598 } | 649 } |
599 existing_iter++; | 650 existing_iter++; |
600 } | 651 } |
601 if (!fetch) { | 652 if (!fetch) { |
602 fetch = new ManifestFetchData(update_url); | 653 fetch = new ManifestFetchData(update_url); |
603 fetches.insert(std::pair<GURL, ManifestFetchData*>(update_url, fetch)); | 654 fetches_.insert(std::pair<GURL, ManifestFetchData*>(update_url, fetch)); |
604 bool added = fetch->AddExtension(id, version, ping_days); | 655 bool added = fetch->AddExtension(id, version.GetString(), ping_days); |
605 DCHECK(added); | 656 DCHECK(added); |
606 } | 657 } |
607 } | 658 } |
608 | 659 |
| 660 // Calculates the value to use for the ping days parameter in manifest |
| 661 // fetches for a given extension. |
| 662 int CalculatePingDays(const std::string& extension_id) { |
| 663 int days = ManifestFetchData::kNeverPinged; |
| 664 Time last_ping_day = service_->LastPingDay(extension_id); |
| 665 if (!last_ping_day.is_null()) { |
| 666 days = (Time::Now() - last_ping_day).InDays(); |
| 667 } |
| 668 return days; |
| 669 } |
| 670 |
| 671 ExtensionUpdateService* service_; |
| 672 |
| 673 // List of data on fetches we're going to do. We limit the number of |
| 674 // extensions grouped together in one batch to avoid running into the limits |
| 675 // on the length of http GET requests, so there might be multiple |
| 676 // ManifestFetchData* objects with the same base_url. |
| 677 std::multimap<GURL, ManifestFetchData*> fetches_; |
| 678 |
| 679 URLStats url_stats_; |
| 680 |
| 681 DISALLOW_COPY_AND_ASSIGN(ManifestFetchesBuilder); |
| 682 }; |
| 683 |
| 684 } // namespace |
| 685 |
| 686 void ExtensionUpdater::CheckNow() { |
| 687 ManifestFetchesBuilder fetches_builder(service_); |
| 688 |
| 689 const ExtensionList* extensions = service_->extensions(); |
| 690 for (ExtensionList::const_iterator iter = extensions->begin(); |
| 691 iter != extensions->end(); ++iter) { |
| 692 fetches_builder.AddExtension(**iter); |
| 693 } |
| 694 |
| 695 const PendingExtensionMap& pending_extensions = |
| 696 service_->pending_extensions(); |
| 697 for (PendingExtensionMap::const_iterator iter = pending_extensions.begin(); |
| 698 iter != pending_extensions.end(); ++iter) { |
| 699 fetches_builder.AddPendingExtension(iter->first, iter->second); |
| 700 } |
| 701 |
| 702 fetches_builder.url_stats().ReportStats(); |
| 703 |
| 704 std::vector<ManifestFetchData*> fetches(fetches_builder.GetFetches()); |
| 705 |
609 // Start a fetch of the blacklist if needed. | 706 // Start a fetch of the blacklist if needed. |
610 if (blacklist_checks_enabled_ && service_->HasInstalledExtensions()) { | 707 if (blacklist_checks_enabled_ && service_->HasInstalledExtensions()) { |
611 ManifestFetchData* blacklist_fetch = | 708 ManifestFetchData* blacklist_fetch = |
612 new ManifestFetchData(GURL(kBlacklistUpdateUrl)); | 709 new ManifestFetchData(GURL(kBlacklistUpdateUrl)); |
613 std::wstring version = prefs_->GetString(kExtensionBlacklistUpdateVersion); | 710 std::wstring version = prefs_->GetString(kExtensionBlacklistUpdateVersion); |
614 blacklist_fetch->AddExtension(kBlacklistAppID, WideToASCII(version), 0); | 711 blacklist_fetch->AddExtension(kBlacklistAppID, WideToASCII(version), 0); |
615 StartUpdateCheck(blacklist_fetch); | 712 StartUpdateCheck(blacklist_fetch); |
616 } | 713 } |
617 | 714 |
618 // Now start fetching regular extension updates | 715 // Now start fetching regular extension updates |
619 std::multimap<GURL, ManifestFetchData*>::iterator i = fetches.begin(); | 716 for (std::vector<ManifestFetchData*>::const_iterator it = fetches.begin(); |
620 while (i != fetches.end()) { | 717 it != fetches.end(); ++it) { |
621 ManifestFetchData *fetch = i->second; | |
622 | |
623 // StartUpdateCheck makes sure the url isn't already downloading or | 718 // StartUpdateCheck makes sure the url isn't already downloading or |
624 // scheduled, so we don't need to check before calling it. Ownership of | 719 // scheduled, so we don't need to check before calling it. Ownership of |
625 // fetch is transferred here. | 720 // fetch is transferred here. |
626 StartUpdateCheck(fetch); | 721 StartUpdateCheck(*it); |
627 fetches.erase(i++); | |
628 } | 722 } |
629 | 723 // We don't want to use fetches after this since StartUpdateCheck() |
630 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtensions", | 724 // takes ownership of its argument. |
631 google_url_count + other_url_count - theme_count); | 725 fetches.clear(); |
632 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckTheme", | |
633 theme_count); | |
634 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckGoogleUrl", | |
635 google_url_count); | |
636 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckOtherUrl", | |
637 other_url_count); | |
638 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckNoUrl", | |
639 no_url_count); | |
640 } | |
641 | |
642 int ExtensionUpdater::CalculatePingDays(const std::string& extension_id) { | |
643 int days = ManifestFetchData::kNeverPinged; | |
644 Time last_ping_day = service_->LastPingDay(extension_id); | |
645 if (!last_ping_day.is_null()) { | |
646 days = (Time::Now() - last_ping_day).InDays(); | |
647 } | |
648 return days; | |
649 } | 726 } |
650 | 727 |
651 bool ExtensionUpdater::GetExistingVersion(const std::string& id, | 728 bool ExtensionUpdater::GetExistingVersion(const std::string& id, |
652 std::string* version) { | 729 std::string* version) { |
653 if (id == kBlacklistAppID) { | 730 if (id == kBlacklistAppID) { |
654 *version = | 731 *version = |
655 WideToASCII(prefs_->GetString(kExtensionBlacklistUpdateVersion)); | 732 WideToASCII(prefs_->GetString(kExtensionBlacklistUpdateVersion)); |
656 return true; | 733 return true; |
657 } | 734 } |
| 735 PendingExtensionMap::const_iterator it = |
| 736 service_->pending_extensions().find(id); |
| 737 if (it != service_->pending_extensions().end()) { |
| 738 *version = it->second.version.GetString(); |
| 739 return true; |
| 740 } |
658 Extension* extension = service_->GetExtensionById(id, false); | 741 Extension* extension = service_->GetExtensionById(id, false); |
659 if (!extension) { | 742 if (!extension) { |
660 return false; | 743 return false; |
661 } | 744 } |
662 *version = extension->version()->GetString(); | 745 *version = extension->version()->GetString(); |
663 return true; | 746 return true; |
664 } | 747 } |
665 | 748 |
666 std::vector<int> ExtensionUpdater::DetermineUpdates( | 749 std::vector<int> ExtensionUpdater::DetermineUpdates( |
667 const ManifestFetchData& fetch_data, | 750 const ManifestFetchData& fetch_data, |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
772 extension_fetcher_.reset( | 855 extension_fetcher_.reset( |
773 URLFetcher::Create(kExtensionFetcherId, url, URLFetcher::GET, this)); | 856 URLFetcher::Create(kExtensionFetcherId, url, URLFetcher::GET, this)); |
774 extension_fetcher_->set_request_context( | 857 extension_fetcher_->set_request_context( |
775 Profile::GetDefaultRequestContext()); | 858 Profile::GetDefaultRequestContext()); |
776 extension_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES | | 859 extension_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES | |
777 net::LOAD_DO_NOT_SAVE_COOKIES); | 860 net::LOAD_DO_NOT_SAVE_COOKIES); |
778 extension_fetcher_->Start(); | 861 extension_fetcher_->Start(); |
779 current_extension_fetch_ = ExtensionFetch(id, url, hash, version); | 862 current_extension_fetch_ = ExtensionFetch(id, url, hash, version); |
780 } | 863 } |
781 } | 864 } |
OLD | NEW |