blob: 6a6cd4e3caf89dc9a5a67ff4d7af21a99fd99798 [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
sorin74e70672016-02-03 03:13:1020#include "components/update_client/url_fetcher_downloader.h"
21#include "components/update_client/utils.h"
[email protected]3cb2a4f2013-12-07 21:54:3422
sorin52ac0882015-01-24 01:15:0023namespace update_client {
[email protected]afa378f22013-12-02 03:37:5424
[email protected]8a5ebd432014-05-02 00:21:2225CrxDownloader::Result::Result()
26 : error(0), downloaded_bytes(-1), total_bytes(-1) {
27}
[email protected]3a0092d2013-12-18 03:04:3528
29CrxDownloader::DownloadMetrics::DownloadMetrics()
30 : downloader(kNone),
31 error(0),
[email protected]8a5ebd432014-05-02 00:21:2232 downloaded_bytes(-1),
33 total_bytes(-1),
34 download_time_ms(0) {
35}
[email protected]3a0092d2013-12-18 03:04:3536
[email protected]3cb2a4f2013-12-07 21:54:3437// On Windows, the first downloader in the chain is a background downloader,
38// which uses the BITS service.
dchengd0fc6aa92016-04-22 18:03:1239std::unique_ptr<CrxDownloader> CrxDownloader::Create(
[email protected]3cb2a4f2013-12-07 21:54:3440 bool is_background_download,
[email protected]afa378f22013-12-02 03:37:5441 net::URLRequestContextGetter* context_getter,
sorin33012532015-10-26 21:05:5442 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
dchengd0fc6aa92016-04-22 18:03:1243 std::unique_ptr<CrxDownloader> url_fetcher_downloader(
44 std::unique_ptr<CrxDownloader>(new UrlFetcherDownloader(
45 std::unique_ptr<CrxDownloader>(), context_getter, task_runner)));
[email protected]d0c8b8b42014-05-06 05:11:4546#if defined(OS_WIN)
[email protected]3cb2a4f2013-12-07 21:54:3447 if (is_background_download) {
dchengd0fc6aa92016-04-22 18:03:1248 return std::unique_ptr<CrxDownloader>(new BackgroundDownloader(
sorin74e70672016-02-03 03:13:1049 std::move(url_fetcher_downloader), context_getter, task_runner));
[email protected]3cb2a4f2013-12-07 21:54:3450 }
51#endif
[email protected]afa378f22013-12-02 03:37:5452
sorin9797aba2015-04-17 17:15:0353 return url_fetcher_downloader;
[email protected]afa378f22013-12-02 03:37:5454}
55
sorin74e70672016-02-03 03:13:1056CrxDownloader::CrxDownloader(
57 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
dchengd0fc6aa92016-04-22 18:03:1258 std::unique_ptr<CrxDownloader> successor)
sorin74e70672016-02-03 03:13:1059 : task_runner_(task_runner),
60 main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
61 successor_(std::move(successor)) {}
[email protected]afa378f22013-12-02 03:37:5462
sorin74e70672016-02-03 03:13:1063CrxDownloader::~CrxDownloader() {}
[email protected]afa378f22013-12-02 03:37:5464
[email protected]8a5ebd432014-05-02 00:21:2265void CrxDownloader::set_progress_callback(
66 const ProgressCallback& progress_callback) {
67 progress_callback_ = progress_callback;
68}
69
[email protected]3a0092d2013-12-18 03:04:3570GURL CrxDownloader::url() const {
71 return current_url_ != urls_.end() ? *current_url_ : GURL();
72}
73
74const std::vector<CrxDownloader::DownloadMetrics>
75CrxDownloader::download_metrics() const {
76 if (!successor_)
77 return download_metrics_;
78
79 std::vector<DownloadMetrics> retval(successor_->download_metrics());
sorin52ac0882015-01-24 01:15:0080 retval.insert(retval.begin(), download_metrics_.begin(),
81 download_metrics_.end());
[email protected]3a0092d2013-12-18 03:04:3582 return retval;
83}
84
[email protected]1b6587dc52014-04-26 00:38:5585void CrxDownloader::StartDownloadFromUrl(
86 const GURL& url,
sorin74e70672016-02-03 03:13:1087 const std::string& expected_hash,
[email protected]1b6587dc52014-04-26 00:38:5588 const DownloadCallback& download_callback) {
[email protected]afa378f22013-12-02 03:37:5489 std::vector<GURL> urls;
90 urls.push_back(url);
sorin74e70672016-02-03 03:13:1091 StartDownload(urls, expected_hash, download_callback);
[email protected]afa378f22013-12-02 03:37:5492}
93
[email protected]1b6587dc52014-04-26 00:38:5594void CrxDownloader::StartDownload(const std::vector<GURL>& urls,
sorin74e70672016-02-03 03:13:1095 const std::string& expected_hash,
[email protected]1b6587dc52014-04-26 00:38:5596 const DownloadCallback& download_callback) {
[email protected]ed6fb982014-07-23 16:56:5297 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]afa378f22013-12-02 03:37:5498
sorin74e70672016-02-03 03:13:1099 auto error = Error::SUCCESS;
[email protected]da37c1d2013-12-19 01:04:38100 if (urls.empty()) {
sorin74e70672016-02-03 03:13:10101 error = Error::NO_URL;
102 } else if (expected_hash.empty()) {
103 error = Error::NO_HASH;
104 }
105
106 if (error != Error::SUCCESS) {
[email protected]da37c1d2013-12-19 01:04:38107 Result result;
sorin74e70672016-02-03 03:13:10108 result.error = error;
109 base::ThreadTaskRunnerHandle::Get()->PostTask(
110 FROM_HERE, base::Bind(download_callback, result));
[email protected]da37c1d2013-12-19 01:04:38111 return;
112 }
[email protected]afa378f22013-12-02 03:37:54113
114 urls_ = urls;
sorin74e70672016-02-03 03:13:10115 expected_hash_ = expected_hash;
[email protected]3cb2a4f2013-12-07 21:54:34116 current_url_ = urls_.begin();
[email protected]1b6587dc52014-04-26 00:38:55117 download_callback_ = download_callback;
[email protected]afa378f22013-12-02 03:37:54118
[email protected]3cb2a4f2013-12-07 21:54:34119 DoStartDownload(*current_url_);
[email protected]afa378f22013-12-02 03:37:54120}
121
[email protected]3a0092d2013-12-18 03:04:35122void CrxDownloader::OnDownloadComplete(
123 bool is_handled,
124 const Result& result,
125 const DownloadMetrics& download_metrics) {
[email protected]ed6fb982014-07-23 16:56:52126 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]afa378f22013-12-02 03:37:54127
sorin74e70672016-02-03 03:13:10128 if (result.error == Error::SUCCESS)
129 task_runner()->PostTask(
130 FROM_HERE,
131 base::Bind(&CrxDownloader::VerifyResponse, base::Unretained(this),
132 is_handled, result, download_metrics));
133 else
134 main_task_runner()->PostTask(
135 FROM_HERE,
136 base::Bind(&CrxDownloader::HandleDownloadError, base::Unretained(this),
137 is_handled, result, download_metrics));
[email protected]afa378f22013-12-02 03:37:54138}
139
[email protected]8a5ebd432014-05-02 00:21:22140void CrxDownloader::OnDownloadProgress(const Result& result) {
[email protected]ed6fb982014-07-23 16:56:52141 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]afa378f22013-12-02 03:37:54142
[email protected]8a5ebd432014-05-02 00:21:22143 if (progress_callback_.is_null())
144 return;
145
146 progress_callback_.Run(result);
147}
148
sorin74e70672016-02-03 03:13:10149// The function mutates the values of the parameters |result| and
150// |download_metrics|.
151void CrxDownloader::VerifyResponse(bool is_handled,
152 Result result,
153 DownloadMetrics download_metrics) {
154 DCHECK(task_runner()->RunsTasksOnCurrentThread());
155 DCHECK_EQ(Error::SUCCESS, result.error);
156 DCHECK_EQ(Error::SUCCESS, download_metrics.error);
157 DCHECK(is_handled);
158
159 if (VerifyFileHash256(result.response, expected_hash_)) {
160 download_metrics_.push_back(download_metrics);
161 main_task_runner()->PostTask(FROM_HERE,
162 base::Bind(download_callback_, result));
163 return;
164 }
165
166 // The download was successful but the response is not trusted. Clean up
167 // the download, mutate the result, and try the remaining fallbacks when
168 // handling the error.
169 result.error = Error::BAD_HASH;
170 download_metrics.error = result.error;
171 DeleteFileAndEmptyParentDirectory(result.response);
172 result.response.clear();
173
174 main_task_runner()->PostTask(
175 FROM_HERE,
176 base::Bind(&CrxDownloader::HandleDownloadError, base::Unretained(this),
177 is_handled, result, download_metrics));
178}
179
180void CrxDownloader::HandleDownloadError(
181 bool is_handled,
182 const Result& result,
183 const DownloadMetrics& download_metrics) {
184 DCHECK(thread_checker_.CalledOnValidThread());
185 DCHECK_NE(Error::SUCCESS, result.error);
186 DCHECK_NE(Error::SUCCESS, download_metrics.error);
187
188 download_metrics_.push_back(download_metrics);
189
190 // If an error has occured, try the next url if there is any,
191 // or try the successor in the chain if there is any successor.
192 // If this downloader has received a 5xx error for the current url,
193 // as indicated by the |is_handled| flag, remove that url from the list of
194 // urls so the url is never tried again down the chain.
195 if (is_handled) {
196 current_url_ = urls_.erase(current_url_);
197 } else {
198 ++current_url_;
199 }
200
201 // Try downloading from another url from the list.
202 if (current_url_ != urls_.end()) {
203 DoStartDownload(*current_url_);
204 return;
205 }
206
207 // Try downloading using the next downloader.
208 if (successor_ && !urls_.empty()) {
209 successor_->StartDownload(urls_, expected_hash_, download_callback_);
210 return;
211 }
212
213 // The download ends here since there is no url nor downloader to handle this
214 // download request further.
215 main_task_runner()->PostTask(FROM_HERE,
216 base::Bind(download_callback_, result));
217}
218
sorin52ac0882015-01-24 01:15:00219} // namespace update_client