Bug 1255576 - Propagate privacy status for removed content preferences to observers. r=adw, a=ritu

This commit is contained in:
Josh Matthews 2016-04-04 15:25:58 -04:00
parent a52202886b
commit bcafe812fb
8 changed files with 158 additions and 108 deletions

View File

@ -115,8 +115,8 @@ var FullZoom = {
this._onContentPrefChanged(aGroup, aValue, aIsPrivate);
},
onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName) {
this._onContentPrefChanged(aGroup, undefined);
onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName, aIsPrivate) {
this._onContentPrefChanged(aGroup, undefined, aIsPrivate);
},
/**

View File

@ -34,8 +34,12 @@ interface nsIContentPrefObserver : nsISupports
* @param aGroup the group to which the pref belongs, or null
* if it's a global pref (applies to all sites)
* @param aName the name of the pref that was removed
* @param aIsPrivate an optional flag determining whether the
* original context is private or not
*/
void onContentPrefRemoved(in AString aGroup, in AString aName);
void onContentPrefRemoved(in AString aGroup,
in AString aName,
[optional] in boolean aIsPrivate);
};
[scriptable, function, uuid(c1b3d6df-5373-4606-8494-8bcf14a7fc62)]

View File

@ -386,6 +386,7 @@ ContentPrefService2.prototype = {
let prefs = new ContentPrefStore();
let isPrivate = context && context.usePrivateBrowsing;
this._execStmts(stmts, {
onRow: function onRow(row) {
let grp = row.getResultByName("grp");
@ -395,7 +396,7 @@ ContentPrefService2.prototype = {
onDone: function onDone(reason, ok) {
if (ok) {
this._cache.set(group, name, undefined);
if (context && context.usePrivateBrowsing) {
if (isPrivate) {
for (let [sgroup, ] of
this._pbStore.match(group, name, includeSubdomains)) {
prefs.set(sgroup, name, undefined);
@ -406,7 +407,7 @@ ContentPrefService2.prototype = {
cbHandleCompletion(callback, reason);
if (ok) {
for (let [sgroup, , ] of prefs) {
this._cps._notifyPrefRemoved(sgroup, name);
this._cps._notifyPrefRemoved(sgroup, name, isPrivate);
}
}
},
@ -498,6 +499,7 @@ ContentPrefService2.prototype = {
let prefs = new ContentPrefStore();
let isPrivate = context && context.usePrivateBrowsing;
this._execStmts(stmts, {
onRow: function onRow(row) {
let grp = row.getResultByName("grp");
@ -506,16 +508,20 @@ ContentPrefService2.prototype = {
this._cache.set(grp, name, undefined);
},
onDone: function onDone(reason, ok) {
if (ok && context && context.usePrivateBrowsing) {
if (ok && isPrivate) {
for (let [sgroup, sname, ] of this._pbStore) {
prefs.set(sgroup, sname, undefined);
this._pbStore.remove(sgroup, sname);
if (!group ||
(!includeSubdomains && group == sgroup) ||
(includeSubdomains && sgroup && this._pbStore.groupsMatchIncludingSubdomains(group, sgroup))) {
prefs.set(sgroup, sname, undefined);
this._pbStore.remove(sgroup, sname);
}
}
}
cbHandleCompletion(callback, reason);
if (ok) {
for (let [sgroup, sname, ] of prefs) {
this._cps._notifyPrefRemoved(sgroup, sname);
this._cps._notifyPrefRemoved(sgroup, sname, isPrivate);
}
}
},
@ -559,6 +565,7 @@ ContentPrefService2.prototype = {
stmts = stmts.concat(this._settingsAndGroupsCleanupStmts());
let prefs = new ContentPrefStore();
let isPrivate = context && context.usePrivateBrowsing;
this._execStmts(stmts, {
onRow: function onRow(row) {
let grp = row.getResultByName("grp");
@ -569,16 +576,18 @@ ContentPrefService2.prototype = {
onDone: function onDone(reason, ok) {
// This nukes all the groups in _pbStore since we don't have their timestamp
// information.
if (ok && context && context.usePrivateBrowsing) {
if (ok && isPrivate) {
for (let [sgroup, sname, ] of this._pbStore) {
prefs.set(sgroup, sname, undefined);
if (sgroup) {
prefs.set(sgroup, sname, undefined);
}
}
this._pbStore.removeAllGroups();
}
cbHandleCompletion(callback, reason);
if (ok) {
for (let [sgroup, sname, ] of prefs) {
this._cps._notifyPrefRemoved(sgroup, sname);
this._cps._notifyPrefRemoved(sgroup, sname, isPrivate);
}
}
},
@ -647,6 +656,7 @@ ContentPrefService2.prototype = {
`));
let prefs = new ContentPrefStore();
let isPrivate = context && context.usePrivateBrowsing;
this._execStmts(stmts, {
onRow: function onRow(row) {
@ -655,7 +665,7 @@ ContentPrefService2.prototype = {
this._cache.set(grp, name, undefined);
},
onDone: function onDone(reason, ok) {
if (ok && context && context.usePrivateBrowsing) {
if (ok && isPrivate) {
for (let [sgroup, sname, ] of this._pbStore) {
if (sname === name) {
prefs.set(sgroup, name, undefined);
@ -666,7 +676,7 @@ ContentPrefService2.prototype = {
cbHandleCompletion(callback, reason);
if (ok) {
for (let [sgroup, , ] of prefs) {
this._cps._notifyPrefRemoved(sgroup, name);
this._cps._notifyPrefRemoved(sgroup, name, isPrivate);
}
}
},

View File

@ -77,6 +77,12 @@ ContentPrefStore.prototype = {
this._globalNames.clear();
},
groupsMatchIncludingSubdomains: function CPS_groupsMatchIncludingSubdomains(group, group2) {
let idx = group2.indexOf(group);
return (idx == group2.length - group.length &&
(idx == 0 || group2[idx - 1] == "."));
},
* [Symbol.iterator]() {
for (let [group, names] of this._groups) {
for (let [name, val] of names) {
@ -100,10 +106,9 @@ ContentPrefStore.prototype = {
if (includeSubdomains) {
for (let [sgroup, , ] of this) {
if (sgroup) {
let idx = sgroup.indexOf(group);
if (idx == sgroup.length - group.length &&
(idx == 0 || sgroup[idx - 1] == "."))
if (this.groupsMatchIncludingSubdomains(group, sgroup)) {
yield sgroup;
}
}
}
}

View File

@ -314,7 +314,7 @@ ContentPrefService.prototype = {
if (aContext && aContext.usePrivateBrowsing) {
this._privModeStorage.remove(group, aName);
this._notifyPrefRemoved(group, aName);
this._notifyPrefRemoved(group, aName, true);
return;
}
@ -337,7 +337,7 @@ ContentPrefService.prototype = {
this._deleteGroupIfUnused(groupID);
this._cache.remove(group, aName);
this._notifyPrefRemoved(group, aName);
this._notifyPrefRemoved(group, aName, false);
},
removeGroupedPrefs: function ContentPrefService_removeGroupedPrefs(aContext) {
@ -376,7 +376,7 @@ ContentPrefService.prototype = {
for (let [group, name, ] of this._privModeStorage) {
if (name === aName) {
this._privModeStorage.remove(group, aName);
this._notifyPrefRemoved(group, aName);
this._notifyPrefRemoved(group, aName, true);
}
}
}
@ -418,7 +418,7 @@ ContentPrefService.prototype = {
if (groupNames[i]) // ie. not null, which will be last (and i == groupIDs.length)
this._deleteGroupIfUnused(groupIDs[i]);
if (!aContext || !aContext.usePrivateBrowsing) {
this._notifyPrefRemoved(groupNames[i], aName);
this._notifyPrefRemoved(groupNames[i], aName, false);
}
}
},
@ -526,10 +526,10 @@ ContentPrefService.prototype = {
/**
* Notify all observers about the removal of a preference.
*/
_notifyPrefRemoved: function ContentPrefService__notifyPrefRemoved(aGroup, aName) {
_notifyPrefRemoved: function ContentPrefService__notifyPrefRemoved(aGroup, aName, aIsPrivate) {
for (var observer of this._getObservers(aName)) {
try {
observer.onContentPrefRemoved(aGroup, aName);
observer.onContentPrefRemoved(aGroup, aName, aIsPrivate);
}
catch(ex) {
Cu.reportError(ex);

View File

@ -284,9 +284,13 @@ function run_test() {
},
numTimesRemovedCalled: 0,
onContentPrefRemoved: function genericObserver_onContentPrefRemoved(group, name) {
onContentPrefRemoved: function genericObserver_onContentPrefRemoved(group, name, isPrivate) {
++this.numTimesRemovedCalled;
do_check_eq(group, "www.example.com");
if (name == "test.observer.private")
do_check_true(isPrivate);
else if (name == "test.observer.normal")
do_check_false(isPrivate);
if (name != "test.observer.1" && name != "test.observer.2" &&
name != "test.observer.normal" && name != "test.observer.private") {
do_throw("genericObserver.onContentPrefSet: " +

View File

@ -2,149 +2,128 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
let global = this;
function run_test() {
runAsyncTests(tests);
var allTests = [];
for (var i = 0; i < tests.length; i++) {
// Generate two wrappers of each test function that invoke the original test with an
// appropriate privacy context.
var pub = eval('var f = function* ' + tests[i].name + '() { yield tests[' + i + ']({ usePrivateBrowsing: false }); }; f');
var priv = eval('var f = function* ' + tests[i].name + '_private() { yield tests[' + i + ']({ usePrivateBrowsing: true }); }; f');
allTests.push(pub);
allTests.push(priv);
}
allTests = allTests.concat(specialTests);
runAsyncTests(allTests);
}
var tests = [
function* observerForName_set() {
yield set("a.com", "foo", 1);
function* observerForName_set(context) {
yield set("a.com", "foo", 1, context);
let args = yield on("Set", ["foo", null, "bar"]);
observerArgsOK(args.foo, [["a.com", "foo", 1, false]]);
observerArgsOK(args.null, [["a.com", "foo", 1, false]]);
observerArgsOK(args.foo, [["a.com", "foo", 1, context.usePrivateBrowsing]]);
observerArgsOK(args.null, [["a.com", "foo", 1, context.usePrivateBrowsing]]);
observerArgsOK(args.bar, []);
yield setGlobal("foo", 2);
yield setGlobal("foo", 2, context);
args = yield on("Set", ["foo", null, "bar"]);
observerArgsOK(args.foo, [[null, "foo", 2, false]]);
observerArgsOK(args.null, [[null, "foo", 2, false]]);
observerArgsOK(args.foo, [[null, "foo", 2, context.usePrivateBrowsing]]);
observerArgsOK(args.null, [[null, "foo", 2, context.usePrivateBrowsing]]);
observerArgsOK(args.bar, []);
},
function* observerForName_set_private() {
yield set("a.com", "foo", 1, { usePrivateBrowsing: true });
let args = yield on("Set", ["foo", null, "bar"]);
observerArgsOK(args.foo, [["a.com", "foo", 1, true]]);
observerArgsOK(args.null, [["a.com", "foo", 1, true]]);
observerArgsOK(args.bar, []);
function* observerForName_remove(context) {
yield set("a.com", "foo", 1, context);
yield setGlobal("foo", 2, context);
yield setGlobal("foo", 2, { usePrivateBrowsing: true });
args = yield on("Set", ["foo", null, "bar"]);
observerArgsOK(args.foo, [[null, "foo", 2, true]]);
observerArgsOK(args.null, [[null, "foo", 2, true]]);
observerArgsOK(args.bar, []);
},
function* observerForName_remove() {
yield set("a.com", "foo", 1);
yield setGlobal("foo", 2);
yield cps.removeByDomainAndName("a.com", "bogus", null, makeCallback());
yield cps.removeByDomainAndName("a.com", "bogus", context, makeCallback());
let args = yield on("Removed", ["foo", null, "bar"]);
observerArgsOK(args.foo, []);
observerArgsOK(args.null, []);
observerArgsOK(args.bar, []);
yield cps.removeByDomainAndName("a.com", "foo", null, makeCallback());
yield cps.removeByDomainAndName("a.com", "foo", context, makeCallback());
args = yield on("Removed", ["foo", null, "bar"]);
observerArgsOK(args.foo, [["a.com", "foo"]]);
observerArgsOK(args.null, [["a.com", "foo"]]);
observerArgsOK(args.foo, [["a.com", "foo", context.usePrivateBrowsing]]);
observerArgsOK(args.null, [["a.com", "foo", context.usePrivateBrowsing]]);
observerArgsOK(args.bar, []);
yield cps.removeGlobal("foo", null, makeCallback());
yield cps.removeGlobal("foo", context, makeCallback());
args = yield on("Removed", ["foo", null, "bar"]);
observerArgsOK(args.foo, [[null, "foo"]]);
observerArgsOK(args.null, [[null, "foo"]]);
observerArgsOK(args.foo, [[null, "foo", context.usePrivateBrowsing]]);
observerArgsOK(args.null, [[null, "foo", context.usePrivateBrowsing]]);
observerArgsOK(args.bar, []);
},
function* observerForName_removeByDomain() {
yield set("a.com", "foo", 1);
yield set("b.a.com", "bar", 2);
yield setGlobal("foo", 3);
function* observerForName_removeByDomain(context) {
yield set("a.com", "foo", 1, context);
yield set("b.a.com", "bar", 2, context);
yield setGlobal("foo", 3, context);
yield cps.removeByDomain("bogus", null, makeCallback());
yield cps.removeByDomain("bogus", context, makeCallback());
let args = yield on("Removed", ["foo", null, "bar"]);
observerArgsOK(args.foo, []);
observerArgsOK(args.null, []);
observerArgsOK(args.bar, []);
yield cps.removeBySubdomain("a.com", null, makeCallback());
yield cps.removeBySubdomain("a.com", context, makeCallback());
args = yield on("Removed", ["foo", null, "bar"]);
observerArgsOK(args.foo, [["a.com", "foo"]]);
observerArgsOK(args.null, [["a.com", "foo"], ["b.a.com", "bar"]]);
observerArgsOK(args.bar, [["b.a.com", "bar"]]);
observerArgsOK(args.foo, [["a.com", "foo", context.usePrivateBrowsing]]);
observerArgsOK(args.null, [["a.com", "foo", context.usePrivateBrowsing], ["b.a.com", "bar", context.usePrivateBrowsing]]);
observerArgsOK(args.bar, [["b.a.com", "bar", context.usePrivateBrowsing]]);
yield cps.removeAllGlobals(null, makeCallback());
yield cps.removeAllGlobals(context, makeCallback());
args = yield on("Removed", ["foo", null, "bar"]);
observerArgsOK(args.foo, [[null, "foo"]]);
observerArgsOK(args.null, [[null, "foo"]]);
observerArgsOK(args.foo, [[null, "foo", context.usePrivateBrowsing]]);
observerArgsOK(args.null, [[null, "foo", context.usePrivateBrowsing]]);
observerArgsOK(args.bar, []);
},
function* observerForName_removeAllDomainsSince() {
yield setWithDate("a.com", "foo", 1, 100);
yield setWithDate("b.com", "foo", 2, 200);
yield setWithDate("c.com", "foo", 3, 300);
function* observerForName_removeAllDomains(context) {
yield set("a.com", "foo", 1, context);
yield setGlobal("foo", 2, context);
yield set("b.com", "bar", 3, context);
yield setWithDate("a.com", "bar", 1, 0);
yield setWithDate("b.com", "bar", 2, 100);
yield setWithDate("c.com", "bar", 3, 200);
yield setGlobal("foo", 2);
yield cps.removeAllDomainsSince(200, null, makeCallback());
let args = yield on("Removed", ["foo", "bar", null]);
observerArgsOK(args.foo, [["b.com", "foo"], ["c.com", "foo"]]);
observerArgsOK(args.bar, [["c.com", "bar"]]);
observerArgsOK(args.null, [["b.com", "foo"], ["c.com", "bar"], ["c.com", "foo"]]);
},
function* observerForName_removeAllDomains() {
yield set("a.com", "foo", 1);
yield setGlobal("foo", 2);
yield set("b.com", "bar", 3);
yield cps.removeAllDomains(null, makeCallback());
yield cps.removeAllDomains(context, makeCallback());
let args = yield on("Removed", ["foo", null, "bar"]);
observerArgsOK(args.foo, [["a.com", "foo"]]);
observerArgsOK(args.null, [["a.com", "foo"], ["b.com", "bar"]]);
observerArgsOK(args.bar, [["b.com", "bar"]]);
observerArgsOK(args.foo, [["a.com", "foo", context.usePrivateBrowsing]]);
observerArgsOK(args.null, [["a.com", "foo", context.usePrivateBrowsing], ["b.com", "bar", context.usePrivateBrowsing]]);
observerArgsOK(args.bar, [["b.com", "bar", context.usePrivateBrowsing]]);
},
function* observerForName_removeByName() {
yield set("a.com", "foo", 1);
yield set("a.com", "bar", 2);
yield setGlobal("foo", 3);
function* observerForName_removeByName(context) {
yield set("a.com", "foo", 1, context);
yield set("a.com", "bar", 2, context);
yield setGlobal("foo", 3, context);
yield cps.removeByName("bogus", null, makeCallback());
yield cps.removeByName("bogus", context, makeCallback());
let args = yield on("Removed", ["foo", null, "bar"]);
observerArgsOK(args.foo, []);
observerArgsOK(args.null, []);
observerArgsOK(args.bar, []);
yield cps.removeByName("foo", null, makeCallback());
yield cps.removeByName("foo", context, makeCallback());
args = yield on("Removed", ["foo", null, "bar"]);
observerArgsOK(args.foo, [["a.com", "foo"], [null, "foo"]]);
observerArgsOK(args.null, [["a.com", "foo"], [null, "foo"]]);
observerArgsOK(args.foo, [["a.com", "foo", context.usePrivateBrowsing], [null, "foo", context.usePrivateBrowsing]]);
observerArgsOK(args.null, [["a.com", "foo", context.usePrivateBrowsing], [null, "foo", context.usePrivateBrowsing]]);
observerArgsOK(args.bar, []);
},
function* removeObserverForName() {
function* removeObserverForName(context) {
let args = yield on("Set", ["foo", null, "bar"], true);
cps.removeObserverForName("foo", args.foo.observer);
yield set("a.com", "foo", 1);
yield set("a.com", "foo", 1, context);
yield wait();
observerArgsOK(args.foo, []);
observerArgsOK(args.null, [["a.com", "foo", 1, false]]);
observerArgsOK(args.null, [["a.com", "foo", 1, context.usePrivateBrowsing]]);
observerArgsOK(args.bar, []);
args.reset();
cps.removeObserverForName(null, args.null.observer);
yield set("a.com", "foo", 2);
yield set("a.com", "foo", 2, context);
yield wait();
observerArgsOK(args.foo, []);
observerArgsOK(args.null, []);
@ -152,3 +131,48 @@ var tests = [
args.reset();
},
];
// These tests are for functionality that doesn't behave the same way in private and public
// contexts, so the expected results cannot be automatically generated like the previous tests.
var specialTests = [
function* observerForName_removeAllDomainsSince() {
yield setWithDate("a.com", "foo", 1, 100, null);
yield setWithDate("b.com", "foo", 2, 200, null);
yield setWithDate("c.com", "foo", 3, 300, null);
yield setWithDate("a.com", "bar", 1, 0, null);
yield setWithDate("b.com", "bar", 2, 100, null);
yield setWithDate("c.com", "bar", 3, 200, null);
yield setGlobal("foo", 2, null);
yield cps.removeAllDomainsSince(200, null, makeCallback());
let args = yield on("Removed", ["foo", "bar", null]);
observerArgsOK(args.foo, [["b.com", "foo", false], ["c.com", "foo", false]]);
observerArgsOK(args.bar, [["c.com", "bar", false]]);
observerArgsOK(args.null, [["b.com", "foo", false], ["c.com", "bar", false], ["c.com", "foo", false]]);
},
function* observerForName_removeAllDomainsSince_private() {
let context = {usePrivateBrowsing: true};
yield setWithDate("a.com", "foo", 1, 100, context);
yield setWithDate("b.com", "foo", 2, 200, context);
yield setWithDate("c.com", "foo", 3, 300, context);
yield setWithDate("a.com", "bar", 1, 0, context);
yield setWithDate("b.com", "bar", 2, 100, context);
yield setWithDate("c.com", "bar", 3, 200, context);
yield setGlobal("foo", 2, context);
yield cps.removeAllDomainsSince(200, context, makeCallback());
let args = yield on("Removed", ["foo", "bar", null]);
observerArgsOK(args.foo, [["a.com", "foo", true], ["b.com", "foo", true], ["c.com", "foo", true]]);
observerArgsOK(args.bar, [["a.com", "bar", true], ["b.com", "bar", true], ["c.com", "bar", true]]);
observerArgsOK(args.null, [["a.com", "foo", true], ["a.com", "bar", true],
["b.com", "foo", true], ["b.com", "bar", true],
["c.com", "foo", true], ["c.com", "bar", true]]);
},
];

View File

@ -130,8 +130,11 @@ var tests = [
let context = { usePrivateBrowsing: true };
yield set("a.com", "foo", 6, context);
yield setGlobal("foo", 7, context);
yield set("b.com", "foo", 7, context);
yield setGlobal("foo", 8, context);
yield cps.removeByDomain("a.com", context, makeCallback());
yield getOK(["b.com", "foo", context], 7);
yield getGlobalOK(["foo", context], 8);
yield cps.removeAllGlobals(context, makeCallback());
yield dbOK([
["b.com", "foo", 5],