Bug 1363014 - Implement browsingData.remove WebExtension API method on android. r=sebastian, bsilverberg draft
authorTushar Saini (:shatur) <tushar.saini1285@gmail.com>
Wed, 30 Aug 2017 00:08:48 +0530
changeset 655256 4258af1f7ad3b0619ecd462eaf97664929f454c2
parent 655235 d814f791de3bba0fce843614b41ca9696ce57b15
child 728783 d17832d9d4656e0d3c1693613947e2361256a69c
push id76816
push userbmo:tushar.saini1285@gmail.com
push dateTue, 29 Aug 2017 19:54:56 +0000
reviewerssebastian, bsilverberg
bugs1363014
milestone57.0a1
Bug 1363014 - Implement browsingData.remove WebExtension API method on android. r=sebastian, bsilverberg MozReview-Commit-ID: 2ipz1wqGpxc
mobile/android/components/extensions/ext-browsingData.js
mobile/android/components/extensions/schemas/browsing_data.json
mobile/android/components/extensions/test/mochitest/test_ext_browsingData_cookies_cache.html
mobile/android/components/extensions/test/mochitest/test_ext_browsingData_downloads.html
mobile/android/components/extensions/test/mochitest/test_ext_browsingData_formdata.html
--- a/mobile/android/components/extensions/ext-browsingData.js
+++ b/mobile/android/components/extensions/ext-browsingData.js
@@ -6,23 +6,22 @@ Cu.import("resource://gre/modules/Task.j
 
 XPCOMUtils.defineLazyModuleGetter(this, "Sanitizer",
                                   "resource://gre/modules/Sanitizer.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SharedPreferences",
                                   "resource://gre/modules/SharedPreferences.jsm");
 
-let clearCookies = async function(options) {
-  if (options.originTypes &&
-      (options.originTypes.protectedWeb || options.originTypes.extension)) {
-    return Promise.reject(
-      {message: "Firefox does not support protectedWeb or extension as originTypes."});
-  }
+const clearCache = () => {
+  // Clearing the cache does not support timestamps.
+  return Sanitizer.clearItem("cache");
+};
 
+const clearCookies = async function(options) {
   let cookieMgr = Services.cookies;
   let yieldCounter = 0;
   const YIELD_PERIOD = 10;
 
   if (options.since) {
     // Convert it to microseconds
     let since =  options.since * 1000;
     // Iterate through the cookies and delete any created after our cutoff.
@@ -41,18 +40,63 @@ let clearCookies = async function(option
       }
     }
   } else {
     // Remove everything.
     cookieMgr.removeAll();
   }
 };
 
+const clearDownloads = options => {
+  return Sanitizer.clearItem("downloadHistory", options.since);
+};
+
+const clearFormData = options => {
+  return Sanitizer.clearItem("formdata", options.since);
+};
+
+const doRemoval = (options, dataToRemove, extension) => {
+  if (options.originTypes &&
+      (options.originTypes.protectedWeb || options.originTypes.extension)) {
+    return Promise.reject(
+      {message: "Firefox does not support protectedWeb or extension as originTypes."});
+  }
+
+  let removalPromises = [];
+  let invalidDataTypes = [];
+  for (let dataType in dataToRemove) {
+    if (dataToRemove[dataType]) {
+      switch (dataType) {
+        case "cache":
+          removalPromises.push(clearCache());
+          break;
+        case "cookies":
+          removalPromises.push(clearCookies(options));
+          break;
+        case "downloads":
+          removalPromises.push(clearDownloads(options));
+          break;
+        case "formData":
+          removalPromises.push(clearFormData(options));
+          break;
+        default:
+          invalidDataTypes.push(dataType);
+      }
+    }
+  }
+  if (extension && invalidDataTypes.length) {
+    extension.logger.warn(
+      `Firefox does not support dataTypes: ${invalidDataTypes.toString()}.`);
+  }
+  return Promise.all(removalPromises);
+};
+
 this.browsingData = class extends ExtensionAPI {
   getAPI(context) {
+    let {extension} = context;
     return {
       browsingData: {
         settings() {
           const PREF_DOMAIN = "android.not_a_preference.privacy.clear";
           const PREF_KEY_PREFIX = "private.data.";
           // The following prefs are the only ones in Firefox that match corresponding
           // values used by Chrome when returning settings.
           const PREF_LIST = ["cache", "history", "formdata", "cookies_sessions", "downloadFiles"];
@@ -83,24 +127,27 @@ this.browsingData = class extends Extens
             // Firefox doesn't have the same concept of dataRemovalPermitted
             // as Chrome, so it will always be true.
             dataRemovalPermitted[name] = true;
           }
           // We do not provide option to delete history by time
           // so, since value is given 0, which means Everything
           return Promise.resolve({options: {since: 0}, dataToRemove, dataRemovalPermitted});
         },
-        removeCookies(options) {
-          return clearCookies(options);
+        remove(options, dataToRemove) {
+          return doRemoval(options, dataToRemove, extension);
         },
         removeCache(options) {
-          return Sanitizer.clearItem("cache");
+          return doRemoval(options, {cache: true});
+        },
+        removeCookies(options) {
+          return doRemoval(options, {cookies: true});
         },
         removeDownloads(options) {
-          return Sanitizer.clearItem("downloadHistory", options.since);
+          return doRemoval(options, {downloads: true});
         },
         removeFormData(options) {
-          return Sanitizer.clearItem("formdata", options.since);
+          return doRemoval(options, {formData: true});
         },
       },
     };
   }
 };
--- a/mobile/android/components/extensions/schemas/browsing_data.json
+++ b/mobile/android/components/extensions/schemas/browsing_data.json
@@ -157,17 +157,16 @@
           }
         ]
       },
       {
         "name": "remove",
         "description": "Clears various types of browsing data stored in a user's profile.",
         "type": "function",
         "async": "callback",
-        "unsupported": true,
         "parameters": [
           {
             "$ref": "RemovalOptions",
             "name": "options"
           },
           {
             "name": "dataToRemove",
             "$ref": "DataTypeSet",
--- a/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_cookies_cache.html
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_cookies_cache.html
@@ -40,17 +40,21 @@ async function setUpCookies() {
 
   // Add a cookie which will end up with a more recent creationTime.
   addCookie(COOKIE);
 }
 
 add_task(async function testCookies() {
   function background() {
     browser.test.onMessage.addListener(async (msg, options) => {
-      await browser.browsingData.removeCookies(options);
+      if (msg == "removeCookies") {
+        await browser.browsingData.removeCookies(options);
+      } else {
+        await browser.browsingData.remove(options, {cookies: true});
+      }
       browser.test.sendMessage("cookiesRemoved");
     });
   }
 
   let extension = ExtensionTestUtils.loadExtension({
     background,
     manifest: {
       permissions: ["browsingData"],
@@ -84,25 +88,28 @@ add_task(async function testCookies() {
 
     ok(!Services.cookies.cookieExists(COOKIE), `Cookie ${COOKIE.name}  was removed.`);
     ok(!Services.cookies.cookieExists(oldCookie), `Cookie ${oldCookie.name}  was removed.`);
   }
 
   await extension.startup();
 
   await testRemovalMethod("removeCookies");
+  await testRemovalMethod("remove");
 
   await extension.unload();
 });
 
 add_task(async function testCache() {
   function background() {
     browser.test.onMessage.addListener(async msg => {
       if (msg == "removeCache") {
         await browser.browsingData.removeCache({});
+      } else {
+        await browser.browsingData.remove({}, {cache: true});
       }
       browser.test.sendMessage("cacheRemoved");
     });
   }
 
   let extension = ExtensionTestUtils.loadExtension({
     background,
     manifest: {
@@ -128,15 +135,16 @@ add_task(async function testCache() {
     extension.sendMessage(method);
     await awaitNotification;
     await extension.awaitMessage("cacheRemoved");
   }
 
   await extension.startup();
 
   await testRemovalMethod("removeCache");
+  await testRemovalMethod("remove");
 
   await extension.unload();
 });
 </script>
 
 </body>
 </html>
--- a/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_downloads.html
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_downloads.html
@@ -72,17 +72,21 @@ async function setupDownloads() {
   downloadsList = await Downloads.getList(Downloads.ALL);
   is((await downloadsList.getAll()).length, 4, "4 fake downloads added.");
   checkDownloads();
 }
 
 add_task(async function testDownloads() {
   function background() {
     browser.test.onMessage.addListener(async (msg, options) => {
-      await browser.browsingData.removeDownloads(options);
+      if (msg == "removeDownloads") {
+        await browser.browsingData.removeDownloads(options);
+      } else {
+        await browser.browsingData.remove(options, {downloads: true});
+      }
       browser.test.sendMessage("downloadsRemoved");
     });
   }
 
   let extension = ExtensionTestUtils.loadExtension({
     background,
     manifest: {
       permissions: ["browsingData"],
@@ -107,15 +111,16 @@ add_task(async function testDownloads() 
     extension.sendMessage(method, {since: REFERENCE_DATE - 100000});
     await extension.awaitMessage("downloadsRemoved");
     await checkDownloads(false, false);
   }
 
   await extension.startup();
 
   await testRemovalMethod("removeDownloads");
+  await testRemovalMethod("remove");
 
   await extension.unload();
 });
 
 </script>
 </body>
 </html>
--- a/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_formdata.html
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_formdata.html
@@ -89,17 +89,21 @@ async function setupFormHistory() {
   await countEntries("reference", "Checking for 10minutes form history entry creation", 1);
   await countEntries("10secondsAgo", "Checking for 1hour form history entry creation", 1);
   await countEntries("10minutesAgo", "Checking for 1hour10minutes form history entry creation", 1);
 }
 
 add_task(async function testFormData() {
   function background() {
     browser.test.onMessage.addListener(async (msg, options) => {
-      await browser.browsingData.removeFormData(options);
+      if (msg == "removeFormData") {
+        await browser.browsingData.removeFormData(options);
+      } else {
+        await browser.browsingData.remove(options, {formData: true});
+      }
       browser.test.sendMessage("formDataRemoved");
     });
   }
 
   let extension = ExtensionTestUtils.loadExtension({
     background,
     manifest: {
       permissions: ["browsingData"],
@@ -133,15 +137,16 @@ add_task(async function testFormData() {
     await countEntries("reference", "reference form entry should be deleted.", 0);
     await countEntries("10secondsAgo", "10secondsAgo form entry should be deleted.", 0);
     await countEntries("10minutesAgo", "10minutesAgo form entry should be deleted.", 0);
   }
 
   await extension.startup();
 
   await testRemovalMethod("removeFormData");
+  await testRemovalMethod("remove");
 
   await extension.unload();
 });
 
 </script>
 </body>
 </html>