1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_EXTENSIONS_UPDATER_EXTENSION_DOWNLOADER_H_
6#define CHROME_BROWSER_EXTENSIONS_UPDATER_EXTENSION_DOWNLOADER_H_
7
8#include <deque>
9#include <map>
10#include <set>
11#include <string>
12#include <utility>
13#include <vector>
14
15#include "base/basictypes.h"
16#include "base/compiler_specific.h"
17#include "base/memory/linked_ptr.h"
18#include "base/memory/scoped_ptr.h"
19#include "base/memory/weak_ptr.h"
20#include "base/version.h"
21#include "chrome/browser/extensions/updater/extension_downloader_delegate.h"
22#include "chrome/browser/extensions/updater/manifest_fetch_data.h"
23#include "chrome/browser/extensions/updater/request_queue.h"
24#include "chrome/common/extensions/extension.h"
25#include "chrome/common/extensions/update_manifest.h"
26#include "net/url_request/url_fetcher_delegate.h"
27#include "url/gurl.h"
28
29namespace net {
30class URLFetcher;
31class URLRequestContextGetter;
32class URLRequestStatus;
33}
34
35namespace extensions {
36
37struct UpdateDetails {
38  UpdateDetails(const std::string& id, const base::Version& version);
39  ~UpdateDetails();
40
41  std::string id;
42  base::Version version;
43};
44
45class ExtensionUpdaterTest;
46
47// A class that checks for updates of a given list of extensions, and downloads
48// the crx file when updates are found. It uses a |ExtensionDownloaderDelegate|
49// that takes ownership of the downloaded crx files, and handles events during
50// the update check.
51class ExtensionDownloader : public net::URLFetcherDelegate {
52 public:
53  // |delegate| is stored as a raw pointer and must outlive the
54  // ExtensionDownloader.
55  ExtensionDownloader(ExtensionDownloaderDelegate* delegate,
56                      net::URLRequestContextGetter* request_context);
57  virtual ~ExtensionDownloader();
58
59  // Adds |extension| to the list of extensions to check for updates.
60  // Returns false if the |extension| can't be updated due to invalid details.
61  // In that case, no callbacks will be performed on the |delegate_|.
62  // The |request_id| is passed on as is to the various |delegate_| callbacks.
63  // This is used for example by ExtensionUpdater to keep track of when
64  // potentially concurrent update checks complete.
65  bool AddExtension(const Extension& extension, int request_id);
66
67  // Adds extension |id| to the list of extensions to check for updates.
68  // Returns false if the |id| can't be updated due to invalid details.
69  // In that case, no callbacks will be performed on the |delegate_|.
70  // The |request_id| is passed on as is to the various |delegate_| callbacks.
71  // This is used for example by ExtensionUpdater to keep track of when
72  // potentially concurrent update checks complete.
73  bool AddPendingExtension(const std::string& id,
74                           const GURL& update_url,
75                           int request_id);
76
77  // Schedules a fetch of the manifest of all the extensions added with
78  // AddExtension() and AddPendingExtension().
79  void StartAllPending();
80
81  // Schedules an update check of the blacklist.
82  void StartBlacklistUpdate(const std::string& version,
83                            const ManifestFetchData::PingData& ping_data,
84                            int request_id);
85
86  // These are needed for unit testing, to help identify the correct mock
87  // URLFetcher objects.
88  static const int kManifestFetcherId = 1;
89  static const int kExtensionFetcherId = 2;
90
91  // Update AppID for extension blacklist.
92  static const char kBlacklistAppID[];
93
94  static const int kMaxRetries = 10;
95
96 private:
97  friend class ExtensionUpdaterTest;
98
99  // These counters are bumped as extensions are added to be fetched. They
100  // are then recorded as UMA metrics when all the extensions have been added.
101  struct URLStats {
102    URLStats()
103        : no_url_count(0),
104          google_url_count(0),
105          other_url_count(0),
106          extension_count(0),
107          theme_count(0),
108          app_count(0),
109          platform_app_count(0),
110          pending_count(0) {}
111
112    int no_url_count, google_url_count, other_url_count;
113    int extension_count, theme_count, app_count, platform_app_count,
114        pending_count;
115  };
116
117  // We need to keep track of some information associated with a url
118  // when doing a fetch.
119  struct ExtensionFetch {
120    ExtensionFetch();
121    ExtensionFetch(const std::string& id, const GURL& url,
122                   const std::string& package_hash, const std::string& version,
123                   const std::set<int>& request_ids);
124    ~ExtensionFetch();
125
126    std::string id;
127    GURL url;
128    std::string package_hash;
129    std::string version;
130    std::set<int> request_ids;
131  };
132
133  // Helper for AddExtension() and AddPendingExtension().
134  bool AddExtensionData(const std::string& id,
135                        const base::Version& version,
136                        Manifest::Type extension_type,
137                        const GURL& extension_update_url,
138                        const std::string& update_url_data,
139                        int request_id);
140
141  // Adds all recorded stats taken so far to histogram counts.
142  void ReportStats() const;
143
144  // Begins an update check.
145  void StartUpdateCheck(scoped_ptr<ManifestFetchData> fetch_data);
146
147  // Called by RequestQueue when a new manifest fetch request is started.
148  void CreateManifestFetcher();
149
150  // net::URLFetcherDelegate implementation.
151  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
152
153  // Handles the result of a manifest fetch.
154  void OnManifestFetchComplete(const GURL& url,
155                               const net::URLRequestStatus& status,
156                               int response_code,
157                               const base::TimeDelta& backoff_delay,
158                               const std::string& data);
159
160  // Once a manifest is parsed, this starts fetches of any relevant crx files.
161  // If |results| is null, it means something went wrong when parsing it.
162  void HandleManifestResults(const ManifestFetchData& fetch_data,
163                             const UpdateManifest::Results* results);
164
165  // Given a list of potential updates, returns the indices of the ones that are
166  // applicable (are actually a new version, etc.) in |result|.
167  void DetermineUpdates(const ManifestFetchData& fetch_data,
168                        const UpdateManifest::Results& possible_updates,
169                        std::vector<int>* result);
170
171  // Begins (or queues up) download of an updated extension.
172  void FetchUpdatedExtension(scoped_ptr<ExtensionFetch> fetch_data);
173
174  // Called by RequestQueue when a new extension fetch request is started.
175  void CreateExtensionFetcher();
176
177  // Handles the result of a crx fetch.
178  void OnCRXFetchComplete(const net::URLFetcher* source,
179                          const GURL& url,
180                          const net::URLRequestStatus& status,
181                          int response_code,
182                          const base::TimeDelta& backoff_delay);
183
184  // Invokes OnExtensionDownloadFailed() on the |delegate_| for each extension
185  // in the set, with |error| as the reason for failure.
186  void NotifyExtensionsDownloadFailed(const std::set<std::string>& id_set,
187                                      const std::set<int>& request_ids,
188                                      ExtensionDownloaderDelegate::Error error);
189
190  // Send a notification that an update was found for |id| that we'll
191  // attempt to download.
192  void NotifyUpdateFound(const std::string& id, const std::string& version);
193
194  // The delegate that receives the crx files downloaded by the
195  // ExtensionDownloader, and that fills in optional ping and update url data.
196  ExtensionDownloaderDelegate* delegate_;
197
198  // The request context to use for the URLFetchers.
199  net::URLRequestContextGetter* request_context_;
200
201  // Used to create WeakPtrs to |this|.
202  base::WeakPtrFactory<ExtensionDownloader> weak_ptr_factory_;
203
204  // Collects UMA samples that are reported when ReportStats() is called.
205  URLStats url_stats_;
206
207  // List of data on fetches we're going to do. We limit the number of
208  // extensions grouped together in one batch to avoid running into the limits
209  // on the length of http GET requests, so there might be multiple
210  // ManifestFetchData* objects with the same base_url.
211  typedef std::map<std::pair<int, GURL>,
212                   std::vector<linked_ptr<ManifestFetchData> > > FetchMap;
213  FetchMap fetches_preparing_;
214
215  // Outstanding url fetch requests for manifests and updates.
216  scoped_ptr<net::URLFetcher> manifest_fetcher_;
217  scoped_ptr<net::URLFetcher> extension_fetcher_;
218
219  // Pending manifests and extensions to be fetched when the appropriate fetcher
220  // is available.
221  RequestQueue<ManifestFetchData> manifests_queue_;
222  RequestQueue<ExtensionFetch> extensions_queue_;
223
224  // Maps an extension-id to its PingResult data.
225  std::map<std::string, ExtensionDownloaderDelegate::PingResult> ping_results_;
226
227  DISALLOW_COPY_AND_ASSIGN(ExtensionDownloader);
228};
229
230}  // namespace extensions
231
232#endif  // CHROME_BROWSER_EXTENSIONS_UPDATER_EXTENSION_DOWNLOADER_H_
233