diff --git a/toolkit/mozapps/extensions/ChromeManifestParser.jsm b/toolkit/mozapps/extensions/ChromeManifestParser.jsm new file mode 100644 index 00000000000..d3829c30a0e --- /dev/null +++ b/toolkit/mozapps/extensions/ChromeManifestParser.jsm @@ -0,0 +1,192 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Extension Manager. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Blair McBride + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; + +var EXPORTED_SYMBOLS = ["ChromeManifestParser"]; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.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", null); + Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIChromeFrameMessageManager) + .sendAsyncMessage(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: function CMP_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: type, baseURI: 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: function CMP_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: function CMP_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: function CMP_hasType(aManifest, aType) { + return aManifest.some(function(aEntry) { + return aEntry.type == aType; + }); + } +}; diff --git a/toolkit/mozapps/extensions/Makefile.in b/toolkit/mozapps/extensions/Makefile.in index 67f8e48b719..b4b01793f00 100644 --- a/toolkit/mozapps/extensions/Makefile.in +++ b/toolkit/mozapps/extensions/Makefile.in @@ -71,6 +71,7 @@ EXTRA_PP_JS_MODULES = \ $(NULL) EXTRA_JS_MODULES = \ + ChromeManifestParser.jsm \ LightweightThemeManager.jsm \ SpellCheckDictionaryBootstrap.js \ $(NULL) diff --git a/toolkit/mozapps/extensions/XPIProvider.jsm b/toolkit/mozapps/extensions/XPIProvider.jsm index cabda6fea8a..a516d0f8141 100644 --- a/toolkit/mozapps/extensions/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/XPIProvider.jsm @@ -21,6 +21,7 @@ # # Contributor(s): # Dave Townsend +# Blair McBride # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or @@ -48,6 +49,7 @@ var EXPORTED_SYMBOLS = []; Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/AddonManager.jsm"); Components.utils.import("resource://gre/modules/AddonRepository.jsm"); +Components.utils.import("resource://gre/modules/ChromeManifestParser.jsm"); Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm"); Components.utils.import("resource://gre/modules/FileUtils.jsm"); Components.utils.import("resource://gre/modules/NetUtil.jsm"); @@ -122,7 +124,7 @@ const TOOLKIT_ID = "toolkit@mozilla.org"; const BRANCH_REGEXP = /^([^\.]+\.[0-9]+[a-z]*).*/gi; -const DB_SCHEMA = 6; +const DB_SCHEMA = 7; const REQ_VERSION = 2; #ifdef MOZ_COMPATIBILITY_NIGHTLY @@ -146,7 +148,8 @@ const DB_METADATA = ["installDate", "updateDate", "size", "sourceURI", "releaseNotesURI", "applyBackgroundUpdates"]; const DB_BOOL_METADATA = ["visible", "active", "userDisabled", "appDisabled", "pendingUninstall", "bootstrap", "skinnable", - "softDisabled", "foreignInstall"]; + "softDisabled", "foreignInstall", + "hasBinaryComponents"]; const BOOTSTRAP_REASONS = { APP_STARTUP : 1, @@ -850,6 +853,13 @@ function loadManifestFromDir(aDir) { let addon = loadManifestFromRDF(Services.io.newFileURI(file), bis); addon._sourceBundle = aDir.clone().QueryInterface(Ci.nsILocalFile); addon.size = getFileSize(aDir); + + file = aDir.clone(); + file.append("chrome.manifest"); + let chromeManifest = ChromeManifestParser.parseSync(Services.io.newFileURI(file)); + addon.hasBinaryComponents = ChromeManifestParser.hasType(chromeManifest, + "binary-component"); + return addon; } finally { @@ -882,6 +892,16 @@ function loadManifestFromZipReader(aZipReader) { while (entries.hasMore()) addon.size += aZipReader.getEntry(entries.getNext()).realSize; + // Binary components can only be loaded from unpacked addons. + if (addon.unpack) { + uri = buildJarURI(aZipReader.file, "chrome.manifest"); + let chromeManifest = ChromeManifestParser.parseSync(uri); + addon.hasBinaryComponents = ChromeManifestParser.hasType(chromeManifest, + "binary-component"); + } else { + addon.hasBinaryComponents = false; + } + return addon; } finally { @@ -3880,7 +3900,7 @@ const FIELDS_ADDON = "internal_id, id, location, version, type, internalName, " "userDisabled, appDisabled, pendingUninstall, descriptor, " + "installDate, updateDate, applyBackgroundUpdates, bootstrap, " + "skinnable, size, sourceURI, releaseNotesURI, softDisabled, " + - "foreignInstall"; + "foreignInstall, hasBinaryComponents"; /** * A helper function to log an SQL error. @@ -4026,7 +4046,7 @@ var XPIDatabase = { ":descriptor, :installDate, :updateDate, " + ":applyBackgroundUpdates, :bootstrap, :skinnable, " + ":size, :sourceURI, :releaseNotesURI, :softDisabled, " + - ":foreignInstall)", + ":foreignInstall, :hasBinaryComponents)", addAddonMetadata_addon_locale: "INSERT INTO addon_locale VALUES " + "(:internal_id, :name, :locale)", addAddonMetadata_locale: "INSERT INTO locale (name, description, creator, " + @@ -4560,6 +4580,7 @@ var XPIDatabase = { "size INTEGER, sourceURI TEXT, " + "releaseNotesURI TEXT, softDisabled INTEGER, " + "foreignInstall INTEGER, " + + "hasBinaryComponents INTEGER, " + "UNIQUE (id, location)"); this.connection.createTable("targetApplication", "addon_internal_id INTEGER, " + @@ -6910,8 +6931,10 @@ AddonInternal.prototype = { // Only extensions can be compatible by default; themes always use strict // compatibility checking. - if (this.type == "extension" && !AddonManager.strictCompatibility) + if (this.type == "extension" && !AddonManager.strictCompatibility && + !this.hasBinaryComponents) { return true; + } if (!aAppVersion) aAppVersion = Services.appinfo.version; @@ -7128,7 +7151,8 @@ function AddonWrapper(aAddon) { ["id", "version", "type", "isCompatible", "isPlatformCompatible", "providesUpdatesSecurely", "blocklistState", "blocklistURL", "appDisabled", - "softDisabled", "skinnable", "size", "foreignInstall"].forEach(function(aProp) { + "softDisabled", "skinnable", "size", "foreignInstall", "hasBinaryComponents" + ].forEach(function(aProp) { this.__defineGetter__(aProp, function() aAddon[aProp]); }, this); diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_1/chrome.manifest b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_1/chrome.manifest new file mode 100644 index 00000000000..4d63b6b06a8 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_1/chrome.manifest @@ -0,0 +1,6 @@ +content test-addon-1 chrome/content +# comment! + locale test-addon-1 en-US locale/en-US + # commentaire! + locale test-addon-1 fr-FR locale/fr-FR +overlay chrome://browser/content/browser.xul chrome://test-addon-1/content/overlay.xul diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_1/install.rdf b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_1/install.rdf new file mode 100644 index 00000000000..486be867000 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_1/install.rdf @@ -0,0 +1,23 @@ + + + + + + addon1@tests.mozilla.org + 1.0 + + + Test 1 + Test Description + + + + xpcshell@tests.mozilla.org + 1 + 2 + + + + + diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_2/chrome.manifest b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_2/chrome.manifest new file mode 100644 index 00000000000..3b0195077ca --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_2/chrome.manifest @@ -0,0 +1,7 @@ +content test-addon-1 chrome/content + + locale test-addon-1 en-US locale/en-US + locale test-addon-1 fr-FR locale/fr-FR +overlay chrome://browser/content/browser.xul chrome://test-addon-1/content/overlay.xul +binary-component components/something.so +manifest thisdoesntexist.manifest diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_2/install.rdf b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_2/install.rdf new file mode 100644 index 00000000000..9a9ee4823cd --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_2/install.rdf @@ -0,0 +1,24 @@ + + + + + + addon2@tests.mozilla.org + 1.0 + + + Test 2 + Test Description + true + + + + xpcshell@tests.mozilla.org + 1 + 2 + + + + + diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/chrome.manifest b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/chrome.manifest new file mode 100644 index 00000000000..73190ed8f5b --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/chrome.manifest @@ -0,0 +1,9 @@ +content test-addon-1 chrome/content + + locale test-addon-1 en-US locale/en-US + locale test-addon-1 fr-FR locale/fr-FR +overlay chrome://browser/content/browser.xul chrome://test-addon-1/content/overlay.xul + + binary-component components/something.so + + manifest jar:inner.jar!/nested.manifest diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/inner.jar b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/inner.jar new file mode 100644 index 00000000000..b4a40052f42 Binary files /dev/null and b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/inner.jar differ diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/install.rdf b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/install.rdf new file mode 100644 index 00000000000..3a4a709e097 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/install.rdf @@ -0,0 +1,24 @@ + + + + + + addon3@tests.mozilla.org + 1.0 + + + Test 3 + Test Description + true + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/chrome.manifest b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/chrome.manifest new file mode 100644 index 00000000000..60d4f01f09c --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/chrome.manifest @@ -0,0 +1,6 @@ +content test-addon-1 chrome/content + + locale test-addon-1 en-US locale/en-US + locale test-addon-1 fr-FR locale/fr-FR +overlay chrome://browser/content/browser.xul chrome://test-addon-1/content/overlay.xul + manifest components/components.manifest diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/components/components.manifest b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/components/components.manifest new file mode 100644 index 00000000000..1e0aea4403a --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/components/components.manifest @@ -0,0 +1,2 @@ +binary-component mycomponent.dll +manifest other/something.manifest diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/components/other/something.manifest b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/components/other/something.manifest new file mode 100644 index 00000000000..73d58dd6686 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/components/other/something.manifest @@ -0,0 +1 @@ +binary-component thermalnuclearwar.dll diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/install.rdf b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/install.rdf new file mode 100644 index 00000000000..463e3f27ef9 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/install.rdf @@ -0,0 +1,24 @@ + + + + + + addon4@tests.mozilla.org + 1.0 + + + Test 4 + Test Description + true + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_5/chrome.manifest b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_5/chrome.manifest new file mode 100644 index 00000000000..b0aa32adc72 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_5/chrome.manifest @@ -0,0 +1,7 @@ +content test-addon-1 chrome/content + + locale test-addon-1 en-US locale/en-US + locale test-addon-1 fr-FR locale/fr-FR +overlay chrome://browser/content/browser.xul chrome://test-addon-1/content/overlay.xul + + binary-component components/something.so diff --git a/toolkit/mozapps/extensions/test/addons/test_chromemanifest_5/install.rdf b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_5/install.rdf new file mode 100644 index 00000000000..7836bced8da --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_chromemanifest_5/install.rdf @@ -0,0 +1,24 @@ + + + + + + addon5@tests.mozilla.org + 1.0 + + + Test 5 + Test Description + false + + + + xpcshell@tests.mozilla.org + 1 + 2 + + + + + diff --git a/toolkit/mozapps/extensions/test/addons/test_migrate8/chrome.manifest b/toolkit/mozapps/extensions/test/addons/test_migrate8/chrome.manifest new file mode 100644 index 00000000000..8570bae82f1 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_migrate8/chrome.manifest @@ -0,0 +1,6 @@ +content test-addon-1 chrome/content + + locale test-addon-1 en-US locale/en-US + locale test-addon-1 fr-FR locale/fr-FR +overlay chrome://browser/content/browser.xul chrome://test-addon-1/content/overlay.xul +binary-component components/something.so diff --git a/toolkit/mozapps/extensions/test/addons/test_migrate8/install.rdf b/toolkit/mozapps/extensions/test/addons/test_migrate8/install.rdf new file mode 100644 index 00000000000..61ed24763d3 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_migrate8/install.rdf @@ -0,0 +1,24 @@ + + + + + + addon8@tests.mozilla.org + 1.0 + + + Test 8 + Test Description + true + + + + xpcshell@tests.mozilla.org + 1 + 2 + + + + + diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_ChromeManifestParser.js b/toolkit/mozapps/extensions/test/xpcshell/test_ChromeManifestParser.js new file mode 100644 index 00000000000..61ffc12f670 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_ChromeManifestParser.js @@ -0,0 +1,108 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Tests ChromeManifestParser.js + +Components.utils.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); + + do_check_true(Array.isArray(manifest)); + do_check_eq(manifest.length, expected.length); + for (let i = 0; i < manifest.length; i++) { + do_check_eq(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); + + do_check_true(Array.isArray(manifest)); + do_check_eq(manifest.length, expected.length); + for (let i = 0; i < manifest.length; i++) { + do_check_eq(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); + + do_check_true(Array.isArray(manifest)); + do_check_eq(manifest.length, expected.length); + for (let i = 0; i < manifest.length; i++) { + do_check_eq(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); + + do_check_true(Array.isArray(manifest)); + do_check_eq(manifest.length, expected.length); + for (let i = 0; i < manifest.length; i++) { + do_check_eq(JSON.stringify(manifest[i]), JSON.stringify(expected[i])); + } + + do_test_finished(); + }); +} diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_hasbinarycomponents.js b/toolkit/mozapps/extensions/test/xpcshell/test_hasbinarycomponents.js new file mode 100644 index 00000000000..2390894d35d --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_hasbinarycomponents.js @@ -0,0 +1,82 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Tests detection of binary components via parsing of chrome manifests. + +const profileDir = gProfD.clone(); +profileDir.append("extensions"); + +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"), + do_get_addon("test_chromemanifest_5")], + function() { + + restartManager(); + + AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", + "addon2@tests.mozilla.org", + "addon3@tests.mozilla.org", + "addon4@tests.mozilla.org", + "addon5@tests.mozilla.org"], + function([a1, a2, a3, a4, a5]) { + // addon1 has no binary components + do_check_neq(a1, null); + do_check_false(a1.userDisabled); + do_check_false(a1.hasBinaryComponents); + do_check_true(a1.isCompatible); + do_check_false(a1.appDisabled); + do_check_true(a1.isActive); + do_check_true(isExtensionInAddonsList(profileDir, a1.id)); + + // addon2 has a binary component, is compatible + do_check_neq(a2, null); + do_check_false(a2.userDisabled); + do_check_true(a2.hasBinaryComponents); + do_check_true(a2.isCompatible); + do_check_false(a2.appDisabled); + do_check_true(a2.isActive); + do_check_true(isExtensionInAddonsList(profileDir, a2.id)); + + // addon3 has a binary component, is incompatible + do_check_neq(a3, null); + do_check_false(a3.userDisabled); + do_check_true(a2.hasBinaryComponents); + do_check_false(a3.isCompatible); + do_check_true(a3.appDisabled); + do_check_false(a3.isActive); + do_check_false(isExtensionInAddonsList(profileDir, a3.id)); + + // addon4 has a binary component listed in a sub-manifest, is incompatible + do_check_neq(a4, null); + do_check_false(a4.userDisabled); + do_check_true(a2.hasBinaryComponents); + do_check_false(a4.isCompatible); + do_check_true(a4.appDisabled); + do_check_false(a4.isActive); + do_check_false(isExtensionInAddonsList(profileDir, a4.id)); + + // addon5 has a binary component, but is set to not unpack + do_check_neq(a5, null); + do_check_false(a5.userDisabled); + if (TEST_UNPACKED) + do_check_true(a5.hasBinaryComponents); + else + do_check_false(a5.hasBinaryComponents); + do_check_true(a5.isCompatible); + do_check_false(a5.appDisabled); + do_check_true(a5.isActive); + do_check_true(isExtensionInAddonsList(profileDir, a5.id)); + + do_test_finished(); + }); + }); +} diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js b/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js index 50c91c8059e..478e697cb78 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js @@ -116,6 +116,13 @@ function run_test() { addon7.copyTo(stagedXPIs, "tmp.xpi"); stagedXPIs = stagedXPIs.parent; + stagedXPIs.append("addon8@tests.mozilla.org"); + stagedXPIs.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0755); + + let addon7 = do_get_addon("test_migrate8"); + addon7.copyTo(stagedXPIs, "tmp.xpi"); + stagedXPIs = stagedXPIs.parent; + let old = do_get_file("data/test_migrate.rdf"); old.copyTo(gProfD, "extensions.rdf"); @@ -144,16 +151,19 @@ function run_test() { "addon5@tests.mozilla.org", "addon6@tests.mozilla.org", "addon7@tests.mozilla.org", + "addon8@tests.mozilla.org", "theme1@tests.mozilla.org", "theme2@tests.mozilla.org"], function([a1, a2, a3, a4, a5, a6, - a7, t1, t2]) { + a7, a8, t1, + t2]) { // addon1 was user and app enabled in the old extensions.rdf do_check_neq(a1, null); do_check_false(a1.userDisabled); do_check_false(a1.appDisabled); do_check_true(a1.isActive); do_check_true(isExtensionInAddonsList(profileDir, a1.id)); + do_check_false(a1.hasBinaryComponents); // addon2 was user disabled and app enabled in the old extensions.rdf do_check_neq(a2, null); @@ -161,6 +171,7 @@ function run_test() { do_check_false(a2.appDisabled); do_check_false(a2.isActive); do_check_false(isExtensionInAddonsList(profileDir, a2.id)); + do_check_false(a2.hasBinaryComponents); // addon3 was pending user disable and app disabled in the old extensions.rdf do_check_neq(a3, null); @@ -168,6 +179,7 @@ function run_test() { do_check_true(a3.appDisabled); do_check_false(a3.isActive); do_check_false(isExtensionInAddonsList(profileDir, a3.id)); + do_check_false(a3.hasBinaryComponents); // addon4 was pending user enable and app disabled in the old extensions.rdf do_check_neq(a4, null); @@ -175,6 +187,7 @@ function run_test() { do_check_true(a4.appDisabled); do_check_false(a4.isActive); do_check_false(isExtensionInAddonsList(profileDir, a4.id)); + do_check_false(a4.hasBinaryComponents); // addon5 was disabled and compatible but a new version has been installed // since, it should still be disabled but should be incompatible @@ -183,6 +196,7 @@ function run_test() { do_check_true(a5.appDisabled); do_check_false(a5.isActive); do_check_false(isExtensionInAddonsList(profileDir, a5.id)); + do_check_false(a5.hasBinaryComponents); // addon6 should be installed and compatible and packed unless unpacking is // forced @@ -195,6 +209,7 @@ function run_test() { do_check_eq(a6.getResourceURI("install.rdf").scheme, "file"); else do_check_eq(a6.getResourceURI("install.rdf").scheme, "jar"); + do_check_false(a6.hasBinaryComponents); // addon7 should be installed and compatible and unpacked do_check_neq(a7, null); @@ -203,6 +218,15 @@ function run_test() { do_check_true(a7.isActive); do_check_true(isExtensionInAddonsList(profileDir, a7.id)); do_check_eq(a7.getResourceURI("install.rdf").scheme, "file"); + do_check_false(a7.hasBinaryComponents); + + // addon8 should be installed and compatible and have binary components + do_check_neq(a8, null); + do_check_false(a8.userDisabled); + do_check_false(a8.appDisabled); + do_check_true(a8.isActive); + do_check_true(isExtensionInAddonsList(profileDir, a8.id)); + do_check_true(a8.hasBinaryComponents); // Theme 1 was previously enabled do_check_neq(t1, null); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js b/toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js index 39d4a7013e7..1a941665f18 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js @@ -98,46 +98,51 @@ function prepare_profile() { writeInstallRDFForExtension(addon6, profileDir); startupManager(); - AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", - "addon2@tests.mozilla.org", - "addon3@tests.mozilla.org", - "addon4@tests.mozilla.org", - "addon5@tests.mozilla.org", - "addon6@tests.mozilla.org"], - function([a1, a2, a3, a4, a5, a6]) { - a2.userDisabled = true; - a2.applyBackgroundUpdates = false; - a4.userDisabled = true; - a6.userDisabled = true; + installAllFiles([do_get_addon("test_migrate8")], + function() { + restartManager(); - a6.findUpdates({ - onUpdateAvailable: function(aAddon, aInstall6) { - AddonManager.getInstallForURL("http://localhost:4444/addons/test_migrate4_7.xpi", function(aInstall7) { - completeAllInstalls([aInstall6, aInstall7], function() { - restartManager(); - - AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", - "addon2@tests.mozilla.org", - "addon3@tests.mozilla.org", - "addon4@tests.mozilla.org", - "addon5@tests.mozilla.org", - "addon6@tests.mozilla.org"], - function([a1, a2, a3, a4, a5, a6]) { - a3.userDisabled = true; - a4.userDisabled = false; - - a5.findUpdates({ - onUpdateFinished: function() { - shutdownManager(); - - perform_migration(); - } - }, AddonManager.UPDATE_WHEN_USER_REQUESTED); + AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", + "addon2@tests.mozilla.org", + "addon3@tests.mozilla.org", + "addon4@tests.mozilla.org", + "addon5@tests.mozilla.org", + "addon6@tests.mozilla.org"], + function([a1, a2, a3, a4, a5, a6]) { + a2.userDisabled = true; + a2.applyBackgroundUpdates = false; + a4.userDisabled = true; + a6.userDisabled = true; + + a6.findUpdates({ + onUpdateAvailable: function(aAddon, aInstall6) { + AddonManager.getInstallForURL("http://localhost:4444/addons/test_migrate4_7.xpi", function(aInstall7) { + completeAllInstalls([aInstall6, aInstall7], function() { + restartManager(); + + AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", + "addon2@tests.mozilla.org", + "addon3@tests.mozilla.org", + "addon4@tests.mozilla.org", + "addon5@tests.mozilla.org", + "addon6@tests.mozilla.org"], + function([a1, a2, a3, a4, a5, a6]) { + a3.userDisabled = true; + a4.userDisabled = false; + + a5.findUpdates({ + onUpdateFinished: function() { + shutdownManager(); + + perform_migration(); + } + }, AddonManager.UPDATE_WHEN_USER_REQUESTED); + }); }); - }); - }, "application/x-xpinstall"); - } - }, AddonManager.UPDATE_WHEN_USER_REQUESTED); + }, "application/x-xpinstall"); + } + }, AddonManager.UPDATE_WHEN_USER_REQUESTED); + }); }); } @@ -169,8 +174,9 @@ function test_results() { "addon4@tests.mozilla.org", "addon5@tests.mozilla.org", "addon6@tests.mozilla.org", - "addon7@tests.mozilla.org"], - function([a1, a2, a3, a4, a5, a6, a7]) { + "addon7@tests.mozilla.org", + "addon8@tests.mozilla.org"], + function([a1, a2, a3, a4, a5, a6, a7, a8]) { // addon1 was enabled do_check_neq(a1, null); do_check_false(a1.userDisabled); @@ -178,6 +184,7 @@ function test_results() { do_check_true(a1.isActive); do_check_true(a1.applyBackgroundUpdates); do_check_true(a1.foreignInstall); + do_check_false(a1.hasBinaryComponents); // addon2 was disabled do_check_neq(a2, null); @@ -186,6 +193,7 @@ function test_results() { do_check_false(a2.isActive); do_check_false(a2.applyBackgroundUpdates); do_check_true(a2.foreignInstall); + do_check_false(a2.hasBinaryComponents); // addon3 was pending-disable in the database do_check_neq(a3, null); @@ -194,6 +202,7 @@ function test_results() { do_check_false(a3.isActive); do_check_true(a3.applyBackgroundUpdates); do_check_true(a3.foreignInstall); + do_check_false(a3.hasBinaryComponents); // addon4 was pending-enable in the database do_check_neq(a4, null); @@ -202,6 +211,7 @@ function test_results() { do_check_true(a4.isActive); do_check_true(a4.applyBackgroundUpdates); do_check_true(a4.foreignInstall); + do_check_false(a4.hasBinaryComponents); // addon5 was enabled in the database but needed a compatibiltiy update do_check_neq(a5, null); @@ -210,6 +220,7 @@ function test_results() { do_check_true(a5.isActive); do_check_true(a5.applyBackgroundUpdates); do_check_true(a5.foreignInstall); + do_check_false(a5.hasBinaryComponents); // addon6 was disabled and compatible but a new version has been installed do_check_neq(a6, null); @@ -221,6 +232,7 @@ function test_results() { do_check_true(a6.foreignInstall); do_check_eq(a6.sourceURI.spec, "http://localhost:4444/addons/test_migrate4_6.xpi"); do_check_eq(a6.releaseNotesURI.spec, "http://example.com/updateInfo.xhtml"); + do_check_false(a6.hasBinaryComponents); // addon7 was installed manually do_check_neq(a7, null); @@ -232,6 +244,15 @@ function test_results() { do_check_false(a7.foreignInstall); do_check_eq(a7.sourceURI.spec, "http://localhost:4444/addons/test_migrate4_7.xpi"); do_check_eq(a7.releaseNotesURI, null); + do_check_false(a7.hasBinaryComponents); + + // addon8 was enabled and has binary components + do_check_neq(a8, null); + do_check_false(a8.userDisabled); + do_check_false(a8.appDisabled); + do_check_true(a8.isActive); + do_check_true(a8.hasBinaryComponents); + testserver.stop(do_test_finished); }); } diff --git a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini index 245c44a6cae..f6585455af0 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini @@ -126,6 +126,7 @@ fail-if = os == "android" [test_bug675371.js] [test_cacheflush.js] [test_checkcompatibility.js] +[test_ChromeManifestParser.js] [test_corrupt.js] [test_corrupt_strictcompat.js] [test_dictionary.js] @@ -157,6 +158,7 @@ skip-if = os == "android" [test_gfxBlacklist_OS.js] [test_gfxBlacklist_Vendor.js] [test_gfxBlacklist_prefs.js] +[test_hasbinarycomponents.js] [test_install.js] # Bug 676992: test consistently hangs on Android skip-if = os == "android"