summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/xpcshell/test_ext_downloads_urlencoded.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_downloads_urlencoded.js')
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_downloads_urlencoded.js257
1 files changed, 257 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_downloads_urlencoded.js b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_urlencoded.js
new file mode 100644
index 0000000000..03288fb5d5
--- /dev/null
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_urlencoded.js
@@ -0,0 +1,257 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+const { Downloads } = ChromeUtils.importESModule(
+ "resource://gre/modules/Downloads.sys.mjs"
+);
+
+function backgroundScript() {
+ let complete = new Map();
+
+ function waitForComplete(id) {
+ if (complete.has(id)) {
+ return complete.get(id).promise;
+ }
+
+ let promise = new Promise(resolve => {
+ complete.set(id, { resolve });
+ });
+ complete.get(id).promise = promise;
+ return promise;
+ }
+
+ browser.downloads.onChanged.addListener(change => {
+ if (change.state && change.state.current == "complete") {
+ // Make sure we have a promise.
+ waitForComplete(change.id);
+ complete.get(change.id).resolve();
+ }
+ });
+
+ browser.test.onMessage.addListener(async (msg, ...args) => {
+ if (msg == "download.request") {
+ try {
+ let id = await browser.downloads.download(args[0]);
+ browser.test.sendMessage("download.done", { status: "success", id });
+ } catch (error) {
+ browser.test.sendMessage("download.done", {
+ status: "error",
+ errmsg: error.message,
+ });
+ }
+ } else if (msg == "search.request") {
+ try {
+ let downloads = await browser.downloads.search(args[0]);
+ browser.test.sendMessage("search.done", {
+ status: "success",
+ downloads,
+ });
+ } catch (error) {
+ browser.test.sendMessage("search.done", {
+ status: "error",
+ errmsg: error.message,
+ });
+ }
+ } else if (msg == "waitForComplete.request") {
+ await waitForComplete(args[0]);
+ browser.test.sendMessage("waitForComplete.done");
+ }
+ });
+
+ browser.test.sendMessage("ready");
+}
+
+async function clearDownloads(callback) {
+ let list = await Downloads.getList(Downloads.ALL);
+ let downloads = await list.getAll();
+
+ await Promise.all(downloads.map(download => list.remove(download)));
+
+ return downloads;
+}
+
+add_task(async function test_decoded_filename_download() {
+ const server = createHttpServer();
+ server.registerPrefixHandler("/data/", (_, res) => res.write("length=8"));
+
+ const BASE = `http://localhost:${server.identity.primaryPort}/data`;
+ const FILE_NAME_ENCODED_1 = "file%2Fencode.txt";
+ const FILE_NAME_DECODED_1 = "file_encode.txt";
+ const FILE_NAME_ENCODED_URL_1 = BASE + "/" + FILE_NAME_ENCODED_1;
+ const FILE_NAME_ENCODED_2 = "file%F0%9F%9A%B2encoded.txt";
+ const FILE_NAME_DECODED_2 = "file\u{0001F6B2}encoded.txt";
+ const FILE_NAME_ENCODED_URL_2 = BASE + "/" + FILE_NAME_ENCODED_2;
+ const FILE_NAME_ENCODED_3 = "file%X%20encode.txt";
+ const FILE_NAME_DECODED_3 = "file%X encode.txt";
+ const FILE_NAME_ENCODED_URL_3 = BASE + "/" + FILE_NAME_ENCODED_3;
+ const FILE_NAME_ENCODED_4 = "file%E3%80%82encode.txt";
+ const FILE_NAME_DECODED_4 = "file\u3002encode.txt";
+ const FILE_NAME_ENCODED_URL_4 = BASE + "/" + FILE_NAME_ENCODED_4;
+ const FILE_ENCODED_LEN = 8;
+
+ const nsIFile = Ci.nsIFile;
+ let downloadDir = FileUtils.getDir("TmpD", ["downloads"]);
+ downloadDir.createUnique(nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
+ info(`downloadDir ${downloadDir.path}`);
+
+ function downloadPath(filename) {
+ let path = downloadDir.clone();
+ path.append(filename);
+ return path.path;
+ }
+
+ Services.prefs.setIntPref("browser.download.folderList", 2);
+ Services.prefs.setComplexValue("browser.download.dir", nsIFile, downloadDir);
+
+ registerCleanupFunction(async () => {
+ Services.prefs.clearUserPref("browser.download.folderList");
+ Services.prefs.clearUserPref("browser.download.dir");
+ await cleanupDir(downloadDir);
+ await clearDownloads();
+ });
+
+ await clearDownloads().then(downloads => {
+ info(`removed ${downloads.length} pre-existing downloads from history`);
+ });
+
+ let extension = ExtensionTestUtils.loadExtension({
+ background: backgroundScript,
+ manifest: {
+ permissions: ["downloads"],
+ },
+ });
+
+ async function download(options) {
+ extension.sendMessage("download.request", options);
+ let result = await extension.awaitMessage("download.done");
+
+ if (result.status == "success") {
+ info(`wait for onChanged event to indicate ${result.id} is complete`);
+ extension.sendMessage("waitForComplete.request", result.id);
+
+ await extension.awaitMessage("waitForComplete.done");
+ }
+
+ return result;
+ }
+
+ function search(query) {
+ extension.sendMessage("search.request", query);
+ return extension.awaitMessage("search.done");
+ }
+
+ await extension.startup();
+ await extension.awaitMessage("ready");
+
+ let downloadIds = {};
+ let msg = await download({ url: FILE_NAME_ENCODED_URL_1 });
+ equal(msg.status, "success", "download() succeeded");
+ downloadIds.fileEncoded1 = msg.id;
+
+ msg = await download({ url: FILE_NAME_ENCODED_URL_2 });
+ equal(msg.status, "success", "download() succeeded");
+ downloadIds.fileEncoded2 = msg.id;
+
+ msg = await download({ url: FILE_NAME_ENCODED_URL_3 });
+ equal(msg.status, "success", "download() succeeded");
+ downloadIds.fileEncoded3 = msg.id;
+
+ msg = await download({ url: FILE_NAME_ENCODED_URL_4 });
+ equal(msg.status, "success", "download() succeeded");
+ downloadIds.fileEncoded4 = msg.id;
+
+ // Search for each individual download and check
+ // the corresponding DownloadItem.
+ async function checkDownloadItem(id, expect) {
+ let item = await search({ id });
+ equal(item.status, "success", "search() succeeded");
+ equal(item.downloads.length, 1, "search() found exactly 1 download");
+ Object.keys(expect).forEach(function (field) {
+ equal(
+ item.downloads[0][field],
+ expect[field],
+ `DownloadItem.${field} is correct"`
+ );
+ });
+ }
+
+ await checkDownloadItem(downloadIds.fileEncoded1, {
+ url: FILE_NAME_ENCODED_URL_1,
+ filename: downloadPath(FILE_NAME_DECODED_1),
+ state: "complete",
+ bytesReceived: FILE_ENCODED_LEN,
+ totalBytes: FILE_ENCODED_LEN,
+ fileSize: FILE_ENCODED_LEN,
+ exists: true,
+ });
+
+ await checkDownloadItem(downloadIds.fileEncoded2, {
+ url: FILE_NAME_ENCODED_URL_2,
+ filename: downloadPath(FILE_NAME_DECODED_2),
+ state: "complete",
+ bytesReceived: FILE_ENCODED_LEN,
+ totalBytes: FILE_ENCODED_LEN,
+ fileSize: FILE_ENCODED_LEN,
+ exists: true,
+ });
+
+ await checkDownloadItem(downloadIds.fileEncoded3, {
+ url: FILE_NAME_ENCODED_URL_3,
+ filename: downloadPath(FILE_NAME_DECODED_3),
+ state: "complete",
+ bytesReceived: FILE_ENCODED_LEN,
+ totalBytes: FILE_ENCODED_LEN,
+ fileSize: FILE_ENCODED_LEN,
+ exists: true,
+ });
+
+ await checkDownloadItem(downloadIds.fileEncoded4, {
+ url: FILE_NAME_ENCODED_URL_4,
+ filename: downloadPath(FILE_NAME_DECODED_4),
+ state: "complete",
+ bytesReceived: FILE_ENCODED_LEN,
+ totalBytes: FILE_ENCODED_LEN,
+ fileSize: FILE_ENCODED_LEN,
+ exists: true,
+ });
+
+ // Searching for downloads by the decoded filename works correctly.
+ async function checkSearch(query, expected, description) {
+ let item = await search(query);
+ equal(item.status, "success", "search() succeeded");
+ equal(
+ item.downloads.length,
+ expected.length,
+ `search() for ${description} found exactly ${expected.length} downloads`
+ );
+ equal(
+ item.downloads[0].id,
+ downloadIds[expected[0]],
+ `search() for ${description} returned ${expected[0]} in position ${0}`
+ );
+ }
+
+ await checkSearch(
+ { filename: downloadPath(FILE_NAME_DECODED_1) },
+ ["fileEncoded1"],
+ "filename"
+ );
+ await checkSearch(
+ { filename: downloadPath(FILE_NAME_DECODED_2) },
+ ["fileEncoded2"],
+ "filename"
+ );
+ await checkSearch(
+ { filename: downloadPath(FILE_NAME_DECODED_3) },
+ ["fileEncoded3"],
+ "filename"
+ );
+ await checkSearch(
+ { filename: downloadPath(FILE_NAME_DECODED_4) },
+ ["fileEncoded4"],
+ "filename"
+ );
+
+ await extension.unload();
+});