Bug 1501688 - Temporary files generated by opening external files with content:// scheme should be sanitized. r=JanH, a=RyanVM
authorAndrei Lazar <andrei.a.lazar@softvision.ro>
Mon, 10 Dec 2018 18:46:32 +0200
changeset 506169 e2336587275ff698b85165c571fbd6bedd77109c
parent 506168 66f0ce8d3d6411977362f1c7f5dbf7615f394dea
child 506170 a4803c65849c00df7b2b094ed2246ff5aaf666b8
push id10318
push userryanvm@gmail.com
push dateTue, 11 Dec 2018 21:26:22 +0000
treeherdermozilla-beta@318239ee898f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersJanH, RyanVM
bugs1501688
milestone65.0
Bug 1501688 - Temporary files generated by opening external files with content:// scheme should be sanitized. r=JanH, a=RyanVM Implemented cache sanitizing for files generated by handling the content:// scheme. Differential Revision: https://phabricator.services.mozilla.com/D11779
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
mobile/android/modules/Sanitizer.jsm
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -144,16 +144,17 @@ import org.mozilla.gecko.toolbar.Browser
 import org.mozilla.gecko.toolbar.PwaConfirm;
 import org.mozilla.gecko.trackingprotection.TrackingProtectionPrompt;
 import org.mozilla.gecko.updater.PostUpdateHandler;
 import org.mozilla.gecko.updater.UpdateServiceHelper;
 import org.mozilla.gecko.util.ActivityUtils;
 import org.mozilla.gecko.util.ContextUtils;
 import org.mozilla.gecko.util.DrawableUtil;
 import org.mozilla.gecko.util.EventCallback;
+import org.mozilla.gecko.util.FileUtils;
 import org.mozilla.gecko.util.GamepadUtils;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.IntentUtils;
 import org.mozilla.gecko.util.MenuUtils;
 import org.mozilla.gecko.util.PrefUtils;
 import org.mozilla.gecko.util.ShortcutUtils;
 import org.mozilla.gecko.util.StrictModeContext;
@@ -780,16 +781,17 @@ public class BrowserApp extends GeckoApp
         EventDispatcher.getInstance().registerBackgroundThreadListener(this,
             "Experiments:GetActive",
             "Experiments:SetOverride",
             "Experiments:ClearOverride",
             "Favicon:Request",
             "Feedback:MaybeLater",
             "Sanitize:ClearHistory",
             "Sanitize:ClearSyncedTabs",
+            "Sanitize:Cache",
             "Telemetry:Gather",
             "Download:AndroidDownloadManager",
             "Website:AppInstalled",
             "Website:AppInstallFailed",
             "Website:Metadata",
             null);
 
         getAppEventDispatcher().registerUiThreadListener(this, "Prompt:ShowTop");
@@ -1515,16 +1517,17 @@ public class BrowserApp extends GeckoApp
         EventDispatcher.getInstance().unregisterBackgroundThreadListener(this,
             "Experiments:GetActive",
             "Experiments:SetOverride",
             "Experiments:ClearOverride",
             "Favicon:Request",
             "Feedback:MaybeLater",
             "Sanitize:ClearHistory",
             "Sanitize:ClearSyncedTabs",
+            "Sanitize:Cache",
             "Telemetry:Gather",
             "Download:AndroidDownloadManager",
             "Website:AppInstalled",
             "Website:AppInstallFailed",
             "Website:Metadata",
             null);
 
         getAppEventDispatcher().unregisterUiThreadListener(this, "Prompt:ShowTop");
@@ -1885,16 +1888,28 @@ public class BrowserApp extends GeckoApp
                 break;
 
             case "Sanitize:ClearHistory":
                 BrowserDB.from(getProfile()).clearHistory(
                         getContentResolver(), message.getBoolean("clearSearchHistory", false));
                 callback.sendSuccess(null);
                 break;
 
+            case "Sanitize:Cache":
+                final File cacheFolder = new File(getCacheDir(), FileUtils.CONTENT_TEMP_DIRECTORY);
+                // file.delete() throws an exception if the path does not exists
+                // e.g you can get in this scenario after two cache clearing in a row
+                if (cacheFolder.exists()) {
+                    FileUtils.delTree(cacheFolder, null, true);
+                    // now we can delete the folder
+                    cacheFolder.delete();
+                }
+                callback.sendSuccess(null);
+                break;
+
             case "Sanitize:ClearSyncedTabs":
                 FennecTabsRepository.deleteNonLocalClientsAndTabs(this);
                 callback.sendSuccess(null);
                 break;
 
             case "Settings:Show":
                 final Intent settingsIntent = new Intent(this, GeckoPreferences.class);
                 final String resource = message.getString(GeckoPreferences.INTENT_EXTRA_RESOURCES);
--- a/mobile/android/modules/Sanitizer.jsm
+++ b/mobile/android/modules/Sanitizer.jsm
@@ -76,36 +76,41 @@ Sanitizer.prototype = {
   // (browser/modules/Sanitzer.jsm), however over the course of time some
   // general differences have evolved:
   // - async shutdown (and seenException handling) isn't implemented in Fennec
   // - currently there is only limited support for range-based clearing of data
 
   // Any further specific differences caused by architectural differences between
   // Fennec and desktop Firefox are documented below for each item.
   items: {
-    // Same as desktop Firefox.
+    // The difference is specifically the Sanitize:Cache message,
+    // so that the Android front-end can clear its caches as well,
+    // while everything else is unchanged.
     cache: {
       clear: function() {
-        return new Promise(function(resolve, reject) {
-          let refObj = {};
-          TelemetryStopwatch.start("FX_SANITIZE_CACHE", refObj);
+        let refObj = {};
+        TelemetryStopwatch.start("FX_SANITIZE_CACHE", refObj);
 
-          try {
-            Services.cache2.clear();
-          } catch (er) {}
+        try {
+          Services.cache2.clear();
+        } catch (er) {}
 
-          let imageCache = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
+        let imageCache = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
                                                            .getImgCacheForDocument(null);
-          try {
-            imageCache.clearCache(false); // true=chrome, false=content
-          } catch (er) {}
+        try {
+          imageCache.clearCache(false); // true=chrome, false=content
+        } catch (er) {}
 
-          TelemetryStopwatch.finish("FX_SANITIZE_CACHE", refObj);
-          resolve();
-        });
+        return EventDispatcher.instance.sendRequestForResult({ type: "Sanitize:Cache" })
+          .catch((err) => {
+            Cu.reportError(`Java-side cache clearing failed with error: ${err}`);
+          })
+          .then(() => {
+            TelemetryStopwatch.finish("FX_SANITIZE_CACHE", refObj);
+          });
       },
 
       get canClear() {
         return true;
       },
     },
 
     // Compared to desktop, we don't clear plugin data, as plugins