summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-27 06:39:31 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-27 06:39:31 +0000
commit83b3214c333463352ae9fe2d1f2df73f618e3712 (patch)
tree79153863f86aa3f02d390be204e41a6557ab80d6 /chrome/browser/extensions
parentcbe9eedbceb2e6ddf8ea3024860985a92acdad0b (diff)
downloadchromium_src-83b3214c333463352ae9fe2d1f2df73f618e3712.zip
chromium_src-83b3214c333463352ae9fe2d1f2df73f618e3712.tar.gz
chromium_src-83b3214c333463352ae9fe2d1f2df73f618e3712.tar.bz2
Fill in a default update_url for extensions with none.
Refactored ManifestFetchesBuilder for unit tests. Added a few unit tests. BUG=28750 TEST=unittests Review URL: http://codereview.chromium.org/1402001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42899 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r--chrome/browser/extensions/extension_updater.cc280
-rw-r--r--chrome/browser/extensions/extension_updater.h53
-rw-r--r--chrome/browser/extensions/extension_updater_unittest.cc43
3 files changed, 232 insertions, 144 deletions
diff --git a/chrome/browser/extensions/extension_updater.cc b/chrome/browser/extensions/extension_updater.cc
index 80621f5..1a8c6a0 100644
--- a/chrome/browser/extensions/extension_updater.cc
+++ b/chrome/browser/extensions/extension_updater.cc
@@ -45,6 +45,11 @@ using prefs::kExtensionBlacklistUpdateVersion;
using prefs::kLastExtensionsUpdateCheck;
using prefs::kNextExtensionsUpdateCheck;
+// The default URL to fall back to if an extension doesn't have an
+// update URL.
+const char kDefaultUpdateURL[] =
+ "http://clients2.google.com/service/update2/crx";
+
// NOTE: HTTPS is used here to ensure the response from omaha can be trusted.
// The response contains a url for fetching the blacklist and a hash value
// for validation.
@@ -138,6 +143,136 @@ bool ManifestFetchData::ShouldPing(int days) const {
}
+ManifestFetchesBuilder::ManifestFetchesBuilder(
+ ExtensionUpdateService* service) : service_(service) {
+ DCHECK(service_);
+}
+
+void ManifestFetchesBuilder::AddExtension(const Extension& extension) {
+ AddExtensionData(extension.location(),
+ extension.id(),
+ *extension.version(),
+ extension.converted_from_user_script(),
+ extension.IsTheme(),
+ extension.update_url());
+}
+
+void ManifestFetchesBuilder::AddPendingExtension(
+ const std::string& id,
+ const PendingExtensionInfo& info) {
+ AddExtensionData(Extension::INTERNAL, id, info.version,
+ false, info.is_theme, info.update_url);
+}
+
+void ManifestFetchesBuilder::ReportStats() const {
+ UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtensions",
+ url_stats_.google_url_count +
+ url_stats_.other_url_count -
+ url_stats_.theme_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckTheme",
+ url_stats_.theme_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckGoogleUrl",
+ url_stats_.google_url_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckOtherUrl",
+ url_stats_.other_url_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckNoUrl",
+ url_stats_.no_url_count);
+}
+
+std::vector<ManifestFetchData*> ManifestFetchesBuilder::GetFetches() {
+ std::vector<ManifestFetchData*> fetches;
+ fetches.reserve(fetches_.size());
+ for (std::multimap<GURL, ManifestFetchData*>::iterator it =
+ fetches_.begin(); it != fetches_.end(); ++it) {
+ fetches.push_back(it->second);
+ }
+ fetches_.clear();
+ url_stats_ = URLStats();
+ return fetches;
+}
+
+void ManifestFetchesBuilder::AddExtensionData(
+ Extension::Location location,
+ const std::string& id,
+ const Version& version,
+ bool converted_from_user_script,
+ bool is_theme,
+ GURL update_url) {
+ // Only internal and external extensions can be autoupdated.
+ if (location != Extension::INTERNAL &&
+ !Extension::IsExternalLocation(location)) {
+ return;
+ }
+
+ // Skip extensions with non-empty invalid update URLs.
+ if (!update_url.is_empty() && !update_url.is_valid()) {
+ LOG(WARNING) << "Extension " << id << " has invalid update url "
+ << update_url;
+ return;
+ }
+
+ // Skip extensions with empty IDs.
+ if (id.empty()) {
+ LOG(WARNING) << "Found extension with empty ID";
+ return;
+ }
+
+ // Skip extensions with empty update URLs converted from user
+ // scripts.
+ if (converted_from_user_script && update_url.is_empty()) {
+ return;
+ }
+
+ if (update_url.DomainIs("google.com")) {
+ url_stats_.google_url_count++;
+ } else if (update_url.is_empty()) {
+ url_stats_.no_url_count++;
+ // Fill in default update URL.
+ update_url = GURL(kDefaultUpdateURL);
+ } else {
+ url_stats_.other_url_count++;
+ }
+
+ if (is_theme) {
+ url_stats_.theme_count++;
+ }
+
+ DCHECK(!update_url.is_empty());
+ DCHECK(update_url.is_valid());
+
+ ManifestFetchData* fetch = NULL;
+ std::multimap<GURL, ManifestFetchData*>::iterator existing_iter =
+ fetches_.find(update_url);
+
+ // Find or create a ManifestFetchData to add this extension to.
+ int ping_days = CalculatePingDays(id);
+ while (existing_iter != fetches_.end()) {
+ if (existing_iter->second->AddExtension(id, version.GetString(),
+ ping_days)) {
+ fetch = existing_iter->second;
+ break;
+ }
+ existing_iter++;
+ }
+ if (!fetch) {
+ fetch = new ManifestFetchData(update_url);
+ fetches_.insert(std::pair<GURL, ManifestFetchData*>(update_url, fetch));
+ bool added = fetch->AddExtension(id, version.GetString(), ping_days);
+ DCHECK(added);
+ }
+}
+
+int ManifestFetchesBuilder::CalculatePingDays(
+ const std::string& extension_id) {
+ int days = ManifestFetchData::kNeverPinged;
+ Time last_ping_day = service_->LastPingDay(extension_id);
+ if (!last_ping_day.is_null()) {
+ days = (Time::Now() - last_ping_day).InDays();
+ }
+ return days;
+}
+
+
// A utility class to do file handling on the file I/O thread.
class ExtensionUpdaterFileHandler
: public base::RefCountedThreadSafe<ExtensionUpdaterFileHandler> {
@@ -540,149 +675,6 @@ void ExtensionUpdater::TimerFired() {
ScheduleNextCheck(TimeDelta::FromSeconds(frequency_seconds_));
}
-namespace {
-
-struct URLStats {
- URLStats()
- : no_url_count(0),
- google_url_count(0),
- other_url_count(0),
- theme_count(0) {}
-
- void ReportStats() const {
- UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtensions",
- google_url_count + other_url_count -
- theme_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckTheme",
- theme_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckGoogleUrl",
- google_url_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckOtherUrl",
- other_url_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckNoUrl",
- no_url_count);
- }
-
- int no_url_count, google_url_count, other_url_count, theme_count;
-};
-
-class ManifestFetchesBuilder {
- public:
- explicit ManifestFetchesBuilder(ExtensionUpdateService* service)
- : service_(service) {
- DCHECK(service_);
- }
-
- void AddExtension(const Extension& extension) {
- AddExtensionData(extension.location(),
- extension.id(),
- *extension.version(),
- extension.converted_from_user_script(),
- extension.IsTheme(),
- extension.update_url());
- }
-
- void AddPendingExtension(const std::string& id,
- const PendingExtensionInfo& info) {
- AddExtensionData(Extension::INTERNAL, id, info.version,
- false, info.is_theme, info.update_url);
- }
-
- const URLStats& url_stats() const { return url_stats_; }
-
- // Caller takes ownership of the returned ManifestFetchData
- // objects. Clears all counters.
- std::vector<ManifestFetchData*> GetFetches() {
- std::vector<ManifestFetchData*> fetches;
- fetches.reserve(fetches_.size());
- for (std::multimap<GURL, ManifestFetchData*>::iterator it =
- fetches_.begin(); it != fetches_.end(); ++it) {
- fetches.push_back(it->second);
- }
- fetches_.clear();
- url_stats_ = URLStats();
- return fetches;
- }
-
- private:
- void AddExtensionData(Extension::Location location,
- const std::string& id,
- const Version& version,
- bool converted_from_user_script,
- bool is_theme,
- const GURL& update_url) {
- // Only internal and external extensions can be autoupdated.
- if (location != Extension::INTERNAL &&
- !Extension::IsExternalLocation(location)) {
- return;
- }
-
- // Collect histogram data and skip extensions with no update url.
- if (update_url.DomainIs("google.com")) {
- url_stats_.google_url_count++;
- } else if (update_url.is_empty() || id.empty()) {
- // TODO(asargent) when a default URL is added, make sure to update
- // the total histogram below. Also, make sure to skip extensions that
- // are "converted_from_user_script".
- if (!converted_from_user_script)
- url_stats_.no_url_count++;
- return;
- } else {
- url_stats_.other_url_count++;
- }
- if (is_theme)
- url_stats_.theme_count++;
-
- DCHECK(update_url.is_valid());
-
- ManifestFetchData* fetch = NULL;
- std::multimap<GURL, ManifestFetchData*>::iterator existing_iter =
- fetches_.find(update_url);
-
- // Find or create a ManifestFetchData to add this extension to.
- int ping_days = CalculatePingDays(id);
- while (existing_iter != fetches_.end()) {
- if (existing_iter->second->AddExtension(id, version.GetString(),
- ping_days)) {
- fetch = existing_iter->second;
- break;
- }
- existing_iter++;
- }
- if (!fetch) {
- fetch = new ManifestFetchData(update_url);
- fetches_.insert(std::pair<GURL, ManifestFetchData*>(update_url, fetch));
- bool added = fetch->AddExtension(id, version.GetString(), ping_days);
- DCHECK(added);
- }
- }
-
- // Calculates the value to use for the ping days parameter in manifest
- // fetches for a given extension.
- int CalculatePingDays(const std::string& extension_id) {
- int days = ManifestFetchData::kNeverPinged;
- Time last_ping_day = service_->LastPingDay(extension_id);
- if (!last_ping_day.is_null()) {
- days = (Time::Now() - last_ping_day).InDays();
- }
- return days;
- }
-
- ExtensionUpdateService* service_;
-
- // List of data on fetches we're going to do. We limit the number of
- // extensions grouped together in one batch to avoid running into the limits
- // on the length of http GET requests, so there might be multiple
- // ManifestFetchData* objects with the same base_url.
- std::multimap<GURL, ManifestFetchData*> fetches_;
-
- URLStats url_stats_;
-
- DISALLOW_COPY_AND_ASSIGN(ManifestFetchesBuilder);
-};
-
-} // namespace
-
void ExtensionUpdater::CheckNow() {
ManifestFetchesBuilder fetches_builder(service_);
@@ -699,7 +691,7 @@ void ExtensionUpdater::CheckNow() {
fetches_builder.AddPendingExtension(iter->first, iter->second);
}
- fetches_builder.url_stats().ReportStats();
+ fetches_builder.ReportStats();
std::vector<ManifestFetchData*> fetches(fetches_builder.GetFetches());
diff --git a/chrome/browser/extensions/extension_updater.h b/chrome/browser/extensions/extension_updater.h
index bd48af8..34043d6 100644
--- a/chrome/browser/extensions/extension_updater.h
+++ b/chrome/browser/extensions/extension_updater.h
@@ -78,6 +78,59 @@ class ManifestFetchData {
DISALLOW_COPY_AND_ASSIGN(ManifestFetchData);
};
+// A class for building a set of ManifestFetchData objects from
+// extensions and pending extensions.
+class ManifestFetchesBuilder {
+ public:
+ explicit ManifestFetchesBuilder(ExtensionUpdateService* service);
+
+ void AddExtension(const Extension& extension);
+
+ void AddPendingExtension(const std::string& id,
+ const PendingExtensionInfo& info);
+
+ // Adds all recorded stats taken so far to histogram counts.
+ void ReportStats() const;
+
+ // Caller takes ownership of the returned ManifestFetchData
+ // objects. Clears all recorded stats.
+ std::vector<ManifestFetchData*> GetFetches();
+
+ private:
+ struct URLStats {
+ URLStats()
+ : no_url_count(0),
+ google_url_count(0),
+ other_url_count(0),
+ theme_count(0) {}
+
+ int no_url_count, google_url_count, other_url_count, theme_count;
+ };
+
+ void AddExtensionData(Extension::Location location,
+ const std::string& id,
+ const Version& version,
+ bool converted_from_user_script,
+ bool is_theme,
+ GURL update_url);
+
+ // Calculates the value to use for the ping days parameter in manifest
+ // fetches for a given extension.
+ int CalculatePingDays(const std::string& extension_id);
+
+ ExtensionUpdateService* service_;
+
+ // List of data on fetches we're going to do. We limit the number of
+ // extensions grouped together in one batch to avoid running into the limits
+ // on the length of http GET requests, so there might be multiple
+ // ManifestFetchData* objects with the same base_url.
+ std::multimap<GURL, ManifestFetchData*> fetches_;
+
+ URLStats url_stats_;
+
+ DISALLOW_COPY_AND_ASSIGN(ManifestFetchesBuilder);
+};
+
// A class for doing auto-updates of installed Extensions. Used like this:
//
// ExtensionUpdater* updater = new ExtensionUpdater(my_extensions_service,
diff --git a/chrome/browser/extensions/extension_updater_unittest.cc b/chrome/browser/extensions/extension_updater_unittest.cc
index b613bee..4658f67 100644
--- a/chrome/browser/extensions/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/extension_updater_unittest.cc
@@ -906,6 +906,49 @@ TEST(ExtensionUpdaterTest, TestHandleManifestResults) {
ExtensionUpdaterTest::TestHandleManifestResults();
}
+TEST(ExtensionUpdaterTest, TestManifestFetchesBuilderAddExtension) {
+ MockService service;
+ ManifestFetchesBuilder builder(&service);
+
+ // Non-internal non-external extensions should be rejected.
+ {
+ ExtensionList extensions;
+ CreateTestExtensions(1, &extensions, NULL);
+ ASSERT_FALSE(extensions.empty());
+ extensions[0]->set_location(Extension::INVALID);
+ builder.AddExtension(*extensions[0]);
+ EXPECT_TRUE(builder.GetFetches().empty());
+ }
+
+ scoped_ptr<Version> version(Version::GetVersionFromString("0"));
+ ASSERT_TRUE(version.get());
+
+ // Extensions with invalid update URLs should be rejected.
+ builder.AddPendingExtension(
+ "id", PendingExtensionInfo(GURL("http:google.com:foo"),
+ *version, false, false));
+ EXPECT_TRUE(builder.GetFetches().empty());
+
+ // Extensions with empty IDs should be rejected.
+ builder.AddPendingExtension(
+ "", PendingExtensionInfo(GURL(), *version, false, false));
+ EXPECT_TRUE(builder.GetFetches().empty());
+
+ // TODO(akalin): Test that extensions with empty update URLs
+ // converted from user scripts are rejected.
+
+ // Extensions with empty update URLs should have a default one
+ // filled in.
+ builder.AddPendingExtension(
+ "id", PendingExtensionInfo(GURL(), *version, false, false));
+ std::vector<ManifestFetchData*> fetches = builder.GetFetches();
+ ASSERT_EQ(1u, fetches.size());
+ scoped_ptr<ManifestFetchData> fetch(fetches[0]);
+ fetches.clear();
+ EXPECT_FALSE(fetch->base_url().is_empty());
+ EXPECT_FALSE(fetch->full_url().is_empty());
+}
+
// TODO(asargent) - (http://crbug.com/12780) add tests for:
// -prodversionmin (shouldn't update if browser version too old)
// -manifests & updates arriving out of order / interleaved