Bug 1037235 - toolkit/loader doesn't check module compatibility r=Mossop

This commit is contained in:
Erik Vold 2014-09-09 18:33:55 -07:00
parent d04483214d
commit b4c44b6d6e
39 changed files with 242 additions and 127 deletions

View File

@ -11,12 +11,15 @@
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
DIRS += ["source/modules/system"]
EXTRA_JS_MODULES.sdk += [
'source/app-extension/bootstrap.js',
]
EXTRA_JS_MODULES.sdk.system += [
'source/modules/system/Startup.js',
'source/modules/system/XulApp.js',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk":
EXTRA_JS_MODULES.commonjs.method.test += [
'source/lib/method/test/browser.js',

View File

@ -14,74 +14,25 @@ module.metadata = {
require('chrome') // Otherwise CFX will complain about Components
require('toolkit/loader') // Otherwise CFX will stip out loader.js
require('sdk/addon/runner') // Otherwise CFX will stip out addon/runner.js
require('sdk/system/xul-app') // Otherwise CFX will stip out sdk/system/xul-app
*/
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
const {
incompatibility
} = Cu.import("resource://gre/modules/sdk/system/XulApp.js", {}).XulApp;
// `loadSandbox` is exposed by bootstrap.js
const loaderURI = module.uri.replace("sdk/loader/cuddlefish.js",
"toolkit/loader.js");
const xulappURI = module.uri.replace("loader/cuddlefish.js",
"system/xul-app.js");
// We need to keep a reference to the sandbox in order to unload it in
// bootstrap.js
const loaderSandbox = loadSandbox(loaderURI);
const loaderModule = loaderSandbox.exports;
const xulappSandbox = loadSandbox(xulappURI);
const xulappModule = xulappSandbox.exports;
const { override, load } = loaderModule;
/**
* Ensure the current application satisfied the requirements specified in the
* module given. If not, an exception related to the incompatibility is
* returned; `null` otherwise.
*
* @param {Object} module
* The module to check
* @returns {Error}
*/
function incompatibility(module) {
let { metadata, id } = module;
// if metadata or engines are not specified we assume compatibility is not
// an issue.
if (!metadata || !("engines" in metadata))
return null;
let { engines } = metadata;
if (engines === null || typeof(engines) !== "object")
return new Error("Malformed engines' property in metadata");
let applications = Object.keys(engines);
let versionRange;
applications.forEach(function(name) {
if (xulappModule.is(name)) {
versionRange = engines[name];
// Continue iteration. We want to ensure the module doesn't
// contain a typo in the applications' name or some unknown
// application - `is` function throws an exception in that case.
}
});
if (typeof(versionRange) === "string") {
if (xulappModule.satisfiesVersion(versionRange))
return null;
return new Error("Unsupported Application version: The module " + id +
" currently supports only version " + versionRange + " of " +
xulappModule.name + ".");
}
return new Error("Unsupported Application: The module " + id +
" currently supports only " + applications.join(", ") + ".")
}
function CuddlefishLoader(options) {
let { manifest } = options;
@ -90,8 +41,7 @@ function CuddlefishLoader(options) {
// cache to avoid subsequent loads via `require`.
modules: override({
'toolkit/loader': loaderModule,
'sdk/loader/cuddlefish': exports,
'sdk/system/xul-app': xulappModule
'sdk/loader/cuddlefish': exports
}, options.modules),
resolve: function resolve(id, requirer) {
let entry = requirer && requirer in manifest && manifest[requirer];

View File

@ -42,6 +42,9 @@ const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
const { Reflect } = Cu.import("resource://gre/modules/reflect.jsm", {});
const { ConsoleAPI } = Cu.import("resource://gre/modules/devtools/Console.jsm");
const { join: pathJoin, normalize, dirname } = Cu.import("resource://gre/modules/osfile/ospath_unix.jsm");
const {
incompatibility
} = Cu.import("resource://gre/modules/sdk/system/XulApp.js", {}).XulApp;
// Define some shortcuts.
const bind = Function.call.bind(Function.bind);
@ -349,6 +352,12 @@ const load = iced(function load(loader, module) {
});
}
let (error = incompatibility(module)) {
if (error) {
throw error;
}
}
if (module.exports && typeof(module.exports) === 'object')
freeze(module.exports);

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var EXPORTED_SYMBOLS = ["Startup"];
this.EXPORTED_SYMBOLS = ["Startup"];
const { utils: Cu, interfaces: Ci, classes: Cc } = Components;
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
@ -20,10 +20,10 @@ const NAME2TOPIC = {
'Thunderbird': 'mail-startup-done'
};
var Startup = {
var exports = {
initialized: !appStartupSrv.startingUp
};
var exports = Startup;
this.Startup = exports;
let gOnceInitializedDeferred = defer();
exports.onceInitialized = gOnceInitializedDeferred.promise;

View File

@ -3,15 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var EXPORTED_SYMBOLS = ["XulApp"];
this.EXPORTED_SYMBOLS = ["XulApp"];
var { classes: Cc, interfaces: Ci } = Components;
var exports = {};
var XulApp = exports;
this.XulApp = exports;
var appInfo = Cc["@mozilla.org/xre/app-info;1"].
getService(Ci.nsIXULAppInfo);
var appInfo = Cc["@mozilla.org/xre/app-info;1"]
.getService(Ci.nsIXULAppInfo);
var vc = Cc["@mozilla.org/xpcom/version-comparator;1"]
.getService(Ci.nsIVersionComparator);
@ -183,3 +184,51 @@ function satisfiesVersion(version, versionRange) {
});
}
exports.satisfiesVersion = satisfiesVersion;
/**
* Ensure the current application satisfied the requirements specified in the
* module given. If not, an exception related to the incompatibility is
* returned; `null` otherwise.
*
* @param {Object} module
* The module to check
* @returns {Error}
*/
function incompatibility(module) {
let { metadata, id } = module;
// if metadata or engines are not specified we assume compatibility is not
// an issue.
if (!metadata || !("engines" in metadata))
return null;
let { engines } = metadata;
if (engines === null || typeof(engines) !== "object")
return new Error("Malformed engines' property in metadata");
let applications = Object.keys(engines);
let versionRange;
applications.forEach(function(name) {
if (is(name)) {
versionRange = engines[name];
// Continue iteration. We want to ensure the module doesn't
// contain a typo in the applications' name or some unknown
// application - `is` function throws an exception in that case.
}
});
if (typeof(versionRange) === "string") {
if (satisfiesVersion(versionRange))
return null;
return new Error("Unsupported Application version: The module " + id +
" currently supports only version " + versionRange + " of " +
name + ".");
}
return new Error("Unsupported Application: The module " + id +
" currently supports only " + applications.join(", ") + ".")
}
exports.incompatibility = incompatibility;

View File

@ -1,10 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXTRA_JS_MODULES.sdk.system += [
'Startup.js',
'XulApp.js',
]

View File

@ -1,10 +1,10 @@
/* 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';
const { Loader, Require, unload, override } = require('sdk/loader/cuddlefish');
const app = require('sdk/system/xul-app');
const packaging = require('@loader/options');
exports['test loader'] = function(assert) {
@ -44,4 +44,19 @@ exports['test loader'] = function(assert) {
'loader.unload() must call listeners in LIFO order.');
};
require('test').run(exports);
exports['test loader on unsupported modules'] = function(assert) {
let loader = Loader({});
let err = "";
assert.throws(() => {
if (!app.is('Firefox')) {
require('./fixtures/loader/unsupported/firefox');
}
else {
require('./fixtures/loader/unsupported/fennec');
}
}, /^Unsupported Application/, "throws Unsupported Application");
unload(loader);
};
require('sdk/test').run(exports);

View File

@ -1,7 +1,6 @@
/* 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';
let {
@ -11,9 +10,10 @@ let { readURI } = require('sdk/net/url');
let root = module.uri.substr(0, module.uri.lastIndexOf('/'))
// The following adds Debugger constructor to the global namespace.
const { Cu } = require('chrome');
const app = require('sdk/system/xul-app');
const { addDebuggerToGlobal } = Cu.import('resource://gre/modules/jsdebugger.jsm', {});
addDebuggerToGlobal(this);
@ -331,7 +331,7 @@ exports['test console global by default'] = function (assert) {
let uri = root + '/fixtures/loader/globals/';
let loader = Loader({ paths: { '': uri }});
let program = main(loader, 'main');
assert.ok(typeof program.console === 'object', 'global `console` exists');
assert.ok(typeof program.console.log === 'function', 'global `console.log` exists');
@ -374,4 +374,19 @@ exports["test require#resolve"] = function(assert) {
assert.equal(root + "toolkit/loader.js", require.resolve("toolkit/loader"), "correct resolution of sdk module");
};
require('test').run(exports);
exports['test loader on unsupported modules'] = function(assert) {
let loader = Loader({});
let err = "";
assert.throws(() => {
if (!app.is('Firefox')) {
require('./fixtures/loader/unsupported/firefox');
}
else {
require('./fixtures/loader/unsupported/fennec');
}
}, /^Unsupported Application/, "throws Unsupported Application");
unload(loader);
};
require('sdk/test').run(exports);

View File

@ -0,0 +1,16 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
const CC = Components.Constructor;
// We also need a valid nsIXulAppInfo service as Webapps.jsm is querying it
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let require = devtools.require;

View File

@ -7,9 +7,6 @@
// Tests the BezierCanvas API in the CubicBezierWidget module
const Cu = Components.utils;
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let require = devtools.require;
let {CubicBezier, BezierCanvas} = require("devtools/shared/widgets/CubicBezierWidget");
function run_test() {

View File

@ -7,9 +7,6 @@
// Tests the CubicBezier API in the CubicBezierWidget module
const Cu = Components.utils;
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let require = devtools.require;
let {CubicBezier} = require("devtools/shared/widgets/CubicBezierWidget");
function run_test() {

View File

@ -3,7 +3,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const Cu = Components.utils;
let {Loader} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
let loader = new Loader.Loader({

View File

@ -1,5 +1,5 @@
[DEFAULT]
head =
head = head.js
tail =
firefox-appdir = browser

View File

@ -0,0 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
const CC = Components.Constructor;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
Cu.import("resource://gre/modules/devtools/Loader.jsm");

View File

@ -3,8 +3,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const Cu = Components.utils;
Cu.import("resource://gre/modules/devtools/Loader.jsm");
const {parseDeclarations} = devtools.require("devtools/styleinspector/css-parsing-utils");
const TEST_DATA = [

View File

@ -3,8 +3,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const Cu = Components.utils;
Cu.import("resource://gre/modules/devtools/Loader.jsm");
const {parseSingleValue} = devtools.require("devtools/styleinspector/css-parsing-utils");
const TEST_DATA = [

View File

@ -1,5 +1,5 @@
[DEFAULT]
head =
head = head.js
tail =
firefox-appdir = browser

View File

@ -7,13 +7,16 @@
* Test that OS.File can be loaded using the CommonJS loader.
*/
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
let { Loader } = Components.utils.import('resource://gre/modules/commonjs/toolkit/loader.js', {});
function run_test() {
run_next_test();
}
add_task(function*() {
let dataDir = Services.io.newFileURI(do_get_file("test_loader/", true)).spec + "/";
let loader = Loader.Loader({
@ -34,4 +37,3 @@ add_task(function*() {
do_print("Require has worked");
});

View File

@ -3,8 +3,6 @@
"use strict";
let {utils: Cu} = Components;
let SHARED_PATH;
let EXISTING_FILE = do_get_file("xpcshell.ini").path;

View File

@ -11,6 +11,10 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
Cu.import("resource://testing-common/httpd.js");
do_get_profile();

View File

@ -1,5 +1,10 @@
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;
@ -68,4 +73,4 @@ let listener = {
};
let consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.registerListener(listener);
consoleService.registerListener(listener);

View File

@ -7,13 +7,26 @@ const Cu = Components.utils;
const Cr = Components.results;
const CC = Components.Constructor;
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
// We have to setup a profile, otherwise indexed db used by webapps
// will throw random exception when trying to get profile folder
do_get_profile();
// The webapps dir isn't registered on b2g xpcshell tests,
// we have to manually set it to the directory service.
do_get_webappsdir();
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
let gClient, gActor;
function connect(onDone) {
@ -66,21 +79,9 @@ function installTestApp(zipName, appId, onDone) {
};
function setup() {
// We have to setup a profile, otherwise indexed db used by webapps
// will throw random exception when trying to get profile folder
do_get_profile();
// The webapps dir isn't registered on b2g xpcshell tests,
// we have to manually set it to the directory service.
do_get_webappsdir();
// We also need a valid nsIXulAppInfo service as Webapps.jsm is querying it
Components.utils.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
// We have to toggle this flag in order to have apps being listed in getAll
// as only launchable apps are returned
Components.utils.import('resource://gre/modules/Webapps.jsm');
Cu.import('resource://gre/modules/Webapps.jsm');
DOMApplicationRegistry.allAppsLaunchable = true;
// Mock WebappOSUtils

View File

@ -0,0 +1,11 @@
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});

View File

@ -3,8 +3,6 @@
"use strict";
const Cu = Components.utils;
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
Services.prefs.setBoolPref("devtools.discovery.log", true);
@ -12,8 +10,6 @@ do_register_cleanup(() => {
Services.prefs.clearUserPref("devtools.discovery.log");
});
const { devtools } =
Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { Promise: promise } =
Cu.import("resource://gre/modules/Promise.jsm", {});
const { require } = devtools;

View File

@ -1,5 +1,5 @@
[DEFAULT]
head =
head = head.js
tail =
[test_discovery.js]

View File

@ -9,7 +9,12 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;
var beautify = require("devtools/jsbeautify");

View File

@ -4,6 +4,10 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;

View File

@ -0,0 +1,11 @@
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});

View File

@ -6,8 +6,6 @@
* Test encoding a simple message.
*/
const { utils: Cu } = Components;
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;
const QR = require("devtools/toolkit/qrcode/index");

View File

@ -1,5 +1,5 @@
[DEFAULT]
head =
head = head.js
tail =
[test_encode.js]

View File

@ -806,7 +806,8 @@ WebappsActor.prototype = {
let deferred = promise.defer();
if (Services.appinfo.ID &&
Services.appinfo.ID != "{3c2e2abc-06d4-11e1-ac3b-374f68613e61}") {
Services.appinfo.ID != "{3c2e2abc-06d4-11e1-ac3b-374f68613e61}" &&
Services.appinfo.ID != "xpcshell@tests.mozilla.org") {
return { error: "notSupported",
message: "Not B2G. Can't launch app." };
}

View File

@ -7,6 +7,10 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { worker } = Cu.import("resource://gre/modules/devtools/worker-loader.js", {})
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});

View File

@ -1,4 +1,11 @@
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;

View File

@ -4,6 +4,10 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
Cu.import("resource://gre/modules/devtools/Loader.jsm");
Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm");
@ -41,3 +45,4 @@ let listener = {
let consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.registerListener(listener);

View File

@ -8,6 +8,10 @@ const Cu = Components.utils;
const Cr = Components.results;
const CC = Components.Constructor;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } =
Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { Promise: promise } =

View File

@ -0,0 +1,11 @@
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
// We also need a valid nsIXulAppInfo
Cu.import("resource://testing-common/AppInfo.jsm");
updateAppInfo();
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});

View File

@ -3,7 +3,6 @@
// http://creativecommons.org/publicdomain/zero/1.0/
"use strict";
const { devtools } = Components.utils.import("resource://gre/modules/devtools/Loader.jsm", {});
let JSPropertyProvider = devtools.require("devtools/toolkit/webconsole/utils").JSPropertyProvider;
Components.utils.import("resource://gre/modules/jsdebugger.jsm");

View File

@ -2,8 +2,6 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const Cu = Components.utils;
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
Object.defineProperty(this, "NetworkHelper", {
get: function() {

View File

@ -1,5 +1,5 @@
[DEFAULT]
head =
head = head.js
tail =
support-files =