OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/component_updater/crx_downloader.h" | 5 #include "chrome/browser/component_updater/crx_downloader.h" |
6 #include "chrome/browser/component_updater/url_fetcher_downloader.h" | 6 #include "chrome/browser/component_updater/url_fetcher_downloader.h" |
7 #include "content/public/browser/browser_thread.h" | 7 #include "content/public/browser/browser_thread.h" |
8 | 8 |
| 9 #if defined(OS_WIN) |
| 10 #include "chrome/browser/component_updater/background_downloader_win.h" |
| 11 #endif |
| 12 |
9 using content::BrowserThread; | 13 using content::BrowserThread; |
10 | 14 |
11 namespace component_updater { | 15 namespace component_updater { |
12 | 16 |
13 // This factory method builds the chain of downloaders. Currently, there is only | 17 // On Windows, the first downloader in the chain is a background downloader, |
14 // a url fetcher downloader but more downloaders can be chained up to handle | 18 // which uses the BITS service. |
15 // the request. | |
16 CrxDownloader* CrxDownloader::Create( | 19 CrxDownloader* CrxDownloader::Create( |
| 20 bool is_background_download, |
17 net::URLRequestContextGetter* context_getter, | 21 net::URLRequestContextGetter* context_getter, |
18 scoped_refptr<base::SequencedTaskRunner> task_runner, | 22 scoped_refptr<base::SequencedTaskRunner> task_runner, |
19 const DownloadCallback& download_callback) { | 23 const DownloadCallback& download_callback) { |
20 CrxDownloader* crx_downloader = | 24 scoped_ptr<CrxDownloader> url_fetcher_downloader( |
21 new UrlFetcherDownloader(context_getter, task_runner); | 25 new UrlFetcherDownloader(scoped_ptr<CrxDownloader>().Pass(), |
| 26 context_getter, |
| 27 task_runner, |
| 28 download_callback)); |
| 29 #if defined (OS_WIN) |
| 30 if (is_background_download) { |
| 31 return new BackgroundDownloader(url_fetcher_downloader.Pass(), |
| 32 context_getter, |
| 33 task_runner, |
| 34 download_callback); |
| 35 } |
| 36 #endif |
22 | 37 |
23 crx_downloader->download_callback_ = download_callback; | 38 return url_fetcher_downloader.release(); |
24 | |
25 return crx_downloader; | |
26 } | 39 } |
27 | 40 |
28 CrxDownloader::CrxDownloader() : current_url_(0) { | 41 CrxDownloader::CrxDownloader( |
29 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 42 scoped_ptr<CrxDownloader> successor, |
| 43 const DownloadCallback& download_callback) |
| 44 : successor_(successor.Pass()), |
| 45 download_callback_(download_callback), |
| 46 is_active_(false) { |
| 47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
30 } | 48 } |
31 | 49 |
32 CrxDownloader::~CrxDownloader() { | 50 CrxDownloader::~CrxDownloader() { |
33 } | 51 } |
34 | 52 |
35 void CrxDownloader::StartDownloadFromUrl(const GURL& url) { | 53 bool CrxDownloader::StartDownloadFromUrl(const GURL& url) { |
36 std::vector<GURL> urls; | 54 std::vector<GURL> urls; |
37 urls.push_back(url); | 55 urls.push_back(url); |
38 StartDownload(urls); | 56 return StartDownload(urls); |
39 } | 57 } |
40 | 58 |
41 void CrxDownloader::StartDownload(const std::vector<GURL>& urls) { | 59 bool CrxDownloader::StartDownload(const std::vector<GURL>& urls) { |
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
43 | 61 |
44 if (urls.empty()) | 62 if (urls.empty() || is_active_) |
45 return; | 63 return false; |
| 64 |
| 65 // |is_active_| defensively protects against mutating the container of urls |
| 66 // once the download has started. |
| 67 is_active_ = true; |
46 | 68 |
47 urls_ = urls; | 69 urls_ = urls; |
| 70 current_url_ = urls_.begin(); |
48 | 71 |
49 current_url_ = 0; | 72 DoStartDownload(*current_url_); |
50 DoStartDownload(urls[current_url_]); | 73 return true; |
51 } | 74 } |
52 | 75 |
53 // Handles the fallback in the case of multiple urls and routing of the | 76 void CrxDownloader::OnDownloadComplete(bool is_handled, const Result& result) { |
54 // download to the following successor in the chain. | |
55 void CrxDownloader::OnDownloadComplete(bool is_handled, | |
56 int error, | |
57 const base::FilePath& response) { | |
58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
59 | 78 |
60 // If an error has occured, try the next url if possible, then move on | 79 // If an error has occured, try the next url if there is any, then move on |
61 // to the successor in the chain, if the request has not been handled | 80 // to the successor in the chain if the request has not been handled. |
62 if (error) { | 81 // In the case of an error, and if the downloader has received a 5xx error, as |
63 ++current_url_; | 82 // indicated by the |is_handled| flag, remove that url from the list of |
64 if (current_url_ != urls_.size()) { | 83 // urls so the url is not handed over to the successor. |
65 DoStartDownload(urls_[current_url_]); | 84 if (result.error) { |
| 85 if (!is_handled) |
| 86 ++current_url_; |
| 87 else |
| 88 current_url_ = urls_.erase(current_url_); |
| 89 |
| 90 if (current_url_ != urls_.end()) { |
| 91 DoStartDownload(*current_url_); |
66 return; | 92 return; |
67 } | 93 } |
68 | 94 |
69 if (!is_handled && successor_) { | 95 if (!is_handled && successor_) { |
70 successor_->StartDownload(urls_); | 96 successor_->StartDownload(urls_); |
71 return; | 97 return; |
72 } | 98 } |
73 } | 99 } |
74 | 100 |
75 DCHECK(is_handled || !error || !successor_); | 101 DCHECK(is_handled || !result.error || !successor_); |
76 | 102 |
77 download_callback_.Run(error, response); | 103 download_callback_.Run(result); |
78 } | 104 } |
79 | 105 |
80 } // namespace component_updater | 106 } // namespace component_updater |
81 | 107 |
OLD | NEW |