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