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