blob: fbffe66c1430ae3bf358ff1e54d2880499ac70a9 [file] [log] [blame]
[email protected]32a83d132013-12-12 13:53:021// Copyright 2013 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
5#include "chrome/browser/component_updater/crx_downloader.h"
6#include "chrome/browser/component_updater/url_fetcher_downloader.h"
7#include "content/public/browser/browser_thread.h"
8
[email protected]3cb2a4f2013-12-07 21:54:349#if defined(OS_WIN)
10#include "chrome/browser/component_updater/background_downloader_win.h"
11#endif
12
[email protected]afa378f22013-12-02 03:37:5413using content::BrowserThread;
14
15namespace component_updater {
16
[email protected]8a5ebd432014-05-02 00:21:2217CrxDownloader::Result::Result()
18 : error(0), downloaded_bytes(-1), total_bytes(-1) {
19}
[email protected]3a0092d2013-12-18 03:04:3520
21CrxDownloader::DownloadMetrics::DownloadMetrics()
22 : downloader(kNone),
23 error(0),
[email protected]8a5ebd432014-05-02 00:21:2224 downloaded_bytes(-1),
25 total_bytes(-1),
26 download_time_ms(0) {
27}
[email protected]3a0092d2013-12-18 03:04:3528
[email protected]3cb2a4f2013-12-07 21:54:3429// On Windows, the first downloader in the chain is a background downloader,
30// which uses the BITS service.
[email protected]afa378f22013-12-02 03:37:5431CrxDownloader* CrxDownloader::Create(
[email protected]3cb2a4f2013-12-07 21:54:3432 bool is_background_download,
[email protected]afa378f22013-12-02 03:37:5433 net::URLRequestContextGetter* context_getter,
[email protected]1b6587dc52014-04-26 00:38:5534 scoped_refptr<base::SequencedTaskRunner> task_runner) {
[email protected]3cb2a4f2013-12-07 21:54:3435 scoped_ptr<CrxDownloader> url_fetcher_downloader(
36 new UrlFetcherDownloader(scoped_ptr<CrxDownloader>().Pass(),
37 context_getter,
[email protected]1b6587dc52014-04-26 00:38:5538 task_runner));
[email protected]3cb2a4f2013-12-07 21:54:3439#if defined (OS_WIN)
40 if (is_background_download) {
41 return new BackgroundDownloader(url_fetcher_downloader.Pass(),
42 context_getter,
[email protected]1b6587dc52014-04-26 00:38:5543 task_runner);
[email protected]3cb2a4f2013-12-07 21:54:3444 }
45#endif
[email protected]afa378f22013-12-02 03:37:5446
[email protected]3cb2a4f2013-12-07 21:54:3447 return url_fetcher_downloader.release();
[email protected]afa378f22013-12-02 03:37:5448}
49
[email protected]1b6587dc52014-04-26 00:38:5550CrxDownloader::CrxDownloader(scoped_ptr<CrxDownloader> successor)
51 : successor_(successor.Pass()) {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]afa378f22013-12-02 03:37:5453}
54
55CrxDownloader::~CrxDownloader() {
56}
57
[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());
73 retval.insert(retval.begin(),
74 download_metrics_.begin(),
75 download_metrics_.end());
76 return retval;
77}
78
[email protected]1b6587dc52014-04-26 00:38:5579void CrxDownloader::StartDownloadFromUrl(
80 const GURL& url,
81 const DownloadCallback& download_callback) {
[email protected]afa378f22013-12-02 03:37:5482 std::vector<GURL> urls;
83 urls.push_back(url);
[email protected]1b6587dc52014-04-26 00:38:5584 StartDownload(urls, download_callback);
[email protected]afa378f22013-12-02 03:37:5485}
86
[email protected]1b6587dc52014-04-26 00:38:5587void CrxDownloader::StartDownload(const std::vector<GURL>& urls,
88 const DownloadCallback& download_callback) {
[email protected]afa378f22013-12-02 03:37:5489 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90
[email protected]da37c1d2013-12-19 01:04:3891 if (urls.empty()) {
92 // Make a result and complete the download with a generic error for now.
93 Result result;
94 result.error = -1;
[email protected]1b6587dc52014-04-26 00:38:5595 download_callback.Run(result);
[email protected]da37c1d2013-12-19 01:04:3896 return;
97 }
[email protected]afa378f22013-12-02 03:37:5498
[email protected]3cb2a4f2013-12-07 21:54:3499 // If the urls are mutated while this downloader is active, then the
100 // behavior is undefined in the sense that the outcome of the download could
101 // be inconsistent for the list of urls. At any rate, the |current_url_| is
102 // reset at this point, and the iterator will be valid in all conditions.
[email protected]afa378f22013-12-02 03:37:54103 urls_ = urls;
[email protected]3cb2a4f2013-12-07 21:54:34104 current_url_ = urls_.begin();
[email protected]1b6587dc52014-04-26 00:38:55105 download_callback_ = download_callback;
[email protected]afa378f22013-12-02 03:37:54106
[email protected]3cb2a4f2013-12-07 21:54:34107 DoStartDownload(*current_url_);
[email protected]afa378f22013-12-02 03:37:54108}
109
[email protected]3a0092d2013-12-18 03:04:35110void CrxDownloader::OnDownloadComplete(
111 bool is_handled,
112 const Result& result,
113 const DownloadMetrics& download_metrics) {
[email protected]afa378f22013-12-02 03:37:54114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
115
[email protected]3a0092d2013-12-18 03:04:35116 download_metrics_.push_back(download_metrics);
117
[email protected]3cb2a4f2013-12-07 21:54:34118 if (result.error) {
119 // If an error has occured, in general try the next url if there is any,
120 // then move on to the successor in the chain if there is any successor.
121 // If this downloader has received a 5xx error for the current url,
122 // as indicated by the |is_handled| flag, remove that url from the list of
123 // urls so the url is never retried. In both cases, move on to the
124 // next url.
125 if (!is_handled) {
126 ++current_url_;
127 } else {
128 current_url_ = urls_.erase(current_url_);
129 }
130
131 // Try downloading from another url from the list.
132 if (current_url_ != urls_.end()) {
133 DoStartDownload(*current_url_);
[email protected]afa378f22013-12-02 03:37:54134 return;
135 }
136
[email protected]3cb2a4f2013-12-07 21:54:34137 // If there is another downloader that can accept this request, then hand
138 // the request over to it so that the successor can try the pruned list
139 // of urls. Otherwise, the request ends here since the current downloader
140 // has tried all urls and it can't fall back on any other downloader.
[email protected]da37c1d2013-12-19 01:04:38141 if (successor_ && !urls_.empty()) {
[email protected]1b6587dc52014-04-26 00:38:55142 successor_->StartDownload(urls_, download_callback_);
[email protected]afa378f22013-12-02 03:37:54143 return;
[email protected]da37c1d2013-12-19 01:04:38144 }
[email protected]afa378f22013-12-02 03:37:54145 }
146
[email protected]3cb2a4f2013-12-07 21:54:34147 download_callback_.Run(result);
[email protected]afa378f22013-12-02 03:37:54148}
149
[email protected]8a5ebd432014-05-02 00:21:22150void CrxDownloader::OnDownloadProgress(const Result& result) {
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]afa378f22013-12-02 03:37:54152
[email protected]8a5ebd432014-05-02 00:21:22153 if (progress_callback_.is_null())
154 return;
155
156 progress_callback_.Run(result);
157}
158
159} // namespace component_updater