blob: 9591b9c680497b4e486cf4cefdef72f253c72d60 [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]3a0092d2013-12-18 03:04:3517CrxDownloader::Result::Result() : error(0) {}
18
19CrxDownloader::DownloadMetrics::DownloadMetrics()
20 : downloader(kNone),
21 error(0),
[email protected]bf46313712014-01-02 22:56:1622 bytes_downloaded(-1),
23 bytes_total(-1),
[email protected]3a0092d2013-12-18 03:04:3524 download_time_ms(0) {}
25
[email protected]3cb2a4f2013-12-07 21:54:3426// On Windows, the first downloader in the chain is a background downloader,
27// which uses the BITS service.
[email protected]afa378f22013-12-02 03:37:5428CrxDownloader* CrxDownloader::Create(
[email protected]3cb2a4f2013-12-07 21:54:3429 bool is_background_download,
[email protected]afa378f22013-12-02 03:37:5430 net::URLRequestContextGetter* context_getter,
[email protected]1b6587dc52014-04-26 00:38:5531 scoped_refptr<base::SequencedTaskRunner> task_runner) {
[email protected]3cb2a4f2013-12-07 21:54:3432 scoped_ptr<CrxDownloader> url_fetcher_downloader(
33 new UrlFetcherDownloader(scoped_ptr<CrxDownloader>().Pass(),
34 context_getter,
[email protected]1b6587dc52014-04-26 00:38:5535 task_runner));
[email protected]3cb2a4f2013-12-07 21:54:3436#if defined (OS_WIN)
37 if (is_background_download) {
38 return new BackgroundDownloader(url_fetcher_downloader.Pass(),
39 context_getter,
[email protected]1b6587dc52014-04-26 00:38:5540 task_runner);
[email protected]3cb2a4f2013-12-07 21:54:3441 }
42#endif
[email protected]afa378f22013-12-02 03:37:5443
[email protected]3cb2a4f2013-12-07 21:54:3444 return url_fetcher_downloader.release();
[email protected]afa378f22013-12-02 03:37:5445}
46
[email protected]1b6587dc52014-04-26 00:38:5547CrxDownloader::CrxDownloader(scoped_ptr<CrxDownloader> successor)
48 : successor_(successor.Pass()) {
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]afa378f22013-12-02 03:37:5450}
51
52CrxDownloader::~CrxDownloader() {
53}
54
[email protected]3a0092d2013-12-18 03:04:3555GURL CrxDownloader::url() const {
56 return current_url_ != urls_.end() ? *current_url_ : GURL();
57}
58
59const std::vector<CrxDownloader::DownloadMetrics>
60CrxDownloader::download_metrics() const {
61 if (!successor_)
62 return download_metrics_;
63
64 std::vector<DownloadMetrics> retval(successor_->download_metrics());
65 retval.insert(retval.begin(),
66 download_metrics_.begin(),
67 download_metrics_.end());
68 return retval;
69}
70
[email protected]1b6587dc52014-04-26 00:38:5571void CrxDownloader::StartDownloadFromUrl(
72 const GURL& url,
73 const DownloadCallback& download_callback) {
[email protected]afa378f22013-12-02 03:37:5474 std::vector<GURL> urls;
75 urls.push_back(url);
[email protected]1b6587dc52014-04-26 00:38:5576 StartDownload(urls, download_callback);
[email protected]afa378f22013-12-02 03:37:5477}
78
[email protected]1b6587dc52014-04-26 00:38:5579void CrxDownloader::StartDownload(const std::vector<GURL>& urls,
80 const DownloadCallback& download_callback) {
[email protected]afa378f22013-12-02 03:37:5481 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
82
[email protected]da37c1d2013-12-19 01:04:3883 if (urls.empty()) {
84 // Make a result and complete the download with a generic error for now.
85 Result result;
86 result.error = -1;
[email protected]1b6587dc52014-04-26 00:38:5587 download_callback.Run(result);
[email protected]da37c1d2013-12-19 01:04:3888 return;
89 }
[email protected]afa378f22013-12-02 03:37:5490
[email protected]3cb2a4f2013-12-07 21:54:3491 // If the urls are mutated while this downloader is active, then the
92 // behavior is undefined in the sense that the outcome of the download could
93 // be inconsistent for the list of urls. At any rate, the |current_url_| is
94 // reset at this point, and the iterator will be valid in all conditions.
[email protected]afa378f22013-12-02 03:37:5495 urls_ = urls;
[email protected]3cb2a4f2013-12-07 21:54:3496 current_url_ = urls_.begin();
[email protected]1b6587dc52014-04-26 00:38:5597 download_callback_ = download_callback;
[email protected]afa378f22013-12-02 03:37:5498
[email protected]3cb2a4f2013-12-07 21:54:3499 DoStartDownload(*current_url_);
[email protected]afa378f22013-12-02 03:37:54100}
101
[email protected]3a0092d2013-12-18 03:04:35102void CrxDownloader::OnDownloadComplete(
103 bool is_handled,
104 const Result& result,
105 const DownloadMetrics& download_metrics) {
[email protected]afa378f22013-12-02 03:37:54106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
107
[email protected]3a0092d2013-12-18 03:04:35108 download_metrics_.push_back(download_metrics);
109
[email protected]3cb2a4f2013-12-07 21:54:34110 if (result.error) {
111 // If an error has occured, in general try the next url if there is any,
112 // then move on to the successor in the chain if there is any successor.
113 // If this downloader has received a 5xx error for the current url,
114 // as indicated by the |is_handled| flag, remove that url from the list of
115 // urls so the url is never retried. In both cases, move on to the
116 // next url.
117 if (!is_handled) {
118 ++current_url_;
119 } else {
120 current_url_ = urls_.erase(current_url_);
121 }
122
123 // Try downloading from another url from the list.
124 if (current_url_ != urls_.end()) {
125 DoStartDownload(*current_url_);
[email protected]afa378f22013-12-02 03:37:54126 return;
127 }
128
[email protected]3cb2a4f2013-12-07 21:54:34129 // If there is another downloader that can accept this request, then hand
130 // the request over to it so that the successor can try the pruned list
131 // of urls. Otherwise, the request ends here since the current downloader
132 // has tried all urls and it can't fall back on any other downloader.
[email protected]da37c1d2013-12-19 01:04:38133 if (successor_ && !urls_.empty()) {
[email protected]1b6587dc52014-04-26 00:38:55134 successor_->StartDownload(urls_, download_callback_);
[email protected]afa378f22013-12-02 03:37:54135 return;
[email protected]da37c1d2013-12-19 01:04:38136 }
[email protected]afa378f22013-12-02 03:37:54137 }
138
[email protected]3cb2a4f2013-12-07 21:54:34139 download_callback_.Run(result);
[email protected]afa378f22013-12-02 03:37:54140}
141
142} // namespace component_updater
143