blob: e07f6c6cce5a6a8838a06cb039a0321dd177cf85 [file] [log] [blame]
[email protected]de0fdca22014-08-19 05:26:091// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]afa378f22013-12-02 03:37:542// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
sorin52ac0882015-01-24 01:15:005#include "components/update_client/crx_downloader.h"
[email protected]ed6fb982014-07-23 16:56:526
dcheng51ace48a2015-12-26 22:45:177#include <utility>
8
sorin6bb8de42015-06-03 00:23:279#include "base/bind.h"
sorin74e70672016-02-03 03:13:1010#include "base/files/file_util.h"
sorin6bb8de42015-06-03 00:23:2711#include "base/location.h"
[email protected]ed6fb982014-07-23 16:56:5212#include "base/logging.h"
Gabriel Charette44db1422018-08-06 11:19:3313#include "base/task/post_task.h"
14#include "base/task/task_traits.h"
gab7966d312016-05-11 20:35:0115#include "base/threading/thread_task_runner_handle.h"
avi5dd91f82015-12-25 22:30:4616#include "build/build_config.h"
[email protected]3cb2a4f2013-12-07 21:54:3417#if defined(OS_WIN)
sorin52ac0882015-01-24 01:15:0018#include "components/update_client/background_downloader_win.h"
[email protected]3cb2a4f2013-12-07 21:54:3419#endif
Sorin Jianuebd652462017-07-23 02:00:5820#include "components/update_client/task_traits.h"
sorin7b8650522016-11-02 18:23:4121#include "components/update_client/update_client_errors.h"
sorin74e70672016-02-03 03:13:1022#include "components/update_client/url_fetcher_downloader.h"
23#include "components/update_client/utils.h"
Antonio Gomes0807dd62018-08-10 14:28:4724#include "services/network/public/cpp/shared_url_loader_factory.h"
[email protected]3cb2a4f2013-12-07 21:54:3425
sorin52ac0882015-01-24 01:15:0026namespace update_client {
[email protected]afa378f22013-12-02 03:37:5427
[email protected]3a0092d2013-12-18 03:04:3528CrxDownloader::DownloadMetrics::DownloadMetrics()
29 : downloader(kNone),
30 error(0),
[email protected]8a5ebd432014-05-02 00:21:2231 downloaded_bytes(-1),
32 total_bytes(-1),
33 download_time_ms(0) {
34}
[email protected]3a0092d2013-12-18 03:04:3535
[email protected]3cb2a4f2013-12-07 21:54:3436// On Windows, the first downloader in the chain is a background downloader,
37// which uses the BITS service.
dchengd0fc6aa92016-04-22 18:03:1238std::unique_ptr<CrxDownloader> CrxDownloader::Create(
[email protected]3cb2a4f2013-12-07 21:54:3439 bool is_background_download,
Antonio Gomes0807dd62018-08-10 14:28:4740 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
Sorin Jianuebd652462017-07-23 02:00:5841 std::unique_ptr<CrxDownloader> url_fetcher_downloader =
Antonio Gomes0807dd62018-08-10 14:28:4742 std::make_unique<UrlFetcherDownloader>(nullptr,
43 std::move(url_loader_factory));
Sorin Jianuebd652462017-07-23 02:00:5844
[email protected]d0c8b8b42014-05-06 05:11:4545#if defined(OS_WIN)
[email protected]3cb2a4f2013-12-07 21:54:3446 if (is_background_download) {
Jinho Bangda4e4282018-01-03 13:21:2347 return std::make_unique<BackgroundDownloader>(
Sorin Jianuebd652462017-07-23 02:00:5848 std::move(url_fetcher_downloader));
[email protected]3cb2a4f2013-12-07 21:54:3449 }
50#endif
[email protected]afa378f22013-12-02 03:37:5451
sorin9797aba2015-04-17 17:15:0352 return url_fetcher_downloader;
[email protected]afa378f22013-12-02 03:37:5453}
54
Sorin Jianu72d8fe0d2017-07-11 18:42:1655CrxDownloader::CrxDownloader(std::unique_ptr<CrxDownloader> successor)
56 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
sorin74e70672016-02-03 03:13:1057 successor_(std::move(successor)) {}
[email protected]afa378f22013-12-02 03:37:5458
sorin74e70672016-02-03 03:13:1059CrxDownloader::~CrxDownloader() {}
[email protected]afa378f22013-12-02 03:37:5460
[email protected]8a5ebd432014-05-02 00:21:2261void CrxDownloader::set_progress_callback(
62 const ProgressCallback& progress_callback) {
63 progress_callback_ = progress_callback;
64}
65
[email protected]3a0092d2013-12-18 03:04:3566GURL CrxDownloader::url() const {
67 return current_url_ != urls_.end() ? *current_url_ : GURL();
68}
69
70const std::vector<CrxDownloader::DownloadMetrics>
71CrxDownloader::download_metrics() const {
72 if (!successor_)
73 return download_metrics_;
74
75 std::vector<DownloadMetrics> retval(successor_->download_metrics());
sorin52ac0882015-01-24 01:15:0076 retval.insert(retval.begin(), download_metrics_.begin(),
77 download_metrics_.end());
[email protected]3a0092d2013-12-18 03:04:3578 return retval;
79}
80
Sorin Jianua8ef73d2017-11-02 16:55:1781void CrxDownloader::StartDownloadFromUrl(const GURL& url,
82 const std::string& expected_hash,
83 DownloadCallback download_callback) {
[email protected]afa378f22013-12-02 03:37:5484 std::vector<GURL> urls;
85 urls.push_back(url);
Sorin Jianua8ef73d2017-11-02 16:55:1786 StartDownload(urls, expected_hash, std::move(download_callback));
[email protected]afa378f22013-12-02 03:37:5487}
88
[email protected]1b6587dc52014-04-26 00:38:5589void CrxDownloader::StartDownload(const std::vector<GURL>& urls,
sorin74e70672016-02-03 03:13:1090 const std::string& expected_hash,
Sorin Jianua8ef73d2017-11-02 16:55:1791 DownloadCallback download_callback) {
[email protected]ed6fb982014-07-23 16:56:5292 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]afa378f22013-12-02 03:37:5493
sorin7b8650522016-11-02 18:23:4194 auto error = CrxDownloaderError::NONE;
[email protected]da37c1d2013-12-19 01:04:3895 if (urls.empty()) {
sorin7b8650522016-11-02 18:23:4196 error = CrxDownloaderError::NO_URL;
sorin74e70672016-02-03 03:13:1097 } else if (expected_hash.empty()) {
sorin7b8650522016-11-02 18:23:4198 error = CrxDownloaderError::NO_HASH;
sorin74e70672016-02-03 03:13:1099 }
100
sorin7b8650522016-11-02 18:23:41101 if (error != CrxDownloaderError::NONE) {
[email protected]da37c1d2013-12-19 01:04:38102 Result result;
sorin7b8650522016-11-02 18:23:41103 result.error = static_cast<int>(error);
Sorin Jianua8ef73d2017-11-02 16:55:17104 main_task_runner()->PostTask(
105 FROM_HERE, base::BindOnce(std::move(download_callback), result));
[email protected]da37c1d2013-12-19 01:04:38106 return;
107 }
[email protected]afa378f22013-12-02 03:37:54108
109 urls_ = urls;
sorin74e70672016-02-03 03:13:10110 expected_hash_ = expected_hash;
[email protected]3cb2a4f2013-12-07 21:54:34111 current_url_ = urls_.begin();
Sorin Jianua8ef73d2017-11-02 16:55:17112 download_callback_ = std::move(download_callback);
[email protected]afa378f22013-12-02 03:37:54113
[email protected]3cb2a4f2013-12-07 21:54:34114 DoStartDownload(*current_url_);
[email protected]afa378f22013-12-02 03:37:54115}
116
[email protected]3a0092d2013-12-18 03:04:35117void CrxDownloader::OnDownloadComplete(
118 bool is_handled,
119 const Result& result,
120 const DownloadMetrics& download_metrics) {
[email protected]ed6fb982014-07-23 16:56:52121 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]afa378f22013-12-02 03:37:54122
sorin7b8650522016-11-02 18:23:41123 if (!result.error)
Sorin Jianu72d8fe0d2017-07-11 18:42:16124 base::PostTaskWithTraits(
Sorin Jianuebd652462017-07-23 02:00:58125 FROM_HERE, kTaskTraits,
126 base::BindOnce(&CrxDownloader::VerifyResponse, base::Unretained(this),
127 is_handled, result, download_metrics));
sorin74e70672016-02-03 03:13:10128 else
129 main_task_runner()->PostTask(
Sorin Jianuebd652462017-07-23 02:00:58130 FROM_HERE, base::BindOnce(&CrxDownloader::HandleDownloadError,
131 base::Unretained(this), is_handled, result,
132 download_metrics));
[email protected]afa378f22013-12-02 03:37:54133}
134
Antonio Gomes31237fb2018-08-27 19:11:03135void CrxDownloader::OnDownloadProgress() {
[email protected]ed6fb982014-07-23 16:56:52136 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]afa378f22013-12-02 03:37:54137
[email protected]8a5ebd432014-05-02 00:21:22138 if (progress_callback_.is_null())
139 return;
140
Antonio Gomes31237fb2018-08-27 19:11:03141 progress_callback_.Run();
[email protected]8a5ebd432014-05-02 00:21:22142}
143
sorin74e70672016-02-03 03:13:10144// The function mutates the values of the parameters |result| and
145// |download_metrics|.
146void CrxDownloader::VerifyResponse(bool is_handled,
147 Result result,
148 DownloadMetrics download_metrics) {
sorin7b8650522016-11-02 18:23:41149 DCHECK_EQ(0, result.error);
150 DCHECK_EQ(0, download_metrics.error);
sorin74e70672016-02-03 03:13:10151 DCHECK(is_handled);
152
153 if (VerifyFileHash256(result.response, expected_hash_)) {
154 download_metrics_.push_back(download_metrics);
Sorin Jianua8ef73d2017-11-02 16:55:17155 main_task_runner()->PostTask(
156 FROM_HERE, base::BindOnce(std::move(download_callback_), result));
sorin74e70672016-02-03 03:13:10157 return;
158 }
159
160 // The download was successful but the response is not trusted. Clean up
161 // the download, mutate the result, and try the remaining fallbacks when
162 // handling the error.
sorin7b8650522016-11-02 18:23:41163 result.error = static_cast<int>(CrxDownloaderError::BAD_HASH);
sorin74e70672016-02-03 03:13:10164 download_metrics.error = result.error;
165 DeleteFileAndEmptyParentDirectory(result.response);
166 result.response.clear();
167
168 main_task_runner()->PostTask(
Sorin Jianuebd652462017-07-23 02:00:58169 FROM_HERE, base::BindOnce(&CrxDownloader::HandleDownloadError,
170 base::Unretained(this), is_handled, result,
171 download_metrics));
sorin74e70672016-02-03 03:13:10172}
173
174void CrxDownloader::HandleDownloadError(
175 bool is_handled,
176 const Result& result,
177 const DownloadMetrics& download_metrics) {
178 DCHECK(thread_checker_.CalledOnValidThread());
sorin7b8650522016-11-02 18:23:41179 DCHECK_NE(0, result.error);
Sorin Jianu52de5fa2017-10-09 23:19:33180 DCHECK(result.response.empty());
sorin7b8650522016-11-02 18:23:41181 DCHECK_NE(0, download_metrics.error);
sorin74e70672016-02-03 03:13:10182
183 download_metrics_.push_back(download_metrics);
184
185 // If an error has occured, try the next url if there is any,
186 // or try the successor in the chain if there is any successor.
187 // If this downloader has received a 5xx error for the current url,
188 // as indicated by the |is_handled| flag, remove that url from the list of
189 // urls so the url is never tried again down the chain.
190 if (is_handled) {
191 current_url_ = urls_.erase(current_url_);
192 } else {
193 ++current_url_;
194 }
195
196 // Try downloading from another url from the list.
197 if (current_url_ != urls_.end()) {
198 DoStartDownload(*current_url_);
199 return;
200 }
201
202 // Try downloading using the next downloader.
203 if (successor_ && !urls_.empty()) {
Sorin Jianua8ef73d2017-11-02 16:55:17204 successor_->StartDownload(urls_, expected_hash_,
205 std::move(download_callback_));
sorin74e70672016-02-03 03:13:10206 return;
207 }
208
209 // The download ends here since there is no url nor downloader to handle this
210 // download request further.
Sorin Jianua8ef73d2017-11-02 16:55:17211 main_task_runner()->PostTask(
212 FROM_HERE, base::BindOnce(std::move(download_callback_), result));
sorin74e70672016-02-03 03:13:10213}
214
sorin52ac0882015-01-24 01:15:00215} // namespace update_client