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_API_DOWNLOADS_DOWNLOADS_API_H_
6 #define CHROME_BROWSER_EXTENSIONS_API_DOWNLOADS_DOWNLOADS_API_H_
7 
8 #include <memory>
9 #include <set>
10 #include <string>
11 
12 #include "base/files/file_path.h"
13 #include "base/macros.h"
14 #include "base/scoped_observer.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/download/download_danger_prompt.h"
17 #include "chrome/common/extensions/api/downloads.h"
18 #include "components/download/content/public/all_download_item_notifier.h"
19 #include "components/download/public/common/download_path_reservation_tracker.h"
20 #include "content/public/browser/download_manager.h"
21 #include "extensions/browser/event_router.h"
22 #include "extensions/browser/extension_function.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/browser/extension_registry_observer.h"
25 #include "extensions/browser/warning_set.h"
26 
27 class DownloadFileIconExtractor;
28 class DownloadOpenPrompt;
29 class Profile;
30 
31 // Functions in the chrome.downloads namespace facilitate
32 // controlling downloads from extensions. See the full API doc at
33 // http://goo.gl/6hO1n
34 
35 namespace download_extension_errors {
36 
37 // Errors that can be returned through chrome.runtime.lastError.message.
38 extern const char kEmptyFile[];
39 extern const char kFileAlreadyDeleted[];
40 extern const char kFileNotRemoved[];
41 extern const char kIconNotFound[];
42 extern const char kInvalidDangerType[];
43 extern const char kInvalidFilename[];
44 extern const char kInvalidFilter[];
45 extern const char kInvalidHeaderName[];
46 extern const char kInvalidHeaderValue[];
47 extern const char kInvalidHeaderUnsafe[];
48 extern const char kInvalidId[];
49 extern const char kInvalidOrderBy[];
50 extern const char kInvalidQueryLimit[];
51 extern const char kInvalidState[];
52 extern const char kInvalidURL[];
53 extern const char kInvisibleContext[];
54 extern const char kNotComplete[];
55 extern const char kNotDangerous[];
56 extern const char kNotInProgress[];
57 extern const char kNotResumable[];
58 extern const char kOpenPermission[];
59 extern const char kShelfDisabled[];
60 extern const char kShelfPermission[];
61 extern const char kTooManyListeners[];
62 extern const char kUnexpectedDeterminer[];
63 extern const char kUserGesture[];
64 
65 }  // namespace download_extension_errors
66 
67 namespace extensions {
68 
69 class DownloadedByExtension : public base::SupportsUserData::Data {
70  public:
71   static DownloadedByExtension* Get(download::DownloadItem* item);
72 
73   DownloadedByExtension(download::DownloadItem* item,
74                         const std::string& id,
75                         const std::string& name);
76 
id()77   const std::string& id() const { return id_; }
name()78   const std::string& name() const { return name_; }
79 
80  private:
81   static const char kKey[];
82 
83   std::string id_;
84   std::string name_;
85 
86   DISALLOW_COPY_AND_ASSIGN(DownloadedByExtension);
87 };
88 
89 class DownloadsDownloadFunction : public ExtensionFunction {
90  public:
91   DECLARE_EXTENSION_FUNCTION("downloads.download", DOWNLOADS_DOWNLOAD)
92   DownloadsDownloadFunction();
93   ResponseAction Run() override;
94 
95  protected:
96   ~DownloadsDownloadFunction() override;
97 
98  private:
99   void OnStarted(const base::FilePath& creator_suggested_filename,
100                  extensions::api::downloads::FilenameConflictAction
101                      creator_conflict_action,
102                  download::DownloadItem* item,
103                  download::DownloadInterruptReason interrupt_reason);
104 
105   DISALLOW_COPY_AND_ASSIGN(DownloadsDownloadFunction);
106 };
107 
108 class DownloadsSearchFunction : public ExtensionFunction {
109  public:
110   DECLARE_EXTENSION_FUNCTION("downloads.search", DOWNLOADS_SEARCH)
111   DownloadsSearchFunction();
112   ResponseAction Run() override;
113 
114  protected:
115   ~DownloadsSearchFunction() override;
116 
117  private:
118   DISALLOW_COPY_AND_ASSIGN(DownloadsSearchFunction);
119 };
120 
121 class DownloadsPauseFunction : public ExtensionFunction {
122  public:
123   DECLARE_EXTENSION_FUNCTION("downloads.pause", DOWNLOADS_PAUSE)
124   DownloadsPauseFunction();
125   ResponseAction Run() override;
126 
127  protected:
128   ~DownloadsPauseFunction() override;
129 
130  private:
131   DISALLOW_COPY_AND_ASSIGN(DownloadsPauseFunction);
132 };
133 
134 class DownloadsResumeFunction : public ExtensionFunction {
135  public:
136   DECLARE_EXTENSION_FUNCTION("downloads.resume", DOWNLOADS_RESUME)
137   DownloadsResumeFunction();
138   ResponseAction Run() override;
139 
140  protected:
141   ~DownloadsResumeFunction() override;
142 
143  private:
144   DISALLOW_COPY_AND_ASSIGN(DownloadsResumeFunction);
145 };
146 
147 class DownloadsCancelFunction : public ExtensionFunction {
148  public:
149   DECLARE_EXTENSION_FUNCTION("downloads.cancel", DOWNLOADS_CANCEL)
150   DownloadsCancelFunction();
151   ResponseAction Run() override;
152 
153  protected:
154   ~DownloadsCancelFunction() override;
155 
156  private:
157   DISALLOW_COPY_AND_ASSIGN(DownloadsCancelFunction);
158 };
159 
160 class DownloadsEraseFunction : public ExtensionFunction {
161  public:
162   DECLARE_EXTENSION_FUNCTION("downloads.erase", DOWNLOADS_ERASE)
163   DownloadsEraseFunction();
164   ResponseAction Run() override;
165 
166  protected:
167   ~DownloadsEraseFunction() override;
168 
169  private:
170   DISALLOW_COPY_AND_ASSIGN(DownloadsEraseFunction);
171 };
172 
173 class DownloadsRemoveFileFunction : public ExtensionFunction {
174  public:
175   DECLARE_EXTENSION_FUNCTION("downloads.removeFile", DOWNLOADS_REMOVEFILE)
176   DownloadsRemoveFileFunction();
177   ResponseAction Run() override;
178 
179  protected:
180   ~DownloadsRemoveFileFunction() override;
181 
182  private:
183   void Done(bool success);
184 
185   DISALLOW_COPY_AND_ASSIGN(DownloadsRemoveFileFunction);
186 };
187 
188 class DownloadsAcceptDangerFunction : public ExtensionFunction {
189  public:
190   typedef base::Callback<void(DownloadDangerPrompt*)> OnPromptCreatedCallback;
OnPromptCreatedForTesting(OnPromptCreatedCallback * callback)191   static void OnPromptCreatedForTesting(
192       OnPromptCreatedCallback* callback) {
193     on_prompt_created_ = callback;
194   }
195 
196   DECLARE_EXTENSION_FUNCTION("downloads.acceptDanger", DOWNLOADS_ACCEPTDANGER)
197   DownloadsAcceptDangerFunction();
198   ResponseAction Run() override;
199 
200  protected:
201   ~DownloadsAcceptDangerFunction() override;
202   void DangerPromptCallback(int download_id,
203                             DownloadDangerPrompt::Action action);
204 
205  private:
206   void PromptOrWait(int download_id, int retries);
207 
208   static OnPromptCreatedCallback* on_prompt_created_;
209   DISALLOW_COPY_AND_ASSIGN(DownloadsAcceptDangerFunction);
210 };
211 
212 class DownloadsShowFunction : public ExtensionFunction {
213  public:
214   DECLARE_EXTENSION_FUNCTION("downloads.show", DOWNLOADS_SHOW)
215   DownloadsShowFunction();
216   ResponseAction Run() override;
217 
218  protected:
219   ~DownloadsShowFunction() override;
220 
221  private:
222   DISALLOW_COPY_AND_ASSIGN(DownloadsShowFunction);
223 };
224 
225 class DownloadsShowDefaultFolderFunction : public ExtensionFunction {
226  public:
227   DECLARE_EXTENSION_FUNCTION(
228       "downloads.showDefaultFolder", DOWNLOADS_SHOWDEFAULTFOLDER)
229   DownloadsShowDefaultFolderFunction();
230   ResponseAction Run() override;
231 
232  protected:
233   ~DownloadsShowDefaultFolderFunction() override;
234 
235  private:
236   DISALLOW_COPY_AND_ASSIGN(DownloadsShowDefaultFolderFunction);
237 };
238 
239 class DownloadsOpenFunction : public ExtensionFunction {
240  public:
241   DECLARE_EXTENSION_FUNCTION("downloads.open", DOWNLOADS_OPEN)
242   DownloadsOpenFunction();
243   ResponseAction Run() override;
244 
245   typedef base::OnceCallback<void(DownloadOpenPrompt*)> OnPromptCreatedCallback;
set_on_prompt_created_cb_for_testing(OnPromptCreatedCallback * on_prompt_created_cb)246   static void set_on_prompt_created_cb_for_testing(
247       OnPromptCreatedCallback* on_prompt_created_cb) {
248     on_prompt_created_cb_ = on_prompt_created_cb;
249   }
250 
251  protected:
252   ~DownloadsOpenFunction() override;
253 
254  private:
255   void OpenPromptDone(int download_id, bool accept);
256 
257   static OnPromptCreatedCallback* on_prompt_created_cb_;
258 
259   DISALLOW_COPY_AND_ASSIGN(DownloadsOpenFunction);
260 };
261 
262 class DownloadsSetShelfEnabledFunction : public ExtensionFunction {
263  public:
264   DECLARE_EXTENSION_FUNCTION("downloads.setShelfEnabled",
265                              DOWNLOADS_SETSHELFENABLED)
266   DownloadsSetShelfEnabledFunction();
267   ResponseAction Run() override;
268 
269  protected:
270   ~DownloadsSetShelfEnabledFunction() override;
271 
272  private:
273   DISALLOW_COPY_AND_ASSIGN(DownloadsSetShelfEnabledFunction);
274 };
275 
276 class DownloadsGetFileIconFunction : public ExtensionFunction {
277  public:
278   DECLARE_EXTENSION_FUNCTION("downloads.getFileIcon", DOWNLOADS_GETFILEICON)
279   DownloadsGetFileIconFunction();
280   ResponseAction Run() override;
281   void SetIconExtractorForTesting(DownloadFileIconExtractor* extractor);
282 
283  protected:
284   ~DownloadsGetFileIconFunction() override;
285 
286  private:
287   void OnIconURLExtracted(const std::string& url);
288   base::FilePath path_;
289   std::unique_ptr<DownloadFileIconExtractor> icon_extractor_;
290   DISALLOW_COPY_AND_ASSIGN(DownloadsGetFileIconFunction);
291 };
292 
293 // Observes a single DownloadManager and many DownloadItems and dispatches
294 // onCreated and onErased events.
295 class ExtensionDownloadsEventRouter
296     : public extensions::EventRouter::Observer,
297       public extensions::ExtensionRegistryObserver,
298       public download::AllDownloadItemNotifier::Observer {
299  public:
300   typedef base::Callback<void(
301       const base::FilePath& changed_filename,
302       download::DownloadPathReservationTracker::FilenameConflictAction)>
303       FilenameChangedCallback;
304 
305   static void SetDetermineFilenameTimeoutSecondsForTesting(int s);
306 
307   // The logic for how to handle conflicting filename suggestions from multiple
308   // extensions is split out here for testing.
309   static void DetermineFilenameInternal(
310       const base::FilePath& filename,
311       extensions::api::downloads::FilenameConflictAction conflict_action,
312       const std::string& suggesting_extension_id,
313       const base::Time& suggesting_install_time,
314       const std::string& incumbent_extension_id,
315       const base::Time& incumbent_install_time,
316       std::string* winner_extension_id,
317       base::FilePath* determined_filename,
318       extensions::api::downloads::FilenameConflictAction*
319         determined_conflict_action,
320       extensions::WarningSet* warnings);
321 
322   // A downloads.onDeterminingFilename listener has returned. If the extension
323   // wishes to override the download's filename, then |filename| will be
324   // non-empty. |filename| will be interpreted as a relative path, appended to
325   // the default downloads directory. If the extension wishes to overwrite any
326   // existing files, then |overwrite| will be true. Returns true on success,
327   // false otherwise.
328   static bool DetermineFilename(
329       content::BrowserContext* browser_context,
330       bool include_incognito,
331       const std::string& ext_id,
332       int download_id,
333       const base::FilePath& filename,
334       extensions::api::downloads::FilenameConflictAction conflict_action,
335       std::string* error);
336 
337   explicit ExtensionDownloadsEventRouter(
338       Profile* profile, content::DownloadManager* manager);
339   ~ExtensionDownloadsEventRouter() override;
340 
341   void SetShelfEnabled(const extensions::Extension* extension, bool enabled);
342   bool IsShelfEnabled() const;
343 
344   // Called by ChromeDownloadManagerDelegate during the filename determination
345   // process, allows extensions to change the item's target filename. If no
346   // extension wants to change the target filename, then |no_change| will be
347   // called and the filename determination process will continue as normal. If
348   // an extension wants to change the target filename, then |change| will be
349   // called with the new filename and a flag indicating whether the new file
350   // should overwrite any old files of the same name.
351   void OnDeterminingFilename(download::DownloadItem* item,
352                              const base::FilePath& suggested_path,
353                              const base::Closure& no_change,
354                              const FilenameChangedCallback& change);
355 
356   // AllDownloadItemNotifier::Observer.
357   void OnDownloadCreated(content::DownloadManager* manager,
358                          download::DownloadItem* download_item) override;
359   void OnDownloadUpdated(content::DownloadManager* manager,
360                          download::DownloadItem* download_item) override;
361   void OnDownloadRemoved(content::DownloadManager* manager,
362                          download::DownloadItem* download_item) override;
363 
364   // extensions::EventRouter::Observer.
365   void OnListenerRemoved(const extensions::EventListenerInfo& details) override;
366 
367   // Used for testing.
368   struct DownloadsNotificationSource {
369     std::string event_name;
370     Profile* profile;
371   };
372 
373   void CheckForHistoryFilesRemoval();
374 
375  private:
376   void DispatchEvent(events::HistogramValue histogram_value,
377                      const std::string& event_name,
378                      bool include_incognito,
379                      Event::WillDispatchCallback will_dispatch_callback,
380                      std::unique_ptr<base::Value> json_arg);
381 
382   // extensions::ExtensionRegistryObserver.
383   void OnExtensionUnloaded(content::BrowserContext* browser_context,
384                            const extensions::Extension* extension,
385                            extensions::UnloadedExtensionReason reason) override;
386 
387   Profile* profile_;
388   download::AllDownloadItemNotifier notifier_;
389   std::set<const extensions::Extension*> shelf_disabling_extensions_;
390 
391   base::Time last_checked_removal_;
392 
393   // Listen to extension unloaded notifications.
394   ScopedObserver<extensions::ExtensionRegistry,
395                  extensions::ExtensionRegistryObserver>
396       extension_registry_observer_{this};
397 
398   DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouter);
399 };
400 
401 }  // namespace extensions
402 
403 #endif  // CHROME_BROWSER_EXTENSIONS_API_DOWNLOADS_DOWNLOADS_API_H_
404