diff --git a/test/driver.js b/test/driver.js
index c7c104378..88be8a7ff 100644
--- a/test/driver.js
+++ b/test/driver.js
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/* globals PDFJS, combineUrl, StatTimer, SpecialPowers, Promise */
+/* globals PDFJS, combineUrl, StatTimer, Promise */
'use strict';
@@ -363,11 +363,7 @@ function quitApp() {
document.body.innerHTML = 'Tests are finished.
CLOSE ME!
' +
document.body.innerHTML;
sendQuitRequest(function () {
- if (window.SpecialPowers) {
- SpecialPowers.quit();
- } else {
- window.close();
- }
+ window.close();
});
}
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome.manifest b/test/resources/firefox/extensions/special-powers@mozilla.org/chrome.manifest
deleted file mode 100644
index cac9fd65b..000000000
--- a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome.manifest
+++ /dev/null
@@ -1,5 +0,0 @@
-category profile-after-change @mozilla.org/special-powers-observer;1 @mozilla.org/special-powers-observer;1
-component {59a52458-13e0-4d93-9d85-a637344f29a1} components/SpecialPowersObserver.js
-content specialpowers chrome/specialpowers/content/
-contract @mozilla.org/special-powers-observer;1 {59a52458-13e0-4d93-9d85-a637344f29a1}
-resource specialpowers chrome/specialpowers/modules/
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/MozillaLogger.js b/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/MozillaLogger.js
deleted file mode 100644
index fdc6c9a09..000000000
--- a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/MozillaLogger.js
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * MozillaLogger, a base class logger that just logs to stdout.
- */
-
-function MozillaLogger(aPath) {
-}
-
-MozillaLogger.prototype = {
-
- init : function(path) {},
-
- getLogCallback : function() {
- return function (msg) {
- var data = msg.num + " " + msg.level + " " + msg.info.join(' ') + "\n";
- dump(data);
- }
- },
-
- log : function(msg) {
- dump(msg);
- },
-
- close : function() {}
-};
-
-
-/**
- * SpecialPowersLogger, inherits from MozillaLogger and utilizes SpecialPowers.
- * intented to be used in content scripts to write to a file
- */
-function SpecialPowersLogger(aPath) {
- // Call the base constructor
- MozillaLogger.call(this);
- this.prototype = new MozillaLogger(aPath);
- this.init(aPath);
-}
-
-SpecialPowersLogger.prototype = {
- init : function (path) {
- SpecialPowers.setLogFile(path);
- },
-
- getLogCallback : function () {
- return function (msg) {
- var data = msg.num + " " + msg.level + " " + msg.info.join(' ') + "\n";
- SpecialPowers.log(data);
-
- if (data.indexOf("SimpleTest FINISH") >= 0) {
- SpecialPowers.closeLogFile();
- }
- }
- },
-
- log : function (msg) {
- SpecialPowers.log(msg);
- },
-
- close : function () {
- SpecialPowers.closeLogFile();
- }
-};
-
-
-/**
- * MozillaFileLogger, a log listener that can write to a local file.
- * intended to be run from chrome space
- */
-
-/** Init the file logger with the absolute path to the file.
- It will create and append if the file already exists **/
-function MozillaFileLogger(aPath) {
- // Call the base constructor
- MozillaLogger.call(this);
- this.prototype = new MozillaLogger(aPath);
- this.init(aPath);
-}
-
-MozillaFileLogger.prototype = {
-
- init : function (path) {
- var PR_WRITE_ONLY = 0x02; // Open for writing only.
- var PR_CREATE_FILE = 0x08;
- var PR_APPEND = 0x10;
- this._file = Components.classes["@mozilla.org/file/local;1"].
- createInstance(Components.interfaces.nsILocalFile);
- this._file.initWithPath(path);
- this._foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
- createInstance(Components.interfaces.nsIFileOutputStream);
- this._foStream.init(this._file, PR_WRITE_ONLY | PR_CREATE_FILE | PR_APPEND,
- 0664, 0);
- },
-
- getLogCallback : function() {
- return function (msg) {
- var data = msg.num + " " + msg.level + " " + msg.info.join(' ') + "\n";
- if (MozillaFileLogger._foStream)
- this._foStream.write(data, data.length);
-
- if (data.indexOf("SimpleTest FINISH") >= 0) {
- MozillaFileLogger.close();
- }
- }
- },
-
- log : function(msg) {
- if (this._foStream)
- this._foStream.write(msg, msg.length);
- },
-
- close : function() {
- if(this._foStream)
- this._foStream.close();
-
- this._foStream = null;
- this._file = null;
- }
-};
-
-this.MozillaLogger = MozillaLogger;
-this.SpecialPowersLogger = SpecialPowersLogger;
-this.MozillaFileLogger = MozillaFileLogger;
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/SpecialPowersObserverAPI.js b/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/SpecialPowersObserverAPI.js
deleted file mode 100644
index 160b82e6e..000000000
--- a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/SpecialPowersObserverAPI.js
+++ /dev/null
@@ -1,413 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-"use strict";
-
-Components.utils.import("resource://gre/modules/Services.jsm");
-
-if (typeof(Ci) == 'undefined') {
- var Ci = Components.interfaces;
-}
-
-if (typeof(Cc) == 'undefined') {
- var Cc = Components.classes;
-}
-
-/**
- * Special Powers Exception - used to throw exceptions nicely
- **/
-function SpecialPowersException(aMsg) {
- this.message = aMsg;
- this.name = "SpecialPowersException";
-}
-
-SpecialPowersException.prototype.toString = function() {
- return this.name + ': "' + this.message + '"';
-};
-
-this.SpecialPowersObserverAPI = function SpecialPowersObserverAPI() {
- this._crashDumpDir = null;
- this._processCrashObserversRegistered = false;
- this._chromeScriptListeners = [];
-}
-
-function parseKeyValuePairs(text) {
- var lines = text.split('\n');
- var data = {};
- for (let i = 0; i < lines.length; i++) {
- if (lines[i] == '')
- continue;
-
- // can't just .split() because the value might contain = characters
- let eq = lines[i].indexOf('=');
- if (eq != -1) {
- let [key, value] = [lines[i].substring(0, eq),
- lines[i].substring(eq + 1)];
- if (key && value)
- data[key] = value.replace(/\\n/g, "\n").replace(/\\\\/g, "\\");
- }
- }
- return data;
-}
-
-function parseKeyValuePairsFromFile(file) {
- var fstream = Cc["@mozilla.org/network/file-input-stream;1"].
- createInstance(Ci.nsIFileInputStream);
- fstream.init(file, -1, 0, 0);
- var is = Cc["@mozilla.org/intl/converter-input-stream;1"].
- createInstance(Ci.nsIConverterInputStream);
- is.init(fstream, "UTF-8", 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
- var str = {};
- var contents = '';
- while (is.readString(4096, str) != 0) {
- contents += str.value;
- }
- is.close();
- fstream.close();
- return parseKeyValuePairs(contents);
-}
-
-SpecialPowersObserverAPI.prototype = {
-
- _observe: function(aSubject, aTopic, aData) {
- function addDumpIDToMessage(propertyName) {
- var id = aSubject.getPropertyAsAString(propertyName);
- if (id) {
- message.dumpIDs.push({id: id, extension: "dmp"});
- message.dumpIDs.push({id: id, extension: "extra"});
- }
- }
-
- switch(aTopic) {
- case "plugin-crashed":
- case "ipc:content-shutdown":
- var message = { type: "crash-observed", dumpIDs: [] };
- aSubject = aSubject.QueryInterface(Ci.nsIPropertyBag2);
- if (aTopic == "plugin-crashed") {
- addDumpIDToMessage("pluginDumpID");
- addDumpIDToMessage("browserDumpID");
-
- let pluginID = aSubject.getPropertyAsAString("pluginDumpID");
- let extra = this._getExtraData(pluginID);
- if (extra && ("additional_minidumps" in extra)) {
- let dumpNames = extra.additional_minidumps.split(',');
- for (let name of dumpNames) {
- message.dumpIDs.push({id: pluginID + "-" + name, extension: "dmp"});
- }
- }
- } else { // ipc:content-shutdown
- addDumpIDToMessage("dumpID");
- }
- this._sendAsyncMessage("SPProcessCrashService", message);
- break;
- }
- },
-
- _getCrashDumpDir: function() {
- if (!this._crashDumpDir) {
- this._crashDumpDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
- this._crashDumpDir.append("minidumps");
- }
- return this._crashDumpDir;
- },
-
- _getExtraData: function(dumpId) {
- let extraFile = this._getCrashDumpDir().clone();
- extraFile.append(dumpId + ".extra");
- if (!extraFile.exists()) {
- return null;
- }
- return parseKeyValuePairsFromFile(extraFile);
- },
-
- _deleteCrashDumpFiles: function(aFilenames) {
- var crashDumpDir = this._getCrashDumpDir();
- if (!crashDumpDir.exists()) {
- return false;
- }
-
- var success = aFilenames.length != 0;
- aFilenames.forEach(function(crashFilename) {
- var file = crashDumpDir.clone();
- file.append(crashFilename);
- if (file.exists()) {
- file.remove(false);
- } else {
- success = false;
- }
- });
- return success;
- },
-
- _findCrashDumpFiles: function(aToIgnore) {
- var crashDumpDir = this._getCrashDumpDir();
- var entries = crashDumpDir.exists() && crashDumpDir.directoryEntries;
- if (!entries) {
- return [];
- }
-
- var crashDumpFiles = [];
- while (entries.hasMoreElements()) {
- var file = entries.getNext().QueryInterface(Ci.nsIFile);
- var path = String(file.path);
- if (path.match(/\.(dmp|extra)$/) && !aToIgnore[path]) {
- crashDumpFiles.push(path);
- }
- }
- return crashDumpFiles.concat();
- },
-
- _getURI: function (url) {
- return Services.io.newURI(url, null, null);
- },
-
- _readUrlAsString: function(aUrl) {
- // Fetch script content as we can't use scriptloader's loadSubScript
- // to evaluate http:// urls...
- var scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
- .getService(Ci.nsIScriptableInputStream);
- var channel = Services.io.newChannel(aUrl, null, null);
- var input = channel.open();
- scriptableStream.init(input);
-
- var str;
- var buffer = [];
-
- while ((str = scriptableStream.read(4096))) {
- buffer.push(str);
- }
-
- var output = buffer.join("");
-
- scriptableStream.close();
- input.close();
-
- var status;
- try {
- channel.QueryInterface(Ci.nsIHttpChannel);
- status = channel.responseStatus;
- } catch(e) {
- /* The channel is not a nsIHttpCHannel, but that's fine */
- dump("-*- _readUrlAsString: Got an error while fetching " +
- "chrome script '" + aUrl + "': (" + e.name + ") " + e.message + ". " +
- "Ignoring.\n");
- }
-
- if (status == 404) {
- throw new SpecialPowersException(
- "Error while executing chrome script '" + aUrl + "':\n" +
- "The script doesn't exists. Ensure you have registered it in " +
- "'support-files' in your mochitest.ini.");
- }
-
- return output;
- },
-
- /**
- * messageManager callback function
- * This will get requests from our API in the window and process them in chrome for it
- **/
- _receiveMessageAPI: function(aMessage) {
- // We explicitly return values in the below code so that this function
- // doesn't trigger a flurry of warnings about "does not always return
- // a value".
- switch(aMessage.name) {
- case "SPPrefService":
- var prefs = Services.prefs;
- var prefType = aMessage.json.prefType.toUpperCase();
- var prefName = aMessage.json.prefName;
- var prefValue = "prefValue" in aMessage.json ? aMessage.json.prefValue : null;
-
- if (aMessage.json.op == "get") {
- if (!prefName || !prefType)
- throw new SpecialPowersException("Invalid parameters for get in SPPrefService");
-
- // return null if the pref doesn't exist
- if (prefs.getPrefType(prefName) == prefs.PREF_INVALID)
- return null;
- } else if (aMessage.json.op == "set") {
- if (!prefName || !prefType || prefValue === null)
- throw new SpecialPowersException("Invalid parameters for set in SPPrefService");
- } else if (aMessage.json.op == "clear") {
- if (!prefName)
- throw new SpecialPowersException("Invalid parameters for clear in SPPrefService");
- } else {
- throw new SpecialPowersException("Invalid operation for SPPrefService");
- }
-
- // Now we make the call
- switch(prefType) {
- case "BOOL":
- if (aMessage.json.op == "get")
- return(prefs.getBoolPref(prefName));
- else
- return(prefs.setBoolPref(prefName, prefValue));
- case "INT":
- if (aMessage.json.op == "get")
- return(prefs.getIntPref(prefName));
- else
- return(prefs.setIntPref(prefName, prefValue));
- case "CHAR":
- if (aMessage.json.op == "get")
- return(prefs.getCharPref(prefName));
- else
- return(prefs.setCharPref(prefName, prefValue));
- case "COMPLEX":
- if (aMessage.json.op == "get")
- return(prefs.getComplexValue(prefName, prefValue[0]));
- else
- return(prefs.setComplexValue(prefName, prefValue[0], prefValue[1]));
- case "":
- if (aMessage.json.op == "clear") {
- prefs.clearUserPref(prefName);
- return undefined;
- }
- }
- return undefined; // See comment at the beginning of this function.
-
- case "SPProcessCrashService":
- switch (aMessage.json.op) {
- case "register-observer":
- this._addProcessCrashObservers();
- break;
- case "unregister-observer":
- this._removeProcessCrashObservers();
- break;
- case "delete-crash-dump-files":
- return this._deleteCrashDumpFiles(aMessage.json.filenames);
- case "find-crash-dump-files":
- return this._findCrashDumpFiles(aMessage.json.crashDumpFilesToIgnore);
- default:
- throw new SpecialPowersException("Invalid operation for SPProcessCrashService");
- }
- return undefined; // See comment at the beginning of this function.
-
- case "SPPermissionManager":
- let msg = aMessage.json;
-
- let secMan = Services.scriptSecurityManager;
- let principal = secMan.getAppCodebasePrincipal(this._getURI(msg.url), msg.appId, msg.isInBrowserElement);
-
- switch (msg.op) {
- case "add":
- Services.perms.addFromPrincipal(principal, msg.type, msg.permission);
- break;
- case "remove":
- Services.perms.removeFromPrincipal(principal, msg.type);
- break;
- case "has":
- let hasPerm = Services.perms.testPermissionFromPrincipal(principal, msg.type);
- if (hasPerm == Ci.nsIPermissionManager.ALLOW_ACTION)
- return true;
- return false;
- break;
- case "test":
- let testPerm = Services.perms.testPermissionFromPrincipal(principal, msg.type, msg.value);
- if (testPerm == msg.value) {
- return true;
- }
- return false;
- break;
- default:
- throw new SpecialPowersException("Invalid operation for " +
- "SPPermissionManager");
- }
- return undefined; // See comment at the beginning of this function.
-
- case "SPWebAppService":
- let Webapps = {};
- Components.utils.import("resource://gre/modules/Webapps.jsm", Webapps);
- switch (aMessage.json.op) {
- case "set-launchable":
- let val = Webapps.DOMApplicationRegistry.allAppsLaunchable;
- Webapps.DOMApplicationRegistry.allAppsLaunchable = aMessage.json.launchable;
- return val;
- default:
- throw new SpecialPowersException("Invalid operation for SPWebAppsService");
- }
- return undefined; // See comment at the beginning of this function.
-
- case "SPObserverService":
- switch (aMessage.json.op) {
- case "notify":
- let topic = aMessage.json.observerTopic;
- let data = aMessage.json.observerData
- Services.obs.notifyObservers(null, topic, data);
- break;
- default:
- throw new SpecialPowersException("Invalid operation for SPObserverervice");
- }
- return undefined; // See comment at the beginning of this function.
-
- case "SPLoadChromeScript":
- var url = aMessage.json.url;
- var id = aMessage.json.id;
-
- var jsScript = this._readUrlAsString(url);
-
- // Setup a chrome sandbox that has access to sendAsyncMessage
- // and addMessageListener in order to communicate with
- // the mochitest.
- var systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
- var sb = Components.utils.Sandbox(systemPrincipal);
- var mm = aMessage.target
- .QueryInterface(Ci.nsIFrameLoaderOwner)
- .frameLoader
- .messageManager;
- sb.sendAsyncMessage = (name, message) => {
- mm.sendAsyncMessage("SPChromeScriptMessage",
- { id: id, name: name, message: message });
- };
- sb.addMessageListener = (name, listener) => {
- this._chromeScriptListeners.push({ id: id, name: name, listener: listener });
- };
-
- // Also expose assertion functions
- let reporter = function (err, message, stack) {
- // Pipe assertions back to parent process
- mm.sendAsyncMessage("SPChromeScriptAssert",
- { id: id, url: url, err: err, message: message,
- stack: stack });
- };
- Object.defineProperty(sb, "assert", {
- get: function () {
- let scope = Components.utils.createObjectIn(sb);
- Services.scriptloader.loadSubScript("resource://specialpowers/Assert.jsm",
- scope);
-
- let assert = new scope.Assert(reporter);
- delete sb.assert;
- return sb.assert = assert;
- },
- configurable: true
- });
-
- // Evaluate the chrome script
- try {
- Components.utils.evalInSandbox(jsScript, sb, "1.8", url, 1);
- } catch(e) {
- throw new SpecialPowersException("Error while executing chrome " +
- "script '" + url + "':\n" + e + "\n" +
- e.fileName + ":" + e.lineNumber);
- }
- return undefined; // See comment at the beginning of this function.
-
- case "SPChromeScriptMessage":
- var id = aMessage.json.id;
- var name = aMessage.json.name;
- var message = aMessage.json.message;
- this._chromeScriptListeners
- .filter(o => (o.name == name && o.id == id))
- .forEach(o => o.listener(message));
- return undefined; // See comment at the beginning of this function.
-
- default:
- throw new SpecialPowersException("Unrecognized Special Powers API");
- }
-
- // We throw an exception before reaching this explicit return because
- // we should never be arriving here anyway.
- throw new SpecialPowersException("Unreached code");
- return undefined;
- }
-};
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/specialpowers.js b/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/specialpowers.js
deleted file mode 100644
index 31ff09303..000000000
--- a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/specialpowers.js
+++ /dev/null
@@ -1,134 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-/* This code is loaded in every child process that is started by mochitest in
- * order to be used as a replacement for UniversalXPConnect
- */
-
-function SpecialPowers(window) {
- this.window = Components.utils.getWeakReference(window);
- this._encounteredCrashDumpFiles = [];
- this._unexpectedCrashDumpFiles = { };
- this._crashDumpDir = null;
- this.DOMWindowUtils = bindDOMWindowUtils(window);
- Object.defineProperty(this, 'Components', {
- configurable: true, enumerable: true, get: function() {
- var win = this.window.get();
- if (!win)
- return null;
- return getRawComponents(win);
- }});
- this._pongHandlers = [];
- this._messageListener = this._messageReceived.bind(this);
- addMessageListener("SPPingService", this._messageListener);
-}
-
-SpecialPowers.prototype = new SpecialPowersAPI();
-
-SpecialPowers.prototype.toString = function() { return "[SpecialPowers]"; };
-SpecialPowers.prototype.sanityCheck = function() { return "foo"; };
-
-// This gets filled in in the constructor.
-SpecialPowers.prototype.DOMWindowUtils = undefined;
-SpecialPowers.prototype.Components = undefined;
-
-SpecialPowers.prototype._sendSyncMessage = function(msgname, msg) {
- return sendSyncMessage(msgname, msg);
-};
-
-SpecialPowers.prototype._sendAsyncMessage = function(msgname, msg) {
- sendAsyncMessage(msgname, msg);
-};
-
-SpecialPowers.prototype._addMessageListener = function(msgname, listener) {
- addMessageListener(msgname, listener);
-};
-
-SpecialPowers.prototype._removeMessageListener = function(msgname, listener) {
- removeMessageListener(msgname, listener);
-};
-
-SpecialPowers.prototype.registerProcessCrashObservers = function() {
- addMessageListener("SPProcessCrashService", this._messageListener);
- sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
-};
-
-SpecialPowers.prototype.unregisterProcessCrashObservers = function() {
- addMessageListener("SPProcessCrashService", this._messageListener);
- sendSyncMessage("SPProcessCrashService", { op: "unregister-observer" });
-};
-
-SpecialPowers.prototype._messageReceived = function(aMessage) {
- switch (aMessage.name) {
- case "SPProcessCrashService":
- if (aMessage.json.type == "crash-observed") {
- for (let e of aMessage.json.dumpIDs) {
- this._encounteredCrashDumpFiles.push(e.id + "." + e.extension);
- }
- }
- break;
-
- case "SPPingService":
- if (aMessage.json.op == "pong") {
- var handler = this._pongHandlers.shift();
- if (handler) {
- handler();
- }
- }
- break;
- }
- return true;
-};
-
-SpecialPowers.prototype.quit = function() {
- sendAsyncMessage("SpecialPowers.Quit", {});
-};
-
-SpecialPowers.prototype.executeAfterFlushingMessageQueue = function(aCallback) {
- this._pongHandlers.push(aCallback);
- sendAsyncMessage("SPPingService", { op: "ping" });
-};
-
-// Expose everything but internal APIs (starting with underscores) to
-// web content. We cannot use Object.keys to view SpecialPowers.prototype since
-// we are using the functions from SpecialPowersAPI.prototype
-SpecialPowers.prototype.__exposedProps__ = {};
-for (var i in SpecialPowers.prototype) {
- if (i.charAt(0) != "_")
- SpecialPowers.prototype.__exposedProps__[i] = "r";
-}
-
-// Attach our API to the window.
-function attachSpecialPowersToWindow(aWindow) {
- try {
- if ((aWindow !== null) &&
- (aWindow !== undefined) &&
- (aWindow.wrappedJSObject) &&
- !(aWindow.wrappedJSObject.SpecialPowers)) {
- aWindow.wrappedJSObject.SpecialPowers = new SpecialPowers(aWindow);
- }
- } catch(ex) {
- dump("TEST-INFO | specialpowers.js | Failed to attach specialpowers to window exception: " + ex + "\n");
- }
-}
-
-// This is a frame script, so it may be running in a content process.
-// In any event, it is targeted at a specific "tab", so we listen for
-// the DOMWindowCreated event to be notified about content windows
-// being created in this context.
-
-function SpecialPowersManager() {
- addEventListener("DOMWindowCreated", this, false);
-}
-
-SpecialPowersManager.prototype = {
- handleEvent: function handleEvent(aEvent) {
- var window = aEvent.target.defaultView;
- attachSpecialPowersToWindow(window);
- }
-};
-
-var specialpowersmanager = new SpecialPowersManager();
-
-this.SpecialPowers = SpecialPowers;
-this.attachSpecialPowersToWindow = attachSpecialPowersToWindow;
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/specialpowersAPI.js b/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/specialpowersAPI.js
deleted file mode 100644
index 7c1344d3f..000000000
--- a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/specialpowersAPI.js
+++ /dev/null
@@ -1,1744 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-/* This code is loaded in every child process that is started by mochitest in
- * order to be used as a replacement for UniversalXPConnect
- */
-
-var Ci = Components.interfaces;
-var Cc = Components.classes;
-var Cu = Components.utils;
-
-Cu.import("resource://specialpowers/MockFilePicker.jsm");
-Cu.import("resource://specialpowers/MockColorPicker.jsm");
-Cu.import("resource://specialpowers/MockPermissionPrompt.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-function SpecialPowersAPI() {
- this._consoleListeners = [];
- this._encounteredCrashDumpFiles = [];
- this._unexpectedCrashDumpFiles = { };
- this._crashDumpDir = null;
- this._mfl = null;
- this._prefEnvUndoStack = [];
- this._pendingPrefs = [];
- this._applyingPrefs = false;
- this._permissionsUndoStack = [];
- this._pendingPermissions = [];
- this._applyingPermissions = false;
- this._fm = null;
- this._cb = null;
-}
-
-function bindDOMWindowUtils(aWindow) {
- if (!aWindow)
- return
-
- var util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils);
- return wrapPrivileged(util);
-}
-
-function getRawComponents(aWindow) {
- // If we're running in automation that supports enablePrivilege, then we also
- // provided access to the privileged Components.
- try {
- let win = Cu.waiveXrays(aWindow);
- if (typeof win.netscape.security.PrivilegeManager == 'object')
- Cu.forcePrivilegedComponentsForScope(aWindow);
- } catch (e) {}
- return Cu.getComponentsForScope(aWindow);
-}
-
-function isWrappable(x) {
- if (typeof x === "object")
- return x !== null;
- return typeof x === "function";
-};
-
-function isWrapper(x) {
- return isWrappable(x) && (typeof x.SpecialPowers_wrappedObject !== "undefined");
-};
-
-function unwrapIfWrapped(x) {
- return isWrapper(x) ? unwrapPrivileged(x) : x;
-};
-
-function wrapIfUnwrapped(x) {
- return isWrapper(x) ? x : wrapPrivileged(x);
-}
-
-function isXrayWrapper(x) {
- return Cu.isXrayWrapper(x);
-}
-
-function callGetOwnPropertyDescriptor(obj, name) {
- // Quickstubbed getters and setters are propertyOps, and don't get reified
- // until someone calls __lookupGetter__ or __lookupSetter__ on them (note
- // that there are special version of those functions for quickstubs, so
- // apply()ing Object.prototype.__lookupGetter__ isn't good enough). Try to
- // trigger reification before calling Object.getOwnPropertyDescriptor.
- //
- // See bug 764315.
- try {
- obj.__lookupGetter__(name);
- obj.__lookupSetter__(name);
- } catch(e) { }
- return Object.getOwnPropertyDescriptor(obj, name);
-}
-
-// We can't call apply() directy on Xray-wrapped functions, so we have to be
-// clever.
-function doApply(fun, invocant, args) {
- return Function.prototype.apply.call(fun, invocant, args);
-}
-
-function wrapPrivileged(obj) {
-
- // Primitives pass straight through.
- if (!isWrappable(obj))
- return obj;
-
- // No double wrapping.
- if (isWrapper(obj))
- throw "Trying to double-wrap object!";
-
- // Make our core wrapper object.
- var handler = new SpecialPowersHandler(obj);
-
- // If the object is callable, make a function proxy.
- if (typeof obj === "function") {
- var callTrap = function() {
- // The invocant and arguments may or may not be wrappers. Unwrap them if necessary.
- var invocant = unwrapIfWrapped(this);
- var unwrappedArgs = Array.prototype.slice.call(arguments).map(unwrapIfWrapped);
-
- try {
- return wrapPrivileged(doApply(obj, invocant, unwrappedArgs));
- } catch (e) {
- // Wrap exceptions and re-throw them.
- throw wrapIfUnwrapped(e);
- }
- };
- var constructTrap = function() {
- // The arguments may or may not be wrappers. Unwrap them if necessary.
- var unwrappedArgs = Array.prototype.slice.call(arguments).map(unwrapIfWrapped);
-
- // We want to invoke "obj" as a constructor, but using unwrappedArgs as
- // the arguments. Make sure to wrap and re-throw exceptions!
- try {
- return wrapPrivileged(new obj(...unwrappedArgs));
- } catch (e) {
- throw wrapIfUnwrapped(e);
- }
- };
-
- return Proxy.createFunction(handler, callTrap, constructTrap);
- }
-
- // Otherwise, just make a regular object proxy.
- return Proxy.create(handler);
-};
-
-function unwrapPrivileged(x) {
-
- // We don't wrap primitives, so sometimes we have a primitive where we'd
- // expect to have a wrapper. The proxy pretends to be the type that it's
- // emulating, so we can just as easily check isWrappable() on a proxy as
- // we can on an unwrapped object.
- if (!isWrappable(x))
- return x;
-
- // If we have a wrappable type, make sure it's wrapped.
- if (!isWrapper(x))
- throw "Trying to unwrap a non-wrapped object!";
-
- // Unwrap.
- return x.SpecialPowers_wrappedObject;
-};
-
-function crawlProtoChain(obj, fn) {
- var rv = fn(obj);
- if (rv !== undefined)
- return rv;
- if (Object.getPrototypeOf(obj))
- return crawlProtoChain(Object.getPrototypeOf(obj), fn);
-};
-
-/*
- * We want to waive the __exposedProps__ security check for SpecialPowers-wrapped
- * objects. We do this by creating a proxy singleton that just always returns 'rw'
- * for any property name.
- */
-function ExposedPropsWaiverHandler() {
- // NB: XPConnect denies access if the relevant member of __exposedProps__ is not
- // enumerable.
- var _permit = { value: 'rw', writable: false, configurable: false, enumerable: true };
- return {
- getOwnPropertyDescriptor: function(name) { return _permit; },
- getPropertyDescriptor: function(name) { return _permit; },
- getOwnPropertyNames: function() { throw Error("Can't enumerate ExposedPropsWaiver"); },
- getPropertyNames: function() { throw Error("Can't enumerate ExposedPropsWaiver"); },
- enumerate: function() { throw Error("Can't enumerate ExposedPropsWaiver"); },
- defineProperty: function(name) { throw Error("Can't define props on ExposedPropsWaiver"); },
- delete: function(name) { throw Error("Can't delete props from ExposedPropsWaiver"); }
- };
-};
-ExposedPropsWaiver = Proxy.create(ExposedPropsWaiverHandler());
-
-function SpecialPowersHandler(obj) {
- this.wrappedObject = obj;
-};
-
-// Allow us to transitively maintain the membrane by wrapping descriptors
-// we return.
-SpecialPowersHandler.prototype.doGetPropertyDescriptor = function(name, own) {
-
- // Handle our special API.
- if (name == "SpecialPowers_wrappedObject")
- return { value: this.wrappedObject, writeable: false, configurable: false, enumerable: false };
-
- // Handle __exposedProps__.
- if (name == "__exposedProps__")
- return { value: ExposedPropsWaiver, writable: false, configurable: false, enumerable: false };
-
- // In general, we want Xray wrappers for content DOM objects, because waiving
- // Xray gives us Xray waiver wrappers that clamp the principal when we cross
- // compartment boundaries. However, Xray adds some gunk to toString(), which
- // has the potential to confuse consumers that aren't expecting Xray wrappers.
- // Since toString() is a non-privileged method that returns only strings, we
- // can just waive Xray for that case.
- var obj = name == 'toString' ? XPCNativeWrapper.unwrap(this.wrappedObject)
- : this.wrappedObject;
-
- //
- // Call through to the wrapped object.
- //
- // Note that we have several cases here, each of which requires special handling.
- //
- var desc;
-
- // Case 1: Own Properties.
- //
- // This one is easy, thanks to Object.getOwnPropertyDescriptor().
- if (own)
- desc = callGetOwnPropertyDescriptor(obj, name);
-
- // Case 2: Not own, not Xray-wrapped.
- //
- // Here, we can just crawl the prototype chain, calling
- // Object.getOwnPropertyDescriptor until we find what we want.
- //
- // NB: Make sure to check this.wrappedObject here, rather than obj, because
- // we may have waived Xray on obj above.
- else if (!isXrayWrapper(this.wrappedObject))
- desc = crawlProtoChain(obj, function(o) {return callGetOwnPropertyDescriptor(o, name);});
-
- // Case 3: Not own, Xray-wrapped.
- //
- // This one is harder, because we Xray wrappers are flattened and don't have
- // a prototype. Xray wrappers are proxies themselves, so we'd love to just call
- // through to XrayWrapper::getPropertyDescriptor(). Unfortunately though,
- // we don't have any way to do that. :-(
- //
- // So we first try with a call to getOwnPropertyDescriptor(). If that fails,
- // we make up a descriptor, using some assumptions about what kinds of things
- // tend to live on the prototypes of Xray-wrapped objects.
- else {
- desc = Object.getOwnPropertyDescriptor(obj, name);
- if (!desc) {
- var getter = Object.prototype.__lookupGetter__.call(obj, name);
- var setter = Object.prototype.__lookupSetter__.call(obj, name);
- if (getter || setter)
- desc = {get: getter, set: setter, configurable: true, enumerable: true};
- else if (name in obj)
- desc = {value: obj[name], writable: false, configurable: true, enumerable: true};
- }
- }
-
- // Bail if we've got nothing.
- if (typeof desc === 'undefined')
- return undefined;
-
- // When accessors are implemented as JSPropertyOps rather than JSNatives (ie,
- // QuickStubs), the js engine does the wrong thing and treats it as a value
- // descriptor rather than an accessor descriptor. Jorendorff suggested this
- // little hack to work around it. See bug 520882.
- if (desc && 'value' in desc && desc.value === undefined)
- desc.value = obj[name];
-
- // A trapping proxy's properties must always be configurable, but sometimes
- // this we get non-configurable properties from Object.getOwnPropertyDescriptor().
- // Tell a white lie.
- desc.configurable = true;
-
- // Transitively maintain the wrapper membrane.
- function wrapIfExists(key) { if (key in desc) desc[key] = wrapPrivileged(desc[key]); };
- wrapIfExists('value');
- wrapIfExists('get');
- wrapIfExists('set');
-
- return desc;
-};
-
-SpecialPowersHandler.prototype.getOwnPropertyDescriptor = function(name) {
- return this.doGetPropertyDescriptor(name, true);
-};
-
-SpecialPowersHandler.prototype.getPropertyDescriptor = function(name) {
- return this.doGetPropertyDescriptor(name, false);
-};
-
-function doGetOwnPropertyNames(obj, props) {
-
- // Insert our special API. It's not enumerable, but getPropertyNames()
- // includes non-enumerable properties.
- var specialAPI = 'SpecialPowers_wrappedObject';
- if (props.indexOf(specialAPI) == -1)
- props.push(specialAPI);
-
- // Do the normal thing.
- var flt = function(a) { return props.indexOf(a) == -1; };
- props = props.concat(Object.getOwnPropertyNames(obj).filter(flt));
-
- // If we've got an Xray wrapper, include the expandos as well.
- if ('wrappedJSObject' in obj)
- props = props.concat(Object.getOwnPropertyNames(obj.wrappedJSObject)
- .filter(flt));
-
- return props;
-}
-
-SpecialPowersHandler.prototype.getOwnPropertyNames = function() {
- return doGetOwnPropertyNames(this.wrappedObject, []);
-};
-
-SpecialPowersHandler.prototype.getPropertyNames = function() {
-
- // Manually walk the prototype chain, making sure to add only property names
- // that haven't been overridden.
- //
- // There's some trickiness here with Xray wrappers. Xray wrappers don't have
- // a prototype, so we need to unwrap them if we want to get all of the names
- // with Object.getOwnPropertyNames(). But we don't really want to unwrap the
- // base object, because that will include expandos that are inaccessible via
- // our implementation of get{,Own}PropertyDescriptor(). So we unwrap just
- // before accessing the prototype. This ensures that we get Xray vision on
- // the base object, and no Xray vision for the rest of the way up.
- var obj = this.wrappedObject;
- var props = [];
- while (obj) {
- props = doGetOwnPropertyNames(obj, props);
- obj = Object.getPrototypeOf(XPCNativeWrapper.unwrap(obj));
- }
- return props;
-};
-
-SpecialPowersHandler.prototype.defineProperty = function(name, desc) {
- return Object.defineProperty(this.wrappedObject, name, desc);
-};
-
-SpecialPowersHandler.prototype.delete = function(name) {
- return delete this.wrappedObject[name];
-};
-
-SpecialPowersHandler.prototype.fix = function() { return undefined; /* Throws a TypeError. */ };
-
-// Per the ES5 spec this is a derived trap, but it's fundamental in spidermonkey
-// for some reason. See bug 665198.
-SpecialPowersHandler.prototype.enumerate = function() {
- var t = this;
- var filt = function(name) { return t.getPropertyDescriptor(name).enumerable; };
- return this.getPropertyNames().filter(filt);
-};
-
-// SPConsoleListener reflects nsIConsoleMessage objects into JS in a
-// tidy, XPCOM-hiding way. Messages that are nsIScriptError objects
-// have their properties exposed in detail. It also auto-unregisters
-// itself when it receives a "sentinel" message.
-function SPConsoleListener(callback) {
- this.callback = callback;
-}
-
-SPConsoleListener.prototype = {
- observe: function(msg) {
- let m = { message: msg.message,
- errorMessage: null,
- sourceName: null,
- sourceLine: null,
- lineNumber: null,
- columnNumber: null,
- category: null,
- windowID: null,
- isScriptError: false,
- isWarning: false,
- isException: false,
- isStrict: false };
- if (msg instanceof Ci.nsIScriptError) {
- m.errorMessage = msg.errorMessage;
- m.sourceName = msg.sourceName;
- m.sourceLine = msg.sourceLine;
- m.lineNumber = msg.lineNumber;
- m.columnNumber = msg.columnNumber;
- m.category = msg.category;
- m.windowID = msg.outerWindowID;
- m.isScriptError = true;
- m.isWarning = ((msg.flags & Ci.nsIScriptError.warningFlag) === 1);
- m.isException = ((msg.flags & Ci.nsIScriptError.exceptionFlag) === 1);
- m.isStrict = ((msg.flags & Ci.nsIScriptError.strictFlag) === 1);
- }
-
- // expose all props of 'm' as read-only
- let expose = {};
- for (let prop in m)
- expose[prop] = 'r';
- m.__exposedProps__ = expose;
- Object.freeze(m);
-
- this.callback.call(undefined, m);
-
- if (!m.isScriptError && m.message === "SENTINEL")
- Services.console.unregisterListener(this);
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleListener])
-};
-
-function wrapCallback(cb) {
- return function SpecialPowersCallbackWrapper() {
- args = Array.prototype.map.call(arguments, wrapIfUnwrapped);
- return cb.apply(this, args);
- }
-}
-
-function wrapCallbackObject(obj) {
- wrapper = { __exposedProps__: ExposedPropsWaiver };
- for (var i in obj) {
- if (typeof obj[i] == 'function')
- wrapper[i] = wrapCallback(obj[i]);
- else
- wrapper[i] = obj[i];
- }
- return wrapper;
-}
-
-SpecialPowersAPI.prototype = {
-
- /*
- * Privileged object wrapping API
- *
- * Usage:
- * var wrapper = SpecialPowers.wrap(obj);
- * wrapper.privilegedMethod(); wrapper.privilegedProperty;
- * obj === SpecialPowers.unwrap(wrapper);
- *
- * These functions provide transparent access to privileged objects using
- * various pieces of deep SpiderMagic. Conceptually, a wrapper is just an
- * object containing a reference to the underlying object, where all method
- * calls and property accesses are transparently performed with the System
- * Principal. Moreover, objects obtained from the wrapper (including properties
- * and method return values) are wrapped automatically. Thus, after a single
- * call to SpecialPowers.wrap(), the wrapper layer is transitively maintained.
- *
- * Known Issues:
- *
- * - The wrapping function does not preserve identity, so
- * SpecialPowers.wrap(foo) !== SpecialPowers.wrap(foo). See bug 718543.
- *
- * - The wrapper cannot see expando properties on unprivileged DOM objects.
- * That is to say, the wrapper uses Xray delegation.
- *
- * - The wrapper sometimes guesses certain ES5 attributes for returned
- * properties. This is explained in a comment in the wrapper code above,
- * and shouldn't be a problem.
- */
- wrap: wrapIfUnwrapped,
- unwrap: unwrapIfWrapped,
- isWrapper: isWrapper,
-
- /*
- * When content needs to pass a callback or a callback object to an API
- * accessed over SpecialPowers, that API may sometimes receive arguments for
- * whom it is forbidden to create a wrapper in content scopes. As such, we
- * need a layer to wrap the values in SpecialPowers wrappers before they ever
- * reach content.
- */
- wrapCallback: wrapCallback,
- wrapCallbackObject: wrapCallbackObject,
-
- /*
- * Create blank privileged objects to use as out-params for privileged functions.
- */
- createBlankObject: function () {
- var obj = new Object;
- obj.__exposedProps__ = ExposedPropsWaiver;
- return obj;
- },
-
- /*
- * Because SpecialPowers wrappers don't preserve identity, comparing with ==
- * can be hazardous. Sometimes we can just unwrap to compare, but sometimes
- * wrapping the underlying object into a content scope is forbidden. This
- * function strips any wrappers if they exist and compare the underlying
- * values.
- */
- compare: function(a, b) {
- return unwrapIfWrapped(a) === unwrapIfWrapped(b);
- },
-
- get MockFilePicker() {
- return MockFilePicker
- },
-
- get MockColorPicker() {
- return MockColorPicker
- },
-
- get MockPermissionPrompt() {
- return MockPermissionPrompt
- },
-
- loadChromeScript: function (url) {
- // Create a unique id for this chrome script
- let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator);
- let id = uuidGenerator.generateUUID().toString();
-
- // Tells chrome code to evaluate this chrome script
- this._sendSyncMessage("SPLoadChromeScript",
- { url: url, id: id });
-
- // Returns a MessageManager like API in order to be
- // able to communicate with this chrome script
- let listeners = [];
- let chromeScript = {
- addMessageListener: (name, listener) => {
- listeners.push({ name: name, listener: listener });
- },
-
- removeMessageListener: (name, listener) => {
- listeners = listeners.filter(
- o => (o.name != name || o.listener != listener)
- );
- },
-
- sendAsyncMessage: (name, message) => {
- this._sendSyncMessage("SPChromeScriptMessage",
- { id: id, name: name, message: message });
- },
-
- destroy: () => {
- listeners = [];
- this._removeMessageListener("SPChromeScriptMessage", chromeScript);
- this._removeMessageListener("SPChromeScriptAssert", chromeScript);
- },
-
- receiveMessage: (aMessage) => {
- let messageId = aMessage.json.id;
- let name = aMessage.json.name;
- let message = aMessage.json.message;
- // Ignore message from other chrome script
- if (messageId != id)
- return;
-
- if (aMessage.name == "SPChromeScriptMessage") {
- listeners.filter(o => (o.name == name))
- .forEach(o => o.listener(this.wrap(message)));
- } else if (aMessage.name == "SPChromeScriptAssert") {
- assert(aMessage.json);
- }
- }
- };
- this._addMessageListener("SPChromeScriptMessage", chromeScript);
- this._addMessageListener("SPChromeScriptAssert", chromeScript);
-
- let assert = json => {
- // An assertion has been done in a mochitest chrome script
- let {url, err, message, stack} = json;
-
- // Try to fetch a test runner from the mochitest
- // in order to properly log these assertions and notify
- // all usefull log observers
- let window = this.window.get();
- let parentRunner, repr = function (o) o;
- if (window) {
- window = window.wrappedJSObject;
- parentRunner = window.TestRunner;
- if (window.repr) {
- repr = window.repr;
- }
- }
-
- // Craft a mochitest-like report string
- var resultString = err ? "TEST-UNEXPECTED-FAIL" : "TEST-PASS";
- var diagnostic =
- message ? message :
- ("assertion @ " + stack.filename + ":" + stack.lineNumber);
- if (err) {
- diagnostic +=
- " - got " + repr(err.actual) +
- ", expected " + repr(err.expected) +
- " (operator " + err.operator + ")";
- }
- var msg = [resultString, url, diagnostic].join(" | ");
- if (parentRunner) {
- if (err) {
- parentRunner.addFailedTest(url);
- parentRunner.error(msg);
- } else {
- parentRunner.log(msg);
- }
- } else {
- // When we are running only a single mochitest, there is no test runner
- dump(msg + "\n");
- }
- };
-
- return this.wrap(chromeScript);
- },
-
- get Services() {
- return wrapPrivileged(Services);
- },
-
- /*
- * In general, any Components object created for unprivileged scopes is
- * neutered (it implements nsIXPCComponentsBase, but not nsIXPCComponents).
- * We override this in certain legacy automation configurations (see the
- * implementation of getRawComponents() above), but don't want to support
- * it in cases where it isn't already required.
- *
- * In scopes with neutered Components, we don't have a natural referent for
- * things like SpecialPowers.Cc. So in those cases, we fall back to the
- * Components object from the SpecialPowers scope. This doesn't quite behave
- * the same way (in particular, SpecialPowers.Cc[foo].createInstance() will
- * create an instance in the SpecialPowers scope), but SpecialPowers wrapping
- * is already a YMMV / Whatever-It-Takes-To-Get-TBPL-Green sort of thing.
- *
- * It probably wouldn't be too much work to just make SpecialPowers.Components
- * unconditionally point to the Components object in the SpecialPowers scope.
- * Try will tell what needs to be fixed up.
- */
- getFullComponents: function() {
- return typeof this.Components.classes == 'object' ? this.Components
- : Components;
- },
-
- /*
- * Convenient shortcuts to the standard Components abbreviations. Note that
- * we don't SpecialPowers-wrap Components.interfaces, because it's available
- * to untrusted content, and wrapping it confuses QI and identity checks.
- */
- get Cc() { return wrapPrivileged(this.getFullComponents()).classes; },
- get Ci() { return this.Components.interfaces; },
- get Cu() { return wrapPrivileged(this.getFullComponents()).utils; },
- get Cr() { return wrapPrivileged(this.Components).results; },
-
- /*
- * SpecialPowers.getRawComponents() allows content to get a reference to a
- * naked (and, in certain automation configurations, privileged) Components
- * object for its scope.
- *
- * SpecialPowers.getRawComponents(window) is defined as the global property
- * window.SpecialPowers.Components for convenience.
- */
- getRawComponents: getRawComponents,
-
- getDOMWindowUtils: function(aWindow) {
- if (aWindow == this.window.get() && this.DOMWindowUtils != null)
- return this.DOMWindowUtils;
-
- return bindDOMWindowUtils(aWindow);
- },
-
- removeExpectedCrashDumpFiles: function(aExpectingProcessCrash) {
- var success = true;
- if (aExpectingProcessCrash) {
- var message = {
- op: "delete-crash-dump-files",
- filenames: this._encounteredCrashDumpFiles
- };
- if (!this._sendSyncMessage("SPProcessCrashService", message)[0]) {
- success = false;
- }
- }
- this._encounteredCrashDumpFiles.length = 0;
- return success;
- },
-
- findUnexpectedCrashDumpFiles: function() {
- var self = this;
- var message = {
- op: "find-crash-dump-files",
- crashDumpFilesToIgnore: this._unexpectedCrashDumpFiles
- };
- var crashDumpFiles = this._sendSyncMessage("SPProcessCrashService", message)[0];
- crashDumpFiles.forEach(function(aFilename) {
- self._unexpectedCrashDumpFiles[aFilename] = true;
- });
- return crashDumpFiles;
- },
-
- _delayCallbackTwice: function(callback) {
- function delayedCallback() {
- function delayAgain() {
- content.window.setTimeout(callback, 0);
- }
- content.window.setTimeout(delayAgain, 0);
- }
- return delayedCallback;
- },
-
- /* apply permissions to the system and when the test case is finished (SimpleTest.finish())
- we will revert the permission back to the original.
-
- inPermissions is an array of objects where each object has a type, action, context, ex:
- [{'type': 'SystemXHR', 'allow': 1, 'context': document},
- {'type': 'SystemXHR', 'allow': Ci.nsIPermissionManager.PROMPT_ACTION, 'context': document}]
-
- Allow can be a boolean value of true/false or ALLOW_ACTION/DENY_ACTION/PROMPT_ACTION/UNKNOWN_ACTION
- */
- pushPermissions: function(inPermissions, callback) {
- var pendingPermissions = [];
- var cleanupPermissions = [];
-
- for (var p in inPermissions) {
- var permission = inPermissions[p];
- var originalValue = Ci.nsIPermissionManager.UNKNOWN_ACTION;
- if (this.testPermission(permission.type, Ci.nsIPermissionManager.ALLOW_ACTION, permission.context)) {
- originalValue = Ci.nsIPermissionManager.ALLOW_ACTION;
- } else if (this.testPermission(permission.type, Ci.nsIPermissionManager.DENY_ACTION, permission.context)) {
- originalValue = Ci.nsIPermissionManager.DENY_ACTION;
- } else if (this.testPermission(permission.type, Ci.nsIPermissionManager.PROMPT_ACTION, permission.context)) {
- originalValue = Ci.nsIPermissionManager.PROMPT_ACTION;
- } else if (this.testPermission(permission.type, Ci.nsICookiePermission.ACCESS_SESSION, permission.context)) {
- originalValue = Ci.nsICookiePermission.ACCESS_SESSION;
- } else if (this.testPermission(permission.type, Ci.nsICookiePermission.ACCESS_ALLOW_FIRST_PARTY_ONLY, permission.context)) {
- originalValue = Ci.nsICookiePermission.ACCESS_ALLOW_FIRST_PARTY_ONLY;
- } else if (this.testPermission(permission.type, Ci.nsICookiePermission.ACCESS_LIMIT_THIRD_PARTY, permission.context)) {
- originalValue = Ci.nsICookiePermission.ACCESS_LIMIT_THIRD_PARTY;
- }
-
- let [url, appId, isInBrowserElement] = this._getInfoFromPermissionArg(permission.context);
-
- let perm;
- if (typeof permission.allow !== 'boolean') {
- perm = permission.allow;
- } else {
- perm = permission.allow ? Ci.nsIPermissionManager.ALLOW_ACTION
- : Ci.nsIPermissionManager.DENY_ACTION;
- }
-
- if (permission.remove == true)
- perm = Ci.nsIPermissionManager.UNKNOWN_ACTION;
-
- if (originalValue == perm) {
- continue;
- }
-
- var todo = {'op': 'add', 'type': permission.type, 'permission': perm, 'value': perm, 'url': url, 'appId': appId, 'isInBrowserElement': isInBrowserElement};
- if (permission.remove == true)
- todo.op = 'remove';
-
- pendingPermissions.push(todo);
-
- /* Push original permissions value or clear into cleanup array */
- var cleanupTodo = {'op': 'add', 'type': permission.type, 'permission': perm, 'value': perm, 'url': url, 'appId': appId, 'isInBrowserElement': isInBrowserElement};
- if (originalValue == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
- cleanupTodo.op = 'remove';
- } else {
- cleanupTodo.value = originalValue;
- cleanupTodo.permission = originalValue;
- }
- cleanupPermissions.push(cleanupTodo);
- }
-
- if (pendingPermissions.length > 0) {
- // The callback needs to be delayed twice. One delay is because the pref
- // service doesn't guarantee the order it calls its observers in, so it
- // may notify the observer holding the callback before the other
- // observers have been notified and given a chance to make the changes
- // that the callback checks for. The second delay is because pref
- // observers often defer making their changes by posting an event to the
- // event loop.
- this._permissionsUndoStack.push(cleanupPermissions);
- this._pendingPermissions.push([pendingPermissions,
- this._delayCallbackTwice(callback)]);
- this._applyPermissions();
- } else {
- content.window.setTimeout(callback, 0);
- }
- },
-
- popPermissions: function(callback) {
- if (this._permissionsUndoStack.length > 0) {
- // See pushPermissions comment regarding delay.
- let cb = callback ? this._delayCallbackTwice(callback) : null;
- /* Each pop from the stack will yield an object {op/type/permission/value/url/appid/isInBrowserElement} or null */
- this._pendingPermissions.push([this._permissionsUndoStack.pop(), cb]);
- this._applyPermissions();
- } else {
- content.window.setTimeout(callback, 0);
- }
- },
-
- flushPermissions: function(callback) {
- while (this._permissionsUndoStack.length > 1)
- this.popPermissions(null);
-
- this.popPermissions(callback);
- },
-
-
- _permissionObserver: {
- _lastPermission: {},
- _callBack: null,
- _nextCallback: null,
-
- observe: function (aSubject, aTopic, aData)
- {
- if (aTopic == "perm-changed") {
- var permission = aSubject.QueryInterface(Ci.nsIPermission);
- if (permission.type == this._lastPermission.type) {
- var os = Components.classes["@mozilla.org/observer-service;1"]
- .getService(Components.interfaces.nsIObserverService);
- os.removeObserver(this, "perm-changed");
- content.window.setTimeout(this._callback, 0);
- content.window.setTimeout(this._nextCallback, 0);
- }
- }
- }
- },
-
- /*
- Iterate through one atomic set of permissions actions and perform allow/deny as appropriate.
- All actions performed must modify the relevant permission.
- */
- _applyPermissions: function() {
- if (this._applyingPermissions || this._pendingPermissions.length <= 0) {
- return;
- }
-
- /* Set lock and get prefs from the _pendingPrefs queue */
- this._applyingPermissions = true;
- var transaction = this._pendingPermissions.shift();
- var pendingActions = transaction[0];
- var callback = transaction[1];
- var lastPermission = pendingActions[pendingActions.length-1];
-
- var self = this;
- var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
- this._permissionObserver._lastPermission = lastPermission;
- this._permissionObserver._callback = callback;
- this._permissionObserver._nextCallback = function () {
- self._applyingPermissions = false;
- // Now apply any permissions that may have been queued while we were applying
- self._applyPermissions();
- }
-
- os.addObserver(this._permissionObserver, "perm-changed", false);
-
- for (var idx in pendingActions) {
- var perm = pendingActions[idx];
- this._sendSyncMessage('SPPermissionManager', perm)[0];
- }
- },
-
- /*
- * Take in a list of pref changes to make, and invoke |callback| once those
- * changes have taken effect. When the test finishes, these changes are
- * reverted.
- *
- * |inPrefs| must be an object with up to two properties: "set" and "clear".
- * pushPrefEnv will set prefs as indicated in |inPrefs.set| and will unset
- * the prefs indicated in |inPrefs.clear|.
- *
- * For example, you might pass |inPrefs| as:
- *
- * inPrefs = {'set': [['foo.bar', 2], ['magic.pref', 'baz']],
- * 'clear': [['clear.this'], ['also.this']] };
- *
- * Notice that |set| and |clear| are both an array of arrays. In |set|, each
- * of the inner arrays must have the form [pref_name, value] or [pref_name,
- * value, iid]. (The latter form is used for prefs with "complex" values.)
- *
- * In |clear|, each inner array should have the form [pref_name].
- *
- * If you set the same pref more than once (or both set and clear a pref),
- * the behavior of this method is undefined.
- *
- * (Implementation note: _prefEnvUndoStack is a stack of values to revert to,
- * not values which have been set!)
- *
- * TODO: complex values for original cleanup?
- *
- */
- pushPrefEnv: function(inPrefs, callback) {
- var prefs = Components.classes["@mozilla.org/preferences-service;1"].
- getService(Components.interfaces.nsIPrefBranch);
-
- var pref_string = [];
- pref_string[prefs.PREF_INT] = "INT";
- pref_string[prefs.PREF_BOOL] = "BOOL";
- pref_string[prefs.PREF_STRING] = "CHAR";
-
- var pendingActions = [];
- var cleanupActions = [];
-
- for (var action in inPrefs) { /* set|clear */
- for (var idx in inPrefs[action]) {
- var aPref = inPrefs[action][idx];
- var prefName = aPref[0];
- var prefValue = null;
- var prefIid = null;
- var prefType = prefs.PREF_INVALID;
- var originalValue = null;
-
- if (aPref.length == 3) {
- prefValue = aPref[1];
- prefIid = aPref[2];
- } else if (aPref.length == 2) {
- prefValue = aPref[1];
- }
-
- /* If pref is not found or invalid it doesn't exist. */
- if (prefs.getPrefType(prefName) != prefs.PREF_INVALID) {
- prefType = pref_string[prefs.getPrefType(prefName)];
- if ((prefs.prefHasUserValue(prefName) && action == 'clear') ||
- (action == 'set'))
- originalValue = this._getPref(prefName, prefType);
- } else if (action == 'set') {
- /* prefName doesn't exist, so 'clear' is pointless */
- if (aPref.length == 3) {
- prefType = "COMPLEX";
- } else if (aPref.length == 2) {
- if (typeof(prefValue) == "boolean")
- prefType = "BOOL";
- else if (typeof(prefValue) == "number")
- prefType = "INT";
- else if (typeof(prefValue) == "string")
- prefType = "CHAR";
- }
- }
-
- /* PREF_INVALID: A non existing pref which we are clearing or invalid values for a set */
- if (prefType == prefs.PREF_INVALID)
- continue;
-
- /* We are not going to set a pref if the value is the same */
- if (originalValue == prefValue)
- continue;
-
- pendingActions.push({'action': action, 'type': prefType, 'name': prefName, 'value': prefValue, 'Iid': prefIid});
-
- /* Push original preference value or clear into cleanup array */
- var cleanupTodo = {'action': action, 'type': prefType, 'name': prefName, 'value': originalValue, 'Iid': prefIid};
- if (originalValue == null) {
- cleanupTodo.action = 'clear';
- } else {
- cleanupTodo.action = 'set';
- }
- cleanupActions.push(cleanupTodo);
- }
- }
-
- if (pendingActions.length > 0) {
- // The callback needs to be delayed twice. One delay is because the pref
- // service doesn't guarantee the order it calls its observers in, so it
- // may notify the observer holding the callback before the other
- // observers have been notified and given a chance to make the changes
- // that the callback checks for. The second delay is because pref
- // observers often defer making their changes by posting an event to the
- // event loop.
- this._prefEnvUndoStack.push(cleanupActions);
- this._pendingPrefs.push([pendingActions,
- this._delayCallbackTwice(callback)]);
- this._applyPrefs();
- } else {
- content.window.setTimeout(callback, 0);
- }
- },
-
- popPrefEnv: function(callback) {
- if (this._prefEnvUndoStack.length > 0) {
- // See pushPrefEnv comment regarding delay.
- let cb = callback ? this._delayCallbackTwice(callback) : null;
- /* Each pop will have a valid block of preferences */
- this._pendingPrefs.push([this._prefEnvUndoStack.pop(), cb]);
- this._applyPrefs();
- } else {
- content.window.setTimeout(callback, 0);
- }
- },
-
- flushPrefEnv: function(callback) {
- while (this._prefEnvUndoStack.length > 1)
- this.popPrefEnv(null);
-
- this.popPrefEnv(callback);
- },
-
- /*
- Iterate through one atomic set of pref actions and perform sets/clears as appropriate.
- All actions performed must modify the relevant pref.
- */
- _applyPrefs: function() {
- if (this._applyingPrefs || this._pendingPrefs.length <= 0) {
- return;
- }
-
- /* Set lock and get prefs from the _pendingPrefs queue */
- this._applyingPrefs = true;
- var transaction = this._pendingPrefs.shift();
- var pendingActions = transaction[0];
- var callback = transaction[1];
-
- var lastPref = pendingActions[pendingActions.length-1];
-
- var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
- var self = this;
- pb.addObserver(lastPref.name, function prefObs(subject, topic, data) {
- pb.removeObserver(lastPref.name, prefObs);
-
- content.window.setTimeout(callback, 0);
- content.window.setTimeout(function () {
- self._applyingPrefs = false;
- // Now apply any prefs that may have been queued while we were applying
- self._applyPrefs();
- }, 0);
- }, false);
-
- for (var idx in pendingActions) {
- var pref = pendingActions[idx];
- if (pref.action == 'set') {
- this._setPref(pref.name, pref.type, pref.value, pref.Iid);
- } else if (pref.action == 'clear') {
- this.clearUserPref(pref.name);
- }
- }
- },
-
- // Disables the app install prompt for the duration of this test. There is
- // no need to re-enable the prompt at the end of the test.
- //
- // The provided callback is invoked once the prompt is disabled.
- autoConfirmAppInstall: function(cb) {
- this.pushPrefEnv({set: [['dom.mozApps.auto_confirm_install', true]]}, cb);
- },
-
- // Allow tests to disable the per platform app validity checks so we can
- // test higher level WebApp functionality without full platform support.
- setAllAppsLaunchable: function(launchable) {
- var message = {
- op: "set-launchable",
- launchable: launchable
- };
- return this._sendSyncMessage("SPWebAppService", message);
- },
-
- _proxiedObservers: {
- "specialpowers-http-notify-request": function(aMessage) {
- let uri = aMessage.json.uri;
- Services.obs.notifyObservers(null, "specialpowers-http-notify-request", uri);
- },
- },
-
- _addObserverProxy: function(notification) {
- if (notification in this._proxiedObservers) {
- this._addMessageListener(notification, this._proxiedObservers[notification]);
- }
- },
-
- _removeObserverProxy: function(notification) {
- if (notification in this._proxiedObservers) {
- this._removeMessageListener(notification, this._proxiedObservers[notification]);
- }
- },
-
- addObserver: function(obs, notification, weak) {
- this._addObserverProxy(notification);
- if (typeof obs == 'object' && obs.observe.name != 'SpecialPowersCallbackWrapper')
- obs.observe = wrapCallback(obs.observe);
- var obsvc = Cc['@mozilla.org/observer-service;1']
- .getService(Ci.nsIObserverService);
- obsvc.addObserver(obs, notification, weak);
- },
- removeObserver: function(obs, notification) {
- this._removeObserverProxy(notification);
- var obsvc = Cc['@mozilla.org/observer-service;1']
- .getService(Ci.nsIObserverService);
- obsvc.removeObserver(obs, notification);
- },
- notifyObservers: function(subject, topic, data) {
- var obsvc = Cc['@mozilla.org/observer-service;1']
- .getService(Ci.nsIObserverService);
- obsvc.notifyObservers(subject, topic, data);
- },
-
- can_QI: function(obj) {
- return obj.QueryInterface !== undefined;
- },
- do_QueryInterface: function(obj, iface) {
- return obj.QueryInterface(Ci[iface]);
- },
-
- call_Instanceof: function (obj1, obj2) {
- obj1=unwrapIfWrapped(obj1);
- obj2=unwrapIfWrapped(obj2);
- return obj1 instanceof obj2;
- },
-
- // Returns a privileged getter from an object. GetOwnPropertyDescriptor does
- // not work here because xray wrappers don't properly implement it.
- //
- // This terribleness is used by content/base/test/test_object.html because
- //