Home | History | Annotate | Download | only in updater
      1 // Copyright (c) 2012 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/updater/extension_downloader.h"
      6 
      7 #include <utility>
      8 
      9 #include "base/bind.h"
     10 #include "base/command_line.h"
     11 #include "base/files/file_path.h"
     12 #include "base/location.h"
     13 #include "base/logging.h"
     14 #include "base/metrics/histogram.h"
     15 #include "base/metrics/sparse_histogram.h"
     16 #include "base/stl_util.h"
     17 #include "base/strings/string_number_conversions.h"
     18 #include "base/strings/string_util.h"
     19 #include "base/strings/stringprintf.h"
     20 #include "base/time/time.h"
     21 #include "base/version.h"
     22 #include "chrome/browser/chrome_notification_types.h"
     23 #include "chrome/browser/extensions/updater/extension_cache.h"
     24 #include "chrome/browser/extensions/updater/request_queue_impl.h"
     25 #include "chrome/common/chrome_switches.h"
     26 #include "chrome/common/chrome_version_info.h"
     27 #include "chrome/common/extensions/manifest_url_handler.h"
     28 #include "content/public/browser/browser_thread.h"
     29 #include "content/public/browser/notification_details.h"
     30 #include "content/public/browser/notification_service.h"
     31 #include "extensions/browser/updater/safe_manifest_parser.h"
     32 #include "extensions/common/extension_urls.h"
     33 #include "google_apis/gaia/identity_provider.h"
     34 #include "net/base/backoff_entry.h"
     35 #include "net/base/load_flags.h"
     36 #include "net/base/net_errors.h"
     37 #include "net/http/http_request_headers.h"
     38 #include "net/http/http_status_code.h"
     39 #include "net/url_request/url_fetcher.h"
     40 #include "net/url_request/url_request_context_getter.h"
     41 #include "net/url_request/url_request_status.h"
     42 
     43 using base::Time;
     44 using base::TimeDelta;
     45 using content::BrowserThread;
     46 
     47 namespace extensions {
     48 
     49 const char ExtensionDownloader::kBlacklistAppID[] = "com.google.crx.blacklist";
     50 
     51 namespace {
     52 
     53 const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
     54   // Number of initial errors (in sequence) to ignore before applying
     55   // exponential back-off rules.
     56   0,
     57 
     58   // Initial delay for exponential back-off in ms.
     59   2000,
     60 
     61   // Factor by which the waiting time will be multiplied.
     62   2,
     63 
     64   // Fuzzing percentage. ex: 10% will spread requests randomly
     65   // between 90%-100% of the calculated time.
     66   0.1,
     67 
     68   // Maximum amount of time we are willing to delay our request in ms.
     69   -1,
     70 
     71   // Time to keep an entry from being discarded even when it
     72   // has no significant state, -1 to never discard.
     73   -1,
     74 
     75   // Don't use initial delay unless the last request was an error.
     76   false,
     77 };
     78 
     79 const char kAuthUserQueryKey[] = "authuser";
     80 
     81 const int kMaxAuthUserValue = 10;
     82 const int kMaxOAuth2Attempts = 3;
     83 
     84 const char kNotFromWebstoreInstallSource[] = "notfromwebstore";
     85 const char kDefaultInstallSource[] = "";
     86 
     87 const char kGoogleDotCom[] = "google.com";
     88 const char kTokenServiceConsumerId[] = "extension_downloader";
     89 const char kWebstoreOAuth2Scope[] =
     90     "https://www.googleapis.com/auth/chromewebstore.readonly";
     91 
     92 #define RETRY_HISTOGRAM(name, retry_count, url)                           \
     93   if ((url).DomainIs(kGoogleDotCom)) {                                    \
     94     UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions." name "RetryCountGoogleUrl", \
     95                                 retry_count,                              \
     96                                 1,                                        \
     97                                 kMaxRetries,                              \
     98                                 kMaxRetries + 1);                         \
     99   } else {                                                                \
    100     UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions." name "RetryCountOtherUrl",  \
    101                                 retry_count,                              \
    102                                 1,                                        \
    103                                 kMaxRetries,                              \
    104                                 kMaxRetries + 1);                         \
    105   }
    106 
    107 bool ShouldRetryRequest(const net::URLRequestStatus& status,
    108                         int response_code) {
    109   // Retry if the response code is a server error, or the request failed because
    110   // of network errors as opposed to file errors.
    111   return ((response_code >= 500 && status.is_success()) ||
    112           status.status() == net::URLRequestStatus::FAILED);
    113 }
    114 
    115 // This parses and updates a URL query such that the value of the |authuser|
    116 // query parameter is incremented by 1. If parameter was not present in the URL,
    117 // it will be added with a value of 1. All other query keys and values are
    118 // preserved as-is. Returns |false| if the user index exceeds a hard-coded
    119 // maximum.
    120 bool IncrementAuthUserIndex(GURL* url) {
    121   int user_index = 0;
    122   std::string old_query = url->query();
    123   std::vector<std::string> new_query_parts;
    124   url::Component query(0, old_query.length());
    125   url::Component key, value;
    126   while (url::ExtractQueryKeyValue(old_query.c_str(), &query, &key, &value)) {
    127     std::string key_string = old_query.substr(key.begin, key.len);
    128     std::string value_string = old_query.substr(value.begin, value.len);
    129     if (key_string == kAuthUserQueryKey) {
    130       base::StringToInt(value_string, &user_index);
    131     } else {
    132       new_query_parts.push_back(base::StringPrintf(
    133           "%s=%s", key_string.c_str(), value_string.c_str()));
    134     }
    135   }
    136   if (user_index >= kMaxAuthUserValue)
    137     return false;
    138   new_query_parts.push_back(
    139       base::StringPrintf("%s=%d", kAuthUserQueryKey, user_index + 1));
    140   std::string new_query_string = JoinString(new_query_parts, '&');
    141   url::Component new_query(0, new_query_string.size());
    142   url::Replacements<char> replacements;
    143   replacements.SetQuery(new_query_string.c_str(), new_query);
    144   *url = url->ReplaceComponents(replacements);
    145   return true;
    146 }
    147 
    148 }  // namespace
    149 
    150 UpdateDetails::UpdateDetails(const std::string& id, const Version& version)
    151     : id(id), version(version) {}
    152 
    153 UpdateDetails::~UpdateDetails() {}
    154 
    155 ExtensionDownloader::ExtensionFetch::ExtensionFetch()
    156     : url(), credentials(CREDENTIALS_NONE) {
    157 }
    158 
    159 ExtensionDownloader::ExtensionFetch::ExtensionFetch(
    160     const std::string& id,
    161     const GURL& url,
    162     const std::string& package_hash,
    163     const std::string& version,
    164     const std::set<int>& request_ids)
    165     : id(id),
    166       url(url),
    167       package_hash(package_hash),
    168       version(version),
    169       request_ids(request_ids),
    170       credentials(CREDENTIALS_NONE),
    171       oauth2_attempt_count(0) {
    172 }
    173 
    174 ExtensionDownloader::ExtensionFetch::~ExtensionFetch() {}
    175 
    176 ExtensionDownloader::ExtensionDownloader(
    177     ExtensionDownloaderDelegate* delegate,
    178     net::URLRequestContextGetter* request_context)
    179     : OAuth2TokenService::Consumer(kTokenServiceConsumerId),
    180       delegate_(delegate),
    181       request_context_(request_context),
    182       manifests_queue_(&kDefaultBackoffPolicy,
    183                        base::Bind(&ExtensionDownloader::CreateManifestFetcher,
    184                                   base::Unretained(this))),
    185       extensions_queue_(&kDefaultBackoffPolicy,
    186                         base::Bind(&ExtensionDownloader::CreateExtensionFetcher,
    187                                    base::Unretained(this))),
    188       extension_cache_(NULL),
    189       enable_extra_update_metrics_(false),
    190       weak_ptr_factory_(this) {
    191   DCHECK(delegate_);
    192   DCHECK(request_context_.get());
    193 }
    194 
    195 ExtensionDownloader::~ExtensionDownloader() {}
    196 
    197 bool ExtensionDownloader::AddExtension(const Extension& extension,
    198                                        int request_id) {
    199   // Skip extensions with empty update URLs converted from user
    200   // scripts.
    201   if (extension.converted_from_user_script() &&
    202       ManifestURL::GetUpdateURL(&extension).is_empty()) {
    203     return false;
    204   }
    205 
    206   // If the extension updates itself from the gallery, ignore any update URL
    207   // data.  At the moment there is no extra data that an extension can
    208   // communicate to the the gallery update servers.
    209   std::string update_url_data;
    210   if (!ManifestURL::UpdatesFromGallery(&extension))
    211     update_url_data = delegate_->GetUpdateUrlData(extension.id());
    212 
    213   std::string install_source;
    214   bool force_update = delegate_->ShouldForceUpdate(extension.id(),
    215                                                    &install_source);
    216   return AddExtensionData(extension.id(),
    217                           *extension.version(),
    218                           extension.GetType(),
    219                           ManifestURL::GetUpdateURL(&extension),
    220                           update_url_data,
    221                           request_id,
    222                           force_update,
    223                           install_source);
    224 }
    225 
    226 bool ExtensionDownloader::AddPendingExtension(const std::string& id,
    227                                               const GURL& update_url,
    228                                               int request_id) {
    229   // Use a zero version to ensure that a pending extension will always
    230   // be updated, and thus installed (assuming all extensions have
    231   // non-zero versions).
    232   Version version("0.0.0.0");
    233   DCHECK(version.IsValid());
    234 
    235   return AddExtensionData(id,
    236                           version,
    237                           Manifest::TYPE_UNKNOWN,
    238                           update_url,
    239                           std::string(),
    240                           request_id,
    241                           false,
    242                           std::string());
    243 }
    244 
    245 void ExtensionDownloader::StartAllPending(ExtensionCache* cache) {
    246   if (cache) {
    247     extension_cache_ = cache;
    248     extension_cache_->Start(base::Bind(
    249         &ExtensionDownloader::DoStartAllPending,
    250         weak_ptr_factory_.GetWeakPtr()));
    251   } else {
    252     DoStartAllPending();
    253   }
    254 }
    255 
    256 void ExtensionDownloader::DoStartAllPending() {
    257   ReportStats();
    258   url_stats_ = URLStats();
    259 
    260   for (FetchMap::iterator it = fetches_preparing_.begin();
    261        it != fetches_preparing_.end(); ++it) {
    262     std::vector<linked_ptr<ManifestFetchData> >& list = it->second;
    263     for (size_t i = 0; i < list.size(); ++i) {
    264       StartUpdateCheck(scoped_ptr<ManifestFetchData>(list[i].release()));
    265     }
    266   }
    267   fetches_preparing_.clear();
    268 }
    269 
    270 void ExtensionDownloader::StartBlacklistUpdate(
    271     const std::string& version,
    272     const ManifestFetchData::PingData& ping_data,
    273     int request_id) {
    274   // Note: it is very important that we use the https version of the update
    275   // url here to avoid DNS hijacking of the blacklist, which is not validated
    276   // by a public key signature like .crx files are.
    277   scoped_ptr<ManifestFetchData> blacklist_fetch(CreateManifestFetchData(
    278       extension_urls::GetWebstoreUpdateUrl(), request_id));
    279   DCHECK(blacklist_fetch->base_url().SchemeIsSecure());
    280   blacklist_fetch->AddExtension(kBlacklistAppID,
    281                                 version,
    282                                 &ping_data,
    283                                 std::string(),
    284                                 kDefaultInstallSource,
    285                                 false);
    286   StartUpdateCheck(blacklist_fetch.Pass());
    287 }
    288 
    289 void ExtensionDownloader::SetWebstoreIdentityProvider(
    290     scoped_ptr<IdentityProvider> identity_provider) {
    291   identity_provider_.swap(identity_provider);
    292 }
    293 
    294 bool ExtensionDownloader::AddExtensionData(
    295     const std::string& id,
    296     const Version& version,
    297     Manifest::Type extension_type,
    298     const GURL& extension_update_url,
    299     const std::string& update_url_data,
    300     int request_id,
    301     bool force_update,
    302     const std::string& install_source_override) {
    303   GURL update_url(extension_update_url);
    304   // Skip extensions with non-empty invalid update URLs.
    305   if (!update_url.is_empty() && !update_url.is_valid()) {
    306     LOG(WARNING) << "Extension " << id << " has invalid update url "
    307                  << update_url;
    308     return false;
    309   }
    310 
    311   // Make sure we use SSL for store-hosted extensions.
    312   if (extension_urls::IsWebstoreUpdateUrl(update_url) &&
    313       !update_url.SchemeIsSecure())
    314     update_url = extension_urls::GetWebstoreUpdateUrl();
    315 
    316   // Skip extensions with empty IDs.
    317   if (id.empty()) {
    318     LOG(WARNING) << "Found extension with empty ID";
    319     return false;
    320   }
    321 
    322   if (update_url.DomainIs(kGoogleDotCom)) {
    323     url_stats_.google_url_count++;
    324   } else if (update_url.is_empty()) {
    325     url_stats_.no_url_count++;
    326     // Fill in default update URL.
    327     update_url = extension_urls::GetWebstoreUpdateUrl();
    328   } else {
    329     url_stats_.other_url_count++;
    330   }
    331 
    332   switch (extension_type) {
    333     case Manifest::TYPE_THEME:
    334       ++url_stats_.theme_count;
    335       break;
    336     case Manifest::TYPE_EXTENSION:
    337     case Manifest::TYPE_USER_SCRIPT:
    338       ++url_stats_.extension_count;
    339       break;
    340     case Manifest::TYPE_HOSTED_APP:
    341     case Manifest::TYPE_LEGACY_PACKAGED_APP:
    342       ++url_stats_.app_count;
    343       break;
    344     case Manifest::TYPE_PLATFORM_APP:
    345       ++url_stats_.platform_app_count;
    346       break;
    347     case Manifest::TYPE_UNKNOWN:
    348     default:
    349       ++url_stats_.pending_count;
    350       break;
    351   }
    352 
    353   std::vector<GURL> update_urls;
    354   update_urls.push_back(update_url);
    355   // If metrics are enabled, also add to ManifestFetchData for the
    356   // webstore update URL.
    357   if (!extension_urls::IsWebstoreUpdateUrl(update_url) &&
    358       enable_extra_update_metrics_) {
    359     update_urls.push_back(extension_urls::GetWebstoreUpdateUrl());
    360   }
    361 
    362   for (size_t i = 0; i < update_urls.size(); ++i) {
    363     DCHECK(!update_urls[i].is_empty());
    364     DCHECK(update_urls[i].is_valid());
    365 
    366     std::string install_source = i == 0 ?
    367         kDefaultInstallSource : kNotFromWebstoreInstallSource;
    368     if (!install_source_override.empty()) {
    369       install_source = install_source_override;
    370     }
    371 
    372     ManifestFetchData::PingData ping_data;
    373     ManifestFetchData::PingData* optional_ping_data = NULL;
    374     if (delegate_->GetPingDataForExtension(id, &ping_data))
    375       optional_ping_data = &ping_data;
    376 
    377     // Find or create a ManifestFetchData to add this extension to.
    378     bool added = false;
    379     FetchMap::iterator existing_iter = fetches_preparing_.find(
    380         std::make_pair(request_id, update_urls[i]));
    381     if (existing_iter != fetches_preparing_.end() &&
    382         !existing_iter->second.empty()) {
    383       // Try to add to the ManifestFetchData at the end of the list.
    384       ManifestFetchData* existing_fetch = existing_iter->second.back().get();
    385       if (existing_fetch->AddExtension(id, version.GetString(),
    386                                        optional_ping_data, update_url_data,
    387                                        install_source,
    388                                        force_update)) {
    389         added = true;
    390       }
    391     }
    392     if (!added) {
    393       // Otherwise add a new element to the list, if the list doesn't exist or
    394       // if its last element is already full.
    395       linked_ptr<ManifestFetchData> fetch(
    396           CreateManifestFetchData(update_urls[i], request_id));
    397       fetches_preparing_[std::make_pair(request_id, update_urls[i])].
    398           push_back(fetch);
    399       added = fetch->AddExtension(id, version.GetString(),
    400                                   optional_ping_data,
    401                                   update_url_data,
    402                                   install_source,
    403                                   force_update);
    404       DCHECK(added);
    405     }
    406   }
    407 
    408   return true;
    409 }
    410 
    411 void ExtensionDownloader::ReportStats() const {
    412   UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtension",
    413                            url_stats_.extension_count);
    414   UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckTheme",
    415                            url_stats_.theme_count);
    416   UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckApp",
    417                            url_stats_.app_count);
    418   UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckPackagedApp",
    419                            url_stats_.platform_app_count);
    420   UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckPending",
    421                            url_stats_.pending_count);
    422   UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckGoogleUrl",
    423                            url_stats_.google_url_count);
    424   UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckOtherUrl",
    425                            url_stats_.other_url_count);
    426   UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckNoUrl",
    427                            url_stats_.no_url_count);
    428 }
    429 
    430 void ExtensionDownloader::StartUpdateCheck(
    431     scoped_ptr<ManifestFetchData> fetch_data) {
    432   const std::set<std::string>& id_set(fetch_data->extension_ids());
    433 
    434   if (CommandLine::ForCurrentProcess()->HasSwitch(
    435       switches::kDisableBackgroundNetworking)) {
    436     NotifyExtensionsDownloadFailed(id_set,
    437                                    fetch_data->request_ids(),
    438                                    ExtensionDownloaderDelegate::DISABLED);
    439     return;
    440   }
    441 
    442   RequestQueue<ManifestFetchData>::iterator i;
    443   for (i = manifests_queue_.begin(); i != manifests_queue_.end(); ++i) {
    444     if (fetch_data->full_url() == i->full_url()) {
    445       // This url is already scheduled to be fetched.
    446       i->Merge(*fetch_data);
    447       return;
    448     }
    449   }
    450 
    451   if (manifests_queue_.active_request() &&
    452       manifests_queue_.active_request()->full_url() == fetch_data->full_url()) {
    453     manifests_queue_.active_request()->Merge(*fetch_data);
    454   } else {
    455     UMA_HISTOGRAM_COUNTS("Extensions.UpdateCheckUrlLength",
    456         fetch_data->full_url().possibly_invalid_spec().length());
    457 
    458     manifests_queue_.ScheduleRequest(fetch_data.Pass());
    459   }
    460 }
    461 
    462 void ExtensionDownloader::CreateManifestFetcher() {
    463   if (VLOG_IS_ON(2)) {
    464     std::vector<std::string> id_vector(
    465         manifests_queue_.active_request()->extension_ids().begin(),
    466         manifests_queue_.active_request()->extension_ids().end());
    467     std::string id_list = JoinString(id_vector, ',');
    468     VLOG(2) << "Fetching " << manifests_queue_.active_request()->full_url()
    469             << " for " << id_list;
    470   }
    471 
    472   manifest_fetcher_.reset(net::URLFetcher::Create(
    473       kManifestFetcherId, manifests_queue_.active_request()->full_url(),
    474       net::URLFetcher::GET, this));
    475   manifest_fetcher_->SetRequestContext(request_context_.get());
    476   manifest_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
    477                                   net::LOAD_DO_NOT_SAVE_COOKIES |
    478                                   net::LOAD_DISABLE_CACHE);
    479   // Update checks can be interrupted if a network change is detected; this is
    480   // common for the retail mode AppPack on ChromeOS. Retrying once should be
    481   // enough to recover in those cases; let the fetcher retry up to 3 times
    482   // just in case. http://crosbug.com/130602
    483   manifest_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3);
    484   manifest_fetcher_->Start();
    485 }
    486 
    487 void ExtensionDownloader::OnURLFetchComplete(
    488     const net::URLFetcher* source) {
    489   VLOG(2) << source->GetResponseCode() << " " << source->GetURL();
    490 
    491   if (source == manifest_fetcher_.get()) {
    492     std::string data;
    493     source->GetResponseAsString(&data);
    494     OnManifestFetchComplete(source->GetURL(),
    495                             source->GetStatus(),
    496                             source->GetResponseCode(),
    497                             source->GetBackoffDelay(),
    498                             data);
    499   } else if (source == extension_fetcher_.get()) {
    500     OnCRXFetchComplete(source,
    501                        source->GetURL(),
    502                        source->GetStatus(),
    503                        source->GetResponseCode(),
    504                        source->GetBackoffDelay());
    505   } else {
    506     NOTREACHED();
    507   }
    508 }
    509 
    510 void ExtensionDownloader::OnManifestFetchComplete(
    511     const GURL& url,
    512     const net::URLRequestStatus& status,
    513     int response_code,
    514     const base::TimeDelta& backoff_delay,
    515     const std::string& data) {
    516   // We want to try parsing the manifest, and if it indicates updates are
    517   // available, we want to fire off requests to fetch those updates.
    518   if (status.status() == net::URLRequestStatus::SUCCESS &&
    519       (response_code == 200 || (url.SchemeIsFile() && data.length() > 0))) {
    520     RETRY_HISTOGRAM("ManifestFetchSuccess",
    521                     manifests_queue_.active_request_failure_count(), url);
    522     VLOG(2) << "beginning manifest parse for " << url;
    523     scoped_refptr<SafeManifestParser> safe_parser(
    524         new SafeManifestParser(
    525             data,
    526             manifests_queue_.reset_active_request().release(),
    527             base::Bind(&ExtensionDownloader::HandleManifestResults,
    528                        weak_ptr_factory_.GetWeakPtr())));
    529     safe_parser->Start();
    530   } else {
    531     VLOG(1) << "Failed to fetch manifest '" << url.possibly_invalid_spec()
    532             << "' response code:" << response_code;
    533     if (ShouldRetryRequest(status, response_code) &&
    534         manifests_queue_.active_request_failure_count() < kMaxRetries) {
    535       manifests_queue_.RetryRequest(backoff_delay);
    536     } else {
    537       RETRY_HISTOGRAM("ManifestFetchFailure",
    538                       manifests_queue_.active_request_failure_count(), url);
    539       NotifyExtensionsDownloadFailed(
    540           manifests_queue_.active_request()->extension_ids(),
    541           manifests_queue_.active_request()->request_ids(),
    542           ExtensionDownloaderDelegate::MANIFEST_FETCH_FAILED);
    543     }
    544   }
    545   manifest_fetcher_.reset();
    546   manifests_queue_.reset_active_request();
    547 
    548   // If we have any pending manifest requests, fire off the next one.
    549   manifests_queue_.StartNextRequest();
    550 }
    551 
    552 void ExtensionDownloader::HandleManifestResults(
    553     const ManifestFetchData& fetch_data,
    554     const UpdateManifest::Results* results) {
    555   // Keep a list of extensions that will not be updated, so that the |delegate_|
    556   // can be notified once we're done here.
    557   std::set<std::string> not_updated(fetch_data.extension_ids());
    558 
    559   if (!results) {
    560     NotifyExtensionsDownloadFailed(
    561         not_updated,
    562         fetch_data.request_ids(),
    563         ExtensionDownloaderDelegate::MANIFEST_INVALID);
    564     return;
    565   }
    566 
    567   // Examine the parsed manifest and kick off fetches of any new crx files.
    568   std::vector<int> updates;
    569   DetermineUpdates(fetch_data, *results, &updates);
    570   for (size_t i = 0; i < updates.size(); i++) {
    571     const UpdateManifest::Result* update = &(results->list.at(updates[i]));
    572     const std::string& id = update->extension_id;
    573     not_updated.erase(id);
    574 
    575     GURL crx_url = update->crx_url;
    576     if (id != kBlacklistAppID) {
    577       NotifyUpdateFound(update->extension_id, update->version);
    578     } else {
    579       // The URL of the blacklist file is returned by the server and we need to
    580       // be sure that we continue to be able to reliably detect whether a URL
    581       // references a blacklist file.
    582       DCHECK(extension_urls::IsBlacklistUpdateUrl(crx_url)) << crx_url;
    583 
    584       // Force https (crbug.com/129587).
    585       if (!crx_url.SchemeIsSecure()) {
    586         url::Replacements<char> replacements;
    587         std::string scheme("https");
    588         replacements.SetScheme(scheme.c_str(),
    589                                url::Component(0, scheme.size()));
    590         crx_url = crx_url.ReplaceComponents(replacements);
    591       }
    592     }
    593     scoped_ptr<ExtensionFetch> fetch(new ExtensionFetch(
    594         update->extension_id, crx_url, update->package_hash,
    595         update->version, fetch_data.request_ids()));
    596     FetchUpdatedExtension(fetch.Pass());
    597   }
    598 
    599   // If the manifest response included a <daystart> element, we want to save
    600   // that value for any extensions which had sent a ping in the request.
    601   if (fetch_data.base_url().DomainIs(kGoogleDotCom) &&
    602       results->daystart_elapsed_seconds >= 0) {
    603     Time day_start =
    604         Time::Now() - TimeDelta::FromSeconds(results->daystart_elapsed_seconds);
    605 
    606     const std::set<std::string>& extension_ids = fetch_data.extension_ids();
    607     std::set<std::string>::const_iterator i;
    608     for (i = extension_ids.begin(); i != extension_ids.end(); i++) {
    609       const std::string& id = *i;
    610       ExtensionDownloaderDelegate::PingResult& result = ping_results_[id];
    611       result.did_ping = fetch_data.DidPing(id, ManifestFetchData::ROLLCALL);
    612       result.day_start = day_start;
    613     }
    614   }
    615 
    616   NotifyExtensionsDownloadFailed(
    617       not_updated,
    618       fetch_data.request_ids(),
    619       ExtensionDownloaderDelegate::NO_UPDATE_AVAILABLE);
    620 }
    621 
    622 void ExtensionDownloader::DetermineUpdates(
    623     const ManifestFetchData& fetch_data,
    624     const UpdateManifest::Results& possible_updates,
    625     std::vector<int>* result) {
    626   // This will only be valid if one of possible_updates specifies
    627   // browser_min_version.
    628   Version browser_version;
    629 
    630   for (size_t i = 0; i < possible_updates.list.size(); i++) {
    631     const UpdateManifest::Result* update = &possible_updates.list[i];
    632     const std::string& id = update->extension_id;
    633 
    634     if (!fetch_data.Includes(id)) {
    635       VLOG(2) << "Ignoring " << id << " from this manifest";
    636       continue;
    637     }
    638 
    639     if (VLOG_IS_ON(2)) {
    640       if (update->version.empty())
    641         VLOG(2) << "manifest indicates " << id << " has no update";
    642       else
    643         VLOG(2) << "manifest indicates " << id
    644                 << " latest version is '" << update->version << "'";
    645     }
    646 
    647     if (!delegate_->IsExtensionPending(id)) {
    648       // If we're not installing pending extension, and the update
    649       // version is the same or older than what's already installed,
    650       // we don't want it.
    651       std::string version;
    652       if (!delegate_->GetExtensionExistingVersion(id, &version)) {
    653         VLOG(2) << id << " is not installed";
    654         continue;
    655       }
    656 
    657       VLOG(2) << id << " is at '" << version << "'";
    658 
    659       // We should skip the version check if update was forced.
    660       if (!fetch_data.DidForceUpdate(id)) {
    661         Version existing_version(version);
    662         Version update_version(update->version);
    663         if (!update_version.IsValid() ||
    664             update_version.CompareTo(existing_version) <= 0) {
    665           continue;
    666         }
    667       }
    668     }
    669 
    670     // If the update specifies a browser minimum version, do we qualify?
    671     if (update->browser_min_version.length() > 0) {
    672       // First determine the browser version if we haven't already.
    673       if (!browser_version.IsValid()) {
    674         chrome::VersionInfo version_info;
    675         if (version_info.is_valid())
    676           browser_version = Version(version_info.Version());
    677       }
    678       Version browser_min_version(update->browser_min_version);
    679       if (browser_version.IsValid() && browser_min_version.IsValid() &&
    680           browser_min_version.CompareTo(browser_version) > 0) {
    681         // TODO(asargent) - We may want this to show up in the extensions UI
    682         // eventually. (http://crbug.com/12547).
    683         LOG(WARNING) << "Updated version of extension " << id
    684                      << " available, but requires chrome version "
    685                      << update->browser_min_version;
    686         continue;
    687       }
    688     }
    689     VLOG(2) << "will try to update " << id;
    690     result->push_back(i);
    691   }
    692 }
    693 
    694   // Begins (or queues up) download of an updated extension.
    695 void ExtensionDownloader::FetchUpdatedExtension(
    696     scoped_ptr<ExtensionFetch> fetch_data) {
    697   if (!fetch_data->url.is_valid()) {
    698     // TODO(asargent): This can sometimes be invalid. See crbug.com/130881.
    699     LOG(ERROR) << "Invalid URL: '" << fetch_data->url.possibly_invalid_spec()
    700                << "' for extension " << fetch_data->id;
    701     return;
    702   }
    703 
    704   for (RequestQueue<ExtensionFetch>::iterator iter =
    705            extensions_queue_.begin();
    706        iter != extensions_queue_.end(); ++iter) {
    707     if (iter->id == fetch_data->id || iter->url == fetch_data->url) {
    708       iter->request_ids.insert(fetch_data->request_ids.begin(),
    709                                fetch_data->request_ids.end());
    710       return;  // already scheduled
    711     }
    712   }
    713 
    714   if (extensions_queue_.active_request() &&
    715       extensions_queue_.active_request()->url == fetch_data->url) {
    716     extensions_queue_.active_request()->request_ids.insert(
    717         fetch_data->request_ids.begin(), fetch_data->request_ids.end());
    718   } else {
    719     std::string version;
    720     if (extension_cache_ &&
    721         extension_cache_->GetExtension(fetch_data->id, NULL, &version) &&
    722         version == fetch_data->version) {
    723       base::FilePath crx_path;
    724       // Now get .crx file path and mark extension as used.
    725       extension_cache_->GetExtension(fetch_data->id, &crx_path, &version);
    726       NotifyDelegateDownloadFinished(fetch_data.Pass(), crx_path, false);
    727     } else {
    728       extensions_queue_.ScheduleRequest(fetch_data.Pass());
    729     }
    730   }
    731 }
    732 
    733 void ExtensionDownloader::NotifyDelegateDownloadFinished(
    734     scoped_ptr<ExtensionFetch> fetch_data,
    735     const base::FilePath& crx_path,
    736     bool file_ownership_passed) {
    737   delegate_->OnExtensionDownloadFinished(fetch_data->id, crx_path,
    738       file_ownership_passed, fetch_data->url, fetch_data->version,
    739       ping_results_[fetch_data->id], fetch_data->request_ids);
    740   ping_results_.erase(fetch_data->id);
    741 }
    742 
    743 void ExtensionDownloader::CreateExtensionFetcher() {
    744   const ExtensionFetch* fetch = extensions_queue_.active_request();
    745   extension_fetcher_.reset(net::URLFetcher::Create(
    746       kExtensionFetcherId, fetch->url, net::URLFetcher::GET, this));
    747   extension_fetcher_->SetRequestContext(request_context_.get());
    748   extension_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3);
    749 
    750   int load_flags = net::LOAD_DISABLE_CACHE;
    751   bool is_secure = fetch->url.SchemeIsSecure();
    752   if (fetch->credentials != ExtensionFetch::CREDENTIALS_COOKIES || !is_secure) {
    753       load_flags |= net::LOAD_DO_NOT_SEND_COOKIES |
    754                     net::LOAD_DO_NOT_SAVE_COOKIES;
    755   }
    756   extension_fetcher_->SetLoadFlags(load_flags);
    757 
    758   // Download CRX files to a temp file. The blacklist is small and will be
    759   // processed in memory, so it is fetched into a string.
    760   if (fetch->id != kBlacklistAppID) {
    761     extension_fetcher_->SaveResponseToTemporaryFile(
    762         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
    763   }
    764 
    765   if (fetch->credentials == ExtensionFetch::CREDENTIALS_OAUTH2_TOKEN &&
    766       is_secure) {
    767     if (access_token_.empty()) {
    768       // We should try OAuth2, but we have no token cached. This
    769       // ExtensionFetcher will be started once the token fetch is complete,
    770       // in either OnTokenFetchSuccess or OnTokenFetchFailure.
    771       DCHECK(identity_provider_.get());
    772       OAuth2TokenService::ScopeSet webstore_scopes;
    773       webstore_scopes.insert(kWebstoreOAuth2Scope);
    774       access_token_request_ =
    775           identity_provider_->GetTokenService()->StartRequest(
    776               identity_provider_->GetActiveAccountId(),
    777               webstore_scopes,
    778               this);
    779       return;
    780     }
    781     extension_fetcher_->AddExtraRequestHeader(
    782         base::StringPrintf("%s: Bearer %s",
    783             net::HttpRequestHeaders::kAuthorization,
    784             access_token_.c_str()));
    785   }
    786 
    787   VLOG(2) << "Starting fetch of " << fetch->url << " for " << fetch->id;
    788   extension_fetcher_->Start();
    789 }
    790 
    791 void ExtensionDownloader::OnCRXFetchComplete(
    792     const net::URLFetcher* source,
    793     const GURL& url,
    794     const net::URLRequestStatus& status,
    795     int response_code,
    796     const base::TimeDelta& backoff_delay) {
    797   ExtensionFetch& active_request = *extensions_queue_.active_request();
    798   const std::string& id = active_request.id;
    799   if (status.status() == net::URLRequestStatus::SUCCESS &&
    800       (response_code == 200 || url.SchemeIsFile())) {
    801     RETRY_HISTOGRAM("CrxFetchSuccess",
    802                     extensions_queue_.active_request_failure_count(), url);
    803     base::FilePath crx_path;
    804     // Take ownership of the file at |crx_path|.
    805     CHECK(source->GetResponseAsFilePath(true, &crx_path));
    806     scoped_ptr<ExtensionFetch> fetch_data =
    807         extensions_queue_.reset_active_request();
    808     if (extension_cache_) {
    809       const std::string& version = fetch_data->version;
    810       extension_cache_->PutExtension(id, crx_path, version,
    811           base::Bind(&ExtensionDownloader::NotifyDelegateDownloadFinished,
    812                      weak_ptr_factory_.GetWeakPtr(),
    813                      base::Passed(&fetch_data)));
    814     } else {
    815       NotifyDelegateDownloadFinished(fetch_data.Pass(), crx_path, true);
    816     }
    817   } else if (IterateFetchCredentialsAfterFailure(
    818                 &active_request,
    819                 status,
    820                 response_code)) {
    821     extensions_queue_.RetryRequest(backoff_delay);
    822   } else {
    823     const std::set<int>& request_ids = active_request.request_ids;
    824     const ExtensionDownloaderDelegate::PingResult& ping = ping_results_[id];
    825     VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec()
    826             << "' response code:" << response_code;
    827     if (ShouldRetryRequest(status, response_code) &&
    828         extensions_queue_.active_request_failure_count() < kMaxRetries) {
    829       extensions_queue_.RetryRequest(backoff_delay);
    830     } else {
    831       RETRY_HISTOGRAM("CrxFetchFailure",
    832                       extensions_queue_.active_request_failure_count(), url);
    833       // status.error() is 0 (net::OK) or negative. (See net/base/net_errors.h)
    834       UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.CrxFetchError", -status.error());
    835       delegate_->OnExtensionDownloadFailed(
    836           id, ExtensionDownloaderDelegate::CRX_FETCH_FAILED, ping, request_ids);
    837     }
    838     ping_results_.erase(id);
    839     extensions_queue_.reset_active_request();
    840   }
    841 
    842   extension_fetcher_.reset();
    843 
    844   // If there are any pending downloads left, start the next one.
    845   extensions_queue_.StartNextRequest();
    846 }
    847 
    848 void ExtensionDownloader::NotifyExtensionsDownloadFailed(
    849     const std::set<std::string>& extension_ids,
    850     const std::set<int>& request_ids,
    851     ExtensionDownloaderDelegate::Error error) {
    852   for (std::set<std::string>::const_iterator it = extension_ids.begin();
    853        it != extension_ids.end(); ++it) {
    854     const ExtensionDownloaderDelegate::PingResult& ping = ping_results_[*it];
    855     delegate_->OnExtensionDownloadFailed(*it, error, ping, request_ids);
    856     ping_results_.erase(*it);
    857   }
    858 }
    859 
    860 void ExtensionDownloader::NotifyUpdateFound(const std::string& id,
    861                                             const std::string& version) {
    862   UpdateDetails updateInfo(id, Version(version));
    863   content::NotificationService::current()->Notify(
    864       extensions::NOTIFICATION_EXTENSION_UPDATE_FOUND,
    865       content::NotificationService::AllBrowserContextsAndSources(),
    866       content::Details<UpdateDetails>(&updateInfo));
    867 }
    868 
    869 bool ExtensionDownloader::IterateFetchCredentialsAfterFailure(
    870     ExtensionFetch* fetch,
    871     const net::URLRequestStatus& status,
    872     int response_code) {
    873   bool auth_failure = status.status() == net::URLRequestStatus::CANCELED ||
    874                       (status.status() == net::URLRequestStatus::SUCCESS &&
    875                        (response_code == net::HTTP_UNAUTHORIZED ||
    876                         response_code == net::HTTP_FORBIDDEN));
    877   if (!auth_failure) {
    878     return false;
    879   }
    880   // Here we decide what to do next if the server refused to authorize this
    881   // fetch.
    882   switch (fetch->credentials) {
    883     case ExtensionFetch::CREDENTIALS_NONE:
    884       if (fetch->url.DomainIs(kGoogleDotCom) && identity_provider_) {
    885         fetch->credentials = ExtensionFetch::CREDENTIALS_OAUTH2_TOKEN;
    886       } else {
    887         fetch->credentials = ExtensionFetch::CREDENTIALS_COOKIES;
    888       }
    889       return true;
    890     case ExtensionFetch::CREDENTIALS_OAUTH2_TOKEN:
    891       fetch->oauth2_attempt_count++;
    892       // OAuth2 may fail due to an expired access token, in which case we
    893       // should invalidate the token and try again.
    894       if (response_code == net::HTTP_UNAUTHORIZED &&
    895           fetch->oauth2_attempt_count <= kMaxOAuth2Attempts) {
    896         DCHECK(identity_provider_.get());
    897         OAuth2TokenService::ScopeSet webstore_scopes;
    898         webstore_scopes.insert(kWebstoreOAuth2Scope);
    899         identity_provider_->GetTokenService()->InvalidateToken(
    900             identity_provider_->GetActiveAccountId(),
    901             webstore_scopes,
    902             access_token_);
    903         access_token_.clear();
    904         return true;
    905       }
    906       // Either there is no Gaia identity available, the active identity
    907       // doesn't have access to this resource, or the server keeps returning
    908       // 401s and we've retried too many times. Fall back on cookies.
    909       if (access_token_.empty() ||
    910           response_code == net::HTTP_FORBIDDEN ||
    911           fetch->oauth2_attempt_count > kMaxOAuth2Attempts) {
    912         fetch->credentials = ExtensionFetch::CREDENTIALS_COOKIES;
    913         return true;
    914       }
    915       // Something else is wrong. Time to give up.
    916       return false;
    917     case ExtensionFetch::CREDENTIALS_COOKIES:
    918       if (response_code == net::HTTP_FORBIDDEN) {
    919         // Try the next session identity, up to some maximum.
    920         return IncrementAuthUserIndex(&fetch->url);
    921       }
    922       return false;
    923     default:
    924       NOTREACHED();
    925   }
    926   NOTREACHED();
    927   return false;
    928 }
    929 
    930 void ExtensionDownloader::OnGetTokenSuccess(
    931     const OAuth2TokenService::Request* request,
    932     const std::string& access_token,
    933     const base::Time& expiration_time) {
    934   access_token_ = access_token;
    935   extension_fetcher_->AddExtraRequestHeader(
    936       base::StringPrintf("%s: Bearer %s",
    937           net::HttpRequestHeaders::kAuthorization,
    938           access_token_.c_str()));
    939   extension_fetcher_->Start();
    940 }
    941 
    942 void ExtensionDownloader::OnGetTokenFailure(
    943     const OAuth2TokenService::Request* request,
    944     const GoogleServiceAuthError& error) {
    945   // If we fail to get an access token, kick the pending fetch and let it fall
    946   // back on cookies.
    947   extension_fetcher_->Start();
    948 }
    949 
    950 ManifestFetchData* ExtensionDownloader::CreateManifestFetchData(
    951     const GURL& update_url,
    952     int request_id) {
    953   ManifestFetchData::PingMode ping_mode = ManifestFetchData::NO_PING;
    954   if (update_url.DomainIs(ping_enabled_domain_.c_str())) {
    955     if (enable_extra_update_metrics_) {
    956       ping_mode = ManifestFetchData::PING_WITH_METRICS;
    957     } else {
    958       ping_mode = ManifestFetchData::PING;
    959     }
    960   }
    961   return new ManifestFetchData(
    962       update_url, request_id, brand_code_, manifest_query_params_, ping_mode);
    963 }
    964 
    965 }  // namespace extensions
    966