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 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
30 } | 47 } |
31 | 48 |
32 CrxDownloader::~CrxDownloader() { | 49 CrxDownloader::~CrxDownloader() { |
33 } | 50 } |
34 | 51 |
35 void CrxDownloader::StartDownloadFromUrl(const GURL& url) { | 52 bool CrxDownloader::StartDownloadFromUrl(const GURL& url) { |
36 std::vector<GURL> urls; | 53 std::vector<GURL> urls; |
37 urls.push_back(url); | 54 urls.push_back(url); |
38 StartDownload(urls); | 55 return StartDownload(urls); |
39 } | 56 } |
40 | 57 |
41 void CrxDownloader::StartDownload(const std::vector<GURL>& urls) { | 58 bool CrxDownloader::StartDownload(const std::vector<GURL>& urls) { |
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
43 | 60 |
44 if (urls.empty()) | 61 if (urls.empty()) |
45 return; | 62 return false; |
46 | 63 |
| 64 // If the urls are mutated while this downloader is active, then the |
| 65 // behavior is undefined in the sense that the outcome of the download could |
| 66 // be inconsistent for the list of urls. At any rate, the |current_url_| is |
| 67 // reset at this point, and the iterator will be valid in all conditions. |
47 urls_ = urls; | 68 urls_ = urls; |
| 69 current_url_ = urls_.begin(); |
48 | 70 |
49 current_url_ = 0; | 71 DoStartDownload(*current_url_); |
50 DoStartDownload(urls[current_url_]); | 72 return true; |
51 } | 73 } |
52 | 74 |
53 // Handles the fallback in the case of multiple urls and routing of the | 75 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)); | 76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
59 | 77 |
60 // If an error has occured, try the next url if possible, then move on | 78 if (result.error) { |
61 // to the successor in the chain, if the request has not been handled | 79 // If an error has occured, in general try the next url if there is any, |
62 if (error) { | 80 // then move on to the successor in the chain if there is any successor. |
63 ++current_url_; | 81 // If this downloader has received a 5xx error for the current url, |
64 if (current_url_ != urls_.size()) { | 82 // as indicated by the |is_handled| flag, remove that url from the list of |
65 DoStartDownload(urls_[current_url_]); | 83 // urls so the url is never retried. In both cases, move on to the |
| 84 // next url. |
| 85 if (!is_handled) { |
| 86 ++current_url_; |
| 87 } else { |
| 88 current_url_ = urls_.erase(current_url_); |
| 89 } |
| 90 |
| 91 // Try downloading from another url from the list. |
| 92 if (current_url_ != urls_.end()) { |
| 93 DoStartDownload(*current_url_); |
66 return; | 94 return; |
67 } | 95 } |
68 | 96 |
69 if (!is_handled && successor_) { | 97 // If there is another downloader that can accept this request, then hand |
70 successor_->StartDownload(urls_); | 98 // the request over to it so that the successor can try the pruned list |
| 99 // of urls. Otherwise, the request ends here since the current downloader |
| 100 // has tried all urls and it can't fall back on any other downloader. |
| 101 if (successor_ && successor_->StartDownload(urls_)) |
71 return; | 102 return; |
72 } | |
73 } | 103 } |
74 | 104 |
75 DCHECK(is_handled || !error || !successor_); | 105 download_callback_.Run(result); |
76 | |
77 download_callback_.Run(error, response); | |
78 } | 106 } |
79 | 107 |
80 } // namespace component_updater | 108 } // namespace component_updater |
81 | 109 |
OLD | NEW |