Bug 1362448 - Support "incognito" in downloads.create r=aswan
authorRob Wu <rob@robwu.nl>
Fri, 14 Jul 2017 17:14:18 +0200
changeset 422363 f257d10ebc4a5df96e1228cd47e807c954e76656
parent 422362 4269e394aa94fd9b3342a491b695bfaf00ca1207
child 422364 357a94f6484f6aafc305fcb643686e0b8863597b
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan
bugs1362448
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1362448 - Support "incognito" in downloads.create r=aswan MozReview-Commit-ID: HN3x6eFT9xB
toolkit/components/extensions/ext-downloads.js
toolkit/components/extensions/schemas/downloads.json
toolkit/components/extensions/test/xpcshell/test_ext_downloads_download.js
toolkit/components/extensions/test/xpcshell/test_ext_downloads_private.js
toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
--- a/toolkit/components/extensions/ext-downloads.js
+++ b/toolkit/components/extensions/ext-downloads.js
@@ -522,16 +522,17 @@ this.downloads = class extends Extension
           }
 
           let download;
           return Downloads.getPreferredDownloadsDirectory()
             .then(downloadsDir => createTarget(downloadsDir))
             .then(target => {
               const source = {
                 url: options.url,
+                isPrivate: options.incognito,
               };
 
               if (options.method || options.headers || options.body) {
                 source.adjustChannel = adjustChannel;
               }
 
               return Downloads.createDownload({
                 source,
--- a/toolkit/components/extensions/schemas/downloads.json
+++ b/toolkit/components/extensions/schemas/downloads.json
@@ -372,16 +372,22 @@
                 "type": "string",
                 "format": "url"
               },
               "filename": {
                 "description": "A file path relative to the Downloads directory to contain the downloaded file.",
                 "optional": true,
                 "type": "string"
               },
+              "incognito": {
+                "description": "Whether to associate the download with a private browsing session.",
+                "optional": true,
+                "default": false,
+                "type": "boolean"
+              },
               "conflictAction": {
                 "$ref": "FilenameConflictAction",
                 "optional": true
               },
               "saveAs": {
                 "description": "Use a file-chooser to allow the user to select a filename.",
                 "optional": true,
                 "type": "boolean"
--- a/toolkit/components/extensions/test/xpcshell/test_ext_downloads_download.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_download.js
@@ -261,16 +261,27 @@ add_task(async function test_downloads()
   }, "download", BLOB_STRING.length, "blob url with no filename");
   extension.sendMessage("killTheBlob");
 
   // Download a normal URL with an empty filename part.
   await testDownload({
     url: BASE + "dir/",
   }, "download", 8, "normal url with empty filename");
 
+  // Check that the "incognito" property is supported.
+  await testDownload({
+    url: FILE_URL,
+    incognito: false,
+  }, FILE_NAME, FILE_LEN, "incognito=false");
+
+  await testDownload({
+    url: FILE_URL,
+    incognito: true,
+  }, FILE_NAME, FILE_LEN, "incognito=true");
+
   await extension.unload();
 });
 
 add_task(async function test_download_post() {
   const server = createHttpServer();
   const url = `http://localhost:${server.identity.primaryPort}/post-log`;
 
   let received;
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_private.js
@@ -0,0 +1,116 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+Cu.import("resource://gre/modules/Downloads.jsm");
+
+const server = createHttpServer();
+server.registerDirectory("/data/", do_get_file("data"));
+
+const BASE = `http://localhost:${server.identity.primaryPort}/data`;
+const TXT_FILE = "file_download.txt";
+const TXT_URL = BASE + "/" + TXT_FILE;
+
+function setup() {
+  let downloadDir = FileUtils.getDir("TmpD", ["downloads"]);
+  downloadDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
+  do_print(`Using download directory ${downloadDir.path}`);
+
+  Services.prefs.setIntPref("browser.download.folderList", 2);
+  Services.prefs.setComplexValue("browser.download.dir", Ci.nsIFile, downloadDir);
+
+  do_register_cleanup(() => {
+    Services.prefs.clearUserPref("browser.download.folderList");
+    Services.prefs.clearUserPref("browser.download.dir");
+
+    let entries = downloadDir.directoryEntries;
+    while (entries.hasMoreElements()) {
+      let entry = entries.getNext().QueryInterface(Ci.nsIFile);
+      ok(false, `Leftover file ${entry.path} in download directory`);
+      entry.remove(false);
+    }
+
+    downloadDir.remove(false);
+  });
+}
+
+add_task(async function test_private_download() {
+  setup();
+
+  let extension = ExtensionTestUtils.loadExtension({
+    background: async function() {
+      function promiseEvent(eventTarget, accept) {
+        return new Promise(resolve => {
+          eventTarget.addListener(function listener(data) {
+            if (accept && !accept(data)) {
+              return;
+            }
+            eventTarget.removeListener(listener);
+            resolve(data);
+          });
+        });
+      }
+      let startTestPromise = promiseEvent(browser.test.onMessage);
+      let onCreatedPromise = promiseEvent(browser.downloads.onCreated);
+      let onDonePromise = promiseEvent(browser.downloads.onChanged,
+        delta => delta.state && delta.state.current === "complete");
+
+      browser.test.sendMessage("ready");
+      let {url, filename} = await startTestPromise;
+
+      browser.test.log("Starting private download");
+      let downloadId = await browser.downloads.download({
+        url,
+        filename,
+        incognito: true,
+      });
+
+      browser.test.log("Waiting for downloads.onCreated");
+      let createdItem = await onCreatedPromise;
+
+      browser.test.log("Waiting for completion notification");
+      await onDonePromise;
+
+      // test_ext_downloads_download.js already tests whether the file exists
+      // in the file system. Here we will only verify that the  downloads API
+      // behaves in a meaningful way.
+
+      let [downloadItem] = await browser.downloads.search({id: downloadId});
+      browser.test.assertEq(url, createdItem.url, "onCreated url should match");
+      browser.test.assertEq(url, downloadItem.url, "download url should match");
+      browser.test.assertTrue(createdItem.incognito,
+        "created download should be private");
+      browser.test.assertTrue(downloadItem.incognito,
+        "stored download should be private");
+
+      browser.test.log("Removing downloaded file");
+      browser.test.assertTrue(downloadItem.exists, "downloaded file exists");
+      await browser.downloads.removeFile(downloadId);
+
+      // Disabled because the assertion fails - https://bugzil.la/1381031
+      // let [downloadItem2] = await browser.downloads.search({id: downloadId});
+      // browser.test.assertFalse(downloadItem2.exists, "file should be deleted");
+
+      browser.test.log("Erasing private download from history");
+      let erasePromise = promiseEvent(browser.downloads.onErased);
+      await browser.downloads.erase({id: downloadId});
+      browser.test.assertEq(downloadId, await erasePromise,
+        "onErased should be fired for the erased private download");
+
+      browser.test.notifyPass("private download test done");
+    },
+    manifest: {
+      permissions: ["downloads"],
+    },
+  });
+
+  await extension.startup();
+  await extension.awaitMessage("ready");
+  extension.sendMessage({
+    url: TXT_URL,
+    filename: TXT_FILE,
+  });
+
+  await extension.awaitFinish("private download test done");
+  await extension.unload();
+});
--- a/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
+++ b/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
@@ -17,16 +17,18 @@ skip-if = os == "android"
 [test_ext_contextual_identities.js]
 skip-if = os == "android" # Containers are not exposed to android.
 [test_ext_debugging_utils.js]
 [test_ext_downloads.js]
 [test_ext_downloads_download.js]
 skip-if = os == "android"
 [test_ext_downloads_misc.js]
 skip-if = os == "android" || (os=='linux' && bits==32) # linux32: bug 1324870
+[test_ext_downloads_private.js]
+skip-if = os == "android"
 [test_ext_downloads_search.js]
 skip-if = os == "android"
 [test_ext_experiments.js]
 [test_ext_extension.js]
 [test_ext_extensionPreferencesManager.js]
 [test_ext_extensionSettingsStore.js]
 [test_ext_extension_content_telemetry.js]
 skip-if = os == "android" # checking for telemetry needs to be updated: 1384923