blob: 96a2d844dc8ac93b1c40cd3d6294c76b0ad2aee6 [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 Charette41ea14152020-03-02 15:43:1113#include "base/task/thread_pool.h"
gab7966d312016-05-11 20:35:0114#include "base/threading/thread_task_runner_handle.h"
avi5dd91f82015-12-25 22:30:4615#include "build/build_config.h"
[email protected]3cb2a4f2013-12-07 21:54:3416#if defined(OS_WIN)
sorin52ac0882015-01-24 01:15:0017#include "components/update_client/background_downloader_win.h"
[email protected]3cb2a4f2013-12-07 21:54:3418#endif
Sorin Jianu75e6bf22019-02-12 16:07:1219#include "components/update_client/network.h"
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"
[email protected]3cb2a4f2013-12-07 21:54:3424
sorin52ac0882015-01-24 01:15:0025namespace update_client {
[email protected]afa378f22013-12-02 03:37:5426
[email protected]3a0092d2013-12-18 03:04:3527CrxDownloader::DownloadMetrics::DownloadMetrics()
28 : downloader(kNone),
29 error(0),
[email protected]8a5ebd432014-05-02 00:21:2230 downloaded_bytes(-1),
31 total_bytes(-1),
Sorin Jianu30881152020-03-16 14:31:1932 download_time_ms(0) {}
[email protected]3a0092d2013-12-18 03:04:3533
[email protected]3cb2a4f2013-12-07 21:54:3434// On Windows, the first downloader in the chain is a background downloader,
35// which uses the BITS service.
dchengd0fc6aa92016-04-22 18:03:1236std::unique_ptr<CrxDownloader> CrxDownloader::Create(
[email protected]3cb2a4f2013-12-07 21:54:3437 bool is_background_download,
Sorin Jianu75e6bf22019-02-12 16:07:1238 scoped_refptr<NetworkFetcherFactory> network_fetcher_factory) {
Sorin Jianuebd652462017-07-23 02:00:5839 std::unique_ptr<CrxDownloader> url_fetcher_downloader =
Sorin Jianu75e6bf22019-02-12 16:07:1240 std::make_unique<UrlFetcherDownloader>(nullptr, network_fetcher_factory);
Sorin Jianuebd652462017-07-23 02:00:5841
[email protected]d0c8b8b42014-05-06 05:11:4542#if defined(OS_WIN)
[email protected]3cb2a4f2013-12-07 21:54:3443 if (is_background_download) {
Jinho Bangda4e4282018-01-03 13:21:2344 return std::make_unique<BackgroundDownloader>(
Sorin Jianuebd652462017-07-23 02:00:5845 std::move(url_fetcher_downloader));
[email protected]3cb2a4f2013-12-07 21:54:3446 }
47#endif
[email protected]afa378f22013-12-02 03:37:5448
sorin9797aba2015-04-17 17:15:0349 return url_fetcher_downloader;
[email protected]afa378f22013-12-02 03:37:5450}
51
Sorin Jianu72d8fe0d2017-07-11 18:42:1652CrxDownloader::CrxDownloader(std::unique_ptr<CrxDownloader> successor)
53 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
sorin74e70672016-02-03 03:13:1054 successor_(std::move(successor)) {}
[email protected]afa378f22013-12-02 03:37:5455
Sorin Jianu30881152020-03-16 14:31:1956CrxDownloader::~CrxDownloader() = default;
[email protected]afa378f22013-12-02 03:37:5457
[email protected]8a5ebd432014-05-02 00:21:2258void CrxDownloader::set_progress_callback(
59 const ProgressCallback& progress_callback) {
60 progress_callback_ = progress_callback;
61}
62
[email protected]3a0092d2013-12-18 03:04:3563GURL CrxDownloader::url() const {
64 return current_url_ != urls_.end() ? *current_url_ : GURL();
65}
66
67const std::vector<CrxDownloader::DownloadMetrics>
68CrxDownloader::download_metrics() const {
69 if (!successor_)
70 return download_metrics_;
71
72 std::vector<DownloadMetrics> retval(successor_->download_metrics());
sorin52ac0882015-01-24 01:15:0073 retval.insert(retval.begin(), download_metrics_.begin(),
74 download_metrics_.end());
[email protected]3a0092d2013-12-18 03:04:3575 return retval;
76}
77
Sorin Jianua8ef73d2017-11-02 16:55:1778void CrxDownloader::StartDownloadFromUrl(const GURL& url,
79 const std::string& expected_hash,
80 DownloadCallback download_callback) {
[email protected]afa378f22013-12-02 03:37:5481 std::vector<GURL> urls;
82 urls.push_back(url);
Sorin Jianua8ef73d2017-11-02 16:55:1783 StartDownload(urls, expected_hash, std::move(download_callback));
[email protected]afa378f22013-12-02 03:37:5484}
85
[email protected]1b6587dc52014-04-26 00:38:5586void CrxDownloader::StartDownload(const std::vector<GURL>& urls,
sorin74e70672016-02-03 03:13:1087 const std::string& expected_hash,
Sorin Jianua8ef73d2017-11-02 16:55:1788 DownloadCallback download_callback) {
[email protected]ed6fb982014-07-23 16:56:5289 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]afa378f22013-12-02 03:37:5490
sorin7b8650522016-11-02 18:23:4191 auto error = CrxDownloaderError::NONE;
[email protected]da37c1d2013-12-19 01:04:3892 if (urls.empty()) {
sorin7b8650522016-11-02 18:23:4193 error = CrxDownloaderError::NO_URL;
sorin74e70672016-02-03 03:13:1094 } else if (expected_hash.empty()) {
sorin7b8650522016-11-02 18:23:4195 error = CrxDownloaderError::NO_HASH;
sorin74e70672016-02-03 03:13:1096 }
97
sorin7b8650522016-11-02 18:23:4198 if (error != CrxDownloaderError::NONE) {
[email protected]da37c1d2013-12-19 01:04:3899 Result result;
sorin7b8650522016-11-02 18:23:41100 result.error = static_cast<int>(error);
Sorin Jianua8ef73d2017-11-02 16:55:17101 main_task_runner()->PostTask(
102 FROM_HERE, base::BindOnce(std::move(download_callback), result));
[email protected]da37c1d2013-12-19 01:04:38103 return;
104 }
[email protected]afa378f22013-12-02 03:37:54105
106 urls_ = urls;
sorin74e70672016-02-03 03:13:10107 expected_hash_ = expected_hash;
[email protected]3cb2a4f2013-12-07 21:54:34108 current_url_ = urls_.begin();
Sorin Jianua8ef73d2017-11-02 16:55:17109 download_callback_ = std::move(download_callback);
[email protected]afa378f22013-12-02 03:37:54110
[email protected]3cb2a4f2013-12-07 21:54:34111 DoStartDownload(*current_url_);
[email protected]afa378f22013-12-02 03:37:54112}
113
[email protected]3a0092d2013-12-18 03:04:35114void CrxDownloader::OnDownloadComplete(
115 bool is_handled,
116 const Result& result,
117 const DownloadMetrics& download_metrics) {
[email protected]ed6fb982014-07-23 16:56:52118 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]afa378f22013-12-02 03:37:54119
sorin7b8650522016-11-02 18:23:41120 if (!result.error)
Gabriel Charette41ea14152020-03-02 15:43:11121 base::ThreadPool::PostTask(
Sorin Jianuebd652462017-07-23 02:00:58122 FROM_HERE, kTaskTraits,
123 base::BindOnce(&CrxDownloader::VerifyResponse, base::Unretained(this),
124 is_handled, result, download_metrics));
sorin74e70672016-02-03 03:13:10125 else
126 main_task_runner()->PostTask(
Sorin Jianuebd652462017-07-23 02:00:58127 FROM_HERE, base::BindOnce(&CrxDownloader::HandleDownloadError,
128 base::Unretained(this), is_handled, result,
129 download_metrics));
[email protected]afa378f22013-12-02 03:37:54130}
131
Antonio Gomes31237fb2018-08-27 19:11:03132void CrxDownloader::OnDownloadProgress() {
[email protected]ed6fb982014-07-23 16:56:52133 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]afa378f22013-12-02 03:37:54134
[email protected]8a5ebd432014-05-02 00:21:22135 if (progress_callback_.is_null())
136 return;
137
Antonio Gomes31237fb2018-08-27 19:11:03138 progress_callback_.Run();
[email protected]8a5ebd432014-05-02 00:21:22139}
140
sorin74e70672016-02-03 03:13:10141// The function mutates the values of the parameters |result| and
142// |download_metrics|.
143void CrxDownloader::VerifyResponse(bool is_handled,
144 Result result,
145 DownloadMetrics download_metrics) {
sorin7b8650522016-11-02 18:23:41146 DCHECK_EQ(0, result.error);
147 DCHECK_EQ(0, download_metrics.error);
sorin74e70672016-02-03 03:13:10148 DCHECK(is_handled);
149
150 if (VerifyFileHash256(result.response, expected_hash_)) {
151 download_metrics_.push_back(download_metrics);
Sorin Jianua8ef73d2017-11-02 16:55:17152 main_task_runner()->PostTask(
153 FROM_HERE, base::BindOnce(std::move(download_callback_), result));
sorin74e70672016-02-03 03:13:10154 return;
155 }
156
157 // The download was successful but the response is not trusted. Clean up
158 // the download, mutate the result, and try the remaining fallbacks when
159 // handling the error.
sorin7b8650522016-11-02 18:23:41160 result.error = static_cast<int>(CrxDownloaderError::BAD_HASH);
sorin74e70672016-02-03 03:13:10161 download_metrics.error = result.error;
162 DeleteFileAndEmptyParentDirectory(result.response);
163 result.response.clear();
164
165 main_task_runner()->PostTask(
Sorin Jianuebd652462017-07-23 02:00:58166 FROM_HERE, base::BindOnce(&CrxDownloader::HandleDownloadError,
167 base::Unretained(this), is_handled, result,
168 download_metrics));
sorin74e70672016-02-03 03:13:10169}
170
171void CrxDownloader::HandleDownloadError(
172 bool is_handled,
173 const Result& result,
174 const DownloadMetrics& download_metrics) {
175 DCHECK(thread_checker_.CalledOnValidThread());
sorin7b8650522016-11-02 18:23:41176 DCHECK_NE(0, result.error);
Sorin Jianu52de5fa2017-10-09 23:19:33177 DCHECK(result.response.empty());
sorin7b8650522016-11-02 18:23:41178 DCHECK_NE(0, download_metrics.error);
sorin74e70672016-02-03 03:13:10179
180 download_metrics_.push_back(download_metrics);
181
182 // If an error has occured, try the next url if there is any,
183 // or try the successor in the chain if there is any successor.
184 // If this downloader has received a 5xx error for the current url,
185 // as indicated by the |is_handled| flag, remove that url from the list of
186 // urls so the url is never tried again down the chain.
187 if (is_handled) {
188 current_url_ = urls_.erase(current_url_);
189 } else {
190 ++current_url_;
191 }
192
193 // Try downloading from another url from the list.
194 if (current_url_ != urls_.end()) {
195 DoStartDownload(*current_url_);
196 return;
197 }
198
199 // Try downloading using the next downloader.
200 if (successor_ && !urls_.empty()) {
Sorin Jianua8ef73d2017-11-02 16:55:17201 successor_->StartDownload(urls_, expected_hash_,
202 std::move(download_callback_));
sorin74e70672016-02-03 03:13:10203 return;
204 }
205
206 // The download ends here since there is no url nor downloader to handle this
207 // download request further.
Sorin Jianua8ef73d2017-11-02 16:55:17208 main_task_runner()->PostTask(
209 FROM_HERE, base::BindOnce(std::move(download_callback_), result));
sorin74e70672016-02-03 03:13:10210}
211
sorin52ac0882015-01-24 01:15:00212} // namespace update_client