172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 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 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/compiler_specific.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h" 13731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/rand_util.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" 203f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/version.h" 22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/sha2.h" 23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_error_reporter.h" 2621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/extensions/extension_service.h" 273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h" 2821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/utility_process_host.h" 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h" 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_version_info.h" 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h" 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_constants.h" 34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/extensions/extension_file_util.h" 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h" 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h" 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/escape.h" 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/load_flags.h" 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_status.h" 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(OS_MACOSX) 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/sys_string_conversions.h" 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define SEND_ACTIVE_PINGS 1 46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::RandDouble; 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::RandInt; 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time; 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta; 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing prefs::kExtensionBlacklistUpdateVersion; 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing prefs::kLastExtensionsUpdateCheck; 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing prefs::kNextExtensionsUpdateCheck; 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Update AppID for extension blacklist. 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* ExtensionUpdater::kBlacklistAppID = "com.google.crx.blacklist"; 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Wait at least 5 minutes after browser startup before we do any checks. If you 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// change this value, make sure to update comments where it is used. 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kStartupWaitSeconds = 60 * 5; 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// For sanity checking on update frequency - enforced in release mode only. 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kMinUpdateFrequencySeconds = 30; 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Maximum length of an extension manifest update check url, since it is a GET 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// request. We want to stay under 2K because of proxies, etc. 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kExtensionsManifestMaxURLSize = 2000; 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 70513209b27ff55e2841eac0e4120199c23acce758Ben MurdochManifestFetchData::ManifestFetchData(const GURL& update_url) 71731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick : base_url_(update_url), 72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick full_url_(update_url) { 73731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 74731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 75731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickManifestFetchData::~ManifestFetchData() {} 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The format for request parameters in update checks is: 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// ?x=EXT1_INFO&x=EXT2_INFO 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// where EXT1_INFO and EXT2_INFO are url-encoded strings of the form: 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// id=EXTENSION_ID&v=VERSION&uc 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Additionally, we may include the parameter ping=PING_DATA where PING_DATA 86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// looks like r=DAYS or a=DAYS for extensions in the Chrome extensions gallery. 87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// ('r' refers to 'roll call' ie installation, and 'a' refers to 'active'). 88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// These values will each be present at most once every 24 hours, and indicate 89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// the number of days 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, 100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const PingData& ping_data, 1014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const std::string& update_url_data) { 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (extension_ids_.find(id) != extension_ids_.end()) { 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Duplicate extension id " << id; 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Compute the string we'd append onto the full_url_, and see if it fits. 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<std::string> parts; 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parts.push_back("id=" + id); 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parts.push_back("v=" + version); 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parts.push_back("uc"); 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (!update_url_data.empty()) { 1144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Make sure the update_url_data string is escaped before using it so that 1154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // there is no chance of overriding the id or v other parameter value 1164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // we place into the x= value. 1174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch parts.push_back("ap=" + EscapeQueryParamValue(update_url_data, true)); 1184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 1194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Append rollcall and active ping parameters. 121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (base_url_.DomainIs("google.com")) { 122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::string ping_value; 123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen pings_[id] = PingData(0, 0); 124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (ping_data.rollcall_days == kNeverPinged || 126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ping_data.rollcall_days > 0) { 127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ping_value += "r=" + base::IntToString(ping_data.rollcall_days); 128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen pings_[id].rollcall_days = ping_data.rollcall_days; 129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if SEND_ACTIVE_PINGS 131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (ping_data.active_days == kNeverPinged || ping_data.active_days > 0) { 132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!ping_value.empty()) 133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ping_value += "&"; 134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ping_value += "a=" + base::IntToString(ping_data.active_days); 135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen pings_[id].active_days = ping_data.active_days; 136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif // SEND_ACTIVE_PINGS 138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!ping_value.empty()) 139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen parts.push_back("ping=" + EscapeQueryParamValue(ping_value, true)); 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string extra = full_url_.has_query() ? "&" : "?"; 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extra += "x=" + EscapeQueryParamValue(JoinString(parts, '&'), true); 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check against our max url size, exempting the first extension added. 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int new_size = full_url_.possibly_invalid_spec().size() + extra.size(); 147dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!extension_ids_.empty() && new_size > kExtensionsManifestMaxURLSize) { 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_PERCENTAGE("Extensions.UpdateCheckHitUrlSizeLimit", 1); 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_PERCENTAGE("Extensions.UpdateCheckHitUrlSizeLimit", 0); 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We have room so go ahead and add the extension. 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_ids_.insert(id); 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch full_url_ = GURL(full_url_.possibly_invalid_spec() + extra); 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool ManifestFetchData::Includes(const std::string& extension_id) const { 160731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return extension_ids_.find(extension_id) != extension_ids_.end(); 161731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 162731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool ManifestFetchData::DidPing(std::string extension_id, PingType type) const { 164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::map<std::string, PingData>::const_iterator i = pings_.find(extension_id); 165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (i == pings_.end()) 166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int value = 0; 168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (type == ROLLCALL) 169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen value = i->second.rollcall_days; 170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen else if (type == ACTIVE) 171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen value = i->second.active_days; 172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen else 173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NOTREACHED(); 174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return value == kNeverPinged || value > 0; 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// When we've computed a days value, we want to make sure we don't send a 180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// negative value (due to the system clock being set backwards, etc.), since -1 181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// is a special sentinel value that means "never pinged", and other negative 182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// values don't make sense. 183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic int SanitizeDays(int days) { 184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (days < 0) 185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return 0; 186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return days; 187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Calculates the value to use for the ping days parameter. 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic int CalculatePingDays(const Time& last_ping_day) { 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int days = ManifestFetchData::kNeverPinged; 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!last_ping_day.is_null()) { 193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen days = SanitizeDays((Time::Now() - last_ping_day).InDays()); 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return days; 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic int CalculateActivePingDays(const Time& last_active_ping_day, 199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool hasActiveBit) { 200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!hasActiveBit) 201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return 0; 202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (last_active_ping_day.is_null()) 203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return ManifestFetchData::kNeverPinged; 204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return SanitizeDays((Time::Now() - last_active_ping_day).InDays()); 205ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochManifestFetchesBuilder::ManifestFetchesBuilder( 210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ExtensionServiceInterface* service, 211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ExtensionPrefs* prefs) 212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen : service_(service), prefs_(prefs) { 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(service_); 214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(prefs_); 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 217731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickManifestFetchesBuilder::~ManifestFetchesBuilder() {} 218731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ManifestFetchesBuilder::AddExtension(const Extension& extension) { 2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Skip extensions with empty update URLs converted from user 2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // scripts. 2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (extension.converted_from_user_script() && 2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick extension.update_url().is_empty()) { 2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // If the extension updates itself from the gallery, ignore any update URL 2284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // data. At the moment there is no extra data that an extension can 2294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // communicate to the the gallery update servers. 2304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch std::string update_url_data; 2314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (!extension.UpdatesFromGallery()) 232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen update_url_data = prefs_->GetUpdateUrlData(extension.id()); 2334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddExtensionData(extension.location(), 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension.id(), 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *extension.version(), 23721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen extension.GetType(), 2384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch extension.update_url(), update_url_data); 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ManifestFetchesBuilder::AddPendingExtension( 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& id, 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const PendingExtensionInfo& info) { 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Use a zero version to ensure that a pending extension will always 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // be updated, and thus installed (assuming all extensions have 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // non-zero versions). 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Version> version( 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Version::GetVersionFromString("0.0.0.0")); 2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 25021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen AddExtensionData( 251dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen info.install_source(), id, *version, 252dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Extension::TYPE_UNKNOWN, info.update_url(), ""); 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ManifestFetchesBuilder::ReportStats() const { 25621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtension", 25721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen url_stats_.extension_count); 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckTheme", 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_stats_.theme_count); 26021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckApp", 26121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen url_stats_.app_count); 26221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckPending", 26321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen url_stats_.pending_count); 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckGoogleUrl", 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_stats_.google_url_count); 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckOtherUrl", 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_stats_.other_url_count); 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckNoUrl", 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_stats_.no_url_count); 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::vector<ManifestFetchData*> ManifestFetchesBuilder::GetFetches() { 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<ManifestFetchData*> fetches; 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetches.reserve(fetches_.size()); 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::multimap<GURL, ManifestFetchData*>::iterator it = 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetches_.begin(); it != fetches_.end(); ++it) { 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetches.push_back(it->second); 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetches_.clear(); 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_stats_ = URLStats(); 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return fetches; 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ManifestFetchesBuilder::AddExtensionData( 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Extension::Location location, 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& id, 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const Version& version, 28821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen Extension::Type extension_type, 2894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch GURL update_url, 2904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const std::string& update_url_data) { 291513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (!Extension::IsAutoUpdateableLocation(location)) { 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Skip extensions with non-empty invalid update URLs. 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!update_url.is_empty() && !update_url.is_valid()) { 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "Extension " << id << " has invalid update url " 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << update_url; 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Skip extensions with empty IDs. 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (id.empty()) { 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "Found extension with empty ID"; 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (update_url.DomainIs("google.com")) { 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_stats_.google_url_count++; 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (update_url.is_empty()) { 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_stats_.no_url_count++; 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Fill in default update URL. 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(akalin): Figure out if we should use the HTTPS version. 315201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch update_url = Extension::GalleryUpdateUrl(false); 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch url_stats_.other_url_count++; 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 32021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen switch (extension_type) { 32121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen case Extension::TYPE_THEME: 32221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ++url_stats_.theme_count; 32321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen break; 32421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen case Extension::TYPE_EXTENSION: 32521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen case Extension::TYPE_USER_SCRIPT: 32621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ++url_stats_.extension_count; 32721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen break; 32821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen case Extension::TYPE_HOSTED_APP: 32921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen case Extension::TYPE_PACKAGED_APP: 33021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ++url_stats_.app_count; 331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen break; 33221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen case Extension::TYPE_UNKNOWN: 33321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen default: 33421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ++url_stats_.pending_count; 33521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen break; 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!update_url.is_empty()); 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(update_url.is_valid()); 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ManifestFetchData* fetch = NULL; 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::multimap<GURL, ManifestFetchData*>::iterator existing_iter = 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetches_.find(update_url); 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Find or create a ManifestFetchData to add this extension to. 346ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ManifestFetchData::PingData ping_data; 347ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ping_data.rollcall_days = CalculatePingDays(prefs_->LastPingDay(id)); 348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ping_data.active_days = 349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CalculateActivePingDays(prefs_->LastActivePingDay(id), 350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen prefs_->GetActiveBit(id)); 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (existing_iter != fetches_.end()) { 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (existing_iter->second->AddExtension(id, version.GetString(), 353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ping_data, update_url_data)) { 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetch = existing_iter->second; 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch existing_iter++; 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!fetch) { 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetch = new ManifestFetchData(update_url); 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetches_.insert(std::pair<GURL, ManifestFetchData*>(update_url, fetch)); 362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool added = fetch->AddExtension(id, version.GetString(), ping_data, 3634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch update_url_data); 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(added); 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A utility class to do file handling on the file I/O thread. 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass ExtensionUpdaterFileHandler 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : public base::RefCountedThreadSafe<ExtensionUpdaterFileHandler> { 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen explicit ExtensionUpdaterFileHandler( 373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::WeakPtr<ExtensionUpdater> updater) 374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen : updater_(updater) { 375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Writes crx file data into a tempfile, and calls back the updater. 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void WriteTempFile(const std::string& extension_id, const std::string& data, 380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const GURL& download_url) { 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure we're running in the right thread. 382731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool failed = false; 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath path; 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!file_util::CreateTemporaryFile(&path)) { 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "Failed to create temporary file path"; 388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen failed = true; 389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else if (file_util::WriteFile(path, data.c_str(), data.length()) != 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(data.length())) { 39172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // TODO(asargent) - It would be nice to back off updating altogether if 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the disk is full. (http://crbug.com/12763). 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(ERROR) << "Failed to write temporary file"; 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_util::Delete(path, false); 395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen failed = true; 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 398ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (failed) { 399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!BrowserThread::PostTask( 400ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen BrowserThread::UI, FROM_HERE, 401ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableMethod( 402ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this, &ExtensionUpdaterFileHandler::OnCRXFileWriteError, 403ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen extension_id))) { 404ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NOTREACHED(); 405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 407ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!BrowserThread::PostTask( 408ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen BrowserThread::UI, FROM_HERE, 409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableMethod( 410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this, &ExtensionUpdaterFileHandler::OnCRXFileWritten, 411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen extension_id, path, download_url))) { 412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NOTREACHED(); 413ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Delete |path| since we couldn't post. 414ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen extension_file_util::DeleteFile(path, false); 415ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 416ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch friend class base::RefCountedThreadSafe<ExtensionUpdaterFileHandler>; 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ~ExtensionUpdaterFileHandler() { 423ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || 424ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen BrowserThread::CurrentlyOn(BrowserThread::FILE)); 425ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 426ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 427ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen void OnCRXFileWritten(const std::string& id, 428ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const FilePath& path, 429ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const GURL& download_url) { 430ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 431ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!updater_) { 432ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Delete |path| since we don't have an updater anymore. 433ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!BrowserThread::PostTask( 434ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen BrowserThread::FILE, FROM_HERE, 435ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableFunction( 436ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen extension_file_util::DeleteFile, path, false))) { 437ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NOTREACHED(); 438ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 439ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 440ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 441ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // The ExtensionUpdater now owns the temp file. 442ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen updater_->OnCRXFileWritten(id, path, download_url); 443ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 444ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 445ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen void OnCRXFileWriteError(const std::string& id) { 446ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 447ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!updater_) { 448ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 449ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 450ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen updater_->OnCRXFileWriteError(id); 451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 452ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 453ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Should be accessed only on UI thread. 454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::WeakPtr<ExtensionUpdater> updater_; 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExtensionUpdater::ExtensionFetch::ExtensionFetch() 45872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen : id(""), 45972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen url(), 46072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen package_hash(""), 46172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen version("") {} 46272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 46372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExtensionUpdater::ExtensionFetch::ExtensionFetch(const std::string& i, 46472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const GURL& u, 46572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const std::string& h, 46672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const std::string& v) 46772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen : id(i), url(u), package_hash(h), version(v) {} 46872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 46972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExtensionUpdater::ExtensionFetch::~ExtensionFetch() {} 47072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 471ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service, 472ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ExtensionPrefs* extension_prefs, 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrefService* prefs, 474ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Profile* profile, 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int frequency_seconds) 476ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen : alive_(false), 477ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), 478ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen service_(service), frequency_seconds_(frequency_seconds), 479ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), 480ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen will_check_soon_(false), extension_prefs_(extension_prefs), 481ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen prefs_(prefs), profile_(profile), blacklist_checks_enabled_(true) { 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Init(); 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::Init() { 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_GE(frequency_seconds_, 5); 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(frequency_seconds_ <= kMaxUpdateFrequencySeconds); 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#ifdef NDEBUG 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // In Release mode we enforce that update checks don't happen too often. 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds); 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds); 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExtensionUpdater::~ExtensionUpdater() { 4964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Stop(); 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void EnsureInt64PrefRegistered(PrefService* prefs, 5003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const char name[]) { 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!prefs->FindPreference(name)) 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->RegisterInt64Pref(name, 0); 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void EnsureBlacklistVersionPrefRegistered(PrefService* prefs) { 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!prefs->FindPreference(kExtensionBlacklistUpdateVersion)) 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->RegisterStringPref(kExtensionBlacklistUpdateVersion, "0"); 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The overall goal here is to balance keeping clients up to date while 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// avoiding a thundering herd against update servers. 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTimeDelta ExtensionUpdater::DetermineFirstCheckDelay() { 5134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(alive_); 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If someone's testing with a quick frequency, just allow it. 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (frequency_seconds_ < kStartupWaitSeconds) 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TimeDelta::FromSeconds(frequency_seconds_); 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we've never scheduled a check before, start at frequency_seconds_. 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!prefs_->HasPrefPath(kNextExtensionsUpdateCheck)) 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TimeDelta::FromSeconds(frequency_seconds_); 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If it's been a long time since our last actual check, we want to do one 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // relatively soon. 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Time now = Time::Now(); 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Time last = Time::FromInternalValue(prefs_->GetInt64( 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kLastExtensionsUpdateCheck)); 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int days = (now - last).InDays(); 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (days >= 30) { 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Wait 5-10 minutes. 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds, 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kStartupWaitSeconds * 2)); 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (days >= 14) { 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Wait 10-20 minutes. 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 2, 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kStartupWaitSeconds * 4)); 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (days >= 3) { 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Wait 20-40 minutes. 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 4, 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kStartupWaitSeconds * 8)); 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Read the persisted next check time, and use that if it isn't too soon. 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Otherwise pick something random. 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Time saved_next = Time::FromInternalValue(prefs_->GetInt64( 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kNextExtensionsUpdateCheck)); 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Time earliest = now + TimeDelta::FromSeconds(kStartupWaitSeconds); 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (saved_next >= earliest) { 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return saved_next - now; 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds, 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frequency_seconds_)); 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::Start() { 5564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(!alive_); 5574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // If these are NULL, then that means we've been called after Stop() 5584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // has been called. 5594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(service_); 560ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(extension_prefs_); 5614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(prefs_); 562ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(profile_); 563ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(!weak_ptr_factory_.HasWeakPtrs()); 564ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen file_handler_ = 565ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new ExtensionUpdaterFileHandler(weak_ptr_factory_.GetWeakPtr()); 5664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch alive_ = true; 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure our prefs are registered, then schedule the first check. 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EnsureInt64PrefRegistered(prefs_, kLastExtensionsUpdateCheck); 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EnsureInt64PrefRegistered(prefs_, kNextExtensionsUpdateCheck); 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EnsureBlacklistVersionPrefRegistered(prefs_); 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleNextCheck(DetermineFirstCheckDelay()); 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::Stop() { 575ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen weak_ptr_factory_.InvalidateWeakPtrs(); 5764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch alive_ = false; 577ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen file_handler_ = NULL; 5784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch service_ = NULL; 579ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen extension_prefs_ = NULL; 5804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch prefs_ = NULL; 581ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen profile_ = NULL; 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch timer_.Stop(); 583ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen will_check_soon_ = false; 584ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen method_factory_.RevokeAll(); 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manifest_fetcher_.reset(); 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_fetcher_.reset(); 5874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch STLDeleteElements(&manifests_pending_); 588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manifests_pending_.clear(); 589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extensions_pending_.clear(); 590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::OnURLFetchComplete( 59372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const URLFetcher* source, 59472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const GURL& url, 59572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const net::URLRequestStatus& status, 59672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int response_code, 59772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const ResponseCookies& cookies, 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& data) { 5994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Stop() destroys all our URLFetchers, which means we shouldn't be 6004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // called after Stop() is called. 6014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(alive_); 6024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (source == manifest_fetcher_.get()) { 604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnManifestFetchComplete(url, status, response_code, data); 605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (source == extension_fetcher_.get()) { 606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnCRXFetchComplete(url, status, response_code, data); 607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 610ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotifyIfFinished(); 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Utility class to handle doing xml parsing in a sandboxed utility process. 614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass SafeManifestParser : public UtilityProcessHost::Client { 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Takes ownership of |fetch_data|. 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SafeManifestParser(const std::string& xml, ManifestFetchData* fetch_data, 618ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::WeakPtr<ExtensionUpdater> updater) 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : xml_(xml), updater_(updater) { 620ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetch_data_.reset(fetch_data); 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Posts a task over to the IO loop to start the parsing of xml_ in a 625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // utility process. 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void Start() { 627731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 628ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!BrowserThread::PostTask( 629ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen BrowserThread::IO, FROM_HERE, 630ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableMethod( 631ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this, &SafeManifestParser::ParseInSandbox, 632ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen g_browser_process->resource_dispatcher_host()))) { 633ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NOTREACHED(); 634ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Creates the sandboxed utility process and tells it to start parsing. 638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void ParseInSandbox(ResourceDispatcherHost* rdh) { 639731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(asargent) we shouldn't need to do this branch here - instead 642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // UtilityProcessHost should handle it for us. (http://crbug.com/19192) 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool use_utility_process = rdh && 644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess); 645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (use_utility_process) { 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UtilityProcessHost* host = new UtilityProcessHost( 647ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this, BrowserThread::UI); 648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host->StartUpdateManifestParse(xml_); 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateManifest manifest; 651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (manifest.Parse(xml_)) { 652ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!BrowserThread::PostTask( 653ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen BrowserThread::UI, FROM_HERE, 654ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableMethod( 655ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this, &SafeManifestParser::OnParseUpdateManifestSucceeded, 656ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen manifest.results()))) { 657ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NOTREACHED(); 658ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 660ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!BrowserThread::PostTask( 661ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen BrowserThread::UI, FROM_HERE, 662ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableMethod( 663ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this, &SafeManifestParser::OnParseUpdateManifestFailed, 664ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen manifest.errors()))) { 665ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NOTREACHED(); 666ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Callback from the utility process when parsing succeeded. 672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void OnParseUpdateManifestSucceeded( 673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const UpdateManifest::Results& results) { 674731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 675ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!updater_) { 676ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 677ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 678ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen updater_->HandleManifestResults(*fetch_data_, &results); 679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Callback from the utility process when parsing failed. 682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void OnParseUpdateManifestFailed(const std::string& error_message) { 683731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 684ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!updater_) { 685ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 686ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "Error parsing update manifest:\n" << error_message; 688ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen updater_->HandleManifestResults(*fetch_data_, NULL); 689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 692ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ~SafeManifestParser() { 693ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // If we're using UtilityProcessHost, we may not be destroyed on 694ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // the UI or IO thread. 695ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 697ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const std::string xml_; 698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 699ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Should be accessed only on UI thread. 700ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen scoped_ptr<ManifestFetchData> fetch_data_; 701ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen base::WeakPtr<ExtensionUpdater> updater_; 702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 70572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionUpdater::OnManifestFetchComplete( 70672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const GURL& url, 70772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const net::URLRequestStatus& status, 70872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int response_code, 70972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const std::string& data) { 710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We want to try parsing the manifest, and if it indicates updates are 711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // available, we want to fire off requests to fetch those updates. 71272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (status.status() == net::URLRequestStatus::SUCCESS && 71372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (response_code == 200 || (url.SchemeIsFile() && data.length() > 0))) { 714513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch scoped_refptr<SafeManifestParser> safe_parser( 715ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new SafeManifestParser(data, current_manifest_fetch_.release(), 716ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen weak_ptr_factory_.GetWeakPtr())); 717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch safe_parser->Start(); 718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(asargent) Do exponential backoff here. (http://crbug.com/12546). 720513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch VLOG(1) << "Failed to fetch manifest '" << url.possibly_invalid_spec() 721513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch << "' response code:" << response_code; 722ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen RemoveFromInProgress(current_manifest_fetch_->extension_ids()); 723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manifest_fetcher_.reset(); 725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_manifest_fetch_.reset(); 726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we have any pending manifest requests, fire off the next one. 728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!manifests_pending_.empty()) { 729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ManifestFetchData* manifest_fetch = manifests_pending_.front(); 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manifests_pending_.pop_front(); 731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartUpdateCheck(manifest_fetch); 732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::HandleManifestResults( 736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const ManifestFetchData& fetch_data, 737ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const UpdateManifest::Results* results) { 738ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(alive_); 739ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 740ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Remove all the ids's from in_progress_ids_ (we will add them back in 741ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // below if they actually have updates we need to fetch and install). 742ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen RemoveFromInProgress(fetch_data.extension_ids()); 743ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 744ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!results) { 745ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotifyIfFinished(); 7464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return; 747ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Examine the parsed manifest and kick off fetches of any new crx files. 750ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::vector<int> updates = DetermineUpdates(fetch_data, *results); 751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < updates.size(); i++) { 752ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const UpdateManifest::Result* update = &(results->list.at(updates[i])); 753ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const std::string& id = update->extension_id; 754ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen in_progress_ids_.insert(id); 755ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (id != std::string(kBlacklistAppID)) 756ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotifyUpdateFound(update->extension_id); 757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FetchUpdatedExtension(update->extension_id, update->crx_url, 758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch update->package_hash, update->version); 759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the manifest response included a <daystart> element, we want to save 762ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // that value for any extensions which had sent a ping in the request. 763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (fetch_data.base_url().DomainIs("google.com") && 764ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen results->daystart_elapsed_seconds >= 0) { 765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Time daystart = 766ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Time::Now() - TimeDelta::FromSeconds(results->daystart_elapsed_seconds); 767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::set<std::string>& extension_ids = fetch_data.extension_ids(); 769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<std::string>::const_iterator i; 770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (i = extension_ids.begin(); i != extension_ids.end(); i++) { 771ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (fetch_data.DidPing(*i, ManifestFetchData::ROLLCALL)) { 772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (*i == kBlacklistAppID) { 773ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen extension_prefs_->SetBlacklistLastPingDay(daystart); 774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (service_->GetExtensionById(*i, true) != NULL) { 775ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen extension_prefs_->SetLastPingDay(*i, daystart); 776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 778ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (extension_prefs_->GetActiveBit(*i)) { 779ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen extension_prefs_->SetActiveBit(*i, false); 780ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen extension_prefs_->SetLastActivePingDay(*i, daystart); 781ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 784ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotifyIfFinished(); 785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::ProcessBlacklist(const std::string& data) { 7884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(alive_); 789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Verify sha256 hash value. 790ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen char sha256_hash_value[crypto::SHA256_LENGTH]; 791ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen crypto::SHA256HashString(data, sha256_hash_value, crypto::SHA256_LENGTH); 7923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::string hash_in_hex = base::HexEncode(sha256_hash_value, 793ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen crypto::SHA256_LENGTH); 794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (current_extension_fetch_.package_hash != hash_in_hex) { 796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Fetched blacklist checksum is not as expected. " 797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "Expected: " << current_extension_fetch_.package_hash 798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << " Actual: " << hash_in_hex; 799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<std::string> blacklist; 802731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick base::SplitString(data, '\n', &blacklist); 803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Tell ExtensionService to update prefs. 805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch service_->UpdateExtensionBlacklist(blacklist); 806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update the pref value for blacklist version 808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs_->SetString(kExtensionBlacklistUpdateVersion, 809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_extension_fetch_.version); 810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs_->ScheduleSavePersistentPrefs(); 811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::OnCRXFetchComplete(const GURL& url, 81472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const net::URLRequestStatus& status, 815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int response_code, 816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& data) { 81772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (status.status() == net::URLRequestStatus::SUCCESS && 81872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (response_code == 200 || (url.SchemeIsFile() && data.length() > 0))) { 819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (current_extension_fetch_.id == kBlacklistAppID) { 820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ProcessBlacklist(data); 821ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen in_progress_ids_.erase(current_extension_fetch_.id); 822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Successfully fetched - now write crx to a file so we can have the 82421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // ExtensionService install it. 825ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!BrowserThread::PostTask( 826ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen BrowserThread::FILE, FROM_HERE, 827ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NewRunnableMethod( 828ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen file_handler_.get(), 829ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &ExtensionUpdaterFileHandler::WriteTempFile, 830ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen current_extension_fetch_.id, data, url))) { 831ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NOTREACHED(); 832ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(asargent) do things like exponential backoff, handling 836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 503 Service Unavailable / Retry-After headers, etc. here. 837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // (http://crbug.com/12546). 838513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec() 839513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch << "' response code:" << response_code; 840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_fetcher_.reset(); 842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_extension_fetch_ = ExtensionFetch(); 843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If there are any pending downloads left, start one. 845dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!extensions_pending_.empty()) { 846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionFetch next = extensions_pending_.front(); 847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extensions_pending_.pop_front(); 848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FetchUpdatedExtension(next.id, next.url, next.package_hash, next.version); 849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::OnCRXFileWritten(const std::string& id, 853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& path, 854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& download_url) { 855ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(alive_); 85621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // The ExtensionService is now responsible for cleaning up the temp file 857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // at |path|. 858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch service_->UpdateExtension(id, path, download_url); 859ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen in_progress_ids_.erase(id); 860ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotifyIfFinished(); 861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 863ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExtensionUpdater::OnCRXFileWriteError(const std::string& id) { 864ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(alive_); 865ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen in_progress_ids_.erase(id); 866ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotifyIfFinished(); 867ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) { 8704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(alive_); 871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!timer_.IsRunning()); 872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(target_delay >= TimeDelta::FromSeconds(1)); 873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add +/- 10% random jitter. 875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double delay_ms = target_delay.InMillisecondsF(); 876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double jitter_factor = (RandDouble() * .2) - 0.1; 877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delay_ms += delay_ms * jitter_factor; 878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TimeDelta actual_delay = TimeDelta::FromMilliseconds( 879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int64>(delay_ms)); 880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Save the time of next check. 882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Time next = Time::Now() + actual_delay; 883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs_->SetInt64(kNextExtensionsUpdateCheck, next.ToInternalValue()); 884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs_->ScheduleSavePersistentPrefs(); 885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch timer_.Start(actual_delay, this, &ExtensionUpdater::TimerFired); 887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::TimerFired() { 8904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(alive_); 891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CheckNow(); 892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the user has overridden the update frequency, don't bother reporting 894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // this. 89521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (frequency_seconds_ == ExtensionService::kDefaultUpdateFrequencySeconds) { 896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Time last = Time::FromInternalValue(prefs_->GetInt64( 897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kLastExtensionsUpdateCheck)); 898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (last.ToInternalValue() != 0) { 899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Use counts rather than time so we can use minutes rather than millis. 900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.UpdateCheckGap", 901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (Time::Now() - last).InMinutes(), 902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::TimeDelta::FromSeconds(kStartupWaitSeconds).InMinutes(), 903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::TimeDelta::FromDays(40).InMinutes(), 904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 50); // 50 buckets seems to be the default. 905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Save the last check time, and schedule the next check. 909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 now = Time::Now().ToInternalValue(); 910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs_->SetInt64(kLastExtensionsUpdateCheck, now); 911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScheduleNextCheck(TimeDelta::FromSeconds(frequency_seconds_)); 912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 914ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExtensionUpdater::CheckSoon() { 915ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(alive_); 916ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (will_check_soon_) { 917ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 918ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 919ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (BrowserThread::PostTask( 920ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen BrowserThread::UI, FROM_HERE, 921ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen method_factory_.NewRunnableMethod( 922ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen &ExtensionUpdater::DoCheckSoon))) { 923ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen will_check_soon_ = true; 924ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } else { 925ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NOTREACHED(); 926ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 927ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 928ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 929ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool ExtensionUpdater::WillCheckSoon() const { 930ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return will_check_soon_; 931ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 932ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 933ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExtensionUpdater::DoCheckSoon() { 934ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(will_check_soon_); 935ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CheckNow(); 936ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen will_check_soon_ = false; 937ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 938ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::CheckNow() { 9404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(alive_); 941ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotifyStarted(); 942ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ManifestFetchesBuilder fetches_builder(service_, extension_prefs_); 943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const ExtensionList* extensions = service_->extensions(); 945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (ExtensionList::const_iterator iter = extensions->begin(); 946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch iter != extensions->end(); ++iter) { 947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetches_builder.AddExtension(**iter); 948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 950ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const PendingExtensionManager* pending_extension_manager = 951ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen service_->pending_extension_manager(); 952ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 953ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen PendingExtensionManager::const_iterator iter; 954ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (iter = pending_extension_manager->begin(); 955ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen iter != pending_extension_manager->end(); iter++) { 956ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // TODO(skerner): Move the determination of what gets fetched into 957ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // class PendingExtensionManager. 958dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Extension::Location location = iter->second.install_source(); 95921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (location != Extension::EXTERNAL_PREF && 96021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen location != Extension::EXTERNAL_REGISTRY) 96121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen fetches_builder.AddPendingExtension(iter->first, iter->second); 962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetches_builder.ReportStats(); 965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<ManifestFetchData*> fetches(fetches_builder.GetFetches()); 967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start a fetch of the blacklist if needed. 969ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (blacklist_checks_enabled_) { 97072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Note: it is very important that we use the https version of the update 971201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // url here to avoid DNS hijacking of the blacklist, which is not validated 972201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // by a public key signature like .crx files are. 973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ManifestFetchData* blacklist_fetch = 974201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch new ManifestFetchData(Extension::GalleryUpdateUrl(true)); 975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string version = prefs_->GetString(kExtensionBlacklistUpdateVersion); 976ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ManifestFetchData::PingData ping_data; 977ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ping_data.rollcall_days = 978ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CalculatePingDays(extension_prefs_->BlacklistLastPingDay()); 979ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen blacklist_fetch->AddExtension(kBlacklistAppID, version, ping_data, ""); 980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartUpdateCheck(blacklist_fetch); 981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Now start fetching regular extension updates 984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::vector<ManifestFetchData*>::const_iterator it = fetches.begin(); 985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != fetches.end(); ++it) { 986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // StartUpdateCheck makes sure the url isn't already downloading or 987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // scheduled, so we don't need to check before calling it. Ownership of 988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // fetch is transferred here. 989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartUpdateCheck(*it); 990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We don't want to use fetches after this since StartUpdateCheck() 992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // takes ownership of its argument. 993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetches.clear(); 994ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 995ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotifyIfFinished(); 996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExtensionUpdater::GetExistingVersion(const std::string& id, 999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string* version) { 10004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(alive_); 1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (id == kBlacklistAppID) { 1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *version = prefs_->GetString(kExtensionBlacklistUpdateVersion); 1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1005513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const Extension* extension = service_->GetExtensionById(id, false); 1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!extension) { 1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *version = extension->version()->GetString(); 1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::vector<int> ExtensionUpdater::DetermineUpdates( 1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const ManifestFetchData& fetch_data, 1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const UpdateManifest::Results& possible_updates) { 10164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(alive_); 1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<int> result; 1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This will only get set if one of possible_updates specifies 1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // browser_min_version. 1021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Version> browser_version; 1022ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen PendingExtensionManager* pending_extension_manager = 1023ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen service_->pending_extension_manager(); 1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < possible_updates.list.size(); i++) { 1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const UpdateManifest::Result* update = &possible_updates.list[i]; 1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!fetch_data.Includes(update->extension_id)) 1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1031ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!pending_extension_manager->IsIdPending(update->extension_id)) { 1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we're not installing pending extension, and the update 1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // version is the same or older than what's already installed, 1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we don't want it. 1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string version; 1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!GetExistingVersion(update->extension_id, &version)) 1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Version> existing_version( 1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Version::GetVersionFromString(version)); 1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Version> update_version( 1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Version::GetVersionFromString(update->version)); 1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!update_version.get() || 1045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch update_version->CompareTo(*(existing_version.get())) <= 0) { 1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the update specifies a browser minimum version, do we qualify? 1051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (update->browser_min_version.length() > 0) { 1052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // First determine the browser version if we haven't already. 1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!browser_version.get()) { 10543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chrome::VersionInfo version_info; 10553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (version_info.is_valid()) { 1056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_version.reset(Version::GetVersionFromString( 10573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick version_info.Version())); 1058c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Version> browser_min_version( 1061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Version::GetVersionFromString(update->browser_min_version)); 1062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (browser_version.get() && browser_min_version.get() && 1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch browser_min_version->CompareTo(*browser_version.get()) > 0) { 1064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(asargent) - We may want this to show up in the extensions UI 1065c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // eventually. (http://crbug.com/12547). 1066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "Updated version of extension " << update->extension_id 1067ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen << " available, but requires chrome version " 1068ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen << update->browser_min_version; 1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1072c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch result.push_back(i); 1073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return result; 1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::StartUpdateCheck(ManifestFetchData* fetch_data) { 1078ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen AddToInProgress(fetch_data->extension_ids()); 1079ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 10804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch scoped_ptr<ManifestFetchData> scoped_fetch_data(fetch_data); 10813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (CommandLine::ForCurrentProcess()->HasSwitch( 10823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick switches::kDisableBackgroundNetworking)) 10833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 10843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::deque<ManifestFetchData*>::const_iterator i; 1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (i = manifests_pending_.begin(); i != manifests_pending_.end(); i++) { 1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (fetch_data->full_url() == (*i)->full_url()) { 1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This url is already scheduled to be fetched. 1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1093c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (manifest_fetcher_.get() != NULL) { 1094c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (manifest_fetcher_->url() != fetch_data->full_url()) { 10954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch manifests_pending_.push_back(scoped_fetch_data.release()); 1096c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1097c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1098c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_COUNTS("Extensions.UpdateCheckUrlLength", 1099c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch fetch_data->full_url().possibly_invalid_spec().length()); 1100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 11014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch current_manifest_fetch_.swap(scoped_fetch_data); 1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manifest_fetcher_.reset( 1103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch URLFetcher::Create(kManifestFetcherId, fetch_data->full_url(), 1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch URLFetcher::GET, this)); 110572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen manifest_fetcher_->set_request_context( 1106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen profile_->GetRequestContext()); 1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manifest_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES | 1108513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch net::LOAD_DO_NOT_SAVE_COOKIES | 1109513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch net::LOAD_DISABLE_CACHE); 1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch manifest_fetcher_->Start(); 1111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionUpdater::FetchUpdatedExtension(const std::string& id, 1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& url, 1116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& hash, 1117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& version) { 1118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (std::deque<ExtensionFetch>::const_iterator iter = 1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extensions_pending_.begin(); 1120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch iter != extensions_pending_.end(); ++iter) { 1121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (iter->id == id || iter->url == url) { 1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; // already scheduled 1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (extension_fetcher_.get() != NULL) { 1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (extension_fetcher_->url() != url) { 1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extensions_pending_.push_back(ExtensionFetch(id, url, hash, version)); 1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 1131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_fetcher_.reset( 1132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch URLFetcher::Create(kExtensionFetcherId, url, URLFetcher::GET, this)); 1133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_fetcher_->set_request_context( 1134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen profile_->GetRequestContext()); 1135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES | 1136513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch net::LOAD_DO_NOT_SAVE_COOKIES | 1137513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch net::LOAD_DISABLE_CACHE); 1138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_fetcher_->Start(); 1139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_extension_fetch_ = ExtensionFetch(id, url, hash, version); 1140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 1143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExtensionUpdater::NotifyStarted() { 1144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotificationService::current()->Notify( 1145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotificationType::EXTENSION_UPDATING_STARTED, 1146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Source<Profile>(profile_), 1147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotificationService::NoDetails()); 1148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 1149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 1150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExtensionUpdater::NotifyUpdateFound(const std::string& extension_id) { 1151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotificationService::current()->Notify( 1152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotificationType::EXTENSION_UPDATE_FOUND, 1153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Source<Profile>(profile_), 1154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Details<const std::string>(&extension_id)); 1155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 1156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 1157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExtensionUpdater::NotifyIfFinished() { 1158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (in_progress_ids_.empty()) { 1159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotificationService::current()->Notify( 1160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotificationType::EXTENSION_UPDATING_FINISHED, 1161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Source<Profile>(profile_), 1162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NotificationService::NoDetails()); 1163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen VLOG(1) << "Sending EXTENSION_UPDATING_FINISHED"; 1164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 1165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 1166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 1167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExtensionUpdater::AddToInProgress(const std::set<std::string>& ids) { 1168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::set<std::string>::const_iterator i; 1169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (i = ids.begin(); i != ids.end(); ++i) 1170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen in_progress_ids_.insert(*i); 1171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 1172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 1173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExtensionUpdater::RemoveFromInProgress(const std::set<std::string>& ids) { 1174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::set<std::string>::const_iterator i; 1175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (i = ids.begin(); i != ids.end(); ++i) 1176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen in_progress_ids_.erase(*i); 1177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 1178