1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/component_updater/crx_downloader.h"
#include "base/logging.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
#include "components/component_updater/url_fetcher_downloader.h"
#if defined(OS_WIN)
#include "components/component_updater/background_downloader_win.h"
#endif
namespace component_updater {
CrxDownloader::Result::Result()
: error(0), downloaded_bytes(-1), total_bytes(-1) {
}
CrxDownloader::DownloadMetrics::DownloadMetrics()
: downloader(kNone),
error(0),
downloaded_bytes(-1),
total_bytes(-1),
download_time_ms(0) {
}
// On Windows, the first downloader in the chain is a background downloader,
// which uses the BITS service.
CrxDownloader* CrxDownloader::Create(
bool is_background_download,
net::URLRequestContextGetter* context_getter,
scoped_refptr<base::SequencedTaskRunner> url_fetcher_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> background_task_runner) {
scoped_ptr<CrxDownloader> url_fetcher_downloader(
new UrlFetcherDownloader(scoped_ptr<CrxDownloader>().Pass(),
context_getter,
url_fetcher_task_runner));
#if defined(OS_WIN)
if (is_background_download) {
return new BackgroundDownloader(
url_fetcher_downloader.Pass(), context_getter, background_task_runner);
}
#endif
return url_fetcher_downloader.release();
}
CrxDownloader::CrxDownloader(scoped_ptr<CrxDownloader> successor)
: successor_(successor.Pass()) {
}
CrxDownloader::~CrxDownloader() {
}
void CrxDownloader::set_progress_callback(
const ProgressCallback& progress_callback) {
progress_callback_ = progress_callback;
}
GURL CrxDownloader::url() const {
return current_url_ != urls_.end() ? *current_url_ : GURL();
}
const std::vector<CrxDownloader::DownloadMetrics>
CrxDownloader::download_metrics() const {
if (!successor_)
return download_metrics_;
std::vector<DownloadMetrics> retval(successor_->download_metrics());
retval.insert(
retval.begin(), download_metrics_.begin(), download_metrics_.end());
return retval;
}
void CrxDownloader::StartDownloadFromUrl(
const GURL& url,
const DownloadCallback& download_callback) {
std::vector<GURL> urls;
urls.push_back(url);
StartDownload(urls, download_callback);
}
void CrxDownloader::StartDownload(const std::vector<GURL>& urls,
const DownloadCallback& download_callback) {
DCHECK(thread_checker_.CalledOnValidThread());
if (urls.empty()) {
// Make a result and complete the download with a generic error for now.
Result result;
result.error = -1;
download_callback.Run(result);
return;
}
// If the urls are mutated while this downloader is active, then the
// behavior is undefined in the sense that the outcome of the download could
// be inconsistent for the list of urls. At any rate, the |current_url_| is
// reset at this point, and the iterator will be valid in all conditions.
urls_ = urls;
current_url_ = urls_.begin();
download_callback_ = download_callback;
DoStartDownload(*current_url_);
}
void CrxDownloader::OnDownloadComplete(
bool is_handled,
const Result& result,
const DownloadMetrics& download_metrics) {
DCHECK(thread_checker_.CalledOnValidThread());
download_metrics_.push_back(download_metrics);
if (result.error) {
// If an error has occured, in general try the next url if there is any,
// then move on to the successor in the chain if there is any successor.
// If this downloader has received a 5xx error for the current url,
// as indicated by the |is_handled| flag, remove that url from the list of
// urls so the url is never retried. In both cases, move on to the
// next url.
if (!is_handled) {
++current_url_;
} else {
current_url_ = urls_.erase(current_url_);
}
// Try downloading from another url from the list.
if (current_url_ != urls_.end()) {
DoStartDownload(*current_url_);
return;
}
// If there is another downloader that can accept this request, then hand
// the request over to it so that the successor can try the pruned list
// of urls. Otherwise, the request ends here since the current downloader
// has tried all urls and it can't fall back on any other downloader.
if (successor_ && !urls_.empty()) {
successor_->StartDownload(urls_, download_callback_);
return;
}
}
download_callback_.Run(result);
}
void CrxDownloader::OnDownloadProgress(const Result& result) {
DCHECK(thread_checker_.CalledOnValidThread());
if (progress_callback_.is_null())
return;
progress_callback_.Run(result);
}
} // namespace component_updater
|