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
47using base::RandDouble;
48using base::RandInt;
49using base::Time;
50using base::TimeDelta;
51using prefs::kExtensionBlacklistUpdateVersion;
52using prefs::kLastExtensionsUpdateCheck;
53using prefs::kNextExtensionsUpdateCheck;
54
55// Update AppID for extension blacklist.
56const 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.
60const int kStartupWaitSeconds = 60 * 5;
61
62// For sanity checking on update frequency - enforced in release mode only.
63static const int kMinUpdateFrequencySeconds = 30;
64static 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.
68static const int kExtensionsManifestMaxURLSize = 2000;
69
70ManifestFetchData::ManifestFetchData(const GURL& update_url)
71    : base_url_(update_url),
72      full_url_(update_url) {
73}
74
75ManifestFetchData::~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.)
99bool 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
159bool ManifestFetchData::Includes(const std::string& extension_id) const {
160  return extension_ids_.find(extension_id) != extension_ids_.end();
161}
162
163bool 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
177namespace {
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.
183static 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.
190static 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
198static 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
209ManifestFetchesBuilder::ManifestFetchesBuilder(
210    ExtensionServiceInterface* service,
211    ExtensionPrefs* prefs)
212    : service_(service), prefs_(prefs) {
213  DCHECK(service_);
214  DCHECK(prefs_);
215}
216
217ManifestFetchesBuilder::~ManifestFetchesBuilder() {}
218
219void 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
241void 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
255void 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
272std::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
284void 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.
369class 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
457ExtensionUpdater::ExtensionFetch::ExtensionFetch()
458    : id(""),
459      url(),
460      package_hash(""),
461      version("") {}
462
463ExtensionUpdater::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
469ExtensionUpdater::ExtensionFetch::~ExtensionFetch() {}
470
471ExtensionUpdater::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
485void 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
495ExtensionUpdater::~ExtensionUpdater() {
496  Stop();
497}
498
499static void EnsureInt64PrefRegistered(PrefService* prefs,
500                                      const char name[]) {
501  if (!prefs->FindPreference(name))
502    prefs->RegisterInt64Pref(name, 0);
503}
504
505static 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.
512TimeDelta 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
555void 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
574void 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
592void 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.
614class 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
705void 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
735void 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
787void 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
813void 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
852void 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
863void ExtensionUpdater::OnCRXFileWriteError(const std::string& id) {
864  DCHECK(alive_);
865  in_progress_ids_.erase(id);
866  NotifyIfFinished();
867}
868
869void 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
889void 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
914void 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
929bool ExtensionUpdater::WillCheckSoon() const {
930  return will_check_soon_;
931}
932
933void ExtensionUpdater::DoCheckSoon() {
934  DCHECK(will_check_soon_);
935  CheckNow();
936  will_check_soon_ = false;
937}
938
939void 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
998bool 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
1013std::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
1077void 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
1114void 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
1143void ExtensionUpdater::NotifyStarted() {
1144  NotificationService::current()->Notify(
1145      NotificationType::EXTENSION_UPDATING_STARTED,
1146      Source<Profile>(profile_),
1147      NotificationService::NoDetails());
1148}
1149
1150void 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
1157void 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
1167void 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
1173void 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