Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
DownloadListener:
"chrome://remote/content/shared/listeners/DownloadListener.sys.mjs",
DownloadPaths: "resource://gre/modules/DownloadPaths.sys.mjs",
FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
});
/**
* A DownloadBehaviorManager class controls per user context and global download behavior.
*/
export class DownloadBehaviorManager {
#defaultBehavior;
#downloadListener;
#userContextBehaviors;
constructor() {
this.#defaultBehavior = null;
this.#userContextBehaviors = new Map();
this.#downloadListener = new lazy.DownloadListener();
this.#downloadListener.on("download-started", this.#onDownloadStarted);
}
destroy() {
this.#defaultBehavior = null;
this.#userContextBehaviors = new Map();
this.#downloadListener.off("download-started", this.#onDownloadStarted);
this.#downloadListener.destroy();
}
/**
* Set the global download behavior.
*
* @param {DownloadBehavior} behavior
* The settings of expected download behavior.
*/
setDefaultBehavior(behavior) {
this.#defaultBehavior = behavior;
this.#controlDownloadListener();
}
/**
* Set the download behavior per user context.
*
* @param {number} userContextId
* The internal id of a user context which holds the settings.
* @param {DownloadBehavior} behavior
* The settings of expected download behavior.
*/
setUserContextBehavior(userContextId, behavior) {
if (behavior === null) {
this.#userContextBehaviors.delete(userContextId);
} else {
this.#userContextBehaviors.set(userContextId, behavior);
}
this.#controlDownloadListener();
}
#controlDownloadListener() {
if (this.#defaultBehavior !== null || this.#userContextBehaviors.size) {
this.#downloadListener.startListening();
} else {
this.#downloadListener.stopListening();
}
}
#onDownloadStarted = async (eventName, data) => {
const { download } = data;
const userContextId = download.source.userContextId;
if (
this.#defaultBehavior !== null ||
this.#userContextBehaviors.has(userContextId)
) {
// Download behavior per user context overrides the global download behavior.
const downloadBehavior =
this.#userContextBehaviors.get(userContextId) || this.#defaultBehavior;
if (downloadBehavior !== null) {
if (downloadBehavior.allowed && downloadBehavior.destinationFolder) {
// Since the temporary and partial data are already saved,
// we have to clean it up before saving the download at the requested location.
// This is a workaround until bug 2017252 is implemented.
// Mark the download as intercepted to avoid sending the event when we pause the download.
download.intercepted = true;
// Pause the download to clean up any data saved.
download.cancel();
await download.removePartialData();
const targetPath = PathUtils.join(
downloadBehavior.destinationFolder,
PathUtils.filename(download.target.path)
);
download.target.path = lazy.DownloadPaths.createNiceUniqueFile(
new lazy.FileUtils.File(targetPath)
).path;
// Restart the download.
download.intercepted = false;
download.start();
} else if (!downloadBehavior.allowed) {
download.cancel();
}
}
}
};
}