blob: b954ac25704edc19e9b9e9602730b192760cbf2b [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// 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/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "chrome/browser/download/download_danger_prompt.h"
#include "chrome/common/extensions/api/downloads.h"
#include "components/download/content/public/all_download_item_notifier.h"
#include "components/download/public/common/download_path_reservation_tracker.h"
#include "content/public/browser/download_manager.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/browser/warning_set.h"
class DownloadFileIconExtractor;
class DownloadOpenPrompt;
class Profile;
// Functions in the chrome.downloads namespace facilitate
// controlling downloads from extensions. See the full API doc at
// https://docs.google.com/document/d/12rNimeeGaA8jEV60PPKtT4pmJYmY9ae_edl3hJyoXYE/
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 kUiDisabled[];
extern const char kUiPermission[];
extern const char kUnexpectedDeterminer[];
extern const char kUserGesture[];
} // namespace download_extension_errors
namespace extensions {
class DownloadedByExtension : public base::SupportsUserData::Data {
public:
static DownloadedByExtension* Get(download::DownloadItem* item);
DownloadedByExtension(download::DownloadItem* item,
const std::string& id,
const std::string& name);
DownloadedByExtension(const DownloadedByExtension&) = delete;
DownloadedByExtension& operator=(const DownloadedByExtension&) = delete;
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_;
};
class DownloadsDownloadFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.download", DOWNLOADS_DOWNLOAD)
DownloadsDownloadFunction();
DownloadsDownloadFunction(const DownloadsDownloadFunction&) = delete;
DownloadsDownloadFunction& operator=(const DownloadsDownloadFunction&) =
delete;
ResponseAction Run() override;
protected:
~DownloadsDownloadFunction() override;
private:
void OnStarted(const base::FilePath& creator_suggested_filename,
extensions::api::downloads::FilenameConflictAction
creator_conflict_action,
download::DownloadItem* item,
download::DownloadInterruptReason interrupt_reason);
};
class DownloadsSearchFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.search", DOWNLOADS_SEARCH)
DownloadsSearchFunction();
DownloadsSearchFunction(const DownloadsSearchFunction&) = delete;
DownloadsSearchFunction& operator=(const DownloadsSearchFunction&) = delete;
ResponseAction Run() override;
protected:
~DownloadsSearchFunction() override;
};
class DownloadsPauseFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.pause", DOWNLOADS_PAUSE)
DownloadsPauseFunction();
DownloadsPauseFunction(const DownloadsPauseFunction&) = delete;
DownloadsPauseFunction& operator=(const DownloadsPauseFunction&) = delete;
ResponseAction Run() override;
protected:
~DownloadsPauseFunction() override;
};
class DownloadsResumeFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.resume", DOWNLOADS_RESUME)
DownloadsResumeFunction();
DownloadsResumeFunction(const DownloadsResumeFunction&) = delete;
DownloadsResumeFunction& operator=(const DownloadsResumeFunction&) = delete;
ResponseAction Run() override;
protected:
~DownloadsResumeFunction() override;
};
class DownloadsCancelFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.cancel", DOWNLOADS_CANCEL)
DownloadsCancelFunction();
DownloadsCancelFunction(const DownloadsCancelFunction&) = delete;
DownloadsCancelFunction& operator=(const DownloadsCancelFunction&) = delete;
ResponseAction Run() override;
protected:
~DownloadsCancelFunction() override;
};
class DownloadsEraseFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.erase", DOWNLOADS_ERASE)
DownloadsEraseFunction();
DownloadsEraseFunction(const DownloadsEraseFunction&) = delete;
DownloadsEraseFunction& operator=(const DownloadsEraseFunction&) = delete;
ResponseAction Run() override;
protected:
~DownloadsEraseFunction() override;
};
class DownloadsRemoveFileFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.removeFile", DOWNLOADS_REMOVEFILE)
DownloadsRemoveFileFunction();
DownloadsRemoveFileFunction(const DownloadsRemoveFileFunction&) = delete;
DownloadsRemoveFileFunction& operator=(const DownloadsRemoveFileFunction&) =
delete;
ResponseAction Run() override;
protected:
~DownloadsRemoveFileFunction() override;
private:
void Done(bool success);
};
class DownloadsAcceptDangerFunction : public ExtensionFunction {
public:
using OnPromptCreatedCallback =
base::OnceCallback<void(DownloadDangerPrompt*)>;
static void OnPromptCreatedForTesting(
OnPromptCreatedCallback* callback) {
on_prompt_created_ = callback;
}
DECLARE_EXTENSION_FUNCTION("downloads.acceptDanger", DOWNLOADS_ACCEPTDANGER)
DownloadsAcceptDangerFunction();
DownloadsAcceptDangerFunction(const DownloadsAcceptDangerFunction&) = delete;
DownloadsAcceptDangerFunction& operator=(
const DownloadsAcceptDangerFunction&) = delete;
ResponseAction Run() 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_;
};
class DownloadsShowFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.show", DOWNLOADS_SHOW)
DownloadsShowFunction();
DownloadsShowFunction(const DownloadsShowFunction&) = delete;
DownloadsShowFunction& operator=(const DownloadsShowFunction&) = delete;
ResponseAction Run() override;
protected:
~DownloadsShowFunction() override;
};
class DownloadsShowDefaultFolderFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION(
"downloads.showDefaultFolder", DOWNLOADS_SHOWDEFAULTFOLDER)
DownloadsShowDefaultFolderFunction();
DownloadsShowDefaultFolderFunction(
const DownloadsShowDefaultFolderFunction&) = delete;
DownloadsShowDefaultFolderFunction& operator=(
const DownloadsShowDefaultFolderFunction&) = delete;
ResponseAction Run() override;
protected:
~DownloadsShowDefaultFolderFunction() override;
};
class DownloadsOpenFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.open", DOWNLOADS_OPEN)
DownloadsOpenFunction();
DownloadsOpenFunction(const DownloadsOpenFunction&) = delete;
DownloadsOpenFunction& operator=(const DownloadsOpenFunction&) = delete;
ResponseAction Run() override;
using OnPromptCreatedCallback = base::OnceCallback<void(DownloadOpenPrompt*)>;
static void set_on_prompt_created_cb_for_testing(
OnPromptCreatedCallback* on_prompt_created_cb) {
on_prompt_created_cb_ = on_prompt_created_cb;
}
protected:
~DownloadsOpenFunction() override;
private:
void OpenPromptDone(int download_id, bool accept);
static OnPromptCreatedCallback* on_prompt_created_cb_;
};
// TODO(crbug.com/40858206): Remove this deprecated function.
class DownloadsSetShelfEnabledFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.setShelfEnabled",
DOWNLOADS_SETSHELFENABLED)
DownloadsSetShelfEnabledFunction();
DownloadsSetShelfEnabledFunction(const DownloadsSetShelfEnabledFunction&) =
delete;
DownloadsSetShelfEnabledFunction& operator=(
const DownloadsSetShelfEnabledFunction&) = delete;
ResponseAction Run() override;
protected:
~DownloadsSetShelfEnabledFunction() override;
};
class DownloadsSetUiOptionsFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.setUiOptions", DOWNLOADS_SETUIOPTIONS)
DownloadsSetUiOptionsFunction();
DownloadsSetUiOptionsFunction(const DownloadsSetUiOptionsFunction&) = delete;
DownloadsSetUiOptionsFunction& operator=(
const DownloadsSetUiOptionsFunction&) = delete;
ResponseAction Run() override;
protected:
~DownloadsSetUiOptionsFunction() override;
};
class DownloadsGetFileIconFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.getFileIcon", DOWNLOADS_GETFILEICON)
DownloadsGetFileIconFunction();
DownloadsGetFileIconFunction(const DownloadsGetFileIconFunction&) = delete;
DownloadsGetFileIconFunction& operator=(const DownloadsGetFileIconFunction&) =
delete;
ResponseAction Run() override;
void SetIconExtractorForTesting(DownloadFileIconExtractor* extractor);
protected:
~DownloadsGetFileIconFunction() override;
private:
void OnIconURLExtracted(const std::string& url);
base::FilePath path_;
std::unique_ptr<DownloadFileIconExtractor> icon_extractor_;
};
// Observes a single DownloadManager and many DownloadItems and dispatches
// onCreated and onErased events.
class ExtensionDownloadsEventRouter
: public extensions::EventRouter::Observer,
public extensions::ExtensionRegistryObserver,
public download::AllDownloadItemNotifier::Observer {
public:
typedef base::OnceCallback<void(
const base::FilePath& changed_filename,
download::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(
content::BrowserContext* browser_context,
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(const ExtensionDownloadsEventRouter&) = delete;
ExtensionDownloadsEventRouter& operator=(
const ExtensionDownloadsEventRouter&) = delete;
~ExtensionDownloadsEventRouter() override;
void SetUiEnabled(const extensions::Extension* extension, bool enabled);
bool IsUiEnabled() 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 |filename_changed| will
// be called with an empty filename and the filename determination process
// will continue as normal. If an extension wants to change the target
// filename, then |filename_changed| 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(download::DownloadItem* item,
const base::FilePath& suggested_path,
FilenameChangedCallback filename_changed);
// AllDownloadItemNotifier::Observer.
void OnDownloadCreated(content::DownloadManager* manager,
download::DownloadItem* download_item) override;
void OnDownloadUpdated(content::DownloadManager* manager,
download::DownloadItem* download_item) override;
void OnDownloadRemoved(content::DownloadManager* manager,
download::DownloadItem* download_item) override;
// extensions::EventRouter::Observer.
void OnListenerRemoved(const extensions::EventListenerInfo& details) override;
void CheckForHistoryFilesRemoval();
private:
void DispatchEvent(events::HistogramValue histogram_value,
const std::string& event_name,
bool include_incognito,
Event::WillDispatchCallback will_dispatch_callback,
base::Value json_arg);
// extensions::ExtensionRegistryObserver.
void OnExtensionUnloaded(content::BrowserContext* browser_context,
const extensions::Extension* extension,
extensions::UnloadedExtensionReason reason) override;
raw_ptr<Profile> profile_;
download::AllDownloadItemNotifier notifier_;
std::set<raw_ptr<const extensions::Extension, SetExperimental>>
ui_disabling_extensions_;
base::Time last_checked_removal_;
// Listen to extension unloaded notifications.
base::ScopedObservation<extensions::ExtensionRegistry,
extensions::ExtensionRegistryObserver>
extension_registry_observation_{this};
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_DOWNLOADS_DOWNLOADS_API_H_