[email protected] | de0fdca2 | 2014-08-19 05:26:09 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors. All rights reserved. |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
sorin | 52ac088 | 2015-01-24 01:15:00 | [diff] [blame] | 5 | #ifndef COMPONENTS_UPDATE_CLIENT_CRX_DOWNLOADER_H_ |
| 6 | #define COMPONENTS_UPDATE_CLIENT_CRX_DOWNLOADER_H_ |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 7 | |
sorin | 5cb1f549 | 2014-09-23 04:07:44 | [diff] [blame] | 8 | #include <stdint.h> |
dcheng | d0fc6aa9 | 2016-04-22 18:03:12 | [diff] [blame] | 9 | |
| 10 | #include <memory> |
sorin | 74e7067 | 2016-02-03 03:13:10 | [diff] [blame] | 11 | #include <string> |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 12 | #include <vector> |
[email protected] | bf4631371 | 2014-01-02 22:56:16 | [diff] [blame] | 13 | |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 14 | #include "base/callback.h" |
| 15 | #include "base/files/file_path.h" |
sorin | 5cb1f549 | 2014-09-23 04:07:44 | [diff] [blame] | 16 | #include "base/macros.h" |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 17 | #include "base/memory/ref_counted.h" |
Sorin Jianu | ebd65246 | 2017-07-23 02:00:58 | [diff] [blame] | 18 | #include "base/single_thread_task_runner.h" |
[email protected] | ed6fb98 | 2014-07-23 16:56:52 | [diff] [blame] | 19 | #include "base/threading/thread_checker.h" |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 20 | #include "url/gurl.h" |
| 21 | |
sorin | 52ac088 | 2015-01-24 01:15:00 | [diff] [blame] | 22 | namespace update_client { |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 23 | |
Sorin Jianu | 75e6bf2 | 2019-02-12 16:07:12 | [diff] [blame] | 24 | class NetworkFetcherFactory; |
| 25 | |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 26 | // Defines a download interface for downloading components, with retrying on |
| 27 | // fallback urls in case of errors. This class implements a chain of |
| 28 | // responsibility design pattern. It can give successors in the chain a chance |
| 29 | // to handle a download request, until one of them succeeds, or there are no |
| 30 | // more urls or successors to try. A callback is always called at the end of |
| 31 | // the download, one time only. |
| 32 | // When multiple urls and downloaders exists, first all the urls are tried, in |
| 33 | // the order they are provided in the StartDownload function argument. After |
| 34 | // that, the download request is routed to the next downloader in the chain. |
[email protected] | ed6fb98 | 2014-07-23 16:56:52 | [diff] [blame] | 35 | // The members of this class expect to be called from the main thread only. |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 36 | class CrxDownloader { |
[email protected] | 3cb2a4f | 2013-12-07 21:54:34 | [diff] [blame] | 37 | public: |
[email protected] | 3a0092d | 2013-12-18 03:04:35 | [diff] [blame] | 38 | struct DownloadMetrics { |
[email protected] | d0c8b8b4 | 2014-05-06 05:11:45 | [diff] [blame] | 39 | enum Downloader { kNone = 0, kUrlFetcher, kBits }; |
[email protected] | 3a0092d | 2013-12-18 03:04:35 | [diff] [blame] | 40 | |
| 41 | DownloadMetrics(); |
| 42 | |
| 43 | GURL url; |
| 44 | |
| 45 | Downloader downloader; |
| 46 | |
| 47 | int error; |
| 48 | |
sorin | 5cb1f549 | 2014-09-23 04:07:44 | [diff] [blame] | 49 | int64_t downloaded_bytes; // -1 means that the byte count is unknown. |
| 50 | int64_t total_bytes; |
[email protected] | 3a0092d | 2013-12-18 03:04:35 | [diff] [blame] | 51 | |
sorin | 5cb1f549 | 2014-09-23 04:07:44 | [diff] [blame] | 52 | uint64_t download_time_ms; |
[email protected] | 3a0092d | 2013-12-18 03:04:35 | [diff] [blame] | 53 | }; |
| 54 | |
[email protected] | 8a5ebd43 | 2014-05-02 00:21:22 | [diff] [blame] | 55 | // Contains the progress or the outcome of the download. |
[email protected] | 3cb2a4f | 2013-12-07 21:54:34 | [diff] [blame] | 56 | struct Result { |
[email protected] | 3cb2a4f | 2013-12-07 21:54:34 | [diff] [blame] | 57 | // Download error: 0 indicates success. |
Antonio Gomes | 31237fb | 2018-08-27 19:11:03 | [diff] [blame] | 58 | int error = 0; |
[email protected] | 3cb2a4f | 2013-12-07 21:54:34 | [diff] [blame] | 59 | |
[email protected] | 3cb2a4f | 2013-12-07 21:54:34 | [diff] [blame] | 60 | // Path of the downloaded file if the download was successful. |
| 61 | base::FilePath response; |
| 62 | }; |
| 63 | |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 64 | // The callback fires only once, regardless of how many urls are tried, and |
| 65 | // how many successors in the chain of downloaders have handled the |
| 66 | // download. The callback interface can be extended if needed to provide |
| 67 | // more visibility into how the download has been handled, including |
| 68 | // specific error codes and download metrics. |
Sorin Jianu | a8ef73d | 2017-11-02 16:55:17 | [diff] [blame] | 69 | using DownloadCallback = base::OnceCallback<void(const Result& result)>; |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 70 | |
Antonio Gomes | 31237fb | 2018-08-27 19:11:03 | [diff] [blame] | 71 | // The callback may fire 0 or once during a download. Since this |
[email protected] | 8a5ebd43 | 2014-05-02 00:21:22 | [diff] [blame] | 72 | // class implements a chain of responsibility, the callback can fire for |
Antonio Gomes | 31237fb | 2018-08-27 19:11:03 | [diff] [blame] | 73 | // different urls and different downloaders. |
| 74 | using ProgressCallback = base::RepeatingCallback<void()>; |
sorin | 9797aba | 2015-04-17 17:15:03 | [diff] [blame] | 75 | |
Sorin Jianu | 75e6bf2 | 2019-02-12 16:07:12 | [diff] [blame] | 76 | using Factory = |
| 77 | std::unique_ptr<CrxDownloader> (*)(bool, |
| 78 | scoped_refptr<NetworkFetcherFactory>); |
[email protected] | 8a5ebd43 | 2014-05-02 00:21:22 | [diff] [blame] | 79 | |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 80 | // Factory method to create an instance of this class and build the |
[email protected] | 3cb2a4f | 2013-12-07 21:54:34 | [diff] [blame] | 81 | // chain of responsibility. |is_background_download| specifies that a |
| 82 | // background downloader be used, if the platform supports it. |
sorin | 74e7067 | 2016-02-03 03:13:10 | [diff] [blame] | 83 | // |task_runner| should be a task runner able to run blocking |
| 84 | // code such as file IO operations. |
dcheng | d0fc6aa9 | 2016-04-22 18:03:12 | [diff] [blame] | 85 | static std::unique_ptr<CrxDownloader> Create( |
[email protected] | 3cb2a4f | 2013-12-07 21:54:34 | [diff] [blame] | 86 | bool is_background_download, |
Sorin Jianu | 75e6bf2 | 2019-02-12 16:07:12 | [diff] [blame] | 87 | scoped_refptr<NetworkFetcherFactory> network_fetcher_factory); |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 88 | virtual ~CrxDownloader(); |
| 89 | |
[email protected] | 8a5ebd43 | 2014-05-02 00:21:22 | [diff] [blame] | 90 | void set_progress_callback(const ProgressCallback& progress_callback); |
| 91 | |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 92 | // Starts the download. One instance of the class handles one download only. |
[email protected] | da37c1d | 2013-12-19 01:04:38 | [diff] [blame] | 93 | // One instance of CrxDownloader can only be started once, otherwise the |
| 94 | // behavior is undefined. The callback gets invoked if the download can't |
sorin | 74e7067 | 2016-02-03 03:13:10 | [diff] [blame] | 95 | // be started. |expected_hash| represents the SHA256 cryptographic hash of |
| 96 | // the download payload, represented as a hexadecimal string. |
[email protected] | 1b6587dc5 | 2014-04-26 00:38:55 | [diff] [blame] | 97 | void StartDownloadFromUrl(const GURL& url, |
sorin | 74e7067 | 2016-02-03 03:13:10 | [diff] [blame] | 98 | const std::string& expected_hash, |
Sorin Jianu | a8ef73d | 2017-11-02 16:55:17 | [diff] [blame] | 99 | DownloadCallback download_callback); |
[email protected] | 1b6587dc5 | 2014-04-26 00:38:55 | [diff] [blame] | 100 | void StartDownload(const std::vector<GURL>& urls, |
sorin | 74e7067 | 2016-02-03 03:13:10 | [diff] [blame] | 101 | const std::string& expected_hash, |
Sorin Jianu | a8ef73d | 2017-11-02 16:55:17 | [diff] [blame] | 102 | DownloadCallback download_callback); |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 103 | |
[email protected] | 3a0092d | 2013-12-18 03:04:35 | [diff] [blame] | 104 | const std::vector<DownloadMetrics> download_metrics() const; |
| 105 | |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 106 | protected: |
Sorin Jianu | 72d8fe0d | 2017-07-11 18:42:16 | [diff] [blame] | 107 | explicit CrxDownloader(std::unique_ptr<CrxDownloader> successor); |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 108 | |
[email protected] | 3cb2a4f | 2013-12-07 21:54:34 | [diff] [blame] | 109 | // Handles the fallback in the case of multiple urls and routing of the |
| 110 | // download to the following successor in the chain. Derived classes must call |
| 111 | // this function after each attempt at downloading the urls provided |
| 112 | // in the StartDownload function. |
| 113 | // In case of errors, |is_handled| indicates that a server side error has |
| 114 | // occured for the current url and the url should not be retried down |
| 115 | // the chain to avoid DDOS of the server. This url will be removed from the |
| 116 | // list of url and never tried again. |
[email protected] | 3a0092d | 2013-12-18 03:04:35 | [diff] [blame] | 117 | void OnDownloadComplete(bool is_handled, |
| 118 | const Result& result, |
| 119 | const DownloadMetrics& download_metrics); |
| 120 | |
[email protected] | 8a5ebd43 | 2014-05-02 00:21:22 | [diff] [blame] | 121 | // Calls the callback when progress is made. |
Antonio Gomes | 31237fb | 2018-08-27 19:11:03 | [diff] [blame] | 122 | void OnDownloadProgress(); |
[email protected] | 8a5ebd43 | 2014-05-02 00:21:22 | [diff] [blame] | 123 | |
| 124 | // Returns the url which is currently being downloaded from. |
[email protected] | 3a0092d | 2013-12-18 03:04:35 | [diff] [blame] | 125 | GURL url() const; |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 126 | |
Sorin Jianu | ebd65246 | 2017-07-23 02:00:58 | [diff] [blame] | 127 | scoped_refptr<base::SingleThreadTaskRunner> main_task_runner() const { |
sorin | 74e7067 | 2016-02-03 03:13:10 | [diff] [blame] | 128 | return main_task_runner_; |
| 129 | } |
| 130 | |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 131 | private: |
| 132 | virtual void DoStartDownload(const GURL& url) = 0; |
| 133 | |
sorin | 74e7067 | 2016-02-03 03:13:10 | [diff] [blame] | 134 | void VerifyResponse(bool is_handled, |
| 135 | Result result, |
| 136 | DownloadMetrics download_metrics); |
| 137 | |
| 138 | void HandleDownloadError(bool is_handled, |
| 139 | const Result& result, |
| 140 | const DownloadMetrics& download_metrics); |
| 141 | |
[email protected] | ed6fb98 | 2014-07-23 16:56:52 | [diff] [blame] | 142 | base::ThreadChecker thread_checker_; |
| 143 | |
sorin | 74e7067 | 2016-02-03 03:13:10 | [diff] [blame] | 144 | // Used to post callbacks to the main thread. |
Sorin Jianu | ebd65246 | 2017-07-23 02:00:58 | [diff] [blame] | 145 | scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; |
sorin | 74e7067 | 2016-02-03 03:13:10 | [diff] [blame] | 146 | |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 147 | std::vector<GURL> urls_; |
sorin | 74e7067 | 2016-02-03 03:13:10 | [diff] [blame] | 148 | |
| 149 | // The SHA256 hash of the download payload in hexadecimal format. |
| 150 | std::string expected_hash_; |
dcheng | d0fc6aa9 | 2016-04-22 18:03:12 | [diff] [blame] | 151 | std::unique_ptr<CrxDownloader> successor_; |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 152 | DownloadCallback download_callback_; |
[email protected] | 8a5ebd43 | 2014-05-02 00:21:22 | [diff] [blame] | 153 | ProgressCallback progress_callback_; |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 154 | |
[email protected] | 3cb2a4f | 2013-12-07 21:54:34 | [diff] [blame] | 155 | std::vector<GURL>::iterator current_url_; |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 156 | |
[email protected] | 3a0092d | 2013-12-18 03:04:35 | [diff] [blame] | 157 | std::vector<DownloadMetrics> download_metrics_; |
| 158 | |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 159 | DISALLOW_COPY_AND_ASSIGN(CrxDownloader); |
| 160 | }; |
| 161 | |
sorin | 52ac088 | 2015-01-24 01:15:00 | [diff] [blame] | 162 | } // namespace update_client |
[email protected] | afa378f2 | 2013-12-02 03:37:54 | [diff] [blame] | 163 | |
sorin | 52ac088 | 2015-01-24 01:15:00 | [diff] [blame] | 164 | #endif // COMPONENTS_UPDATE_CLIENT_CRX_DOWNLOADER_H_ |