Bug 1324760 - Expose a function that clears plugin data in sanitize.js, r?mak
MozReview-Commit-ID: A8AxhyzyEwk
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -273,89 +273,26 @@ Sanitizer.prototype = {
let mediaMgr = Components.classes["@mozilla.org/mediaManagerService;1"]
.getService(Ci.nsIMediaManagerService);
mediaMgr.sanitizeDeviceIds(range && range[0]);
} catch (ex) {
seenException = ex;
}
// Clear plugin data.
- // As evidenced in bug 1253204, clearing plugin data can sometimes be
- // very, very long, for mysterious reasons. Unfortunately, this is not
- // something actionable by Mozilla, so crashing here serves no purpose.
- //
- // For this reason, instead of waiting for sanitization to always
- // complete, we introduce a soft timeout. Once this timeout has
- // elapsed, we proceed with the shutdown of Firefox.
- let promiseClearPluginCookies;
try {
- // We don't want to wait for this operation to complete...
- promiseClearPluginCookies = this.promiseClearPluginCookies(range);
-
- // ... at least, not for more than 10 seconds.
- yield Promise.race([
- promiseClearPluginCookies,
- new Promise(resolve => setTimeout(resolve, 10000 /* 10 seconds */))
- ]);
+ yield Sanitizer.clearPluginData(range);
} catch (ex) {
seenException = ex;
}
- // Detach waiting for plugin cookies to be cleared.
- promiseClearPluginCookies.catch(() => {
- // If this exception is raised before the soft timeout, it
- // will appear in `seenException`. Otherwise, it's too late
- // to do anything about it.
- });
-
if (seenException) {
throw seenException;
}
}),
-
- promiseClearPluginCookies: Task.async(function* (range) {
- const FLAG_CLEAR_ALL = Ci.nsIPluginHost.FLAG_CLEAR_ALL;
- let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
-
- // Determine age range in seconds. (-1 means clear all.) We don't know
- // that range[1] is actually now, so we compute age range based
- // on the lower bound. If range results in a negative age, do nothing.
- let age = range ? (Date.now() / 1000 - range[0] / 1000000) : -1;
- if (!range || age >= 0) {
- let tags = ph.getPluginTags();
- for (let tag of tags) {
- let refObj = {};
- let probe = "";
- if (/\bFlash\b/.test(tag.name)) {
- probe = tag.loaded ? "FX_SANITIZE_LOADED_FLASH"
- : "FX_SANITIZE_UNLOADED_FLASH";
- TelemetryStopwatch.start(probe, refObj);
- }
- try {
- let rv = yield new Promise(resolve =>
- ph.clearSiteData(tag, null, FLAG_CLEAR_ALL, age, resolve)
- );
- // If the plugin doesn't support clearing by age, clear everything.
- if (rv == Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED) {
- yield new Promise(resolve =>
- ph.clearSiteData(tag, null, FLAG_CLEAR_ALL, -1, resolve)
- );
- }
- if (probe) {
- TelemetryStopwatch.finish(probe, refObj);
- }
- } catch (ex) {
- // Ignore errors from plug-ins
- if (probe) {
- TelemetryStopwatch.cancel(probe, refObj);
- }
- }
- }
- }
- })
},
offlineApps: {
clear: Task.async(function* (range) {
Components.utils.import("resource:///modules/offlineAppCache.jsm");
// This doesn't wait for the cleanup to be complete.
OfflineAppCacheHelper.clear();
})
@@ -700,16 +637,22 @@ Sanitizer.prototype = {
// Start the process of closing windows
while (windowList.length) {
windowList.pop().close();
}
newWindow.focus();
yield promiseReady;
})
},
+
+ pluginData: {
+ clear: Task.async(function* (range) {
+ yield Sanitizer.clearPluginData(range);
+ }),
+ },
}
};
// The preferences branch for the sanitizer.
Sanitizer.PREF_DOMAIN = "privacy.sanitize.";
// Whether we should sanitize on shutdown.
Sanitizer.PREF_SANITIZE_ON_SHUTDOWN = "privacy.sanitize.sanitizeOnShutdown";
// During a sanitization this is set to a json containing the array of items
@@ -769,16 +712,93 @@ Sanitizer.getClearRange = function(ts) {
startDate = endDate - 86400000000; // 24*60*60*1000000
break;
default:
throw "Invalid time span for clear private data: " + ts;
}
return [startDate, endDate];
};
+Sanitizer.clearPluginData = Task.async(function* (range) {
+ // Clear plugin data.
+ // As evidenced in bug 1253204, clearing plugin data can sometimes be
+ // very, very long, for mysterious reasons. Unfortunately, this is not
+ // something actionable by Mozilla, so crashing here serves no purpose.
+ //
+ // For this reason, instead of waiting for sanitization to always
+ // complete, we introduce a soft timeout. Once this timeout has
+ // elapsed, we proceed with the shutdown of Firefox.
+ let seenException;
+
+ let promiseClearPluginData = Task.async(function* () {
+ const FLAG_CLEAR_ALL = Ci.nsIPluginHost.FLAG_CLEAR_ALL;
+ let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+
+ // Determine age range in seconds. (-1 means clear all.) We don't know
+ // that range[1] is actually now, so we compute age range based
+ // on the lower bound. If range results in a negative age, do nothing.
+ let age = range ? (Date.now() / 1000 - range[0] / 1000000) : -1;
+ if (!range || age >= 0) {
+ let tags = ph.getPluginTags();
+ for (let tag of tags) {
+ let refObj = {};
+ let probe = "";
+ if (/\bFlash\b/.test(tag.name)) {
+ probe = tag.loaded ? "FX_SANITIZE_LOADED_FLASH"
+ : "FX_SANITIZE_UNLOADED_FLASH";
+ TelemetryStopwatch.start(probe, refObj);
+ }
+ try {
+ let rv = yield new Promise(resolve =>
+ ph.clearSiteData(tag, null, FLAG_CLEAR_ALL, age, resolve)
+ );
+ // If the plugin doesn't support clearing by age, clear everything.
+ if (rv == Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED) {
+ yield new Promise(resolve =>
+ ph.clearSiteData(tag, null, FLAG_CLEAR_ALL, -1, resolve)
+ );
+ }
+ if (probe) {
+ TelemetryStopwatch.finish(probe, refObj);
+ }
+ } catch (ex) {
+ // Ignore errors from plug-ins
+ if (probe) {
+ TelemetryStopwatch.cancel(probe, refObj);
+ }
+ }
+ }
+ }
+ });
+
+ try {
+ // We don't want to wait for this operation to complete...
+ promiseClearPluginData = promiseClearPluginData(range);
+
+ // ... at least, not for more than 10 seconds.
+ yield Promise.race([
+ promiseClearPluginData,
+ new Promise(resolve => setTimeout(resolve, 10000 /* 10 seconds */))
+ ]);
+ } catch (ex) {
+ seenException = ex;
+ }
+
+ // Detach waiting for plugin data to be cleared.
+ promiseClearPluginData.catch(() => {
+ // If this exception is raised before the soft timeout, it
+ // will appear in `seenException`. Otherwise, it's too late
+ // to do anything about it.
+ });
+
+ if (seenException) {
+ throw seenException;
+ }
+});
+
Sanitizer._prefs = null;
Sanitizer.__defineGetter__("prefs", function()
{
return Sanitizer._prefs ? Sanitizer._prefs
: Sanitizer._prefs = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService)
.getBranch(Sanitizer.PREF_DOMAIN);
});
--- a/browser/base/content/test/plugins/browser_clearplugindata.js
+++ b/browser/base/content/test/plugins/browser_clearplugindata.js
@@ -41,87 +41,79 @@ add_task(function* () {
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
if (gTestBrowser) {
gBrowser.removeCurrentTab();
}
window.focus();
gTestBrowser = null;
});
-});
-add_task(function* () {
Services.prefs.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+});
+function* setPrefs(cookies, pluginData) {
sanitizer = new Sanitizer();
sanitizer.ignoreTimespan = false;
sanitizer.prefDomain = "privacy.cpd.";
let itemPrefs = gPrefService.getBranch(sanitizer.prefDomain);
itemPrefs.setBoolPref("history", false);
itemPrefs.setBoolPref("downloads", false);
itemPrefs.setBoolPref("cache", false);
- itemPrefs.setBoolPref("cookies", true); // plugin data
+ itemPrefs.setBoolPref("cookies", cookies);
itemPrefs.setBoolPref("formdata", false);
itemPrefs.setBoolPref("offlineApps", false);
itemPrefs.setBoolPref("passwords", false);
itemPrefs.setBoolPref("sessions", false);
itemPrefs.setBoolPref("siteSettings", false);
-});
+ itemPrefs.setBoolPref("pluginData", pluginData);
+}
-add_task(function* () {
+function* testClearingData(url) {
// Load page to set data for the plugin.
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
- yield promiseTabLoadEvent(gBrowser.selectedTab, testURL1);
+ yield promiseTabLoadEvent(gBrowser.selectedTab, url);
yield promiseUpdatePluginBindings(gTestBrowser);
ok(stored(["foo.com", "bar.com", "baz.com", "qux.com"]),
"Data stored for sites");
- // Clear 20 seconds ago
- let now_uSec = Date.now() * 1000;
- sanitizer.range = [now_uSec - 20 * 1000000, now_uSec];
- yield sanitizer.sanitize();
-
- ok(stored(["bar.com", "qux.com"]), "Data stored for sites");
- ok(!stored(["foo.com"]), "Data cleared for foo.com");
- ok(!stored(["baz.com"]), "Data cleared for baz.com");
-
- // Clear everything
- sanitizer.range = null;
- yield sanitizer.sanitize();
-
- ok(!stored(null), "All data cleared");
-
- gBrowser.removeCurrentTab();
- gTestBrowser = null;
-});
-
-add_task(function* () {
- // Load page to set data for the plugin.
- gBrowser.selectedTab = gBrowser.addTab();
- gTestBrowser = gBrowser.selectedBrowser;
-
- yield promiseTabLoadEvent(gBrowser.selectedTab, testURL2);
-
- yield promiseUpdatePluginBindings(gTestBrowser);
-
- ok(stored(["foo.com", "bar.com", "baz.com", "qux.com"]),
- "Data stored for sites");
-
- // Attempt to clear 20 seconds ago. The plugin will throw
+ // Clear 20 seconds ago.
+ // In the case of testURL2 the plugin will throw
// NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED, which should result in us
// clearing all data regardless of age.
let now_uSec = Date.now() * 1000;
sanitizer.range = [now_uSec - 20 * 1000000, now_uSec];
yield sanitizer.sanitize();
+ if (url == testURL1) {
+ ok(stored(["bar.com", "qux.com"]), "Data stored for sites");
+ ok(!stored(["foo.com"]), "Data cleared for foo.com");
+ ok(!stored(["baz.com"]), "Data cleared for baz.com");
+
+ // Clear everything.
+ sanitizer.range = null;
+ yield sanitizer.sanitize();
+ }
+
ok(!stored(null), "All data cleared");
gBrowser.removeCurrentTab();
gTestBrowser = null;
+}
+
+add_task(function* () {
+ // Test when santizing cookies.
+ yield setPrefs(true, false);
+ yield testClearingData(testURL1);
+ yield testClearingData(testURL2);
+
+ // Test when santizing pluginData.
+ yield setPrefs(false, true);
+ yield testClearingData(testURL1);
+ yield testClearingData(testURL2);
});
-