blob: f31593352a123aaa0e2807e203b40874e0904bbc [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/bind_helpers.h"
11#include "base/files/file_util.h"
sorin6bb8de42015-06-03 00:23:2712#include "base/location.h"
[email protected]ed6fb982014-07-23 16:56:5213#include "base/logging.h"
14#include "base/sequenced_task_runner.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
sorin7b8650522016-11-02 18:23:4120#include "components/update_client/update_client_errors.h"
sorin74e70672016-02-03 03:13:1021#include "components/update_client/url_fetcher_downloader.h"
22#include "components/update_client/utils.h"
[email protected]3cb2a4f2013-12-07 21:54:3423
sorin52ac0882015-01-24 01:15:0024namespace update_client {
[email protected]afa378f22013-12-02 03:37:5425
[email protected]8a5ebd432014-05-02 00:21:2226CrxDownloader::Result::Result()
27 : error(0), downloaded_bytes(-1), total_bytes(-1) {
28}
[email protected]3a0092d2013-12-18 03:04:3529
30CrxDownloader::DownloadMetrics::DownloadMetrics()
31 : downloader(kNone),
32 error(0),
[email protected]8a5ebd432014-05-02 00:21:2233 downloaded_bytes(-1),
34 total_bytes(-1),
35 download_time_ms(0) {
36}
[email protected]3a0092d2013-12-18 03:04:3537
[email protected]3cb2a4f2013-12-07 21:54:3438// On Windows, the first downloader in the chain is a background downloader,
39// which uses the BITS service.
dchengd0fc6aa92016-04-22 18:03:1240std::unique_ptr<CrxDownloader> CrxDownloader::Create(
[email protected]3cb2a4f2013-12-07 21:54:3441 bool is_background_download,
[email protected]afa378f22013-12-02 03:37:5442 net::URLRequestContextGetter* context_getter,
sorin33012532015-10-26 21:05:5443 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:1244 std::unique_ptr<CrxDownloader> url_fetcher_downloader(
45 std::unique_ptr<CrxDownloader>(new UrlFetcherDownloader(
46 std::unique_ptr<CrxDownloader>(), context_getter, task_runner)));
[email protected]d0c8b8b42014-05-06 05:11:4547#if defined(OS_WIN)
[email protected]3cb2a4f2013-12-07 21:54:3448 if (is_background_download) {
dchengd0fc6aa92016-04-22 18:03:1249 return std::unique_ptr<CrxDownloader>(new BackgroundDownloader(
sorin74e70672016-02-03 03:13:1050 std::move(url_fetcher_downloader), context_getter, task_runner));
[email protected]3cb2a4f2013-12-07 21:54:3451 }
52#endif
[email protected]afa378f22013-12-02 03:37:5453
sorin9797aba2015-04-17 17:15:0354 return url_fetcher_downloader;
[email protected]afa378f22013-12-02 03:37:5455}
56
sorin74e70672016-02-03 03:13:1057CrxDownloader::CrxDownloader(
58 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
dchengd0fc6aa92016-04-22 18:03:1259 std::unique_ptr<CrxDownloader> successor)
sorin74e70672016-02-03 03:13:1060 : task_runner_(task_runner),
61 main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
62 successor_(std::move(successor)) {}
[email protected]afa378f22013-12-02 03:37:5463
sorin74e70672016-02-03 03:13:1064CrxDownloader::~CrxDownloader() {}
[email protected]afa378f22013-12-02 03:37:5465
[email protected]8a5ebd432014-05-02 00:21:2266void CrxDownloader::set_progress_callback(
67 const ProgressCallback& progress_callback) {
68 progress_callback_ = progress_callback;
69}
70
[email protected]3a0092d2013-12-18 03:04:3571GURL CrxDownloader::url() const {
72 return current_url_ != urls_.end() ? *current_url_ : GURL();
73}
74
75const std::vector<CrxDownloader::DownloadMetrics>
76CrxDownloader::download_metrics() const {
77 if (!successor_)
78 return download_metrics_;
79
80 std::vector<DownloadMetrics> retval(successor_->download_metrics());
sorin52ac0882015-01-24 01:15:0081 retval.insert(retval.begin(), download_metrics_.begin(),
82 download_metrics_.end());
[email protected]3a0092d2013-12-18 03:04:3583 return retval;
84}
85
[email protected]1b6587dc52014-04-26 00:38:5586void CrxDownloader::StartDownloadFromUrl(
87 const GURL& url,
sorin74e70672016-02-03 03:13:1088 const std::string& expected_hash,
[email protected]1b6587dc52014-04-26 00:38:5589 const DownloadCallback& download_callback) {
[email protected]afa378f22013-12-02 03:37:5490 std::vector<GURL> urls;
91 urls.push_back(url);
sorin74e70672016-02-03 03:13:1092 StartDownload(urls, expected_hash, download_callback);
[email protected]afa378f22013-12-02 03:37:5493}
94
[email protected]1b6587dc52014-04-26 00:38:5595void CrxDownloader::StartDownload(const std::vector<GURL>& urls,
sorin74e70672016-02-03 03:13:1096 const std::string& expected_hash,
[email protected]1b6587dc52014-04-26 00:38:5597 const DownloadCallback& download_callback) {
[email protected]ed6fb982014-07-23 16:56:5298 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]afa378f22013-12-02 03:37:5499
sorin7b8650522016-11-02 18:23:41100 auto error = CrxDownloaderError::NONE;
[email protected]da37c1d2013-12-19 01:04:38101 if (urls.empty()) {
sorin7b8650522016-11-02 18:23:41102 error = CrxDownloaderError::NO_URL;
sorin74e70672016-02-03 03:13:10103 } else if (expected_hash.empty()) {
sorin7b8650522016-11-02 18:23:41104 error = CrxDownloaderError::NO_HASH;
sorin74e70672016-02-03 03:13:10105 }
106
sorin7b8650522016-11-02 18:23:41107 if (error != CrxDownloaderError::NONE) {
[email protected]da37c1d2013-12-19 01:04:38108 Result result;
sorin7b8650522016-11-02 18:23:41109 result.error = static_cast<int>(error);
sorin74e70672016-02-03 03:13:10110 base::ThreadTaskRunnerHandle::Get()->PostTask(
111 FROM_HERE, base::Bind(download_callback, result));
[email protected]da37c1d2013-12-19 01:04:38112 return;
113 }
[email protected]afa378f22013-12-02 03:37:54114
115 urls_ = urls;
sorin74e70672016-02-03 03:13:10116 expected_hash_ = expected_hash;
[email protected]3cb2a4f2013-12-07 21:54:34117 current_url_ = urls_.begin();
[email protected]1b6587dc52014-04-26 00:38:55118 download_callback_ = download_callback;
[email protected]afa378f22013-12-02 03:37:54119
[email protected]3cb2a4f2013-12-07 21:54:34120 DoStartDownload(*current_url_);
[email protected]afa378f22013-12-02 03:37:54121}
122
[email protected]3a0092d2013-12-18 03:04:35123void CrxDownloader::OnDownloadComplete(
124 bool is_handled,
125 const Result& result,
126 const DownloadMetrics& download_metrics) {
[email protected]ed6fb982014-07-23 16:56:52127 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]afa378f22013-12-02 03:37:54128
sorin7b8650522016-11-02 18:23:41129 if (!result.error)
sorin74e70672016-02-03 03:13:10130 task_runner()->PostTask(
131 FROM_HERE,
132 base::Bind(&CrxDownloader::VerifyResponse, base::Unretained(this),
133 is_handled, result, download_metrics));
134 else
135 main_task_runner()->PostTask(
136 FROM_HERE,
137 base::Bind(&CrxDownloader::HandleDownloadError, base::Unretained(this),
138 is_handled, result, download_metrics));
[email protected]afa378f22013-12-02 03:37:54139}
140
[email protected]8a5ebd432014-05-02 00:21:22141void CrxDownloader::OnDownloadProgress(const Result& result) {
[email protected]ed6fb982014-07-23 16:56:52142 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]afa378f22013-12-02 03:37:54143
[email protected]8a5ebd432014-05-02 00:21:22144 if (progress_callback_.is_null())
145 return;
146
147 progress_callback_.Run(result);
148}
149
sorin74e70672016-02-03 03:13:10150// The function mutates the values of the parameters |result| and
151// |download_metrics|.
152void CrxDownloader::VerifyResponse(bool is_handled,
153 Result result,
154 DownloadMetrics download_metrics) {
155 DCHECK(task_runner()->RunsTasksOnCurrentThread());
sorin7b8650522016-11-02 18:23:41156 DCHECK_EQ(0, result.error);
157 DCHECK_EQ(0, download_metrics.error);
sorin74e70672016-02-03 03:13:10158 DCHECK(is_handled);
159
160 if (VerifyFileHash256(result.response, expected_hash_)) {
161 download_metrics_.push_back(download_metrics);
162 main_task_runner()->PostTask(FROM_HERE,
163 base::Bind(download_callback_, result));
164 return;
165 }
166
167 // The download was successful but the response is not trusted. Clean up
168 // the download, mutate the result, and try the remaining fallbacks when
169 // handling the error.
sorin7b8650522016-11-02 18:23:41170 result.error = static_cast<int>(CrxDownloaderError::BAD_HASH);
sorin74e70672016-02-03 03:13:10171 download_metrics.error = result.error;
172 DeleteFileAndEmptyParentDirectory(result.response);
173 result.response.clear();
174
175 main_task_runner()->PostTask(
176 FROM_HERE,
177 base::Bind(&CrxDownloader::HandleDownloadError, base::Unretained(this),
178 is_handled, result, download_metrics));
179}
180
181void CrxDownloader::HandleDownloadError(
182 bool is_handled,
183 const Result& result,
184 const DownloadMetrics& download_metrics) {
185 DCHECK(thread_checker_.CalledOnValidThread());
sorin7b8650522016-11-02 18:23:41186 DCHECK_NE(0, result.error);
187 DCHECK_NE(0, download_metrics.error);
sorin74e70672016-02-03 03:13:10188
189 download_metrics_.push_back(download_metrics);
190
191 // If an error has occured, try the next url if there is any,
192 // or try the successor in the chain if there is any successor.
193 // If this downloader has received a 5xx error for the current url,
194 // as indicated by the |is_handled| flag, remove that url from the list of
195 // urls so the url is never tried again down the chain.
196 if (is_handled) {
197 current_url_ = urls_.erase(current_url_);
198 } else {
199 ++current_url_;
200 }
201
202 // Try downloading from another url from the list.
203 if (current_url_ != urls_.end()) {
204 DoStartDownload(*current_url_);
205 return;
206 }
207
208 // Try downloading using the next downloader.
209 if (successor_ && !urls_.empty()) {
210 successor_->StartDownload(urls_, expected_hash_, download_callback_);
211 return;
212 }
213
214 // The download ends here since there is no url nor downloader to handle this
215 // download request further.
216 main_task_runner()->PostTask(FROM_HERE,
217 base::Bind(download_callback_, result));
218}
219
sorin52ac0882015-01-24 01:15:00220} // namespace update_client