103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file.
4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/component_updater/crx_downloader.h"
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/logging.h"
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/sequenced_task_runner.h"
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/single_thread_task_runner.h"
1003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/component_updater/url_fetcher_downloader.h"
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#if defined(OS_WIN)
1303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/component_updater/background_downloader_win.h"
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace component_updater {
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
18010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)CrxDownloader::Result::Result()
19010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    : error(0), downloaded_bytes(-1), total_bytes(-1) {
20010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CrxDownloader::DownloadMetrics::DownloadMetrics()
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : downloader(kNone),
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      error(0),
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      downloaded_bytes(-1),
26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      total_bytes(-1),
27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      download_time_ms(0) {
28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// On Windows, the first downloader in the chain is a background downloader,
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// which uses the BITS service.
32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)CrxDownloader* CrxDownloader::Create(
33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    bool is_background_download,
34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    net::URLRequestContextGetter* context_getter,
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> url_fetcher_task_runner,
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_refptr<base::SingleThreadTaskRunner> background_task_runner) {
37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<CrxDownloader> url_fetcher_downloader(
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      new UrlFetcherDownloader(scoped_ptr<CrxDownloader>().Pass(),
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                               context_getter,
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               url_fetcher_task_runner));
41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#if defined(OS_WIN)
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (is_background_download) {
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return new BackgroundDownloader(
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        url_fetcher_downloader.Pass(), context_getter, background_task_runner);
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#endif
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return url_fetcher_downloader.release();
49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuCrxDownloader::CrxDownloader(scoped_ptr<CrxDownloader> successor)
525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : successor_(successor.Pass()) {
53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)CrxDownloader::~CrxDownloader() {
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void CrxDownloader::set_progress_callback(
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const ProgressCallback& progress_callback) {
60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  progress_callback_ = progress_callback;
61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GURL CrxDownloader::url() const {
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return current_url_ != urls_.end() ? *current_url_ : GURL();
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const std::vector<CrxDownloader::DownloadMetrics>
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CrxDownloader::download_metrics() const {
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!successor_)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return download_metrics_;
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<DownloadMetrics> retval(successor_->download_metrics());
73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  retval.insert(
74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      retval.begin(), download_metrics_.begin(), download_metrics_.end());
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return retval;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid CrxDownloader::StartDownloadFromUrl(
795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const GURL& url,
805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const DownloadCallback& download_callback) {
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<GURL> urls;
82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  urls.push_back(url);
835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  StartDownload(urls, download_callback);
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid CrxDownloader::StartDownload(const std::vector<GURL>& urls,
875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                  const DownloadCallback& download_callback) {
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (urls.empty()) {
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Make a result and complete the download with a generic error for now.
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Result result;
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.error = -1;
945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    download_callback.Run(result);
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // If the urls are mutated while this downloader is active, then the
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // behavior is undefined in the sense that the outcome of the download could
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // be inconsistent for the list of urls. At any rate, the |current_url_| is
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // reset at this point, and the iterator will be valid in all conditions.
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  urls_ = urls;
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  current_url_ = urls_.begin();
1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  download_callback_ = download_callback;
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DoStartDownload(*current_url_);
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CrxDownloader::OnDownloadComplete(
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool is_handled,
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const Result& result,
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const DownloadMetrics& download_metrics) {
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  download_metrics_.push_back(download_metrics);
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (result.error) {
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // If an error has occured, in general try the next url if there is any,
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // then move on to the successor in the chain if there is any successor.
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // If this downloader has received a 5xx error for the current url,
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // as indicated by the |is_handled| flag, remove that url from the list of
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // urls so the url is never retried. In both cases, move on to the
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // next url.
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (!is_handled) {
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ++current_url_;
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else {
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      current_url_ = urls_.erase(current_url_);
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Try downloading from another url from the list.
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (current_url_ != urls_.end()) {
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      DoStartDownload(*current_url_);
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return;
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // If there is another downloader that can accept this request, then hand
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // the request over to it so that the successor can try the pruned list
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // of urls. Otherwise, the request ends here since the current downloader
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // has tried all urls and it can't fall back on any other downloader.
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (successor_ && !urls_.empty()) {
1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      successor_->StartDownload(urls_, download_callback_);
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return;
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  download_callback_.Run(result);
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
149010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void CrxDownloader::OnDownloadProgress(const Result& result) {
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
151010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
152010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (progress_callback_.is_null())
153010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
155010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  progress_callback_.Run(result);
156010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
157010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
158010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace component_updater
159