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 |