From 2aecbe9b0b42a4032a2d0454085b5ed2656803e1 Mon Sep 17 00:00:00 2001 From: Geoff Lankow Date: Fri, 4 Sep 2009 21:22:19 -0500 Subject: [PATCH] Bug 506799 - "nsIContentPrefService should accept string arguments for URI as well as nsIURI" [r=myk sr=mconnor] --- .../src/nsPrivateBrowsingService.js | 4 +- .../public/nsIContentPrefService.idl | 52 ++++-- .../contentprefs/src/nsContentPrefService.js | 85 ++++++--- .../tests/unit/test_stringGroups.js | 161 ++++++++++++++++++ 4 files changed, 255 insertions(+), 47 deletions(-) create mode 100644 toolkit/components/contentprefs/tests/unit/test_stringGroups.js diff --git a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js index 631f5c50b6d..a2307a09e96 100644 --- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js +++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js @@ -567,9 +567,7 @@ PrivateBrowsingService.prototype = { // Now, for each name we got back, remove all of its prefs. for (let i = 0; i < names.length; i++) { - // The service only cares about the host of the URI, so we don't need a - // full nsIURI object here. - let uri = { host: names[i]}; + let uri = names[i]; let enumerator = cp.getPrefs(uri).enumerator; while (enumerator.hasMoreElements()) { let pref = enumerator.getNext().QueryInterface(Ci.nsIProperty); diff --git a/toolkit/components/contentprefs/public/nsIContentPrefService.idl b/toolkit/components/contentprefs/public/nsIContentPrefService.idl index cacaac482b9..7ec369fc553 100644 --- a/toolkit/components/contentprefs/public/nsIContentPrefService.idl +++ b/toolkit/components/contentprefs/public/nsIContentPrefService.idl @@ -19,6 +19,7 @@ * * Contributor(s): * Myk Melez + * Geoff Lankow * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -37,19 +38,18 @@ #include "nsISupports.idl" interface nsIVariant; -interface nsIURI; interface nsIPropertyBag2; interface nsIContentURIGrouper; interface mozIStorageConnection; -[scriptable, uuid(746c7a02-f6c1-4869-b434-7c8b86e60e61)] +[scriptable, uuid(0d896125-a97e-4617-84e1-004a5de27e76)] interface nsIContentPrefObserver : nsISupports { /** * Called when a content pref is set to a different value. * * @param aGroup the group to which the pref belongs, or null - * if it's a global pref (applies to all URIs) + * if it's a global pref (applies to all sites) * @param aName the name of the pref that was set * @param aValue the new value of the pref */ @@ -59,7 +59,7 @@ interface nsIContentPrefObserver : nsISupports * Called when a content pref is removed. * * @param aGroup the group to which the pref belongs, or null - * if it's a global pref (applies to all URIs) + * if it's a global pref (applies to all sites) * @param aName the name of the pref that was removed */ void onContentPrefRemoved(in AString aGroup, in AString aName); @@ -76,43 +76,57 @@ interface nsIContentPrefService : nsISupports * to NULL in the database, as well as undefined (nsIDataType::VTYPE_VOID), * which means there is no record for this pref in the database. * - * @param aURI the URI for which to get the pref, or null to get - * the global pref (applies to all URIs) + * @param aGroup the group for which to get the pref, as an nsIURI + * from which the hostname will be used, a string + * (typically in the format of a hostname), or null + * to get the global pref (applies to all sites) * @param aName the name of the pref to get * * @returns the value of the pref + * @throws NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null * @throws NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string */ - nsIVariant getPref(in nsIURI aURI, in AString aName); + nsIVariant getPref(in nsIVariant aGroup, in AString aName); /** * Set a pref. * - * @param aURI the URI for which to set the pref, or null to set - * the global pref (applies to all URIs) + * @param aGroup the group for which to set the pref, as an nsIURI + * from which the hostname will be used, a string + * (typically in the format of a hostname), or null + * to set the global pref (applies to all sites) * @param aName the name of the pref to set * @param aValue the new value of the pref + * @throws NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null * @throws NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string */ - void setPref(in nsIURI aURI, in AString aName, in nsIVariant aValue); + void setPref(in nsIVariant aGroup, in AString aName, in nsIVariant aValue); /** * Check whether or not a pref exists. * - * @param aURI the URI for which to check for the pref + * @param aGroup the group for which to check for the pref, as an nsIURI + * from which the hostname will be used, a string + * (typically in the format of a hostname), or null + * to check for the global pref (applies to all sites) * @param aName the name of the pref to check for + * @throws NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null * @throws NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string */ - boolean hasPref(in nsIURI aURI, in AString aName); + boolean hasPref(in nsIVariant aGroup, in AString aName); /** * Remove a pref. * - * @param aURI the URI for which to remove the pref + * @param aGroup the group for which to remove the pref, as an nsIURI + * from which the hostname will be used, a string + * (typically in the format of a hostname), or null + * to remove the global pref (applies to all sites) * @param aName the name of the pref to remove + * @throws NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null * @throws NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string */ - void removePref(in nsIURI aURI, in AString aName); + void removePref(in nsIVariant aGroup, in AString aName); /** * Remove all grouped prefs. Useful for removing references to the sites @@ -129,13 +143,17 @@ interface nsIContentPrefService : nsISupports void removePrefsByName(in AString aName); /** - * Get the prefs that apply to the given URI. + * Get the prefs that apply to the given site. * - * @param aURI the URI for which to retrieve prefs + * @param aGroup the group for which to retrieve prefs, as an nsIURI + * from which the hostname will be used, a string + * (typically in the format of a hostname), or null + * to get the global prefs (apply to all sites) * * @returns a property bag of prefs + * @throws NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null */ - nsIPropertyBag2 getPrefs(in nsIURI aURI); + nsIPropertyBag2 getPrefs(in nsIVariant aGroup); /** * Get the prefs with the given name. diff --git a/toolkit/components/contentprefs/src/nsContentPrefService.js b/toolkit/components/contentprefs/src/nsContentPrefService.js index 8bd8818a3e9..85273b6ea6c 100644 --- a/toolkit/components/contentprefs/src/nsContentPrefService.js +++ b/toolkit/components/contentprefs/src/nsContentPrefService.js @@ -20,6 +20,7 @@ * Contributor(s): * Myk Melez * Ehsan Akhgari + * Geoff Lankow * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -127,22 +128,27 @@ ContentPrefService.prototype = { //**************************************************************************// // nsIContentPrefService - getPref: function ContentPrefService_getPref(aURI, aName) { + getPref: function ContentPrefService_getPref(aGroup, aName) { if (!aName) throw Components.Exception("aName cannot be null or an empty string", Cr.NS_ERROR_ILLEGAL_VALUE); - if (aURI) { - var group = this.grouper.group(aURI); + if (aGroup == null) + return this._selectGlobalPref(aName); + if (aGroup.constructor.name == "String") + return this._selectPref(aGroup.toString(), aName); + if (aGroup instanceof Ci.nsIURI) { + var group = this.grouper.group(aGroup); return this._selectPref(group, aName); } - return this._selectGlobalPref(aName); + throw Components.Exception("aGroup is not a string, nsIURI or null", + Cr.NS_ERROR_ILLEGAL_VALUE); }, - setPref: function ContentPrefService_setPref(aURI, aName, aValue) { + setPref: function ContentPrefService_setPref(aGroup, aName, aValue) { // If the pref is already set to the value, there's nothing more to do. - var currentValue = this.getPref(aURI, aName); + var currentValue = this.getPref(aGroup, aName); if (typeof currentValue != "undefined") { if (currentValue == aValue) return; @@ -161,15 +167,25 @@ ContentPrefService.prototype = { var settingID = this._selectSettingID(aName) || this._insertSetting(aName); var group, groupID, prefID; - if (aURI) { - group = this.grouper.group(aURI); + if (aGroup == null) { + group = null; + groupID = null; + prefID = this._selectGlobalPrefID(settingID); + } + else if (aGroup.constructor.name == "String") { + group = aGroup.toString(); + groupID = this._selectGroupID(group) || this._insertGroup(group); + prefID = this._selectPrefID(groupID, settingID); + } + else if (aGroup instanceof Ci.nsIURI) { + group = this.grouper.group(aGroup); groupID = this._selectGroupID(group) || this._insertGroup(group); prefID = this._selectPrefID(groupID, settingID); } else { - group = null; - groupID = null; - prefID = this._selectGlobalPrefID(settingID); + // Should never get here, due to earlier getPref call + throw Components.Exception("aGroup is not a string, nsIURI or null", + Cr.NS_ERROR_ILLEGAL_VALUE); } // Update the existing record, if any, or create a new one. @@ -188,28 +204,38 @@ ContentPrefService.prototype = { } }, - hasPref: function ContentPrefService_hasPref(aURI, aName) { + hasPref: function ContentPrefService_hasPref(aGroup, aName) { // XXX If consumers end up calling this method regularly, then we should // optimize this to query the database directly. - return (typeof this.getPref(aURI, aName) != "undefined"); + return (typeof this.getPref(aGroup, aName) != "undefined"); }, - removePref: function ContentPrefService_removePref(aURI, aName) { + removePref: function ContentPrefService_removePref(aGroup, aName) { // If there's no old value, then there's nothing to remove. - if (!this.hasPref(aURI, aName)) + if (!this.hasPref(aGroup, aName)) return; var settingID = this._selectSettingID(aName); var group, groupID, prefID; - if (aURI) { - group = this.grouper.group(aURI); + if (aGroup == null) { + group = null; + groupID = null; + prefID = this._selectGlobalPrefID(settingID); + } + else if (aGroup.constructor.name == "String") { + group = aGroup.toString(); + groupID = this._selectGroupID(group); + prefID = this._selectPrefID(groupID, settingID); + } + else if (aGroup instanceof Ci.nsIURI) { + group = this.grouper.group(aGroup); groupID = this._selectGroupID(group); prefID = this._selectPrefID(groupID, settingID); } else { - group = null; - groupID = null; - prefID = this._selectGlobalPrefID(settingID); + // Should never get here, due to earlier hasPref call + throw Components.Exception("aGroup is not a string, nsIURI or null", + Cr.NS_ERROR_ILLEGAL_VALUE); } this._deletePref(prefID); @@ -241,9 +267,8 @@ ContentPrefService.prototype = { Cr.NS_ERROR_ILLEGAL_VALUE); var settingID = this._selectSettingID(aName); - if (!settingID) { + if (!settingID) return; - } var selectGroupsStmt = this._dbCreateStatement( "SELECT groups.name AS groupName " + @@ -278,13 +303,19 @@ ContentPrefService.prototype = { } }, - getPrefs: function ContentPrefService_getPrefs(aURI) { - if (aURI) { - var group = this.grouper.group(aURI); + getPrefs: function ContentPrefService_getPrefs(aGroup) { + if (aGroup == null) + return this._selectGlobalPrefs(); + if (aGroup.constructor.name == "String") { + group = aGroup.toString(); return this._selectPrefs(group); } - - return this._selectGlobalPrefs(); + if (aGroup instanceof Ci.nsIURI) { + var group = this.grouper.group(aGroup); + return this._selectPrefs(group); + } + throw Components.Exception("aGroup is not a string, nsIURI or null", + Cr.NS_ERROR_ILLEGAL_VALUE); }, getPrefsByName: function ContentPrefService_getPrefsByName(aName) { diff --git a/toolkit/components/contentprefs/tests/unit/test_stringGroups.js b/toolkit/components/contentprefs/tests/unit/test_stringGroups.js new file mode 100644 index 00000000000..0f87fe1a0ba --- /dev/null +++ b/toolkit/components/contentprefs/tests/unit/test_stringGroups.js @@ -0,0 +1,161 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Content Preferences (cpref). + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Geoff Lankow + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +function run_test() { + + var cps = Cc["@mozilla.org/content-pref/service;1"]. + getService(Ci.nsIContentPrefService); + + // Make sure disk synchronization checking is turned off by default. + var statement = cps.DBConnection.createStatement("PRAGMA synchronous"); + statement.executeStep(); + do_check_eq(0, statement.getInt32(0)); + + // These are the different types of aGroup arguments we'll test. + var anObject = {"foo":"bar"}; // a simple object + var uri = ContentPrefTest.getURI("http://www.example.com/"); // nsIURI + var stringURI = "www.example.com"; // typeof = "string" + var stringObjectURI = new String("www.example.com"); // typeof = "object" + + { + // First check that all the methods work or don't work. + function simple_test_methods(aGroup, shouldThrow) { + var prefName = "test.pref.0"; + var prefValue = Math.floor(Math.random() * 100); + + if (shouldThrow) { + do_check_thrown(function () { cps.getPref(aGroup, prefName); }); + do_check_thrown(function () { cps.setPref(aGroup, prefName, prefValue); }); + do_check_thrown(function () { cps.hasPref(aGroup, prefName); }); + do_check_thrown(function () { cps.removePref(aGroup, prefName); }); + do_check_thrown(function () { cps.getPrefs(aGroup); }); + } else { + do_check_eq(cps.setPref(aGroup, prefName, prefValue), undefined); + do_check_true(cps.hasPref(aGroup, prefName)); + do_check_eq(cps.getPref(aGroup, prefName), prefValue); + do_check_eq(cps.removePref(aGroup, prefName), undefined); + do_check_false(cps.hasPref(aGroup, prefName)); + } + } + + simple_test_methods(cps, true); // arbitrary nsISupports object, should throw too + simple_test_methods(anObject, true); + simple_test_methods(uri, false); + simple_test_methods(stringURI, false); + simple_test_methods(stringObjectURI, false); + } + + { + // Now we'll check that each argument produces the same result. + function complex_test_methods(aGroup) { + var prefName = "test.pref.1"; + var prefValue = Math.floor(Math.random() * 100); + + do_check_eq(cps.setPref(aGroup, prefName, prefValue), undefined); + + do_check_true(cps.hasPref(uri, prefName)); + do_check_true(cps.hasPref(stringURI, prefName)); + do_check_true(cps.hasPref(stringObjectURI, prefName)); + + do_check_eq(cps.getPref(uri, prefName), prefValue); + do_check_eq(cps.getPref(stringURI, prefName), prefValue); + do_check_eq(cps.getPref(stringObjectURI, prefName), prefValue); + + do_check_eq(cps.removePref(aGroup, prefName), undefined); + + do_check_false(cps.hasPref(uri, prefName)); + do_check_false(cps.hasPref(stringURI, prefName)); + do_check_false(cps.hasPref(stringObjectURI, prefName)); + } + + complex_test_methods(uri); + complex_test_methods(stringURI); + complex_test_methods(stringObjectURI); + } + + { + // test getPrefs returns the same prefs + do_check_eq(cps.setPref(stringObjectURI, "test.5", 5), undefined); + do_check_eq(cps.setPref(stringURI, "test.2", 2), undefined); + do_check_eq(cps.setPref(uri, "test.1", 1), undefined); + + enumerateAndCheck(cps.getPrefs(uri), 8, ["test.1","test.2","test.5"]); + enumerateAndCheck(cps.getPrefs(stringURI), 8, ["test.1","test.2","test.5"]); + enumerateAndCheck(cps.getPrefs(stringObjectURI), 8, ["test.1","test.2","test.5"]); + + do_check_eq(cps.setPref(uri, "test.4", 4), undefined); + do_check_eq(cps.setPref(stringObjectURI, "test.0", 0), undefined); + + enumerateAndCheck(cps.getPrefs(uri), 12, ["test.0","test.1","test.2","test.4","test.5"]); + enumerateAndCheck(cps.getPrefs(stringURI), 12, ["test.0","test.1","test.2","test.4","test.5"]); + enumerateAndCheck(cps.getPrefs(stringObjectURI), 12, ["test.0","test.1","test.2","test.4","test.5"]); + + do_check_eq(cps.setPref(stringURI, "test.3", 3), undefined); + + enumerateAndCheck(cps.getPrefs(uri), 15, ["test.0","test.1","test.2","test.3","test.4","test.5"]); + enumerateAndCheck(cps.getPrefs(stringURI), 15, ["test.0","test.1","test.2","test.3","test.4","test.5"]); + enumerateAndCheck(cps.getPrefs(stringObjectURI), 15, ["test.0","test.1","test.2","test.3","test.4","test.5"]); + } +} + +function do_check_thrown (aCallback) { + var exThrown = false; + try { + aCallback(); + do_throw("NS_ERROR_ILLEGAL_VALUE should have been thrown here"); + } catch (e) { + do_check_eq(e.result, Cr.NS_ERROR_ILLEGAL_VALUE); + exThrown = true; + } + do_check_true(exThrown); +} + +function enumerateAndCheck(prefs, expectedSum, expectedNames) { + var enumerator = prefs.enumerator; + var sum = 0; + while (enumerator.hasMoreElements()) { + var property = enumerator.getNext().QueryInterface(Components.interfaces.nsIProperty); + sum += parseInt(property.value); + + // remove the pref name from the list of expected names + var index = expectedNames.indexOf(property.name); + do_check_true(index >= 0); + expectedNames.splice(index, 1); + } + do_check_eq(sum, expectedSum); + // check all pref names have been removed from the array + do_check_eq(expectedNames.length, 0); +}