blob: 6ad08a15c0d2bb8683a952096eb900aa36f1aa52 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_EXTENSIONS_API_DOWNLOADS_DOWNLOADS_API_H_
#define CHROME_BROWSER_EXTENSIONS_API_DOWNLOADS_DOWNLOADS_API_H_
#include <memory>
#include <set>
#include <string>
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/scoped_observer.h"
#include "base/time/time.h"
#include "chrome/browser/download/all_download_item_notifier.h"
#include "chrome/browser/download/download_danger_prompt.h"
#include "chrome/browser/download/download_path_reservation_tracker.h"
#include "chrome/browser/extensions/chrome_extension_function.h"
#include "chrome/common/extensions/api/downloads.h"
#include "content/public/browser/download_manager.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/browser/warning_set.h"
class DownloadFileIconExtractor;
class DownloadQuery;
namespace content {
class ResourceContext;
class ResourceDispatcherHost;
}
namespace extensions {
class ExtensionRegistry;
}
// Functions in the chrome.downloads namespace facilitate
// controlling downloads from extensions. See the full API doc at
// http://goo.gl/6hO1n
namespace download_extension_errors {
// Errors that can be returned through chrome.runtime.lastError.message.
extern const char kEmptyFile[];
extern const char kFileAlreadyDeleted[];
extern const char kFileNotRemoved[];
extern const char kIconNotFound[];
extern const char kInvalidDangerType[];
extern const char kInvalidFilename[];
extern const char kInvalidFilter[];
extern const char kInvalidHeaderName[];
extern const char kInvalidHeaderValue[];
extern const char kInvalidHeaderUnsafe[];
extern const char kInvalidId[];
extern const char kInvalidOrderBy[];
extern const char kInvalidQueryLimit[];
extern const char kInvalidState[];
extern const char kInvalidURL[];
extern const char kInvisibleContext[];
extern const char kNotComplete[];
extern const char kNotDangerous[];
extern const char kNotInProgress[];
extern const char kNotResumable[];
extern const char kOpenPermission[];
extern const char kShelfDisabled[];
extern const char kShelfPermission[];
extern const char kTooManyListeners[];
extern const char kUnexpectedDeterminer[];
extern const char kUserGesture[];
} // namespace download_extension_errors
namespace extensions {
class DownloadedByExtension : public base::SupportsUserData::Data {
public:
static DownloadedByExtension* Get(content::DownloadItem* item);
DownloadedByExtension(content::DownloadItem* item,
const std::string& id,
const std::string& name);
const std::string& id() const { return id_; }
const std::string& name() const { return name_; }
private:
static const char kKey[];
std::string id_;
std::string name_;
DISALLOW_COPY_AND_ASSIGN(DownloadedByExtension);
};
class DownloadsDownloadFunction : public ChromeAsyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.download", DOWNLOADS_DOWNLOAD)
DownloadsDownloadFunction();
bool RunAsync() override;
protected:
~DownloadsDownloadFunction() override;
private:
void OnStarted(const base::FilePath& creator_suggested_filename,
extensions::api::downloads::FilenameConflictAction
creator_conflict_action,
content::DownloadItem* item,
content::DownloadInterruptReason interrupt_reason);
DISALLOW_COPY_AND_ASSIGN(DownloadsDownloadFunction);
};
class DownloadsSearchFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.search", DOWNLOADS_SEARCH)
DownloadsSearchFunction();
ResponseAction Run() override;
protected:
~DownloadsSearchFunction() override;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsSearchFunction);
};
class DownloadsPauseFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.pause", DOWNLOADS_PAUSE)
DownloadsPauseFunction();
ResponseAction Run() override;
protected:
~DownloadsPauseFunction() override;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsPauseFunction);
};
class DownloadsResumeFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.resume", DOWNLOADS_RESUME)
DownloadsResumeFunction();
ResponseAction Run() override;
protected:
~DownloadsResumeFunction() override;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsResumeFunction);
};
class DownloadsCancelFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.cancel", DOWNLOADS_CANCEL)
DownloadsCancelFunction();
ResponseAction Run() override;
protected:
~DownloadsCancelFunction() override;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsCancelFunction);
};
class DownloadsEraseFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.erase", DOWNLOADS_ERASE)
DownloadsEraseFunction();
ResponseAction Run() override;
protected:
~DownloadsEraseFunction() override;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsEraseFunction);
};
class DownloadsRemoveFileFunction : public ChromeAsyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.removeFile", DOWNLOADS_REMOVEFILE)
DownloadsRemoveFileFunction();
bool RunAsync() override;
protected:
~DownloadsRemoveFileFunction() override;
private:
void Done(bool success);
DISALLOW_COPY_AND_ASSIGN(DownloadsRemoveFileFunction);
};
class DownloadsAcceptDangerFunction : public ChromeAsyncExtensionFunction {
public:
typedef base::Callback<void(DownloadDangerPrompt*)> OnPromptCreatedCallback;
static void OnPromptCreatedForTesting(
OnPromptCreatedCallback* callback) {
on_prompt_created_ = callback;
}
DECLARE_EXTENSION_FUNCTION("downloads.acceptDanger", DOWNLOADS_ACCEPTDANGER)
DownloadsAcceptDangerFunction();
bool RunAsync() override;
protected:
~DownloadsAcceptDangerFunction() override;
void DangerPromptCallback(int download_id,
DownloadDangerPrompt::Action action);
private:
void PromptOrWait(int download_id, int retries);
static OnPromptCreatedCallback* on_prompt_created_;
DISALLOW_COPY_AND_ASSIGN(DownloadsAcceptDangerFunction);
};
class DownloadsShowFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.show", DOWNLOADS_SHOW)
DownloadsShowFunction();
ResponseAction Run() override;
protected:
~DownloadsShowFunction() override;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsShowFunction);
};
class DownloadsShowDefaultFolderFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION(
"downloads.showDefaultFolder", DOWNLOADS_SHOWDEFAULTFOLDER)
DownloadsShowDefaultFolderFunction();
ResponseAction Run() override;
protected:
~DownloadsShowDefaultFolderFunction() override;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsShowDefaultFolderFunction);
};
class DownloadsOpenFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.open", DOWNLOADS_OPEN)
DownloadsOpenFunction();
ResponseAction Run() override;
protected:
~DownloadsOpenFunction() override;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsOpenFunction);
};
class DownloadsSetShelfEnabledFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.setShelfEnabled",
DOWNLOADS_SETSHELFENABLED)
DownloadsSetShelfEnabledFunction();
ResponseAction Run() override;
protected:
~DownloadsSetShelfEnabledFunction() override;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsSetShelfEnabledFunction);
};
class DownloadsDragFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.drag", DOWNLOADS_DRAG)
DownloadsDragFunction();
ResponseAction Run() override;
protected:
~DownloadsDragFunction() override;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsDragFunction);
};
class DownloadsGetFileIconFunction : public ChromeAsyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.getFileIcon", DOWNLOADS_GETFILEICON)
DownloadsGetFileIconFunction();
bool RunAsync() override;
void SetIconExtractorForTesting(DownloadFileIconExtractor* extractor);
protected:
~DownloadsGetFileIconFunction() override;
private:
void OnIconURLExtracted(const std::string& url);
base::FilePath path_;
std::unique_ptr<DownloadFileIconExtractor> icon_extractor_;
DISALLOW_COPY_AND_ASSIGN(DownloadsGetFileIconFunction);
};
// Observes a single DownloadManager and many DownloadItems and dispatches
// onCreated and onErased events.
class ExtensionDownloadsEventRouter
: public extensions::EventRouter::Observer,
public extensions::ExtensionRegistryObserver,
public AllDownloadItemNotifier::Observer {
public:
typedef base::Callback<void(
const base::FilePath& changed_filename,
DownloadPathReservationTracker::FilenameConflictAction)>
FilenameChangedCallback;
static void SetDetermineFilenameTimeoutSecondsForTesting(int s);
// The logic for how to handle conflicting filename suggestions from multiple
// extensions is split out here for testing.
static void DetermineFilenameInternal(
const base::FilePath& filename,
extensions::api::downloads::FilenameConflictAction conflict_action,
const std::string& suggesting_extension_id,
const base::Time& suggesting_install_time,
const std::string& incumbent_extension_id,
const base::Time& incumbent_install_time,
std::string* winner_extension_id,
base::FilePath* determined_filename,
extensions::api::downloads::FilenameConflictAction*
determined_conflict_action,
extensions::WarningSet* warnings);
// A downloads.onDeterminingFilename listener has returned. If the extension
// wishes to override the download's filename, then |filename| will be
// non-empty. |filename| will be interpreted as a relative path, appended to
// the default downloads directory. If the extension wishes to overwrite any
// existing files, then |overwrite| will be true. Returns true on success,
// false otherwise.
static bool DetermineFilename(
Profile* profile,
bool include_incognito,
const std::string& ext_id,
int download_id,
const base::FilePath& filename,
extensions::api::downloads::FilenameConflictAction conflict_action,
std::string* error);
explicit ExtensionDownloadsEventRouter(
Profile* profile, content::DownloadManager* manager);
~ExtensionDownloadsEventRouter() override;
void SetShelfEnabled(const extensions::Extension* extension, bool enabled);
bool IsShelfEnabled() const;
// Called by ChromeDownloadManagerDelegate during the filename determination
// process, allows extensions to change the item's target filename. If no
// extension wants to change the target filename, then |no_change| will be
// called and the filename determination process will continue as normal. If
// an extension wants to change the target filename, then |change| will be
// called with the new filename and a flag indicating whether the new file
// should overwrite any old files of the same name.
void OnDeterminingFilename(
content::DownloadItem* item,
const base::FilePath& suggested_path,
const base::Closure& no_change,
const FilenameChangedCallback& change);
// AllDownloadItemNotifier::Observer.
void OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* download_item) override;
void OnDownloadUpdated(content::DownloadManager* manager,
content::DownloadItem* download_item) override;
void OnDownloadRemoved(content::DownloadManager* manager,
content::DownloadItem* download_item) override;
// extensions::EventRouter::Observer.
void OnListenerRemoved(const extensions::EventListenerInfo& details) override;
// Used for testing.
struct DownloadsNotificationSource {
std::string event_name;
Profile* profile;
};
void CheckForHistoryFilesRemoval();
private:
void DispatchEvent(
events::HistogramValue histogram_value,
const std::string& event_name,
bool include_incognito,
const extensions::Event::WillDispatchCallback& will_dispatch_callback,
std::unique_ptr<base::Value> json_arg);
// extensions::ExtensionRegistryObserver.
void OnExtensionUnloaded(
content::BrowserContext* browser_context,
const extensions::Extension* extension,
extensions::UnloadedExtensionInfo::Reason reason) override;
Profile* profile_;
AllDownloadItemNotifier notifier_;
std::set<const extensions::Extension*> shelf_disabling_extensions_;
base::Time last_checked_removal_;
// Listen to extension unloaded notifications.
ScopedObserver<extensions::ExtensionRegistry,
extensions::ExtensionRegistryObserver>
extension_registry_observer_;
DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouter);
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_DOWNLOADS_DOWNLOADS_API_H_