Bug 1446585: Remove support for resource entries in bootstrapped chrome.manifest files. r=aswan,MattN,k88hudson

MozReview-Commit-ID: EjymzU6koYX

--HG--
extra : rebase_source : 7b4fc250b5be0f2c16f3797eafb61e7c3955309d
This commit is contained in:
Kris Maglione 2018-03-16 20:18:46 -07:00
parent 883c7e5fce
commit 5edc701bb6
23 changed files with 95 additions and 432 deletions

View File

@ -9,6 +9,12 @@ Cu.importGlobalProperties(["fetch"]);
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "resProto",
"@mozilla.org/network/protocol;1?name=resource",
"nsISubstitutingProtocolHandler");
const RESOURCE_HOST = "activity-stream";
const BROWSER_READY_NOTIFICATION = "sessionstore-windows-restored";
const RESOURCE_BASE = "resource://activity-stream";
@ -148,6 +154,10 @@ function observe(subject, topic, data) {
this.install = function install(data, reason) {};
this.startup = function startup(data, reason) {
resProto.setSubstitutionWithFlags(RESOURCE_HOST,
Services.io.newURI("chrome/content/", null, data.resourceURI),
resProto.ALLOW_CONTENT_ACCESS);
// Cache startup data which contains stuff like the version number, etc.
// so we can use it when we init
startupData = data;
@ -163,6 +173,8 @@ this.startup = function startup(data, reason) {
};
this.shutdown = function shutdown(data, reason) {
resProto.setSubstitution(RESOURCE_HOST, null);
// Uninitialize Activity Stream
startupData = null;
startupReason = null;

View File

@ -20,6 +20,12 @@ ChromeUtils.defineModuleGetter(this, "formAutofillParent",
ChromeUtils.defineModuleGetter(this, "FormAutofillUtils",
"resource://formautofill/FormAutofillUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "resProto",
"@mozilla.org/network/protocol;1?name=resource",
"nsISubstitutingProtocolHandler");
const RESOURCE_HOST = "formautofill";
function insertStyleSheet(domWindow, url) {
let doc = domWindow.document;
let styleSheetAttr = `href="${url}" type="text/css"`;
@ -80,6 +86,9 @@ function startup(data) {
return;
}
resProto.setSubstitution(RESOURCE_HOST,
Services.io.newURI("chrome/res/", null, data.resourceURI));
if (data.hasOwnProperty("instanceID") && data.instanceID) {
if (AddonManagerPrivate.isDBLoaded()) {
addUpgradeListener(data.instanceID);
@ -121,6 +130,8 @@ function startup(data) {
}
function shutdown() {
resProto.setSubstitution(RESOURCE_HOST, null);
Services.mm.removeMessageListener("FormAutoComplete:MaybeOpenPopup", onMaybeOpenPopup);
let enumerator = Services.wm.getEnumerator("navigator:browser");

View File

@ -22,6 +22,10 @@ ChromeUtils.defineModuleGetter(this, "DownloadPaths",
ChromeUtils.defineModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "resProto",
"@mozilla.org/network/protocol;1?name=resource",
"nsISubstitutingProtocolHandler");
do_get_profile();
// ================================================
@ -50,6 +54,9 @@ if (!extensionDir.exists()) {
}
Components.manager.addBootstrappedManifestLocation(extensionDir);
let resURI = Services.io.newURI("chrome/res/", null, Services.io.newURI(bootstrapURI));
resProto.setSubstitution("formautofill", resURI);
// Returns a reference to a temporary file that is guaranteed not to exist and
// is cleaned up later. See FileTestUtils.getTempFile for details.
function getTempFile(leafName) {

View File

@ -13,6 +13,12 @@ XPCOMUtils.defineLazyModuleGetters(this, {
UIState: "resource://services-sync/UIState.jsm",
});
XPCOMUtils.defineLazyServiceGetter(this, "resProto",
"@mozilla.org/network/protocol;1?name=resource",
"nsISubstitutingProtocolHandler");
const RESOURCE_HOST = "onboarding";
const {PREF_STRING, PREF_BOOL, PREF_INT} = Ci.nsIPrefBranch;
const BROWSER_READY_NOTIFICATION = "browser-delayed-startup-finished";
@ -197,6 +203,10 @@ function install(aData, aReason) {}
function uninstall(aData, aReason) {}
function startup(aData, aReason) {
resProto.setSubstitutionWithFlags(RESOURCE_HOST,
Services.io.newURI("chrome/content/", null, aData.resourceURI),
resProto.ALLOW_CONTENT_ACCESS);
// Cache startup data which contains stuff like the version number, etc.
// so we can use it when we init the telemetry
startupData = aData;
@ -211,6 +221,8 @@ function startup(aData, aReason) {
}
function shutdown(aData, aReason) {
resProto.setSubstitution(RESOURCE_HOST, null);
startupData = null;
// Stop waiting for browser to be ready
if (waitingForBrowserReady) {

View File

@ -9,6 +9,10 @@ ChromeUtils.import("resource://gre/modules/Preferences.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "resProto",
"@mozilla.org/network/protocol;1?name=resource",
"nsISubstitutingProtocolHandler");
// Load our bootstrap extension manifest so we can access our chrome/resource URIs.
// Cargo culted from formautofill system add-on
const EXTENSION_ID = "onboarding@mozilla.org";
@ -16,12 +20,19 @@ let extensionDir = Services.dirsvc.get("GreD", Ci.nsIFile);
extensionDir.append("browser");
extensionDir.append("features");
extensionDir.append(EXTENSION_ID);
let resourceURI;
// If the unpacked extension doesn't exist, use the packed version.
if (!extensionDir.exists()) {
extensionDir.leafName += ".xpi";
resourceURI = "jar:" + Services.io.newFileURI(extensionDir).spec + "!/chrome/content/";
} else {
resourceURI = Services.io.newFileURI(extensionDir).spec + "/chrome/content/";
}
Components.manager.addBootstrappedManifestLocation(extensionDir);
resProto.setSubstitution("onboarding", Services.io.newURI(resourceURI));
const TOURSET_VERSION = 1;
const NEXT_TOURSET_VERSION = 2;
const PREF_TOUR_TYPE = "browser.onboarding.tour-type";

View File

@ -1,151 +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";
var EXPORTED_SYMBOLS = ["ChromeManifestParser"];
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
const MSG_JAR_FLUSH = "AddonJarFlush";
/**
* Sends local and remote notifications to flush a JAR file cache entry
*
* @param aJarFile
* The ZIP/XPI/JAR file as a nsIFile
*/
function flushJarCache(aJarFile) {
Services.obs.notifyObservers(aJarFile, "flush-cache-entry");
Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageBroadcaster)
.broadcastAsyncMessage(MSG_JAR_FLUSH, aJarFile.path);
}
/**
* Parses chrome manifest files.
*/
var ChromeManifestParser = {
/**
* Reads and parses a chrome manifest file located at a specified URI, and all
* secondary manifests it references.
*
* @param aURI
* A nsIURI pointing to a chrome manifest.
* Typically a file: or jar: URI.
* @return Array of objects describing each manifest instruction, in the form:
* { type: instruction-type, baseURI: string-uri, args: [arguments] }
**/
parseSync(aURI) {
function parseLine(aLine) {
let line = aLine.trim();
if (line.length == 0 || line.charAt(0) == "#")
return;
let tokens = line.split(/\s+/);
let type = tokens.shift();
if (type == "manifest") {
let uri = NetUtil.newURI(tokens.shift(), null, aURI);
data = data.concat(this.parseSync(uri));
} else {
data.push({type, baseURI, args: tokens});
}
}
let contents = "";
try {
if (aURI.scheme == "jar")
contents = this._readFromJar(aURI);
else
contents = this._readFromFile(aURI);
} catch (e) {
// Silently fail.
}
if (!contents)
return [];
let baseURI = NetUtil.newURI(".", null, aURI).spec;
let data = [];
let lines = contents.split("\n");
lines.forEach(parseLine.bind(this));
return data;
},
_readFromJar(aURI) {
let data = "";
let entries = [];
let readers = [];
try {
// Deconstrict URI, which can be nested jar: URIs.
let uri = aURI.clone();
while (uri instanceof Ci.nsIJARURI) {
entries.push(uri.JAREntry);
uri = uri.JARFile;
}
// Open the base jar.
let reader = Cc["@mozilla.org/libjar/zip-reader;1"].
createInstance(Ci.nsIZipReader);
reader.open(uri.QueryInterface(Ci.nsIFileURL).file);
readers.push(reader);
// Open the nested jars.
for (let i = entries.length - 1; i > 0; i--) {
let innerReader = Cc["@mozilla.org/libjar/zip-reader;1"].
createInstance(Ci.nsIZipReader);
innerReader.openInner(reader, entries[i]);
readers.push(innerReader);
reader = innerReader;
}
// First entry is the actual file we want to read.
let zis = reader.getInputStream(entries[0]);
data = NetUtil.readInputStreamToString(zis, zis.available());
} finally {
// Close readers in reverse order.
for (let i = readers.length - 1; i >= 0; i--) {
readers[i].close();
flushJarCache(readers[i].file);
}
}
return data;
},
_readFromFile(aURI) {
let file = aURI.QueryInterface(Ci.nsIFileURL).file;
if (!file.exists() || !file.isFile())
return "";
let data = "";
let fis = Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(Ci.nsIFileInputStream);
try {
fis.init(file, -1, -1, false);
data = NetUtil.readInputStreamToString(fis, fis.available());
} finally {
fis.close();
}
return data;
},
/**
* Detects if there were any instructions of a specified type in a given
* chrome manifest.
*
* @param aManifest
* Manifest data, as returned by ChromeManifestParser.parseSync().
* @param aType
* Instruction type to filter by.
* @return True if any matching instructions were found in the manifest.
*/
hasType(aManifest, aType) {
return aManifest.some(entry => entry.type == aType);
}
};

View File

@ -16,7 +16,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
AddonRepository: "resource://gre/modules/addons/AddonRepository.jsm",
AddonSettings: "resource://gre/modules/addons/AddonSettings.jsm",
AppConstants: "resource://gre/modules/AppConstants.jsm",
ChromeManifestParser: "resource://gre/modules/ChromeManifestParser.jsm",
Extension: "resource://gre/modules/Extension.jsm",
Langpack: "resource://gre/modules/Extension.jsm",
LightweightThemeManager: "resource://gre/modules/LightweightThemeManager.jsm",
@ -45,8 +44,6 @@ const {nsIBlocklistService} = Ci;
XPCOMUtils.defineLazyServiceGetters(this, {
Blocklist: ["@mozilla.org/extensions/blocklist;1", "nsIBlocklistService"],
ChromeRegistry: ["@mozilla.org/chrome/chrome-registry;1", "nsIChromeRegistry"],
ResProtocolHandler: ["@mozilla.org/network/protocol;1?name=resource", "nsIResProtocolHandler"],
AddonPolicyService: ["@mozilla.org/addons/policy-service;1", "nsIAddonPolicyService"],
aomStartup: ["@mozilla.org/addons/addon-manager-startup;1", "amIAddonManagerStartup"],
});
@ -1908,66 +1905,6 @@ var XPIProvider = {
}
},
/**
* Resolve a URI back to physical file.
*
* Of course, this works only for URIs pointing to local resources.
*
* @param aURI
* URI to resolve
* @return
* resolved nsIFileURL
*/
_resolveURIToFile(aURI) {
switch (aURI.scheme) {
case "jar":
case "file":
if (aURI instanceof Ci.nsIJARURI) {
return this._resolveURIToFile(aURI.JARFile);
}
return aURI;
case "chrome":
aURI = ChromeRegistry.convertChromeURL(aURI);
return this._resolveURIToFile(aURI);
case "resource":
aURI = Services.io.newURI(ResProtocolHandler.resolveURI(aURI));
return this._resolveURIToFile(aURI);
case "view-source":
aURI = Services.io.newURI(aURI.pathQueryRef);
return this._resolveURIToFile(aURI);
case "about":
if (aURI.spec == "about:blank") {
// Do not attempt to map about:blank
return null;
}
let chan;
try {
chan = NetUtil.newChannel({
uri: aURI,
loadUsingSystemPrincipal: true
});
} catch (ex) {
return null;
}
// Avoid looping
if (chan.URI.equals(aURI)) {
return null;
}
// We want to clone the channel URI to avoid accidentially keeping
// unnecessary references to the channel or implementation details
// around.
return this._resolveURIToFile(chan.URI.clone());
default:
return null;
}
},
/**
* Starts the XPI provider initializes the install locations and prefs.
*
@ -4386,13 +4323,6 @@ var XPIProvider = {
if (CHROME_TYPES.has(aAddon.type) && aMethod == "shutdown" && aReason != BOOTSTRAP_REASONS.APP_SHUTDOWN) {
logger.debug("Removing manifest for " + aFile.path);
Components.manager.removeBootstrappedManifestLocation(aFile);
let manifest = getURIForResourceInFile(aFile, "chrome.manifest");
for (let line of ChromeManifestParser.parseSync(manifest)) {
if (line.type == "resource") {
ResProtocolHandler.setSubstitution(line.args[0], null);
}
}
}
this.setTelemetry(aAddon.id, aMethod + "_MS", new Date() - timeStart);
}

View File

@ -39,7 +39,6 @@ EXTRA_PP_COMPONENTS += [
EXTRA_JS_MODULES += [
'AddonManager.jsm',
'ChromeManifestParser.jsm',
'LightweightThemeManager.jsm',
]

View File

@ -1 +0,0 @@
resource test-addon-1 .

View File

@ -1,24 +0,0 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>addon6@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<!-- Front End MetaData -->
<em:name>Test 6</em:name>
<em:description>Test Description</em:description>
<em:bootstrap>true</em:bootstrap>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>2</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -3,11 +3,18 @@
*/
/* exported startup, shutdown, install, uninstall */
ChromeUtils.import("resource://gre/modules/Services.jsm");
const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"]
.getService(Ci.nsISubstitutingProtocolHandler);
function install(data, reason) {}
function startup(data, reason) {
ChromeUtils.import("resource://gre/modules/Services.jsm");
resProto.setSubstitution("my-addon", data.resourceURI);
Services.ppmm.loadProcessScript(
"resource://my-addon/frame-script.js", false);
}
function shutdown(data, reason) {}
function shutdown(data, reason) {
resProto.setSubstitution("my-addon", null);
}
function uninstall(data, reason) {}

View File

@ -3,11 +3,18 @@
*/
/* exported startup, shutdown, install, uninstall */
ChromeUtils.import("resource://gre/modules/Services.jsm");
const resProto = Cc["@mozilla.org/network/protocol;1?name=resource"]
.getService(Ci.nsISubstitutingProtocolHandler);
function install(data, reason) {}
function startup(data, reason) {
ChromeUtils.import("resource://gre/modules/Services.jsm");
resProto.setSubstitution("my-addon", data.resourceURI);
Services.ppmm.loadProcessScript(
"resource://my-addon/frame-script.js", false);
}
function shutdown(data, reason) {}
function shutdown(data, reason) {
resProto.setSubstitution("my-addon", null);
}
function uninstall(data, reason) {}

View File

@ -10,6 +10,7 @@ function test() {
SpecialPowers.pushPrefEnv({"set": [
["extensions.checkUpdateSecurity", false],
["xpinstall.signatures.required", false]
]});
run_next_test();

View File

@ -1,108 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests ChromeManifestParser.js
ChromeUtils.import("resource://gre/modules/ChromeManifestParser.jsm");
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "2");
startupManager();
installAllFiles([do_get_addon("test_chromemanifest_1"),
do_get_addon("test_chromemanifest_2"),
do_get_addon("test_chromemanifest_3"),
do_get_addon("test_chromemanifest_4")],
function() {
restartManager();
run_test_1();
});
}
function run_test_1() {
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org",
"addon3@tests.mozilla.org",
"addon4@tests.mozilla.org"],
function([a1, a2, a3, a4]) {
// addon1
let a1Uri = a1.getResourceURI("/").spec;
let expected = [
{type: "content", baseURI: a1Uri, args: ["test-addon-1", "chrome/content"]},
{type: "locale", baseURI: a1Uri, args: ["test-addon-1", "en-US", "locale/en-US"]},
{type: "locale", baseURI: a1Uri, args: ["test-addon-1", "fr-FR", "locale/fr-FR"]},
{type: "overlay", baseURI: a1Uri, args: ["chrome://browser/content/browser.xul", "chrome://test-addon-1/content/overlay.xul"]}
];
let manifestURI = a1.getResourceURI("chrome.manifest");
let manifest = ChromeManifestParser.parseSync(manifestURI);
Assert.ok(Array.isArray(manifest));
Assert.equal(manifest.length, expected.length);
for (let i = 0; i < manifest.length; i++) {
Assert.equal(JSON.stringify(manifest[i]), JSON.stringify(expected[i]));
}
// addon2
let a2Uri = a2.getResourceURI("/").spec;
expected = [
{type: "content", baseURI: a2Uri, args: ["test-addon-1", "chrome/content"]},
{type: "locale", baseURI: a2Uri, args: ["test-addon-1", "en-US", "locale/en-US"]},
{type: "locale", baseURI: a2Uri, args: ["test-addon-1", "fr-FR", "locale/fr-FR"]},
{type: "overlay", baseURI: a2Uri, args: ["chrome://browser/content/browser.xul", "chrome://test-addon-1/content/overlay.xul"]},
{type: "binary-component", baseURI: a2Uri, args: ["components/something.so"]}
];
manifestURI = a2.getResourceURI("chrome.manifest");
manifest = ChromeManifestParser.parseSync(manifestURI);
Assert.ok(Array.isArray(manifest));
Assert.equal(manifest.length, expected.length);
for (let i = 0; i < manifest.length; i++) {
Assert.equal(JSON.stringify(manifest[i]), JSON.stringify(expected[i]));
}
// addon3
let a3Uri = a3.getResourceURI("/").spec;
expected = [
{type: "content", baseURI: a3Uri, args: ["test-addon-1", "chrome/content"]},
{type: "locale", baseURI: a3Uri, args: ["test-addon-1", "en-US", "locale/en-US"]},
{type: "locale", baseURI: a3Uri, args: ["test-addon-1", "fr-FR", "locale/fr-FR"]},
{type: "overlay", baseURI: a3Uri, args: ["chrome://browser/content/browser.xul", "chrome://test-addon-1/content/overlay.xul"]},
{type: "binary-component", baseURI: a3Uri, args: ["components/something.so"]},
{type: "locale", baseURI: "jar:" + a3.getResourceURI("/inner.jar").spec + "!/", args: ["test-addon-1", "en-NZ", "locale/en-NZ"]},
];
manifestURI = a3.getResourceURI("chrome.manifest");
manifest = ChromeManifestParser.parseSync(manifestURI);
Assert.ok(Array.isArray(manifest));
Assert.equal(manifest.length, expected.length);
for (let i = 0; i < manifest.length; i++) {
Assert.equal(JSON.stringify(manifest[i]), JSON.stringify(expected[i]));
}
// addon4
let a4Uri = a4.getResourceURI("/").spec;
expected = [
{type: "content", baseURI: a4Uri, args: ["test-addon-1", "chrome/content"]},
{type: "locale", baseURI: a4Uri, args: ["test-addon-1", "en-US", "locale/en-US"]},
{type: "locale", baseURI: a4Uri, args: ["test-addon-1", "fr-FR", "locale/fr-FR"]},
{type: "overlay", baseURI: a4Uri, args: ["chrome://browser/content/browser.xul", "chrome://test-addon-1/content/overlay.xul"]},
{type: "binary-component", baseURI: a4.getResourceURI("components/").spec, args: ["mycomponent.dll"]},
{type: "binary-component", baseURI: a4.getResourceURI("components/other/").spec, args: ["thermalnuclearwar.dll"]}
];
manifestURI = a4.getResourceURI("chrome.manifest");
manifest = ChromeManifestParser.parseSync(manifestURI);
Assert.ok(Array.isArray(manifest));
Assert.equal(manifest.length, expected.length);
for (let i = 0; i < manifest.length; i++) {
Assert.equal(JSON.stringify(manifest[i]), JSON.stringify(expected[i]));
}
executeSoon(do_test_finished);
});
}

View File

@ -1,56 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that resource protocol substitutions are set and unset for bootstrapped add-ons.
const profileDir = gProfD.clone();
profileDir.append("extensions");
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "2");
let resourceProtocol = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
startupManager();
installAllFiles([do_get_addon("test_chromemanifest_6")],
function() {
AddonManager.getAddonByID("addon6@tests.mozilla.org", function(addon) {
Assert.notEqual(addon, null);
Assert.ok(addon.isActive);
Assert.ok(resourceProtocol.hasSubstitution("test-addon-1"));
prepare_test({
"addon6@tests.mozilla.org": [
["onDisabling", false],
"onDisabled"
]
});
Assert.equal(addon.operationsRequiringRestart &
AddonManager.OP_NEEDS_RESTART_DISABLE, 0);
addon.userDisabled = true;
ensure_test_completed();
Assert.ok(!resourceProtocol.hasSubstitution("test-addon-1"));
prepare_test({
"addon6@tests.mozilla.org": [
["onEnabling", false],
"onEnabled"
]
});
Assert.equal(addon.operationsRequiringRestart &
AddonManager.OP_NEEDS_RESTART_ENABLE, 0);
addon.userDisabled = false;
ensure_test_completed();
Assert.ok(resourceProtocol.hasSubstitution("test-addon-1"));
executeSoon(do_test_finished);
});
});
}

View File

@ -118,7 +118,7 @@ function run_test_4() {
gExpectedFile.append("addon2@tests.mozilla.org.xpi");
a2.uninstall();
Assert.equal(gCacheFlushCount, 2);
Assert.equal(gCacheFlushCount, 1);
gExpectedFile = null;
gCacheFlushCount = 0;

View File

@ -20,6 +20,19 @@ const userExtensions = userAppDir.clone();
userExtensions.append(APP_ID);
userExtensions.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
XPCOMUtils.defineLazyServiceGetters(this, {
ChromeRegistry: ["@mozilla.org/chrome/chrome-registry;1", "nsIChromeRegistry"],
});
function hasChromeEntry(package) {
try {
void ChromeRegistry.convertChromeURL(Services.io.newURI(`chrome://${package}/content/`));
return true;
} catch (e) {
return false;
}
}
add_task(async function() {
await promiseWriteInstallRDFToXPI({
id: "langpack-foo@addons.mozilla.org",
@ -33,7 +46,7 @@ add_task(async function() {
name: "Invalid install.rdf extension",
}, userExtensions, undefined, {
"chrome.manifest": `
resource foo-langpack ./
content foo-langpack ./
`,
});
@ -48,30 +61,27 @@ add_task(async function() {
name: "Invalid install.rdf extension",
}, userExtensions, undefined, {
"chrome.manifest": `
resource foo ./
content foo ./
`,
});
const resProto = Services.io.getProtocolHandler("resource");
resProto.QueryInterface(Ci.nsIResProtocolHandler);
equal(resProto.hasSubstitution("foo-langpack"), false,
equal(hasChromeEntry("foo-langpack"), false,
"Should not foo-langpack resource before AOM startup");
equal(resProto.hasSubstitution("foo"), false,
equal(hasChromeEntry("foo"), false,
"Should not foo resource before AOM startup");
await promiseStartupManager();
equal(resProto.hasSubstitution("foo-langpack"), false,
equal(hasChromeEntry("foo-langpack"), false,
"Should not have registered chrome manifest for invalid extension");
equal(resProto.hasSubstitution("foo"), true,
equal(hasChromeEntry("foo"), true,
"Should have registered chrome manifest for valid extension");
await promiseRestartManager();
equal(resProto.hasSubstitution("foo-langpack"), false,
equal(hasChromeEntry("foo-langpack"), false,
"Should still not have registered chrome manifest for invalid extension after restart");
equal(resProto.hasSubstitution("foo"), true,
equal(hasChromeEntry("foo"), true,
"Should still have registered chrome manifest for valid extension after restart");
await promiseShutdownManager();

View File

@ -94,7 +94,6 @@ tags = blocklist
[test_bootstrap.js]
skip-if = true # Bug 1358846 Bug 1365021 Bug 676992
[test_bootstrap_const.js]
[test_bootstrap_resource.js]
[test_bug299716.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"
@ -216,7 +215,6 @@ tags = blocklist
[test_bug953156.js]
[test_checkcompatibility.js]
[test_childprocess.js]
[test_ChromeManifestParser.js]
[test_compatoverrides.js]
[test_corrupt.js]
[test_corrupt_strictcompat.js]

View File

@ -122,7 +122,7 @@ static const ManifestDirective kParsingTable[] = {
nullptr, &nsChromeRegistry::ManifestOverride,
},
{
"resource", 2, false, true, true, true, true,
"resource", 2, false, true, true, false, true,
nullptr, &nsChromeRegistry::ManifestResource,
}
};