extension_updater.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_updater.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h"
12731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/rand_util.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/sha2.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/stl_util-inl.h"
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_split.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/thread.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/version.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_error_reporter.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extensions_service.h"
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/utility_process_host.h"
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_version_info.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h"
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_constants.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/escape.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/load_flags.h"
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_status.h"
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(OS_MACOSX)
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/sys_string_conversions.h"
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::RandDouble;
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::RandInt;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time;
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing prefs::kExtensionBlacklistUpdateVersion;
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing prefs::kLastExtensionsUpdateCheck;
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing prefs::kNextExtensionsUpdateCheck;
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// NOTE: HTTPS is used here to ensure the response from omaha can be trusted.
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The response contains a url for fetching the blacklist and a hash value
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// for validation.
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* ExtensionUpdater::kBlacklistUpdateUrl =
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    "https://clients2.google.com/service/update2/crx";
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Update AppID for extension blacklist.
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* ExtensionUpdater::kBlacklistAppID = "com.google.crx.blacklist";
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Wait at least 5 minutes after browser startup before we do any checks. If you
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// change this value, make sure to update comments where it is used.
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kStartupWaitSeconds = 60 * 5;
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// For sanity checking on update frequency - enforced in release mode only.
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kMinUpdateFrequencySeconds = 30;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7;  // 7 days
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Maximum length of an extension manifest update check url, since it is a GET
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// request. We want to stay under 2K because of proxies, etc.
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kExtensionsManifestMaxURLSize = 2000;
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71513209b27ff55e2841eac0e4120199c23acce758Ben MurdochManifestFetchData::ManifestFetchData(const GURL& update_url)
72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    : base_url_(update_url),
73731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      full_url_(update_url) {
74731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
75731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
76731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickManifestFetchData::~ManifestFetchData() {}
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The format for request parameters in update checks is:
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   ?x=EXT1_INFO&x=EXT2_INFO
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// where EXT1_INFO and EXT2_INFO are url-encoded strings of the form:
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   id=EXTENSION_ID&v=VERSION&uc
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Additionally, we may include the parameter ping=PING_DATA where PING_DATA
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// looks like r=DAYS for extensions in the Chrome extensions gallery. This value
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// will be present at most once every 24 hours, and indicate the number of days
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// since the last time it was present in an update check.
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// So for two extensions like:
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   Extension 1- id:aaaa version:1.1
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   Extension 2- id:bbbb version:2.0
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the full update url would be:
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   http://somehost/path?x=id%3Daaaa%26v%3D1.1%26uc&x=id%3Dbbbb%26v%3D2.0%26uc
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// (Note that '=' is %3D and '&' is %26 when urlencoded.)
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ManifestFetchData::AddExtension(std::string id, std::string version,
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     int days) {
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (extension_ids_.find(id) != extension_ids_.end()) {
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED() << "Duplicate extension id " << id;
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Compute the string we'd append onto the full_url_, and see if it fits.
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<std::string> parts;
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  parts.push_back("id=" + id);
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  parts.push_back("v=" + version);
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  parts.push_back("uc");
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (ShouldPing(days)) {
1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    parts.push_back("ping=" +
1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        EscapeQueryParamValue("r=" + base::IntToString(days), true));
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string extra = full_url_.has_query() ? "&" : "?";
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  extra += "x=" + EscapeQueryParamValue(JoinString(parts, '&'), true);
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check against our max url size, exempting the first extension added.
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int new_size = full_url_.possibly_invalid_spec().size() + extra.size();
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (extension_ids_.size() > 0 && new_size > kExtensionsManifestMaxURLSize) {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_PERCENTAGE("Extensions.UpdateCheckHitUrlSizeLimit", 1);
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_PERCENTAGE("Extensions.UpdateCheckHitUrlSizeLimit", 0);
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We have room so go ahead and add the extension.
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  extension_ids_.insert(id);
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ping_days_[id] = days;
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  full_url_ = GURL(full_url_.possibly_invalid_spec() + extra);
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
135731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ManifestFetchData::Includes(std::string extension_id) const {
136731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return extension_ids_.find(extension_id) != extension_ids_.end();
137731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
138731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ManifestFetchData::DidPing(std::string extension_id) const {
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<std::string, int>::const_iterator i = ping_days_.find(extension_id);
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (i != ping_days_.end()) {
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ShouldPing(i->second);
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ManifestFetchData::ShouldPing(int days) const {
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return base_url_.DomainIs("google.com") &&
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         (days == kNeverPinged || days > 0);
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Calculates the value to use for the ping days parameter.
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic int CalculatePingDays(const Time& last_ping_day) {
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int days = ManifestFetchData::kNeverPinged;
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!last_ping_day.is_null()) {
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    days = (Time::Now() - last_ping_day).InDays();
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return days;
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochManifestFetchesBuilder::ManifestFetchesBuilder(
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExtensionUpdateService* service) : service_(service) {
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(service_);
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
170731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickManifestFetchesBuilder::~ManifestFetchesBuilder() {}
171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ManifestFetchesBuilder::AddExtension(const Extension& extension) {
1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Skip extensions with empty update URLs converted from user
1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // scripts.
1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (extension.converted_from_user_script() &&
1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      extension.update_url().is_empty()) {
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddExtensionData(extension.location(),
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   extension.id(),
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   *extension.version(),
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   (extension.is_theme() ? PendingExtensionInfo::THEME
1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                         : PendingExtensionInfo::EXTENSION),
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   extension.update_url());
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ManifestFetchesBuilder::AddPendingExtension(
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& id,
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const PendingExtensionInfo& info) {
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Use a zero version to ensure that a pending extension will always
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // be updated, and thus installed (assuming all extensions have
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // non-zero versions).
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<Version> version(
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Version::GetVersionFromString("0.0.0.0"));
1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
197731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AddExtensionData(info.install_source, id, *version,
1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   info.expected_crx_type, info.update_url);
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ManifestFetchesBuilder::ReportStats() const {
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtensions",
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           url_stats_.google_url_count +
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           url_stats_.other_url_count -
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           url_stats_.theme_count);
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckTheme",
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           url_stats_.theme_count);
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckGoogleUrl",
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           url_stats_.google_url_count);
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckOtherUrl",
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           url_stats_.other_url_count);
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckNoUrl",
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           url_stats_.no_url_count);
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::vector<ManifestFetchData*> ManifestFetchesBuilder::GetFetches() {
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<ManifestFetchData*> fetches;
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  fetches.reserve(fetches_.size());
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::multimap<GURL, ManifestFetchData*>::iterator it =
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           fetches_.begin(); it != fetches_.end(); ++it) {
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    fetches.push_back(it->second);
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  fetches_.clear();
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  url_stats_ = URLStats();
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return fetches;
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ManifestFetchesBuilder::AddExtensionData(
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Extension::Location location,
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& id,
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const Version& version,
2323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    PendingExtensionInfo::ExpectedCrxType crx_type,
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL update_url) {
2343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
235513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!Extension::IsAutoUpdateableLocation(location)) {
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Skip extensions with non-empty invalid update URLs.
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!update_url.is_empty() && !update_url.is_valid()) {
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Extension " << id << " has invalid update url "
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 << update_url;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Skip extensions with empty IDs.
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (id.empty()) {
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Found extension with empty ID";
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_url.DomainIs("google.com")) {
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_stats_.google_url_count++;
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (update_url.is_empty()) {
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_stats_.no_url_count++;
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Fill in default update URL.
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(akalin): Figure out if we should use the HTTPS version.
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    update_url = GURL(extension_urls::kGalleryUpdateHttpUrl);
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_stats_.other_url_count++;
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (crx_type == PendingExtensionInfo::THEME) {
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_stats_.theme_count++;
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!update_url.is_empty());
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(update_url.is_valid());
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ManifestFetchData* fetch = NULL;
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::multimap<GURL, ManifestFetchData*>::iterator existing_iter =
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      fetches_.find(update_url);
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Find or create a ManifestFetchData to add this extension to.
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int ping_days =
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CalculatePingDays(service_->extension_prefs()->LastPingDay(id));
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (existing_iter != fetches_.end()) {
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (existing_iter->second->AddExtension(id, version.GetString(),
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            ping_days)) {
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      fetch = existing_iter->second;
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    existing_iter++;
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!fetch) {
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    fetch = new ManifestFetchData(update_url);
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    fetches_.insert(std::pair<GURL, ManifestFetchData*>(update_url, fetch));
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool added = fetch->AddExtension(id, version.GetString(), ping_days);
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(added);
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A utility class to do file handling on the file I/O thread.
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass ExtensionUpdaterFileHandler
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : public base::RefCountedThreadSafe<ExtensionUpdaterFileHandler> {
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Writes crx file data into a tempfile, and calls back the updater.
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void WriteTempFile(const std::string& extension_id, const std::string& data,
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     const GURL& download_url,
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     scoped_refptr<ExtensionUpdater> updater) {
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Make sure we're running in the right thread.
303731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FilePath path;
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!file_util::CreateTemporaryFile(&path)) {
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(WARNING) << "Failed to create temporary file path";
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (file_util::WriteFile(path, data.c_str(), data.length()) !=
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        static_cast<int>(data.length())) {
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // TODO(asargent) - It would be nice to back off updating alltogether if
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // the disk is full. (http://crbug.com/12763).
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "Failed to write temporary file";
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      file_util::Delete(path, false);
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The ExtensionUpdater now owns the temp file.
320731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(
321731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::UI, FROM_HERE,
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NewRunnableMethod(
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            updater.get(), &ExtensionUpdater::OnCRXFileWritten, extension_id,
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            path, download_url));
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  friend class base::RefCountedThreadSafe<ExtensionUpdaterFileHandler>;
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~ExtensionUpdaterFileHandler() {}
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExtensionUpdater::ExtensionUpdater(ExtensionUpdateService* service,
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   PrefService* prefs,
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   int frequency_seconds)
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : service_(service), frequency_seconds_(frequency_seconds),
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      prefs_(prefs), file_handler_(new ExtensionUpdaterFileHandler()),
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      blacklist_checks_enabled_(true) {
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Init();
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::Init() {
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GE(frequency_seconds_, 5);
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(frequency_seconds_ <= kMaxUpdateFrequencySeconds);
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#ifdef NDEBUG
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // In Release mode we enforce that update checks don't happen too often.
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds);
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds);
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExtensionUpdater::~ExtensionUpdater() {
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  STLDeleteElements(&manifests_pending_);
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void EnsureInt64PrefRegistered(PrefService* prefs,
3573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                      const char name[]) {
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!prefs->FindPreference(name))
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    prefs->RegisterInt64Pref(name, 0);
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void EnsureBlacklistVersionPrefRegistered(PrefService* prefs) {
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!prefs->FindPreference(kExtensionBlacklistUpdateVersion))
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    prefs->RegisterStringPref(kExtensionBlacklistUpdateVersion, "0");
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The overall goal here is to balance keeping clients up to date while
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// avoiding a thundering herd against update servers.
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTimeDelta ExtensionUpdater::DetermineFirstCheckDelay() {
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If someone's testing with a quick frequency, just allow it.
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (frequency_seconds_ < kStartupWaitSeconds)
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return TimeDelta::FromSeconds(frequency_seconds_);
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we've never scheduled a check before, start at frequency_seconds_.
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!prefs_->HasPrefPath(kNextExtensionsUpdateCheck))
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return TimeDelta::FromSeconds(frequency_seconds_);
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If it's been a long time since our last actual check, we want to do one
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // relatively soon.
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time now = Time::Now();
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time last = Time::FromInternalValue(prefs_->GetInt64(
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kLastExtensionsUpdateCheck));
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int days = (now - last).InDays();
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (days >= 30) {
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Wait 5-10 minutes.
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          kStartupWaitSeconds * 2));
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (days >= 14) {
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Wait 10-20 minutes.
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 2,
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          kStartupWaitSeconds * 4));
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (days >= 3) {
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Wait 20-40 minutes.
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 4,
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          kStartupWaitSeconds * 8));
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Read the persisted next check time, and use that if it isn't too soon.
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Otherwise pick something random.
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time saved_next = Time::FromInternalValue(prefs_->GetInt64(
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kNextExtensionsUpdateCheck));
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time earliest = now + TimeDelta::FromSeconds(kStartupWaitSeconds);
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (saved_next >= earliest) {
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return saved_next - now;
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          frequency_seconds_));
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::Start() {
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure our prefs are registered, then schedule the first check.
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EnsureInt64PrefRegistered(prefs_, kLastExtensionsUpdateCheck);
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EnsureInt64PrefRegistered(prefs_, kNextExtensionsUpdateCheck);
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EnsureBlacklistVersionPrefRegistered(prefs_);
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleNextCheck(DetermineFirstCheckDelay());
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::Stop() {
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  timer_.Stop();
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  manifest_fetcher_.reset();
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  extension_fetcher_.reset();
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  manifests_pending_.clear();
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  extensions_pending_.clear();
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::OnURLFetchComplete(
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const URLFetcher* source, const GURL& url, const URLRequestStatus& status,
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int response_code, const ResponseCookies& cookies,
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& data) {
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (source == manifest_fetcher_.get()) {
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnManifestFetchComplete(url, status, response_code, data);
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (source == extension_fetcher_.get()) {
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnCRXFetchComplete(url, status, response_code, data);
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Utility class to handle doing xml parsing in a sandboxed utility process.
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass SafeManifestParser : public UtilityProcessHost::Client {
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Takes ownership of |fetch_data|.
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SafeManifestParser(const std::string& xml, ManifestFetchData* fetch_data,
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     ExtensionUpdater* updater)
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : xml_(xml), updater_(updater) {
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    fetch_data_.reset(fetch_data);
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Posts a task over to the IO loop to start the parsing of xml_ in a
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // utility process.
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Start() {
453731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
454731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(
455731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::IO, FROM_HERE,
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NewRunnableMethod(
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            this, &SafeManifestParser::ParseInSandbox,
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            g_browser_process->resource_dispatcher_host()));
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Creates the sandboxed utility process and tells it to start parsing.
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void ParseInSandbox(ResourceDispatcherHost* rdh) {
463731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(asargent) we shouldn't need to do this branch here - instead
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // UtilityProcessHost should handle it for us. (http://crbug.com/19192)
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool use_utility_process = rdh &&
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (use_utility_process) {
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UtilityProcessHost* host = new UtilityProcessHost(
471731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          rdh, this, BrowserThread::UI);
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      host->StartUpdateManifestParse(xml_);
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UpdateManifest manifest;
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (manifest.Parse(xml_)) {
476731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::PostTask(
477731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick            BrowserThread::UI, FROM_HERE,
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            NewRunnableMethod(
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                this, &SafeManifestParser::OnParseUpdateManifestSucceeded,
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                manifest.results()));
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
482731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::PostTask(
483731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick            BrowserThread::UI, FROM_HERE,
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            NewRunnableMethod(
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                this, &SafeManifestParser::OnParseUpdateManifestFailed,
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                manifest.errors()));
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Callback from the utility process when parsing succeeded.
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnParseUpdateManifestSucceeded(
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const UpdateManifest::Results& results) {
494731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    updater_->HandleManifestResults(*fetch_data_, results);
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Callback from the utility process when parsing failed.
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnParseUpdateManifestFailed(const std::string& error_message) {
500731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Error parsing update manifest:\n" << error_message;
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~SafeManifestParser() {}
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string& xml_;
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<ManifestFetchData> fetch_data_;
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<ExtensionUpdater> updater_;
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::OnManifestFetchComplete(const GURL& url,
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               const URLRequestStatus& status,
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               int response_code,
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               const std::string& data) {
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We want to try parsing the manifest, and if it indicates updates are
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // available, we want to fire off requests to fetch those updates.
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (status.status() == URLRequestStatus::SUCCESS && response_code == 200) {
521513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    scoped_refptr<SafeManifestParser> safe_parser(
522513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        new SafeManifestParser(data, current_manifest_fetch_.release(), this));
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    safe_parser->Start();
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(asargent) Do exponential backoff here. (http://crbug.com/12546).
526513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    VLOG(1) << "Failed to fetch manifest '" << url.possibly_invalid_spec()
527513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch            << "' response code:" << response_code;
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  manifest_fetcher_.reset();
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  current_manifest_fetch_.reset();
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we have any pending manifest requests, fire off the next one.
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!manifests_pending_.empty()) {
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ManifestFetchData* manifest_fetch = manifests_pending_.front();
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    manifests_pending_.pop_front();
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    StartUpdateCheck(manifest_fetch);
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::HandleManifestResults(
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ManifestFetchData& fetch_data,
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const UpdateManifest::Results& results) {
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Examine the parsed manifest and kick off fetches of any new crx files.
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<int> updates = DetermineUpdates(fetch_data, results);
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < updates.size(); i++) {
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const UpdateManifest::Result* update = &(results.list.at(updates[i]));
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FetchUpdatedExtension(update->extension_id, update->crx_url,
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        update->package_hash, update->version);
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the manifest response included a <daystart> element, we want to save
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // that value for any extensions which had sent ping_days in the request.
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (fetch_data.base_url().DomainIs("google.com") &&
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      results.daystart_elapsed_seconds >= 0) {
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Time daystart =
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Time::Now() - TimeDelta::FromSeconds(results.daystart_elapsed_seconds);
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::set<std::string>& extension_ids = fetch_data.extension_ids();
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::set<std::string>::const_iterator i;
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (i = extension_ids.begin(); i != extension_ids.end(); i++) {
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bool did_ping = fetch_data.DidPing(*i);
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (did_ping) {
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (*i == kBlacklistAppID) {
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          service_->extension_prefs()->SetBlacklistLastPingDay(daystart);
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        } else if (service_->GetExtensionById(*i, true) != NULL) {
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          service_->extension_prefs()->SetLastPingDay(*i, daystart);
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::ProcessBlacklist(const std::string& data) {
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Verify sha256 hash value.
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  char sha256_hash_value[base::SHA256_LENGTH];
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::SHA256HashString(data, sha256_hash_value, base::SHA256_LENGTH);
5783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string hash_in_hex = base::HexEncode(sha256_hash_value,
5793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                            base::SHA256_LENGTH);
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (current_extension_fetch_.package_hash != hash_in_hex) {
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED() << "Fetched blacklist checksum is not as expected. "
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << "Expected: " << current_extension_fetch_.package_hash
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << " Actual: " << hash_in_hex;
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<std::string> blacklist;
588731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  base::SplitString(data, '\n', &blacklist);
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Tell ExtensionService to update prefs.
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  service_->UpdateExtensionBlacklist(blacklist);
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Update the pref value for blacklist version
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs_->SetString(kExtensionBlacklistUpdateVersion,
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    current_extension_fetch_.version);
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs_->ScheduleSavePersistentPrefs();
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::OnCRXFetchComplete(const GURL& url,
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const URLRequestStatus& status,
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          int response_code,
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const std::string& data) {
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (status.status() == URLRequestStatus::SUCCESS &&
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      response_code == 200) {
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (current_extension_fetch_.id == kBlacklistAppID) {
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ProcessBlacklist(data);
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Successfully fetched - now write crx to a file so we can have the
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // ExtensionsService install it.
610731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
611731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::FILE, FROM_HERE,
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NewRunnableMethod(
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              file_handler_.get(), &ExtensionUpdaterFileHandler::WriteTempFile,
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              current_extension_fetch_.id, data, url,
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              make_scoped_refptr(this)));
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(asargent) do things like exponential backoff, handling
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // 503 Service Unavailable / Retry-After headers, etc. here.
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // (http://crbug.com/12546).
621513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec()
622513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch            << "' response code:" << response_code;
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  extension_fetcher_.reset();
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  current_extension_fetch_ = ExtensionFetch();
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If there are any pending downloads left, start one.
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (extensions_pending_.size() > 0) {
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExtensionFetch next = extensions_pending_.front();
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    extensions_pending_.pop_front();
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FetchUpdatedExtension(next.id, next.url, next.package_hash, next.version);
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::OnCRXFileWritten(const std::string& id,
636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const FilePath& path,
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const GURL& download_url) {
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The ExtensionsService is now responsible for cleaning up the temp file
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // at |path|.
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  service_->UpdateExtension(id, path, download_url);
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) {
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!timer_.IsRunning());
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(target_delay >= TimeDelta::FromSeconds(1));
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add +/- 10% random jitter.
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  double delay_ms = target_delay.InMillisecondsF();
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  double jitter_factor = (RandDouble() * .2) - 0.1;
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delay_ms += delay_ms * jitter_factor;
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TimeDelta actual_delay = TimeDelta::FromMilliseconds(
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      static_cast<int64>(delay_ms));
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Save the time of next check.
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time next = Time::Now() + actual_delay;
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs_->SetInt64(kNextExtensionsUpdateCheck, next.ToInternalValue());
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs_->ScheduleSavePersistentPrefs();
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  timer_.Start(actual_delay, this, &ExtensionUpdater::TimerFired);
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::TimerFired() {
664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CheckNow();
665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the user has overridden the update frequency, don't bother reporting
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // this.
668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (frequency_seconds_ == ExtensionsService::kDefaultUpdateFrequencySeconds) {
669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Time last = Time::FromInternalValue(prefs_->GetInt64(
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        kLastExtensionsUpdateCheck));
671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (last.ToInternalValue() != 0) {
672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Use counts rather than time so we can use minutes rather than millis.
673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.UpdateCheckGap",
674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          (Time::Now() - last).InMinutes(),
675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          base::TimeDelta::FromSeconds(kStartupWaitSeconds).InMinutes(),
676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          base::TimeDelta::FromDays(40).InMinutes(),
677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          50);  // 50 buckets seems to be the default.
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Save the last check time, and schedule the next check.
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 now = Time::Now().ToInternalValue();
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs_->SetInt64(kLastExtensionsUpdateCheck, now);
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScheduleNextCheck(TimeDelta::FromSeconds(frequency_seconds_));
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::CheckNow() {
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ManifestFetchesBuilder fetches_builder(service_);
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const ExtensionList* extensions = service_->extensions();
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (ExtensionList::const_iterator iter = extensions->begin();
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       iter != extensions->end(); ++iter) {
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    fetches_builder.AddExtension(**iter);
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const PendingExtensionMap& pending_extensions =
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      service_->pending_extensions();
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (PendingExtensionMap::const_iterator iter = pending_extensions.begin();
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       iter != pending_extensions.end(); ++iter) {
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    fetches_builder.AddPendingExtension(iter->first, iter->second);
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  fetches_builder.ReportStats();
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<ManifestFetchData*> fetches(fetches_builder.GetFetches());
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Start a fetch of the blacklist if needed.
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (blacklist_checks_enabled_ && service_->HasInstalledExtensions()) {
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ManifestFetchData* blacklist_fetch =
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new ManifestFetchData(GURL(kBlacklistUpdateUrl));
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string version = prefs_->GetString(kExtensionBlacklistUpdateVersion);
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int ping_days =
713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        CalculatePingDays(service_->extension_prefs()->BlacklistLastPingDay());
714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    blacklist_fetch->AddExtension(kBlacklistAppID, version, ping_days);
715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    StartUpdateCheck(blacklist_fetch);
716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now start fetching regular extension updates
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<ManifestFetchData*>::const_iterator it = fetches.begin();
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       it != fetches.end(); ++it) {
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // StartUpdateCheck makes sure the url isn't already downloading or
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // scheduled, so we don't need to check before calling it. Ownership of
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // fetch is transferred here.
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    StartUpdateCheck(*it);
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't want to use fetches after this since StartUpdateCheck()
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // takes ownership of its argument.
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  fetches.clear();
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExtensionUpdater::GetExistingVersion(const std::string& id,
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          std::string* version) {
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (id == kBlacklistAppID) {
734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *version = prefs_->GetString(kExtensionBlacklistUpdateVersion);
735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
737513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const Extension* extension = service_->GetExtensionById(id, false);
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!extension) {
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *version = extension->version()->GetString();
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::vector<int> ExtensionUpdater::DetermineUpdates(
746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const ManifestFetchData& fetch_data,
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const UpdateManifest::Results& possible_updates) {
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<int> result;
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This will only get set if one of possible_updates specifies
751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // browser_min_version.
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<Version> browser_version;
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < possible_updates.list.size(); i++) {
755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const UpdateManifest::Result* update = &possible_updates.list[i];
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!fetch_data.Includes(update->extension_id))
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (service_->pending_extensions().find(update->extension_id) ==
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        service_->pending_extensions().end()) {
762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // If we're not installing pending extension, and the update
763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // version is the same or older than what's already installed,
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // we don't want it.
765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::string version;
766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!GetExistingVersion(update->extension_id, &version))
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      scoped_ptr<Version> existing_version(
770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          Version::GetVersionFromString(version));
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      scoped_ptr<Version> update_version(
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          Version::GetVersionFromString(update->version));
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!update_version.get() ||
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          update_version->CompareTo(*(existing_version.get())) <= 0) {
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the update specifies a browser minimum version, do we qualify?
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (update->browser_min_version.length() > 0) {
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // First determine the browser version if we haven't already.
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!browser_version.get()) {
7843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        chrome::VersionInfo version_info;
7853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (version_info.is_valid()) {
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          browser_version.reset(Version::GetVersionFromString(
7873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                    version_info.Version()));
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      scoped_ptr<Version> browser_min_version(
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          Version::GetVersionFromString(update->browser_min_version));
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (browser_version.get() && browser_min_version.get() &&
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          browser_min_version->CompareTo(*browser_version.get()) > 0) {
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // TODO(asargent) - We may want this to show up in the extensions UI
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // eventually. (http://crbug.com/12547).
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LOG(WARNING) << "Updated version of extension " << update->extension_id
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          << " available, but requires chrome version "
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          << update->browser_min_version;
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result.push_back(i);
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::StartUpdateCheck(ManifestFetchData* fetch_data) {
8093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (CommandLine::ForCurrentProcess()->HasSwitch(
8103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      switches::kDisableBackgroundNetworking))
8113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
8123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::deque<ManifestFetchData*>::const_iterator i;
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (i = manifests_pending_.begin(); i != manifests_pending_.end(); i++) {
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (fetch_data->full_url() == (*i)->full_url()) {
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // This url is already scheduled to be fetched.
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delete fetch_data;
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (manifest_fetcher_.get() != NULL) {
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (manifest_fetcher_->url() != fetch_data->full_url()) {
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      manifests_pending_.push_back(fetch_data);
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_COUNTS("Extensions.UpdateCheckUrlLength",
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        fetch_data->full_url().possibly_invalid_spec().length());
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    current_manifest_fetch_.reset(fetch_data);
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    manifest_fetcher_.reset(
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        URLFetcher::Create(kManifestFetcherId, fetch_data->full_url(),
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           URLFetcher::GET, this));
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    manifest_fetcher_->set_request_context(Profile::GetDefaultRequestContext());
835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    manifest_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES |
836513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                      net::LOAD_DO_NOT_SAVE_COOKIES |
837513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                      net::LOAD_DISABLE_CACHE);
838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    manifest_fetcher_->Start();
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::FetchUpdatedExtension(const std::string& id,
843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             const GURL& url,
844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             const std::string& hash,
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             const std::string& version) {
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::deque<ExtensionFetch>::const_iterator iter =
847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           extensions_pending_.begin();
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       iter != extensions_pending_.end(); ++iter) {
849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (iter->id == id || iter->url == url) {
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;  // already scheduled
851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (extension_fetcher_.get() != NULL) {
855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (extension_fetcher_->url() != url) {
856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      extensions_pending_.push_back(ExtensionFetch(id, url, hash, version));
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    extension_fetcher_.reset(
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        URLFetcher::Create(kExtensionFetcherId, url, URLFetcher::GET, this));
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    extension_fetcher_->set_request_context(
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Profile::GetDefaultRequestContext());
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    extension_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES |
864513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                       net::LOAD_DO_NOT_SAVE_COOKIES |
865513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                       net::LOAD_DISABLE_CACHE);
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    extension_fetcher_->Start();
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    current_extension_fetch_ = ExtensionFetch(id, url, hash, version);
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
870