summaryrefslogtreecommitdiffstats
path: root/extensions/browser/updater
diff options
context:
space:
mode:
authorrockot@chromium.org <rockot@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-15 05:21:17 +0000
committerrockot@chromium.org <rockot@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-15 05:24:05 +0000
commitab284123c7d60fc2888ab124816720ce99e900af (patch)
tree9451dbdf45bc4ca2905ed2026e1dc70b81a53c01 /extensions/browser/updater
parent7411a3cef00c2e6a751a20557dddbbde00ac60ff (diff)
downloadchromium_src-ab284123c7d60fc2888ab124816720ce99e900af.zip
chromium_src-ab284123c7d60fc2888ab124816720ce99e900af.tar.gz
chromium_src-ab284123c7d60fc2888ab124816720ce99e900af.tar.bz2
Factor Chrome details out of update manifest fetching.
This establishes a ManifestFetchDataDelegate for use by ExtensionDownloader and ManifestFetchData, and moves ManifestFetchData into //extensions/browser/updater. The delegate provides implementation details for update manifest fetching, including brand code, boilerplate query parameters, and ping data. Chrome's implementation has knowledge of the Google brand, the metrics service, and Omaha-specific query parameters necessary for CRX item queries. BUG=398671 Review URL: https://codereview.chromium.org/465543004 Cr-Commit-Position: refs/heads/master@{#289800} git-svn-id: svn://svn.chromium.org/chrome/trunk/src@289800 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'extensions/browser/updater')
-rw-r--r--extensions/browser/updater/manifest_fetch_data.cc165
-rw-r--r--extensions/browser/updater/manifest_fetch_data.h128
2 files changed, 293 insertions, 0 deletions
diff --git a/extensions/browser/updater/manifest_fetch_data.cc b/extensions/browser/updater/manifest_fetch_data.cc
new file mode 100644
index 0000000..1c38494
--- /dev/null
+++ b/extensions/browser/updater/manifest_fetch_data.cc
@@ -0,0 +1,165 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/updater/manifest_fetch_data.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "net/base/escape.h"
+
+namespace {
+
+// Maximum length of an extension manifest update check url, since it is a GET
+// request. We want to stay under 2K because of proxies, etc.
+const int kExtensionsManifestMaxURLSize = 2000;
+
+} // namespace
+
+namespace extensions {
+
+ManifestFetchData::ManifestFetchData(const GURL& update_url,
+ int request_id,
+ const std::string& brand_code,
+ const std::string& base_query_params,
+ PingMode ping_mode)
+ : base_url_(update_url),
+ full_url_(update_url),
+ brand_code_(brand_code),
+ ping_mode_(ping_mode) {
+ std::string query =
+ full_url_.has_query() ? full_url_.query() + "&" : std::string();
+ query += base_query_params;
+ GURL::Replacements replacements;
+ replacements.SetQueryStr(query);
+ full_url_ = full_url_.ReplaceComponents(replacements);
+
+ request_ids_.insert(request_id);
+}
+
+ManifestFetchData::~ManifestFetchData() {
+}
+
+// The format for request parameters in update checks is:
+//
+// ?x=EXT1_INFO&x=EXT2_INFO
+//
+// where EXT1_INFO and EXT2_INFO are url-encoded strings of the form:
+//
+// id=EXTENSION_ID&v=VERSION&uc
+//
+// Provide ping data with the parameter ping=PING_DATA where PING_DATA
+// looks like r=DAYS or a=DAYS for extensions in the Chrome extensions gallery.
+// ('r' refers to 'roll call' ie installation, and 'a' refers to 'active').
+// These values will each be present at most once every 24 hours, and indicate
+// the number of days since the last time it was present in an update check.
+//
+// So for two extensions like:
+// Extension 1- id:aaaa version:1.1
+// Extension 2- id:bbbb version:2.0
+//
+// the full update url would be:
+// http://somehost/path?x=id%3Daaaa%26v%3D1.1%26uc&x=id%3Dbbbb%26v%3D2.0%26uc
+//
+// (Note that '=' is %3D and '&' is %26 when urlencoded.)
+bool ManifestFetchData::AddExtension(const std::string& id,
+ const std::string& version,
+ const PingData* ping_data,
+ const std::string& update_url_data,
+ const std::string& install_source) {
+ if (extension_ids_.find(id) != extension_ids_.end()) {
+ NOTREACHED() << "Duplicate extension id " << id;
+ return false;
+ }
+
+ // Compute the string we'd append onto the full_url_, and see if it fits.
+ std::vector<std::string> parts;
+ parts.push_back("id=" + id);
+ parts.push_back("v=" + version);
+ if (!install_source.empty())
+ parts.push_back("installsource=" + install_source);
+ parts.push_back("uc");
+
+ if (!update_url_data.empty()) {
+ // Make sure the update_url_data string is escaped before using it so that
+ // there is no chance of overriding the id or v other parameter value
+ // we place into the x= value.
+ parts.push_back("ap=" + net::EscapeQueryParamValue(update_url_data, true));
+ }
+
+ // Append brand code, rollcall and active ping parameters.
+ if (ping_mode_ != NO_PING) {
+ if (!brand_code_.empty())
+ parts.push_back(base::StringPrintf("brand=%s", brand_code_.c_str()));
+
+ std::string ping_value;
+ pings_[id] = PingData(0, 0, false);
+ if (ping_data) {
+ if (ping_data->rollcall_days == kNeverPinged ||
+ ping_data->rollcall_days > 0) {
+ ping_value += "r=" + base::IntToString(ping_data->rollcall_days);
+ if (ping_mode_ == PING_WITH_METRICS) {
+ ping_value += "&e=" + std::string(ping_data->is_enabled ? "1" : "0");
+ }
+ pings_[id].rollcall_days = ping_data->rollcall_days;
+ pings_[id].is_enabled = ping_data->is_enabled;
+ }
+ if (ping_data->active_days == kNeverPinged ||
+ ping_data->active_days > 0) {
+ if (!ping_value.empty())
+ ping_value += "&";
+ ping_value += "a=" + base::IntToString(ping_data->active_days);
+ pings_[id].active_days = ping_data->active_days;
+ }
+ }
+ if (!ping_value.empty())
+ parts.push_back("ping=" + net::EscapeQueryParamValue(ping_value, true));
+ }
+
+ std::string extra = full_url_.has_query() ? "&" : "?";
+ extra += "x=" + net::EscapeQueryParamValue(JoinString(parts, '&'), true);
+
+ // Check against our max url size, exempting the first extension added.
+ int new_size = full_url_.possibly_invalid_spec().size() + extra.size();
+ if (!extension_ids_.empty() && new_size > kExtensionsManifestMaxURLSize) {
+ UMA_HISTOGRAM_PERCENTAGE("Extensions.UpdateCheckHitUrlSizeLimit", 1);
+ return false;
+ }
+ UMA_HISTOGRAM_PERCENTAGE("Extensions.UpdateCheckHitUrlSizeLimit", 0);
+
+ // We have room so go ahead and add the extension.
+ extension_ids_.insert(id);
+ full_url_ = GURL(full_url_.possibly_invalid_spec() + extra);
+ return true;
+}
+
+bool ManifestFetchData::Includes(const std::string& extension_id) const {
+ return extension_ids_.find(extension_id) != extension_ids_.end();
+}
+
+bool ManifestFetchData::DidPing(const std::string& extension_id,
+ PingType type) const {
+ std::map<std::string, PingData>::const_iterator i = pings_.find(extension_id);
+ if (i == pings_.end())
+ return false;
+ int value = 0;
+ if (type == ROLLCALL)
+ value = i->second.rollcall_days;
+ else if (type == ACTIVE)
+ value = i->second.active_days;
+ else
+ NOTREACHED();
+ return value == kNeverPinged || value > 0;
+}
+
+void ManifestFetchData::Merge(const ManifestFetchData& other) {
+ DCHECK(full_url() == other.full_url());
+ request_ids_.insert(other.request_ids_.begin(), other.request_ids_.end());
+}
+
+} // namespace extensions
diff --git a/extensions/browser/updater/manifest_fetch_data.h b/extensions/browser/updater/manifest_fetch_data.h
new file mode 100644
index 0000000..49f91b6
--- /dev/null
+++ b/extensions/browser/updater/manifest_fetch_data.h
@@ -0,0 +1,128 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_UPDATER_MANIFEST_FETCH_DATA_H_
+#define EXTENSIONS_BROWSER_UPDATER_MANIFEST_FETCH_DATA_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+// To save on server resources we can request updates for multiple extensions
+// in one manifest check. This class helps us keep track of the id's for a
+// given fetch, building up the actual URL, and what if anything to include
+// in the ping parameter.
+class ManifestFetchData {
+ public:
+ static const int kNeverPinged = -1;
+
+ // What ping mode this fetch should use.
+ enum PingMode {
+ // No ping, no extra metrics.
+ NO_PING,
+
+ // Ping without extra metrics.
+ PING,
+
+ // Ping with extra metrics.
+ PING_WITH_METRICS,
+ };
+
+ // Each ping type is sent at most once per day.
+ enum PingType {
+ // Used for counting total installs of an extension/app/theme.
+ ROLLCALL,
+
+ // Used for counting number of active users of an app, where "active" means
+ // the app was launched at least once since the last active ping.
+ ACTIVE,
+ };
+
+ struct PingData {
+ // The number of days it's been since our last rollcall or active ping,
+ // respectively. These are calculated based on the start of day from the
+ // server's perspective.
+ int rollcall_days;
+ int active_days;
+ // Wether the extension is enabled or not.
+ bool is_enabled;
+
+ PingData() : rollcall_days(0), active_days(0), is_enabled(true) {}
+ PingData(int rollcall, int active, bool enabled)
+ : rollcall_days(rollcall), active_days(active), is_enabled(enabled) {}
+ };
+
+ ManifestFetchData(const GURL& update_url,
+ int request_id,
+ const std::string& brand_code,
+ const std::string& base_query_params,
+ PingMode ping_mode);
+ ~ManifestFetchData();
+
+ // Returns true if this extension information was successfully added. If the
+ // return value is false it means the full_url would have become too long, and
+ // this ManifestFetchData object remains unchanged.
+ bool AddExtension(const std::string& id,
+ const std::string& version,
+ const PingData* ping_data,
+ const std::string& update_url_data,
+ const std::string& install_source);
+
+ const GURL& base_url() const { return base_url_; }
+ const GURL& full_url() const { return full_url_; }
+ const std::set<std::string>& extension_ids() const { return extension_ids_; }
+ const std::set<int>& request_ids() const { return request_ids_; }
+
+ // Returns true if the given id is included in this manifest fetch.
+ bool Includes(const std::string& extension_id) const;
+
+ // Returns true if a ping parameter for |type| was added to full_url for this
+ // extension id.
+ bool DidPing(const std::string& extension_id, PingType type) const;
+
+ // Assuming that both this ManifestFetchData and |other| have the same
+ // full_url, this method merges the other information associated with the
+ // fetch (in particular this adds all request ids associated with |other|
+ // to this ManifestFetchData).
+ void Merge(const ManifestFetchData& other);
+
+ private:
+ // The set of extension id's for this ManifestFetchData.
+ std::set<std::string> extension_ids_;
+
+ // The set of ping data we actually sent.
+ std::map<std::string, PingData> pings_;
+
+ // The base update url without any arguments added.
+ GURL base_url_;
+
+ // The base update url plus arguments indicating the id, version, etc.
+ // information about each extension.
+ GURL full_url_;
+
+ // The set of request ids associated with this manifest fetch. If multiple
+ // requests are trying to fetch the same manifest, they can be merged into
+ // one fetch, so potentially multiple request ids can get associated with
+ // one ManifestFetchData.
+ std::set<int> request_ids_;
+
+ // The brand code to include with manifest fetch queries, if non-empty and
+ // |ping_mode_| >= PING.
+ const std::string brand_code_;
+
+ // The ping mode for this fetch. This determines whether or not ping data
+ // (and possibly extra metrics) will be included in the fetch query.
+ const PingMode ping_mode_;
+
+ DISALLOW_COPY_AND_ASSIGN(ManifestFetchData);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_UPDATER_MANIFEST_FETCH_DATA_H_