| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/updater/extension_downloader.h" | 5 #include "chrome/browser/extensions/updater/extension_downloader.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 #include "content/public/browser/browser_thread.h" | 28 #include "content/public/browser/browser_thread.h" |
| 29 #include "content/public/browser/notification_details.h" | 29 #include "content/public/browser/notification_details.h" |
| 30 #include "content/public/browser/notification_service.h" | 30 #include "content/public/browser/notification_service.h" |
| 31 #include "net/base/load_flags.h" | 31 #include "net/base/load_flags.h" |
| 32 #include "net/url_request/url_fetcher.h" | 32 #include "net/url_request/url_fetcher.h" |
| 33 #include "net/url_request/url_request_status.h" | 33 #include "net/url_request/url_request_status.h" |
| 34 | 34 |
| 35 using base::Time; | 35 using base::Time; |
| 36 using base::TimeDelta; | 36 using base::TimeDelta; |
| 37 using content::BrowserThread; | 37 using content::BrowserThread; |
| 38 using extensions::ManifestFetchData; |
| 38 | 39 |
| 39 namespace extensions { | 40 namespace extensions { |
| 40 | 41 |
| 41 const char ExtensionDownloader::kBlacklistAppID[] = "com.google.crx.blacklist"; | 42 const char ExtensionDownloader::kBlacklistAppID[] = "com.google.crx.blacklist"; |
| 42 | 43 |
| 43 namespace { | 44 namespace { |
| 44 | 45 |
| 45 const char kNotFromWebstoreInstallSource[] = "notfromwebstore"; | 46 const char kNotFromWebstoreInstallSource[] = "notfromwebstore"; |
| 46 const char kDefaultInstallSource[] = ""; | 47 const char kDefaultInstallSource[] = ""; |
| 47 | 48 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 base::Bind(&CheckThatCRXIsReadable, crx_path)); | 100 base::Bind(&CheckThatCRXIsReadable, crx_path)); |
| 100 } | 101 } |
| 101 } | 102 } |
| 102 | 103 |
| 103 } // namespace | 104 } // namespace |
| 104 | 105 |
| 105 ExtensionDownloader::ExtensionFetch::ExtensionFetch() | 106 ExtensionDownloader::ExtensionFetch::ExtensionFetch() |
| 106 : id(""), | 107 : id(""), |
| 107 url(), | 108 url(), |
| 108 package_hash(""), | 109 package_hash(""), |
| 109 version("") {} | 110 version(""), |
| 111 is_sync(false) {} |
| 110 | 112 |
| 111 ExtensionDownloader::ExtensionFetch::ExtensionFetch( | 113 ExtensionDownloader::ExtensionFetch::ExtensionFetch( |
| 112 const std::string& id, | 114 const std::string& id, |
| 113 const GURL& url, | 115 const GURL& url, |
| 114 const std::string& package_hash, | 116 const std::string& package_hash, |
| 115 const std::string& version) | 117 const std::string& version, |
| 116 : id(id), url(url), package_hash(package_hash), version(version) {} | 118 const bool is_sync) |
| 119 : id(id), url(url), package_hash(package_hash), version(version), |
| 120 is_sync(is_sync) {} |
| 117 | 121 |
| 118 ExtensionDownloader::ExtensionFetch::~ExtensionFetch() {} | 122 ExtensionDownloader::ExtensionFetch::~ExtensionFetch() {} |
| 119 | 123 |
| 120 ExtensionDownloader::ExtensionDownloader( | 124 ExtensionDownloader::ExtensionDownloader( |
| 121 ExtensionDownloaderDelegate* delegate, | 125 ExtensionDownloaderDelegate* delegate, |
| 122 net::URLRequestContextGetter* request_context) | 126 net::URLRequestContextGetter* request_context) |
| 123 : delegate_(delegate), | 127 : delegate_(delegate), |
| 124 request_context_(request_context), | 128 request_context_(request_context), |
| 125 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | 129 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| 126 DCHECK(delegate_); | 130 DCHECK(delegate_); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 145 | 149 |
| 146 // If the extension updates itself from the gallery, ignore any update URL | 150 // If the extension updates itself from the gallery, ignore any update URL |
| 147 // data. At the moment there is no extra data that an extension can | 151 // data. At the moment there is no extra data that an extension can |
| 148 // communicate to the the gallery update servers. | 152 // communicate to the the gallery update servers. |
| 149 std::string update_url_data; | 153 std::string update_url_data; |
| 150 if (!extension.UpdatesFromGallery()) | 154 if (!extension.UpdatesFromGallery()) |
| 151 update_url_data = delegate_->GetUpdateUrlData(extension.id()); | 155 update_url_data = delegate_->GetUpdateUrlData(extension.id()); |
| 152 | 156 |
| 153 return AddExtensionData(extension.id(), *extension.version(), | 157 return AddExtensionData(extension.id(), *extension.version(), |
| 154 extension.GetType(), extension.update_url(), | 158 extension.GetType(), extension.update_url(), |
| 155 update_url_data); | 159 update_url_data, false); |
| 156 } | 160 } |
| 157 | 161 |
| 158 bool ExtensionDownloader::AddPendingExtension(const std::string& id, | 162 bool ExtensionDownloader::AddPendingExtension(const std::string& id, |
| 159 const GURL& update_url) { | 163 const GURL& update_url, |
| 164 bool is_sync) { |
| 160 // Use a zero version to ensure that a pending extension will always | 165 // Use a zero version to ensure that a pending extension will always |
| 161 // be updated, and thus installed (assuming all extensions have | 166 // be updated, and thus installed (assuming all extensions have |
| 162 // non-zero versions). | 167 // non-zero versions). |
| 163 Version version("0.0.0.0"); | 168 Version version("0.0.0.0"); |
| 164 DCHECK(version.IsValid()); | 169 DCHECK(version.IsValid()); |
| 165 | 170 |
| 166 return AddExtensionData(id, version, Extension::TYPE_UNKNOWN, update_url, ""); | 171 return AddExtensionData(id, version, Extension::TYPE_UNKNOWN, update_url, "", |
| 172 is_sync); |
| 167 } | 173 } |
| 168 | 174 |
| 169 void ExtensionDownloader::StartAllPending() { | 175 void ExtensionDownloader::StartAllPending() { |
| 170 ReportStats(); | 176 ReportStats(); |
| 171 url_stats_ = URLStats(); | 177 url_stats_ = URLStats(); |
| 172 | 178 |
| 173 for (FetchMap::iterator it = fetches_preparing_.begin(); | 179 for (FetchMap::iterator it = fetches_preparing_.begin(); |
| 174 it != fetches_preparing_.end(); ++it) { | 180 it != fetches_preparing_.end(); ++it) { |
| 175 const std::vector<ManifestFetchData*>& list = it->second; | 181 const std::vector<ManifestFetchData*>& list = it->second; |
| 176 for (size_t i = 0; i < list.size(); ++i) { | 182 for (size_t i = 0; i < list.size(); ++i) { |
| 177 StartUpdateCheck(list[i]); | 183 StartUpdateCheck(list[i]); |
| 178 } | 184 } |
| 179 } | 185 } |
| 180 fetches_preparing_.clear(); | 186 fetches_preparing_.clear(); |
| 181 } | 187 } |
| 182 | 188 |
| 183 void ExtensionDownloader::StartBlacklistUpdate( | 189 void ExtensionDownloader::StartBlacklistUpdate( |
| 184 const std::string& version, | 190 const std::string& version, const ManifestFetchData::PingData& ping_data) { |
| 185 const ManifestFetchData::PingData& ping_data) { | |
| 186 // Note: it is very important that we use the https version of the update | 191 // Note: it is very important that we use the https version of the update |
| 187 // url here to avoid DNS hijacking of the blacklist, which is not validated | 192 // url here to avoid DNS hijacking of the blacklist, which is not validated |
| 188 // by a public key signature like .crx files are. | 193 // by a public key signature like .crx files are. |
| 189 ManifestFetchData* blacklist_fetch = | 194 ManifestFetchData* blacklist_fetch = |
| 190 new ManifestFetchData(extension_urls::GetWebstoreUpdateUrl(true)); | 195 new ManifestFetchData(extension_urls::GetWebstoreUpdateUrl(true)); |
| 191 blacklist_fetch->AddExtension(kBlacklistAppID, version, &ping_data, "", | 196 blacklist_fetch->AddExtension(kBlacklistAppID, version, &ping_data, "", |
| 192 kDefaultInstallSource); | 197 kDefaultInstallSource, false /* is_sync */); |
| 193 StartUpdateCheck(blacklist_fetch); | 198 StartUpdateCheck(blacklist_fetch); |
| 194 } | 199 } |
| 195 | 200 |
| 196 bool ExtensionDownloader::AddExtensionData(const std::string& id, | 201 bool ExtensionDownloader::AddExtensionData(const std::string& id, |
| 197 const Version& version, | 202 const Version& version, |
| 198 Extension::Type extension_type, | 203 Extension::Type extension_type, |
| 199 GURL update_url, | 204 GURL update_url, |
| 200 const std::string& update_url_data) { | 205 const std::string& update_url_data, |
| 206 bool is_sync) { |
| 201 // Skip extensions with non-empty invalid update URLs. | 207 // Skip extensions with non-empty invalid update URLs. |
| 202 if (!update_url.is_empty() && !update_url.is_valid()) { | 208 if (!update_url.is_empty() && !update_url.is_valid()) { |
| 203 LOG(WARNING) << "Extension " << id << " has invalid update url " | 209 LOG(WARNING) << "Extension " << id << " has invalid update url " |
| 204 << update_url; | 210 << update_url; |
| 205 return false; | 211 return false; |
| 206 } | 212 } |
| 207 | 213 |
| 208 // Skip extensions with empty IDs. | 214 // Skip extensions with empty IDs. |
| 209 if (id.empty()) { | 215 if (id.empty()) { |
| 210 LOG(WARNING) << "Found extension with empty ID"; | 216 LOG(WARNING) << "Found extension with empty ID"; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 | 270 |
| 265 // Find or create a ManifestFetchData to add this extension to. | 271 // Find or create a ManifestFetchData to add this extension to. |
| 266 ManifestFetchData* fetch = NULL; | 272 ManifestFetchData* fetch = NULL; |
| 267 FetchMap::iterator existing_iter = fetches_preparing_.find(update_urls[i]); | 273 FetchMap::iterator existing_iter = fetches_preparing_.find(update_urls[i]); |
| 268 if (existing_iter != fetches_preparing_.end() && | 274 if (existing_iter != fetches_preparing_.end() && |
| 269 !existing_iter->second.empty()) { | 275 !existing_iter->second.empty()) { |
| 270 // Try to add to the ManifestFetchData at the end of the list. | 276 // Try to add to the ManifestFetchData at the end of the list. |
| 271 ManifestFetchData* existing_fetch = existing_iter->second.back(); | 277 ManifestFetchData* existing_fetch = existing_iter->second.back(); |
| 272 if (existing_fetch->AddExtension(id, version.GetString(), | 278 if (existing_fetch->AddExtension(id, version.GetString(), |
| 273 optional_ping_data, update_url_data, | 279 optional_ping_data, update_url_data, |
| 274 install_source)) { | 280 install_source, is_sync)) { |
| 275 fetch = existing_fetch; | 281 fetch = existing_fetch; |
| 276 } | 282 } |
| 277 } | 283 } |
| 278 if (!fetch) { | 284 if (!fetch) { |
| 279 // Otherwise add a new element to the list, if the list doesn't exist or | 285 // Otherwise add a new element to the list, if the list doesn't exist or |
| 280 // if its last element is already full. | 286 // if its last element is already full. |
| 281 fetch = new ManifestFetchData(update_urls[i]); | 287 fetch = new ManifestFetchData(update_urls[i]); |
| 282 fetches_preparing_[update_urls[i]].push_back(fetch); | 288 fetches_preparing_[update_urls[i]].push_back(fetch); |
| 283 bool added = fetch->AddExtension(id, version.GetString(), | 289 bool added = fetch->AddExtension(id, version.GetString(), |
| 284 optional_ping_data, | 290 optional_ping_data, |
| 285 update_url_data, | 291 update_url_data, |
| 286 install_source); | 292 install_source, |
| 293 is_sync); |
| 287 DCHECK(added); | 294 DCHECK(added); |
| 288 } | 295 } |
| 289 } | 296 } |
| 290 | 297 |
| 291 return true; | 298 return true; |
| 292 } | 299 } |
| 293 | 300 |
| 294 void ExtensionDownloader::ReportStats() const { | 301 void ExtensionDownloader::ReportStats() const { |
| 295 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtension", | 302 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtension", |
| 296 url_stats_.extension_count); | 303 url_stats_.extension_count); |
| 297 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckTheme", | 304 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckTheme", |
| 298 url_stats_.theme_count); | 305 url_stats_.theme_count); |
| 299 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckApp", | 306 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckApp", |
| 300 url_stats_.app_count); | 307 url_stats_.app_count); |
| 301 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckPending", | 308 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckPending", |
| 302 url_stats_.pending_count); | 309 url_stats_.pending_count); |
| 303 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckGoogleUrl", | 310 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckGoogleUrl", |
| 304 url_stats_.google_url_count); | 311 url_stats_.google_url_count); |
| 305 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckOtherUrl", | 312 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckOtherUrl", |
| 306 url_stats_.other_url_count); | 313 url_stats_.other_url_count); |
| 307 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckNoUrl", | 314 UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckNoUrl", |
| 308 url_stats_.no_url_count); | 315 url_stats_.no_url_count); |
| 309 } | 316 } |
| 310 | 317 |
| 311 void ExtensionDownloader::StartUpdateCheck(ManifestFetchData* fetch_data) { | 318 void ExtensionDownloader::StartUpdateCheck(ManifestFetchData* fetch_data) { |
| 312 scoped_ptr<ManifestFetchData> scoped_fetch_data(fetch_data); | 319 scoped_ptr<ManifestFetchData> scoped_fetch_data(fetch_data); |
| 313 const std::set<std::string>& id_set(fetch_data->extension_ids()); | 320 const ManifestFetchData::ExtensionInfoMap& id_map( |
| 321 fetch_data->extension_infos()); |
| 314 | 322 |
| 315 if (CommandLine::ForCurrentProcess()->HasSwitch( | 323 if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 316 switches::kDisableBackgroundNetworking)) { | 324 switches::kDisableBackgroundNetworking)) { |
| 317 NotifyExtensionsDownloadFailed(id_set, | 325 NotifyExtensionsDownloadFailed(id_map, |
| 318 ExtensionDownloaderDelegate::DISABLED); | 326 ExtensionDownloaderDelegate::DISABLED); |
| 319 return; | 327 return; |
| 320 } | 328 } |
| 321 | 329 |
| 322 std::deque<ManifestFetchData*>::const_iterator i; | 330 std::deque<ManifestFetchData*>::const_iterator i; |
| 323 for (i = manifests_pending_.begin(); i != manifests_pending_.end(); i++) { | 331 for (i = manifests_pending_.begin(); i != manifests_pending_.end(); i++) { |
| 324 if (fetch_data->full_url() == (*i)->full_url()) { | 332 if (fetch_data->full_url() == (*i)->full_url()) { |
| 325 // This url is already scheduled to be fetched. | 333 // This url is already scheduled to be fetched. |
| 326 return; | 334 return; |
| 327 } | 335 } |
| 328 } | 336 } |
| 329 | 337 |
| 330 if (manifest_fetcher_.get() != NULL) { | 338 if (manifest_fetcher_.get() != NULL) { |
| 331 if (manifest_fetcher_->GetURL() != fetch_data->full_url()) { | 339 if (manifest_fetcher_->GetURL() != fetch_data->full_url()) { |
| 332 manifests_pending_.push_back(scoped_fetch_data.release()); | 340 manifests_pending_.push_back(scoped_fetch_data.release()); |
| 333 } | 341 } |
| 334 } else { | 342 } else { |
| 335 UMA_HISTOGRAM_COUNTS("Extensions.UpdateCheckUrlLength", | 343 UMA_HISTOGRAM_COUNTS("Extensions.UpdateCheckUrlLength", |
| 336 fetch_data->full_url().possibly_invalid_spec().length()); | 344 fetch_data->full_url().possibly_invalid_spec().length()); |
| 337 | 345 |
| 338 if (VLOG_IS_ON(2)) { | 346 if (VLOG_IS_ON(2)) { |
| 339 std::vector<std::string> id_vector(id_set.begin(), id_set.end()); | 347 std::vector<std::string> id_vector; |
| 348 ManifestFetchData::ExtensionInfoMap::const_iterator it; |
| 349 for (it = id_map.begin(); it != id_map.end(); ++it) |
| 350 id_vector.push_back(it->first); |
| 340 std::string id_list = JoinString(id_vector, ','); | 351 std::string id_list = JoinString(id_vector, ','); |
| 341 VLOG(2) << "Fetching " << fetch_data->full_url() << " for " | 352 VLOG(2) << "Fetching " << fetch_data->full_url() << " for " << id_list; |
| 342 << id_list; | |
| 343 } | 353 } |
| 344 | 354 |
| 345 current_manifest_fetch_.swap(scoped_fetch_data); | 355 current_manifest_fetch_.swap(scoped_fetch_data); |
| 346 manifest_fetcher_.reset(net::URLFetcher::Create( | 356 manifest_fetcher_.reset(net::URLFetcher::Create( |
| 347 kManifestFetcherId, fetch_data->full_url(), net::URLFetcher::GET, | 357 kManifestFetcherId, fetch_data->full_url(), net::URLFetcher::GET, |
| 348 this)); | 358 this)); |
| 349 manifest_fetcher_->SetRequestContext(request_context_); | 359 manifest_fetcher_->SetRequestContext(request_context_); |
| 350 manifest_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 360 manifest_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 351 net::LOAD_DO_NOT_SAVE_COOKIES | | 361 net::LOAD_DO_NOT_SAVE_COOKIES | |
| 352 net::LOAD_DISABLE_CACHE); | 362 net::LOAD_DISABLE_CACHE); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 data, | 400 data, |
| 391 current_manifest_fetch_.release(), | 401 current_manifest_fetch_.release(), |
| 392 base::Bind(&ExtensionDownloader::HandleManifestResults, | 402 base::Bind(&ExtensionDownloader::HandleManifestResults, |
| 393 weak_ptr_factory_.GetWeakPtr()))); | 403 weak_ptr_factory_.GetWeakPtr()))); |
| 394 safe_parser->Start(); | 404 safe_parser->Start(); |
| 395 } else { | 405 } else { |
| 396 // TODO(asargent) Do exponential backoff here. (http://crbug.com/12546). | 406 // TODO(asargent) Do exponential backoff here. (http://crbug.com/12546). |
| 397 VLOG(1) << "Failed to fetch manifest '" << url.possibly_invalid_spec() | 407 VLOG(1) << "Failed to fetch manifest '" << url.possibly_invalid_spec() |
| 398 << "' response code:" << response_code; | 408 << "' response code:" << response_code; |
| 399 NotifyExtensionsDownloadFailed( | 409 NotifyExtensionsDownloadFailed( |
| 400 current_manifest_fetch_->extension_ids(), | 410 current_manifest_fetch_->extension_infos(), |
| 401 ExtensionDownloaderDelegate::MANIFEST_FETCH_FAILED); | 411 ExtensionDownloaderDelegate::MANIFEST_FETCH_FAILED); |
| 402 } | 412 } |
| 403 manifest_fetcher_.reset(); | 413 manifest_fetcher_.reset(); |
| 404 current_manifest_fetch_.reset(); | 414 current_manifest_fetch_.reset(); |
| 405 | 415 |
| 406 // If we have any pending manifest requests, fire off the next one. | 416 // If we have any pending manifest requests, fire off the next one. |
| 407 if (!manifests_pending_.empty()) { | 417 if (!manifests_pending_.empty()) { |
| 408 ManifestFetchData* manifest_fetch = manifests_pending_.front(); | 418 ManifestFetchData* manifest_fetch = manifests_pending_.front(); |
| 409 manifests_pending_.pop_front(); | 419 manifests_pending_.pop_front(); |
| 410 StartUpdateCheck(manifest_fetch); | 420 StartUpdateCheck(manifest_fetch); |
| 411 } | 421 } |
| 412 } | 422 } |
| 413 | 423 |
| 414 void ExtensionDownloader::HandleManifestResults( | 424 void ExtensionDownloader::HandleManifestResults( |
| 415 const ManifestFetchData& fetch_data, | 425 const ManifestFetchData& fetch_data, |
| 416 const UpdateManifest::Results* results) { | 426 const UpdateManifest::Results* results) { |
| 417 // Keep a list of extensions that will not be updated, so that the |delegate_| | 427 // Keep a list of extensions that will not be updated, so that the |delegate_| |
| 418 // can be notified once we're done here. | 428 // can be notified once we're done here. |
| 419 std::set<std::string> not_updated(fetch_data.extension_ids()); | 429 ManifestFetchData::ExtensionInfoMap not_updated(fetch_data.extension_infos()); |
| 420 | 430 |
| 421 if (!results) { | 431 if (!results) { |
| 422 NotifyExtensionsDownloadFailed( | 432 NotifyExtensionsDownloadFailed( |
| 423 not_updated, | 433 not_updated, |
| 424 ExtensionDownloaderDelegate::MANIFEST_INVALID); | 434 ExtensionDownloaderDelegate::MANIFEST_INVALID); |
| 425 return; | 435 return; |
| 426 } | 436 } |
| 427 | 437 |
| 428 // Examine the parsed manifest and kick off fetches of any new crx files. | 438 // Examine the parsed manifest and kick off fetches of any new crx files. |
| 429 std::vector<int> updates; | 439 std::vector<int> updates; |
| 430 DetermineUpdates(fetch_data, *results, &updates); | 440 DetermineUpdates(fetch_data, *results, &updates); |
| 431 for (size_t i = 0; i < updates.size(); i++) { | 441 for (size_t i = 0; i < updates.size(); i++) { |
| 432 const UpdateManifest::Result* update = &(results->list.at(updates[i])); | 442 const UpdateManifest::Result* update = &(results->list.at(updates[i])); |
| 433 const std::string& id = update->extension_id; | 443 const std::string& id = update->extension_id; |
| 444 bool is_sync = not_updated[id].is_sync; |
| 434 not_updated.erase(id); | 445 not_updated.erase(id); |
| 435 if (id != kBlacklistAppID) { | 446 if (id != kBlacklistAppID) { |
| 436 NotifyUpdateFound(update->extension_id); | 447 NotifyUpdateFound(update->extension_id); |
| 437 } else { | 448 } else { |
| 438 // The URL of the blacklist file is returned by the server and we need to | 449 // The URL of the blacklist file is returned by the server and we need to |
| 439 // be sure that we continue to be able to reliably detect whether a URL | 450 // be sure that we continue to be able to reliably detect whether a URL |
| 440 // references a blacklist file. | 451 // references a blacklist file. |
| 441 DCHECK(extension_urls::IsBlacklistUpdateUrl(update->crx_url)) | 452 DCHECK(extension_urls::IsBlacklistUpdateUrl(update->crx_url)) |
| 442 << update->crx_url; | 453 << update->crx_url; |
| 443 } | 454 } |
| 444 FetchUpdatedExtension(update->extension_id, update->crx_url, | 455 FetchUpdatedExtension(update->extension_id, update->crx_url, |
| 445 update->package_hash, update->version); | 456 update->package_hash, update->version, |
| 457 is_sync); |
| 446 } | 458 } |
| 447 | 459 |
| 448 // If the manifest response included a <daystart> element, we want to save | 460 // If the manifest response included a <daystart> element, we want to save |
| 449 // that value for any extensions which had sent a ping in the request. | 461 // that value for any extensions which had sent a ping in the request. |
| 450 if (fetch_data.base_url().DomainIs("google.com") && | 462 if (fetch_data.base_url().DomainIs("google.com") && |
| 451 results->daystart_elapsed_seconds >= 0) { | 463 results->daystart_elapsed_seconds >= 0) { |
| 452 Time day_start = | 464 Time day_start = |
| 453 Time::Now() - TimeDelta::FromSeconds(results->daystart_elapsed_seconds); | 465 Time::Now() - TimeDelta::FromSeconds(results->daystart_elapsed_seconds); |
| 454 | 466 |
| 455 const std::set<std::string>& extension_ids = fetch_data.extension_ids(); | 467 const ManifestFetchData::ExtensionInfoMap& extension_ids = |
| 456 std::set<std::string>::const_iterator i; | 468 fetch_data.extension_infos(); |
| 469 ManifestFetchData::ExtensionInfoMap::const_iterator i; |
| 457 for (i = extension_ids.begin(); i != extension_ids.end(); i++) { | 470 for (i = extension_ids.begin(); i != extension_ids.end(); i++) { |
| 458 const std::string& id = *i; | 471 const std::string& id = i->first; |
| 459 ExtensionDownloaderDelegate::PingResult& result = ping_results_[id]; | 472 ExtensionDownloaderDelegate::PingResult& result = ping_results_[id]; |
| 460 result.did_ping = fetch_data.DidPing(id, ManifestFetchData::ROLLCALL); | 473 result.did_ping = fetch_data.DidPing(id, ManifestFetchData::ROLLCALL); |
| 461 result.day_start = day_start; | 474 result.day_start = day_start; |
| 462 } | 475 } |
| 463 } | 476 } |
| 464 | 477 |
| 465 NotifyExtensionsDownloadFailed( | 478 NotifyExtensionsDownloadFailed( |
| 466 not_updated, | 479 not_updated, |
| 467 ExtensionDownloaderDelegate::NO_UPDATE_AVAILABLE); | 480 ExtensionDownloaderDelegate::NO_UPDATE_AVAILABLE); |
| 468 } | 481 } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 534 } | 547 } |
| 535 VLOG(2) << "will try to update " << id; | 548 VLOG(2) << "will try to update " << id; |
| 536 result->push_back(i); | 549 result->push_back(i); |
| 537 } | 550 } |
| 538 } | 551 } |
| 539 | 552 |
| 540 // Begins (or queues up) download of an updated extension. | 553 // Begins (or queues up) download of an updated extension. |
| 541 void ExtensionDownloader::FetchUpdatedExtension(const std::string& id, | 554 void ExtensionDownloader::FetchUpdatedExtension(const std::string& id, |
| 542 const GURL& url, | 555 const GURL& url, |
| 543 const std::string& hash, | 556 const std::string& hash, |
| 544 const std::string& version) { | 557 const std::string& version, |
| 558 const bool is_sync) { |
| 545 if (!url.is_valid()) { | 559 if (!url.is_valid()) { |
| 546 // TODO(asargent): This can sometimes be invalid. See crbug.com/130881. | 560 // TODO(asargent): This can sometimes be invalid. See crbug.com/130881. |
| 547 LOG(ERROR) << "Invalid URL: '" << url.possibly_invalid_spec() | 561 LOG(ERROR) << "Invalid URL: '" << url.possibly_invalid_spec() |
| 548 << "' for extension " << id; | 562 << "' for extension " << id; |
| 549 return; | 563 return; |
| 550 } | 564 } |
| 551 | 565 |
| 552 for (std::deque<ExtensionFetch>::const_iterator iter = | 566 for (std::deque<ExtensionFetch>::const_iterator iter = |
| 553 extensions_pending_.begin(); | 567 extensions_pending_.begin(); |
| 554 iter != extensions_pending_.end(); ++iter) { | 568 iter != extensions_pending_.end(); ++iter) { |
| 555 if (iter->id == id || iter->url == url) { | 569 if (iter->id == id || iter->url == url) { |
| 556 return; // already scheduled | 570 return; // already scheduled |
| 557 } | 571 } |
| 558 } | 572 } |
| 559 | 573 |
| 560 if (extension_fetcher_.get() != NULL) { | 574 if (extension_fetcher_.get() != NULL) { |
| 561 if (extension_fetcher_->GetURL() != url) { | 575 if (extension_fetcher_->GetURL() != url) { |
| 562 extensions_pending_.push_back(ExtensionFetch(id, url, hash, version)); | 576 extensions_pending_.push_back(ExtensionFetch(id, url, hash, version, |
| 577 is_sync)); |
| 563 } | 578 } |
| 564 } else { | 579 } else { |
| 565 extension_fetcher_.reset(net::URLFetcher::Create( | 580 extension_fetcher_.reset(net::URLFetcher::Create( |
| 566 kExtensionFetcherId, url, net::URLFetcher::GET, this)); | 581 kExtensionFetcherId, url, net::URLFetcher::GET, this)); |
| 567 extension_fetcher_->SetRequestContext(request_context_); | 582 extension_fetcher_->SetRequestContext(request_context_); |
| 568 extension_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 583 extension_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 569 net::LOAD_DO_NOT_SAVE_COOKIES | | 584 net::LOAD_DO_NOT_SAVE_COOKIES | |
| 570 net::LOAD_DISABLE_CACHE); | 585 net::LOAD_DISABLE_CACHE); |
| 571 // Download CRX files to a temp file. The blacklist is small and will be | 586 // Download CRX files to a temp file. The blacklist is small and will be |
| 572 // processed in memory, so it is fetched into a string. | 587 // processed in memory, so it is fetched into a string. |
| 573 if (id != kBlacklistAppID) { | 588 if (id != kBlacklistAppID) { |
| 574 extension_fetcher_->SaveResponseToTemporaryFile( | 589 extension_fetcher_->SaveResponseToTemporaryFile( |
| 575 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)); | 590 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)); |
| 576 } | 591 } |
| 577 | 592 |
| 578 VLOG(2) << "Starting fetch of " << url << " for " << id; | 593 VLOG(2) << "Starting fetch of " << url << " for " << id; |
| 579 | 594 |
| 580 extension_fetcher_->Start(); | 595 extension_fetcher_->Start(); |
| 581 current_extension_fetch_ = ExtensionFetch(id, url, hash, version); | 596 current_extension_fetch_ = ExtensionFetch(id, url, hash, version, is_sync); |
| 582 } | 597 } |
| 583 } | 598 } |
| 584 | 599 |
| 585 void ExtensionDownloader::OnCRXFetchComplete( | 600 void ExtensionDownloader::OnCRXFetchComplete( |
| 586 const net::URLFetcher* source, | 601 const net::URLFetcher* source, |
| 587 const GURL& url, | 602 const GURL& url, |
| 588 const net::URLRequestStatus& status, | 603 const net::URLRequestStatus& status, |
| 589 int response_code) { | 604 int response_code) { |
| 590 const std::string& id = current_extension_fetch_.id; | 605 const std::string& id = current_extension_fetch_.id; |
| 591 const ExtensionDownloaderDelegate::PingResult& ping = ping_results_[id]; | 606 const ExtensionDownloaderDelegate::PingResult& ping = ping_results_[id]; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 607 delegate_->OnBlacklistDownloadFinished( | 622 delegate_->OnBlacklistDownloadFinished( |
| 608 data, current_extension_fetch_.package_hash, | 623 data, current_extension_fetch_.package_hash, |
| 609 current_extension_fetch_.version, ping); | 624 current_extension_fetch_.version, ping); |
| 610 } else { | 625 } else { |
| 611 FilePath crx_path; | 626 FilePath crx_path; |
| 612 // Take ownership of the file at |crx_path|. | 627 // Take ownership of the file at |crx_path|. |
| 613 CHECK(source->GetResponseAsFilePath(true, &crx_path)); | 628 CHECK(source->GetResponseAsFilePath(true, &crx_path)); |
| 614 RecordCRXWriteHistogram(true, crx_path); | 629 RecordCRXWriteHistogram(true, crx_path); |
| 615 delegate_->OnExtensionDownloadFinished(id, crx_path, url, | 630 delegate_->OnExtensionDownloadFinished(id, crx_path, url, |
| 616 current_extension_fetch_.version, | 631 current_extension_fetch_.version, |
| 617 ping); | 632 ping, |
| 633 current_extension_fetch_.is_sync); |
| 618 } | 634 } |
| 619 } else { | 635 } else { |
| 620 // TODO(asargent) do things like exponential backoff, handling | 636 // TODO(asargent) do things like exponential backoff, handling |
| 621 // 503 Service Unavailable / Retry-After headers, etc. here. | 637 // 503 Service Unavailable / Retry-After headers, etc. here. |
| 622 // (http://crbug.com/12546). | 638 // (http://crbug.com/12546). |
| 623 VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec() | 639 VLOG(1) << "Failed to fetch extension '" << url.possibly_invalid_spec() |
| 624 << "' response code:" << response_code; | 640 << "' response code:" << response_code; |
| 625 delegate_->OnExtensionDownloadFailed( | 641 delegate_->OnExtensionDownloadFailed( |
| 626 id, ExtensionDownloaderDelegate::CRX_FETCH_FAILED, ping); | 642 id, ExtensionDownloaderDelegate::CRX_FETCH_FAILED, ping); |
| 627 } | 643 } |
| 628 | 644 |
| 629 extension_fetcher_.reset(); | 645 extension_fetcher_.reset(); |
| 630 current_extension_fetch_ = ExtensionFetch(); | 646 current_extension_fetch_ = ExtensionFetch(); |
| 631 ping_results_.erase(id); | 647 ping_results_.erase(id); |
| 632 | 648 |
| 633 // If there are any pending downloads left, start the next one. | 649 // If there are any pending downloads left, start the next one. |
| 634 if (!extensions_pending_.empty()) { | 650 if (!extensions_pending_.empty()) { |
| 635 ExtensionFetch next = extensions_pending_.front(); | 651 ExtensionFetch next = extensions_pending_.front(); |
| 636 extensions_pending_.pop_front(); | 652 extensions_pending_.pop_front(); |
| 637 FetchUpdatedExtension(next.id, next.url, next.package_hash, next.version); | 653 FetchUpdatedExtension(next.id, next.url, next.package_hash, next.version, |
| 654 next.is_sync); |
| 638 } | 655 } |
| 639 } | 656 } |
| 640 | 657 |
| 641 void ExtensionDownloader::NotifyExtensionsDownloadFailed( | 658 void ExtensionDownloader::NotifyExtensionsDownloadFailed( |
| 642 const std::set<std::string>& extension_ids, | 659 const ManifestFetchData::ExtensionInfoMap& extension_ids, |
| 643 ExtensionDownloaderDelegate::Error error) { | 660 ExtensionDownloaderDelegate::Error error) { |
| 644 for (std::set<std::string>::const_iterator it = extension_ids.begin(); | 661 ManifestFetchData::ExtensionInfoMap::const_iterator it; |
| 645 it != extension_ids.end(); ++it) { | 662 for (it = extension_ids.begin(); it != extension_ids.end(); ++it) { |
| 646 delegate_->OnExtensionDownloadFailed(*it, error, ping_results_[*it]); | 663 delegate_->OnExtensionDownloadFailed(it->first, error, |
| 647 ping_results_.erase(*it); | 664 ping_results_[it->first]); |
| 665 ping_results_.erase(it->first); |
| 648 } | 666 } |
| 649 } | 667 } |
| 650 | 668 |
| 651 void ExtensionDownloader::NotifyUpdateFound(const std::string& id) { | 669 void ExtensionDownloader::NotifyUpdateFound(const std::string& id) { |
| 652 content::NotificationService::current()->Notify( | 670 content::NotificationService::current()->Notify( |
| 653 chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND, | 671 chrome::NOTIFICATION_EXTENSION_UPDATE_FOUND, |
| 654 content::NotificationService::AllBrowserContextsAndSources(), | 672 content::NotificationService::AllBrowserContextsAndSources(), |
| 655 content::Details<const std::string>(&id)); | 673 content::Details<const std::string>(&id)); |
| 656 } | 674 } |
| 657 | 675 |
| 658 } // namespace extensions | 676 } // namespace extensions |
| OLD | NEW |