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