mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 552742: Support multi-package XPIs in the new add-ons manager. r=robstrong
This commit is contained in:
parent
e8f6daf69e
commit
e65cba989c
2
nsprpub/configure
vendored
2
nsprpub/configure
vendored
@ -6396,7 +6396,7 @@ s%\[%\\&%g
|
||||
s%\]%\\&%g
|
||||
s%\$%$$%g
|
||||
EOF
|
||||
DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' ' | tr '\015' ' '` # Manually modified for MKS support.
|
||||
DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
|
||||
rm -f conftest.defs
|
||||
|
||||
|
||||
|
@ -79,6 +79,7 @@ const FILE_XPI_ADDONS_LIST = "extensions.ini";
|
||||
|
||||
const KEY_PROFILEDIR = "ProfD";
|
||||
const KEY_APPDIR = "XCurProcD";
|
||||
const KEY_TEMPDIR = "TmpD";
|
||||
|
||||
const KEY_APP_PROFILE = "app-profile";
|
||||
const KEY_APP_GLOBAL = "app-global";
|
||||
@ -132,7 +133,8 @@ const BOOTSTRAP_REASONS = {
|
||||
const TYPES = {
|
||||
extension: 2,
|
||||
theme: 4,
|
||||
locale: 8
|
||||
locale: 8,
|
||||
multipackage: 32
|
||||
};
|
||||
|
||||
/**
|
||||
@ -405,10 +407,6 @@ function loadManifestFromRDF(aUri, aStream) {
|
||||
PROP_METADATA.forEach(function(aProp) {
|
||||
addon[aProp] = getRDFProperty(ds, root, aProp);
|
||||
});
|
||||
if (!addon.id || !addon.version)
|
||||
throw new Error("No ID or version in install manifest");
|
||||
if (!gIDTest.test(addon.id))
|
||||
throw new Error("Illegal add-on ID " + addon.id);
|
||||
|
||||
if (!addon.type) {
|
||||
addon.type = addon.internalName ? "theme" : "extension";
|
||||
@ -425,6 +423,15 @@ function loadManifestFromRDF(aUri, aStream) {
|
||||
if (!(addon.type in TYPES))
|
||||
throw new Error("Install manifest specifies unknown type: " + addon.type);
|
||||
|
||||
if (addon.type != "multipackage") {
|
||||
if (!addon.id)
|
||||
throw new Error("No ID in install manifest");
|
||||
if (!gIDTest.test(addon.id))
|
||||
throw new Error("Illegal add-on ID " + addon.id);
|
||||
if (!addon.version)
|
||||
throw new Error("No version in install manifest");
|
||||
}
|
||||
|
||||
// Only read the bootstrapped property for extensions
|
||||
if (addon.type == "extension") {
|
||||
addon.bootstrap = getRDFProperty(ds, root, "bootstrap") == "true";
|
||||
@ -563,12 +570,12 @@ function loadManifestFromDir(aDir) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an AddonInternal object from an add-on in a zip file.
|
||||
* Loads an AddonInternal object from an nsIZipReader for an add-on.
|
||||
*
|
||||
* @param aZipReader
|
||||
* An nsIZipReader open reading from the add-on XPI file
|
||||
* An open nsIZipReader for the add-on's files
|
||||
* @return an AddonInternal object
|
||||
* @throws if the directory does not contain a valid install manifest
|
||||
* @throws if the XPI file does not contain a valid install manifest
|
||||
*/
|
||||
function loadManifestFromZipReader(aZipReader) {
|
||||
let zis = aZipReader.getInputStream(FILE_INSTALL_MANIFEST);
|
||||
@ -594,6 +601,27 @@ function loadManifestFromZipReader(aZipReader) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an AddonInternal object from an add-on in an XPI file.
|
||||
*
|
||||
* @param aXPIFile
|
||||
* An nsIFile pointing to the add-on's XPI file
|
||||
* @return an AddonInternal object
|
||||
* @throws if the XPI file does not contain a valid install manifest
|
||||
*/
|
||||
function loadManifestFromZipFile(aXPIFile) {
|
||||
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
try {
|
||||
zipReader.open(aXPIFile);
|
||||
|
||||
return loadManifestFromZipReader(zipReader);
|
||||
}
|
||||
finally {
|
||||
zipReader.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a jar: URI for a file inside a ZIP file.
|
||||
*
|
||||
@ -609,6 +637,21 @@ function buildJarURI(aJarfile, aPath) {
|
||||
return NetUtil.newURI(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new unique temporary file. The caller should delete
|
||||
* the file when it is no longer needed.
|
||||
* @return an nsIFile that points to a randomly named, initially empty file in
|
||||
* the OS temporary files directory
|
||||
*/
|
||||
function getTemporaryFile() {
|
||||
let file = FileUtils.getDir(KEY_TEMPDIR, []);
|
||||
let random = Math.random().toString(36).replace(/0./, '').substr(-3);
|
||||
file.append("tmp-" + random + ".xpi");
|
||||
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts files from a ZIP file into a directory.
|
||||
*
|
||||
@ -3869,7 +3912,36 @@ function AddonInstall(aCallback, aInstallLocation, aUrl, aHash, aName, aType,
|
||||
}
|
||||
|
||||
try {
|
||||
this.loadManifest();
|
||||
let self = this;
|
||||
this.loadManifest(function() {
|
||||
XPIDatabase.getVisibleAddonForID(self.addon.id, function(aAddon) {
|
||||
self.existingAddon = aAddon;
|
||||
|
||||
if (!self.addon.isCompatible) {
|
||||
// TODO Should we send some event here?
|
||||
self.state = AddonManager.STATE_CHECKING;
|
||||
new UpdateChecker(self.addon, {
|
||||
onUpdateFinished: function(aAddon) {
|
||||
self.state = AddonManager.STATE_DOWNLOADED;
|
||||
XPIProvider.installs.push(self);
|
||||
AddonManagerPrivate.callInstallListeners("onNewInstall",
|
||||
self.listeners,
|
||||
self.wrapper);
|
||||
|
||||
aCallback(self);
|
||||
}
|
||||
}, AddonManager.UPDATE_WHEN_ADDON_INSTALLED);
|
||||
}
|
||||
else {
|
||||
XPIProvider.installs.push(self);
|
||||
AddonManagerPrivate.callInstallListeners("onNewInstall",
|
||||
self.listeners,
|
||||
self.wrapper);
|
||||
|
||||
aCallback(self);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
WARN("Invalid XPI: " + e);
|
||||
@ -3878,34 +3950,6 @@ function AddonInstall(aCallback, aInstallLocation, aUrl, aHash, aName, aType,
|
||||
aCallback(this);
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
XPIDatabase.getVisibleAddonForID(this.addon.id, function(aAddon) {
|
||||
self.existingAddon = aAddon;
|
||||
|
||||
if (!self.addon.isCompatible) {
|
||||
// TODO Should we send some event here?
|
||||
self.state = AddonManager.STATE_CHECKING;
|
||||
new UpdateChecker(self.addon, {
|
||||
onUpdateFinished: function(aAddon) {
|
||||
self.state = AddonManager.STATE_DOWNLOADED;
|
||||
XPIProvider.installs.push(self);
|
||||
AddonManagerPrivate.callInstallListeners("onNewInstall",
|
||||
self.listeners,
|
||||
self.wrapper);
|
||||
|
||||
aCallback(self);
|
||||
}
|
||||
}, AddonManager.UPDATE_WHEN_ADDON_INSTALLED);
|
||||
}
|
||||
else {
|
||||
XPIProvider.installs.push(self);
|
||||
AddonManagerPrivate.callInstallListeners("onNewInstall", self.listeners,
|
||||
self.wrapper);
|
||||
|
||||
aCallback(self);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.state = AddonManager.STATE_AVAILABLE;
|
||||
@ -3940,9 +3984,11 @@ AddonInstall.prototype = {
|
||||
releaseNotesURI: null,
|
||||
sourceURI: null,
|
||||
file: null,
|
||||
ownsTempFile: false,
|
||||
certificate: null,
|
||||
certName: null,
|
||||
|
||||
linkedInstalls: null,
|
||||
existingAddon: null,
|
||||
addon: null,
|
||||
|
||||
@ -4044,60 +4090,212 @@ AddonInstall.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the temporary file owned by this AddonInstall if there is one.
|
||||
*/
|
||||
removeTemporaryFile: function AI_removeTemporaryFile() {
|
||||
// Only proceed if this AddonInstall owns its XPI file
|
||||
if (!this.ownsTempFile)
|
||||
return;
|
||||
|
||||
try {
|
||||
this.file.remove(true);
|
||||
this.ownsTempFile = false;
|
||||
}
|
||||
catch (e) {
|
||||
WARN("Failed to remove temporary file " + this.file.path + ": " + e);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the sourceURI and releaseNotesURI values on the Addon being
|
||||
* installed by this AddonInstall instance.
|
||||
*/
|
||||
updateAddonURIs: function AI_updateAddonURIs() {
|
||||
this.addon.sourceURI = this.sourceURI.spec;
|
||||
if (this.releaseNotesURI)
|
||||
this.addon.releaseNotesURI = this.releaseNotesURI.spec;
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads add-on manifests from a multi-package XPI file. Each of the
|
||||
* XPI and JAR files contained in the XPI will be extracted. Any that
|
||||
* do not contain valid add-ons will be ignored. The first valid add-on will
|
||||
* be installed by this AddonInstall instance, the rest will have new
|
||||
* AddonInstall instances created for them.
|
||||
*
|
||||
* @param aZipReader
|
||||
* An open nsIZipReader for the multi-package XPI's files. This will
|
||||
* be closed before this method returns.
|
||||
* @param aCallback
|
||||
* A function to call when all of the add-on manifests have been
|
||||
* loaded.
|
||||
*/
|
||||
loadMultipackageManifests: function AI_loadMultipackageManifests(aZipReader,
|
||||
aCallback) {
|
||||
let files = [];
|
||||
let entries = aZipReader.findEntries("(*.[Xx][Pp][Ii]|*.[Jj][Aa][Rr])");
|
||||
while (entries.hasMore()) {
|
||||
let entryName = entries.getNext();
|
||||
var target = getTemporaryFile();
|
||||
try {
|
||||
aZipReader.extract(entryName, target);
|
||||
files.push(target);
|
||||
}
|
||||
catch (e) {
|
||||
WARN("Failed to extract " + entryName + " from multi-package " +
|
||||
"XPI: " + e);
|
||||
target.remove(false);
|
||||
}
|
||||
}
|
||||
|
||||
aZipReader.close();
|
||||
|
||||
if (files.length == 0) {
|
||||
throw new Error("Multi-package XPI does not contain any packages " +
|
||||
"to install");
|
||||
}
|
||||
|
||||
let addon = null;
|
||||
|
||||
// Find the first file that has a valid install manifest and use it for
|
||||
// the add-on that this AddonInstall instance will install.
|
||||
while (files.length > 0) {
|
||||
this.removeTemporaryFile();
|
||||
this.file = files.shift();
|
||||
this.ownsTempFile = true;
|
||||
try {
|
||||
addon = loadManifestFromZipFile(this.file);
|
||||
break;
|
||||
}
|
||||
catch (e) {
|
||||
WARN(this.file.leafName + " cannot be installed from multi-package " +
|
||||
"XPI: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!addon) {
|
||||
// No valid add-on was found
|
||||
aCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
this.addon = addon;
|
||||
|
||||
this.updateAddonURIs();
|
||||
|
||||
this.addon._install = this;
|
||||
this.name = this.addon.selectedLocale.name;
|
||||
this.type = this.addon.type;
|
||||
this.version = this.addon.version;
|
||||
|
||||
// Setting the iconURL to something inside the XPI locks the XPI and
|
||||
// makes it impossible to delete on Windows.
|
||||
//let newIcon = createWrapper(this.addon).iconURL;
|
||||
//if (newIcon)
|
||||
// this.iconURL = newIcon;
|
||||
|
||||
// Create new AddonInstall instances for every remaining file
|
||||
if (files.length > 0) {
|
||||
this.linkedInstalls = [];
|
||||
let count = 0;
|
||||
let self = this;
|
||||
files.forEach(function(file) {
|
||||
AddonInstall.createInstall(function(aInstall) {
|
||||
// Ignore bad add-ons (createInstall will have logged the error)
|
||||
if (aInstall.state == AddonManager.STATE_DOWNLOAD_FAILED) {
|
||||
// Manually remove the temporary file
|
||||
file.remove(true);
|
||||
}
|
||||
else {
|
||||
// Make the new install own its temporary file
|
||||
aInstall.ownsTempFile = true;
|
||||
|
||||
self.linkedInstalls.push(aInstall)
|
||||
|
||||
aInstall.sourceURI = self.sourceURI;
|
||||
aInstall.releaseNotesURI = self.releaseNotesURI;
|
||||
aInstall.updateAddonURIs();
|
||||
}
|
||||
|
||||
count++;
|
||||
if (count == files.length)
|
||||
aCallback();
|
||||
}, file);
|
||||
}, this);
|
||||
}
|
||||
else {
|
||||
aCallback();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called after the add-on is a local file and the signature and install
|
||||
* manifest can be read.
|
||||
*
|
||||
* @param aCallback
|
||||
* A function to call when the manifest has been loaded
|
||||
* @throws if the add-on does not contain a valid install manifest or the
|
||||
* XPI is incorrectly signed
|
||||
*/
|
||||
loadManifest: function AI_loadManifest() {
|
||||
loadManifest: function AI_loadManifest(aCallback) {
|
||||
let zipreader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zipreader.open(this.file);
|
||||
try {
|
||||
zipreader.open(this.file);
|
||||
}
|
||||
catch (e) {
|
||||
zipreader.close();
|
||||
throw e;
|
||||
}
|
||||
|
||||
let principal = zipreader.getCertificatePrincipal(null);
|
||||
if (principal && principal.hasCertificate) {
|
||||
LOG("Verifying XPI signature");
|
||||
if (verifyZipSigning(zipreader, principal)) {
|
||||
let x509 = principal.certificate;
|
||||
if (x509 instanceof Ci.nsIX509Cert)
|
||||
this.certificate = x509;
|
||||
if (this.certificate && this.certificate.commonName.length > 0)
|
||||
this.certName = this.certificate.commonName;
|
||||
else
|
||||
this.certName = principal.prettyName;
|
||||
}
|
||||
else {
|
||||
zipreader.close();
|
||||
throw new Error("XPI is incorrectly signed");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
let principal = zipreader.getCertificatePrincipal(null);
|
||||
if (principal && principal.hasCertificate) {
|
||||
LOG("Verifying XPI signature");
|
||||
if (verifyZipSigning(zipreader, principal)) {
|
||||
let x509 = principal.certificate;
|
||||
if (x509 instanceof Ci.nsIX509Cert)
|
||||
this.certificate = x509;
|
||||
if (this.certificate && this.certificate.commonName.length > 0)
|
||||
this.certName = this.certificate.commonName;
|
||||
else
|
||||
this.certName = principal.prettyName;
|
||||
}
|
||||
else {
|
||||
throw new Error("XPI is incorrectly signed");
|
||||
}
|
||||
}
|
||||
|
||||
if (!zipreader.hasEntry(FILE_INSTALL_MANIFEST)) {
|
||||
zipreader.close();
|
||||
throw new Error("Missing install.rdf");
|
||||
}
|
||||
|
||||
this.addon = loadManifestFromZipReader(zipreader);
|
||||
this.addon.sourceURI = this.sourceURI.spec;
|
||||
if (this.releaseNotesURI)
|
||||
this.addon.releaseNotesURI = this.releaseNotesURI.spec;
|
||||
this.addon._install = this;
|
||||
|
||||
this.name = this.addon.selectedLocale.name;
|
||||
this.type = this.addon.type;
|
||||
this.version = this.addon.version;
|
||||
|
||||
// Setting the iconURL to something inside the XPI locks the XPI and
|
||||
// makes it impossible to delete on Windows.
|
||||
//let newIcon = createWrapper(this.addon).iconURL;
|
||||
//if (newIcon)
|
||||
// this.iconURL = newIcon;
|
||||
}
|
||||
finally {
|
||||
catch (e) {
|
||||
zipreader.close();
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (this.addon.type == "multipackage") {
|
||||
this.loadMultipackageManifests(zipreader, aCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
zipreader.close();
|
||||
|
||||
this.updateAddonURIs();
|
||||
|
||||
this.addon._install = this;
|
||||
this.name = this.addon.selectedLocale.name;
|
||||
this.type = this.addon.type;
|
||||
this.version = this.addon.version;
|
||||
|
||||
// Setting the iconURL to something inside the XPI locks the XPI and
|
||||
// makes it impossible to delete on Windows.
|
||||
//let newIcon = createWrapper(this.addon).iconURL;
|
||||
//if (newIcon)
|
||||
// this.iconURL = newIcon;
|
||||
|
||||
aCallback();
|
||||
},
|
||||
|
||||
observe: function AI_observe(aSubject, aTopic, aData) {
|
||||
@ -4146,10 +4344,8 @@ AddonInstall.prototype = {
|
||||
}
|
||||
|
||||
try {
|
||||
this.file = FileUtils.getDir("TmpD", []);
|
||||
let random = Math.random().toString(36).replace(/0./, '').substr(-3);
|
||||
this.file.append("tmp-" + random + ".xpi");
|
||||
this.file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
|
||||
this.file = getTemporaryFile();
|
||||
this.ownsTempFile = true;
|
||||
this.stream = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
this.stream.init(this.file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE |
|
||||
@ -4272,21 +4468,21 @@ AddonInstall.prototype = {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.loadManifest();
|
||||
|
||||
if (this.addon.isCompatible) {
|
||||
this.downloadCompleted();
|
||||
}
|
||||
else {
|
||||
// TODO Should we send some event here (bug 557716)?
|
||||
this.state = AddonManager.STATE_CHECKING;
|
||||
let self = this;
|
||||
new UpdateChecker(this.addon, {
|
||||
onUpdateFinished: function(aAddon) {
|
||||
self.downloadCompleted();
|
||||
}
|
||||
}, AddonManager.UPDATE_WHEN_ADDON_INSTALLED);
|
||||
}
|
||||
let self = this;
|
||||
this.loadManifest(function() {
|
||||
if (self.addon.isCompatible) {
|
||||
self.downloadCompleted();
|
||||
}
|
||||
else {
|
||||
// TODO Should we send some event here (bug 557716)?
|
||||
self.state = AddonManager.STATE_CHECKING;
|
||||
new UpdateChecker(self.addon, {
|
||||
onUpdateFinished: function(aAddon) {
|
||||
self.downloadCompleted();
|
||||
}
|
||||
}, AddonManager.UPDATE_WHEN_ADDON_INSTALLED);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
this.downloadFailed(AddonManager.ERROR_CORRUPT_FILE, e);
|
||||
@ -4321,12 +4517,7 @@ AddonInstall.prototype = {
|
||||
XPIProvider.removeActiveInstall(this);
|
||||
AddonManagerPrivate.callInstallListeners("onDownloadFailed", this.listeners,
|
||||
this.wrapper);
|
||||
try {
|
||||
this.file.remove(true);
|
||||
}
|
||||
catch (e) {
|
||||
WARN("Failed to remove temporary file " + this.file.path + ": " + e);
|
||||
}
|
||||
this.removeTemporaryFile();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -4339,8 +4530,15 @@ AddonInstall.prototype = {
|
||||
self.state = AddonManager.STATE_DOWNLOADED;
|
||||
if (AddonManagerPrivate.callInstallListeners("onDownloadEnded",
|
||||
self.listeners,
|
||||
self.wrapper))
|
||||
self.wrapper)) {
|
||||
self.install();
|
||||
|
||||
if (self.linkedInstalls) {
|
||||
self.linkedInstalls.forEach(function(aInstall) {
|
||||
aInstall.install();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@ -4515,15 +4713,7 @@ AddonInstall.prototype = {
|
||||
this.wrapper);
|
||||
}
|
||||
finally {
|
||||
// If the file was downloaded then delete it
|
||||
if (!(this.sourceURI instanceof Ci.nsIFileURL)) {
|
||||
try {
|
||||
this.file.remove(true);
|
||||
}
|
||||
catch (e) {
|
||||
WARN("Failed to remove temporary file " + this.file.path + ": " + e);
|
||||
}
|
||||
}
|
||||
this.removeTemporaryFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4619,6 +4809,12 @@ function AddonInstallWrapper(aInstall) {
|
||||
this.__defineGetter__("addon", function() createWrapper(aInstall.addon));
|
||||
this.__defineGetter__("sourceURI", function() aInstall.sourceURI);
|
||||
|
||||
this.__defineGetter__("linkedInstalls", function() {
|
||||
if (!aInstall.linkedInstalls)
|
||||
return null;
|
||||
return [i.wrapper for each (i in aInstall.linkedInstalls)];
|
||||
});
|
||||
|
||||
this.install = function() {
|
||||
aInstall.install();
|
||||
}
|
||||
|
@ -137,6 +137,17 @@ Installer.prototype = {
|
||||
failed.push(install);
|
||||
else
|
||||
installs.push(install);
|
||||
|
||||
if (install.linkedInstalls) {
|
||||
install.linkedInstalls.forEach(function(aInstall) {
|
||||
aInstall.addListener(this);
|
||||
// App disabled items are not compatible and so fail to install
|
||||
if (aInstall.addon.appDisabled)
|
||||
failed.push(aInstall);
|
||||
else
|
||||
installs.push(aInstall);
|
||||
}, this);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARN("Download of " + install.sourceURI + " in unexpected state " +
|
||||
|
BIN
toolkit/mozapps/extensions/test/addons/test_install4/addon4.xpi
Normal file
BIN
toolkit/mozapps/extensions/test/addons/test_install4/addon4.xpi
Normal file
Binary file not shown.
BIN
toolkit/mozapps/extensions/test/addons/test_install4/addon5.jar
Normal file
BIN
toolkit/mozapps/extensions/test/addons/test_install4/addon5.jar
Normal file
Binary file not shown.
BIN
toolkit/mozapps/extensions/test/addons/test_install4/addon6.xpi
Normal file
BIN
toolkit/mozapps/extensions/test/addons/test_install4/addon6.xpi
Normal file
Binary file not shown.
BIN
toolkit/mozapps/extensions/test/addons/test_install4/addon7.jar
Normal file
BIN
toolkit/mozapps/extensions/test/addons/test_install4/addon7.jar
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
||||
This is corrupt
|
@ -0,0 +1 @@
|
||||
This is corrupt
|
@ -0,0 +1 @@
|
||||
This is ignored
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!-- A multi-package XPI -->
|
||||
<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:type>32</em:type>
|
||||
</Description>
|
||||
</RDF>
|
@ -22,4 +22,42 @@
|
||||
</em:updates>
|
||||
</Description>
|
||||
|
||||
<Description about="urn:mozilla:extension:addon4@tests.mozilla.org">
|
||||
<em:updates>
|
||||
<Seq>
|
||||
<li>
|
||||
<Description>
|
||||
<em:version>1.0</em:version>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>xpcshell@tests.mozilla.org</em:id>
|
||||
<em:minVersion>0</em:minVersion>
|
||||
<em:maxVersion>1</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</li>
|
||||
</Seq>
|
||||
</em:updates>
|
||||
</Description>
|
||||
|
||||
<Description about="urn:mozilla:extension:addon7@tests.mozilla.org">
|
||||
<em:updates>
|
||||
<Seq>
|
||||
<li>
|
||||
<Description>
|
||||
<em:version>5.0</em:version>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>xpcshell@tests.mozilla.org</em:id>
|
||||
<em:minVersion>0</em:minVersion>
|
||||
<em:maxVersion>1</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</li>
|
||||
</Seq>
|
||||
</em:updates>
|
||||
</Description>
|
||||
|
||||
</RDF>
|
||||
|
@ -795,4 +795,20 @@ Services.prefs.setBoolPref("extensions.logging.enabled", true);
|
||||
// By default only load extensions from the profile install location
|
||||
Services.prefs.setIntPref("extensions.enabledScopes", AddonManager.SCOPE_PROFILE);
|
||||
|
||||
do_register_cleanup(shutdownManager);
|
||||
// Register a temporary directory for the tests.
|
||||
const gTmpD = gProfD.clone();
|
||||
gTmpD.append("temp");
|
||||
gTmpD.create(AM_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
||||
registerDirectory("TmpD", gTmpD);
|
||||
|
||||
do_register_cleanup(function() {
|
||||
// Check that the temporary directory is empty
|
||||
var dirEntries = gTmpD.directoryEntries
|
||||
.QueryInterface(AM_Ci.nsIDirectoryEnumerator);
|
||||
var entry;
|
||||
while (entry = dirEntries.nextFile) {
|
||||
do_throw("Found unexpected file in temporary directory: " + entry.leafName);
|
||||
}
|
||||
|
||||
shutdownManager();
|
||||
});
|
||||
|
@ -17,6 +17,7 @@ const ADDON1_SIZE = 705 + 16;
|
||||
do_load_httpd_js();
|
||||
var testserver;
|
||||
var gInstallDate;
|
||||
var gInstall = null;
|
||||
|
||||
// The test extension uses an insecure update url.
|
||||
Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
|
||||
@ -58,6 +59,7 @@ function run_test_1() {
|
||||
ensure_test_completed();
|
||||
|
||||
do_check_neq(install, null);
|
||||
do_check_eq(install.linkedInstalls, null);
|
||||
do_check_eq(install.type, "extension");
|
||||
do_check_eq(install.version, "1.0");
|
||||
do_check_eq(install.name, "Test 1");
|
||||
@ -165,6 +167,7 @@ function run_test_2() {
|
||||
let url = "http://localhost:4444/addons/test_install2_1.xpi";
|
||||
AddonManager.getInstallForURL(url, function(install) {
|
||||
do_check_neq(install, null);
|
||||
do_check_eq(install.linkedInstalls, null);
|
||||
do_check_eq(install.version, "1.0");
|
||||
do_check_eq(install.name, "Test 2");
|
||||
do_check_eq(install.state, AddonManager.STATE_AVAILABLE);
|
||||
@ -564,6 +567,238 @@ function check_test_10(install) {
|
||||
AddonManager.getAllInstalls(function(activeInstalls) {
|
||||
do_check_eq(activeInstalls.length, 0);
|
||||
|
||||
run_test_11();
|
||||
});
|
||||
}
|
||||
|
||||
// Tests that a multi-package install shows up as multiple installs with the
|
||||
// correct sourceURI.
|
||||
function run_test_11() {
|
||||
prepare_test({ }, [
|
||||
"onNewInstall",
|
||||
"onNewInstall",
|
||||
"onNewInstall",
|
||||
"onNewInstall"
|
||||
]);
|
||||
|
||||
AddonManager.getInstallForFile(do_get_addon("test_install4"), function(install) {
|
||||
ensure_test_completed();
|
||||
do_check_neq(install, null);
|
||||
do_check_neq(install.linkedInstalls, null);
|
||||
do_check_eq(install.linkedInstalls.length, 3);
|
||||
|
||||
// Might be in any order so sort them based on ID
|
||||
let installs = [install].concat(install.linkedInstalls);
|
||||
installs.sort(function(a, b) {
|
||||
if (a.addon.id < b.addon.id)
|
||||
return -1;
|
||||
if (a.addon.id > b.addon.id)
|
||||
return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Comes from addon4.xpi and is made compatible by an update check
|
||||
do_check_eq(installs[0].sourceURI, install.sourceURI);
|
||||
do_check_eq(installs[0].addon.id, "addon4@tests.mozilla.org");
|
||||
do_check_false(installs[0].addon.appDisabled);
|
||||
do_check_eq(installs[0].version, "1.0");
|
||||
do_check_eq(installs[0].name, "Multi Test 1");
|
||||
do_check_eq(installs[0].state, AddonManager.STATE_DOWNLOADED);
|
||||
|
||||
// Comes from addon5.jar and is compatible by default
|
||||
do_check_eq(installs[1].sourceURI, install.sourceURI);
|
||||
do_check_eq(installs[1].addon.id, "addon5@tests.mozilla.org");
|
||||
do_check_false(installs[1].addon.appDisabled);
|
||||
do_check_eq(installs[1].version, "3.0");
|
||||
do_check_eq(installs[1].name, "Multi Test 2");
|
||||
do_check_eq(installs[1].state, AddonManager.STATE_DOWNLOADED);
|
||||
|
||||
// Comes from addon6.xpi and is incompatible
|
||||
do_check_eq(installs[2].sourceURI, install.sourceURI);
|
||||
do_check_eq(installs[2].addon.id, "addon6@tests.mozilla.org");
|
||||
do_check_true(installs[2].addon.appDisabled);
|
||||
do_check_eq(installs[2].version, "2.0");
|
||||
do_check_eq(installs[2].name, "Multi Test 3");
|
||||
do_check_eq(installs[2].state, AddonManager.STATE_DOWNLOADED);
|
||||
|
||||
// Comes from addon7.jar and is made compatible by an update check
|
||||
do_check_eq(installs[3].sourceURI, install.sourceURI);
|
||||
do_check_eq(installs[3].addon.id, "addon7@tests.mozilla.org");
|
||||
do_check_false(installs[3].addon.appDisabled);
|
||||
do_check_eq(installs[3].version, "5.0");
|
||||
do_check_eq(installs[3].name, "Multi Test 4");
|
||||
do_check_eq(installs[3].state, AddonManager.STATE_DOWNLOADED);
|
||||
|
||||
AddonManager.getAllInstalls(function(aInstalls) {
|
||||
do_check_eq(aInstalls.length, 4);
|
||||
|
||||
prepare_test({
|
||||
"addon4@tests.mozilla.org": [
|
||||
"onInstalling"
|
||||
],
|
||||
"addon5@tests.mozilla.org": [
|
||||
"onInstalling"
|
||||
],
|
||||
"addon6@tests.mozilla.org": [
|
||||
"onInstalling"
|
||||
],
|
||||
"addon7@tests.mozilla.org": [
|
||||
"onInstalling"
|
||||
]
|
||||
}, [
|
||||
"onInstallStarted",
|
||||
"onInstallEnded",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded"
|
||||
], check_test_11);
|
||||
|
||||
installs[0].install();
|
||||
installs[1].install();
|
||||
installs[2].install();
|
||||
installs[3].install();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function check_test_11() {
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon4@tests.mozilla.org",
|
||||
"addon5@tests.mozilla.org",
|
||||
"addon6@tests.mozilla.org",
|
||||
"addon7@tests.mozilla.org"],
|
||||
function([a4, a5, a6, a7]) {
|
||||
do_check_neq(a4, null);
|
||||
do_check_neq(a5, null);
|
||||
do_check_neq(a6, null);
|
||||
do_check_neq(a7, null);
|
||||
|
||||
a4.uninstall();
|
||||
a5.uninstall();
|
||||
a6.uninstall();
|
||||
a7.uninstall();
|
||||
|
||||
restartManager();
|
||||
|
||||
run_test_12();
|
||||
});
|
||||
}
|
||||
|
||||
// Same as test 11 but for a remote XPI
|
||||
function run_test_12() {
|
||||
prepare_test({ }, [
|
||||
"onNewInstall",
|
||||
]);
|
||||
|
||||
let url = "http://localhost:4444/addons/test_install4.xpi";
|
||||
AddonManager.getInstallForURL(url, function(install) {
|
||||
gInstall = install;
|
||||
|
||||
ensure_test_completed();
|
||||
do_check_neq(install, null);
|
||||
do_check_eq(install.linkedInstalls, null);
|
||||
do_check_eq(install.state, AddonManager.STATE_AVAILABLE);
|
||||
|
||||
prepare_test({
|
||||
"addon4@tests.mozilla.org": [
|
||||
"onInstalling"
|
||||
],
|
||||
"addon5@tests.mozilla.org": [
|
||||
"onInstalling"
|
||||
],
|
||||
"addon6@tests.mozilla.org": [
|
||||
"onInstalling"
|
||||
],
|
||||
"addon7@tests.mozilla.org": [
|
||||
"onInstalling"
|
||||
]
|
||||
}, [
|
||||
"onDownloadStarted",
|
||||
"onNewInstall",
|
||||
"onNewInstall",
|
||||
"onNewInstall",
|
||||
"onDownloadEnded",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded",
|
||||
"onInstallStarted",
|
||||
"onInstallEnded"
|
||||
], check_test_12);
|
||||
install.install();
|
||||
}, "application/x-xpinstall", null, "Multi Test 4");
|
||||
}
|
||||
|
||||
function check_test_12() {
|
||||
do_check_eq(gInstall.linkedInstalls.length, 3);
|
||||
|
||||
// Might be in any order so sort them based on ID
|
||||
let installs = [gInstall].concat(gInstall.linkedInstalls);
|
||||
installs.sort(function(a, b) {
|
||||
if (a.addon.id < b.addon.id)
|
||||
return -1;
|
||||
if (a.addon.id > b.addon.id)
|
||||
return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Comes from addon4.xpi and is made compatible by an update check
|
||||
do_check_eq(installs[0].sourceURI, gInstall.sourceURI);
|
||||
do_check_eq(installs[0].addon.id, "addon4@tests.mozilla.org");
|
||||
do_check_false(installs[0].addon.appDisabled);
|
||||
do_check_eq(installs[0].version, "1.0");
|
||||
do_check_eq(installs[0].name, "Multi Test 1");
|
||||
do_check_eq(installs[0].state, AddonManager.STATE_INSTALLED);
|
||||
|
||||
// Comes from addon5.jar and is compatible by default
|
||||
do_check_eq(installs[1].sourceURI, gInstall.sourceURI);
|
||||
do_check_eq(installs[1].addon.id, "addon5@tests.mozilla.org");
|
||||
do_check_false(installs[1].addon.appDisabled);
|
||||
do_check_eq(installs[1].version, "3.0");
|
||||
do_check_eq(installs[1].name, "Multi Test 2");
|
||||
do_check_eq(installs[1].state, AddonManager.STATE_INSTALLED);
|
||||
|
||||
// Comes from addon6.xpi and is incompatible
|
||||
do_check_eq(installs[2].sourceURI, gInstall.sourceURI);
|
||||
do_check_eq(installs[2].addon.id, "addon6@tests.mozilla.org");
|
||||
do_check_true(installs[2].addon.appDisabled);
|
||||
do_check_eq(installs[2].version, "2.0");
|
||||
do_check_eq(installs[2].name, "Multi Test 3");
|
||||
do_check_eq(installs[2].state, AddonManager.STATE_INSTALLED);
|
||||
|
||||
// Comes from addon7.jar and is made compatible by an update check
|
||||
do_check_eq(installs[3].sourceURI, gInstall.sourceURI);
|
||||
do_check_eq(installs[3].addon.id, "addon7@tests.mozilla.org");
|
||||
do_check_false(installs[3].addon.appDisabled);
|
||||
do_check_eq(installs[3].version, "5.0");
|
||||
do_check_eq(installs[3].name, "Multi Test 4");
|
||||
do_check_eq(installs[3].state, AddonManager.STATE_INSTALLED);
|
||||
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon4@tests.mozilla.org",
|
||||
"addon5@tests.mozilla.org",
|
||||
"addon6@tests.mozilla.org",
|
||||
"addon7@tests.mozilla.org"],
|
||||
function([a4, a5, a6, a7]) {
|
||||
do_check_neq(a4, null);
|
||||
do_check_neq(a5, null);
|
||||
do_check_neq(a6, null);
|
||||
do_check_neq(a7, null);
|
||||
|
||||
a4.uninstall();
|
||||
a5.uninstall();
|
||||
a6.uninstall();
|
||||
a7.uninstall();
|
||||
|
||||
restartManager();
|
||||
|
||||
end_test();
|
||||
});
|
||||
}
|
||||
|
@ -83,6 +83,7 @@ _BROWSER_FILES = head.js \
|
||||
browser_bug540558.js \
|
||||
browser_relative.js \
|
||||
browser_cancel.js \
|
||||
browser_multipackage.js \
|
||||
unsigned.xpi \
|
||||
signed.xpi \
|
||||
signed2.xpi \
|
||||
@ -94,6 +95,7 @@ _BROWSER_FILES = head.js \
|
||||
incompatible.xpi \
|
||||
empty.xpi \
|
||||
corrupt.xpi \
|
||||
multipackage.xpi \
|
||||
enabled.html \
|
||||
installtrigger.html \
|
||||
startsoftwareupdate.html \
|
||||
|
@ -0,0 +1,50 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// Tests installing an signed add-on by navigating directly to the url
|
||||
function test() {
|
||||
Harness.installConfirmCallback = confirm_install;
|
||||
Harness.installEndedCallback = install_ended;
|
||||
Harness.installsCompletedCallback = finish_test;
|
||||
Harness.setup();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.loadURI(TESTROOT + "multipackage.xpi");
|
||||
}
|
||||
|
||||
function get_item(items, name) {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].name == name)
|
||||
return items[i];
|
||||
}
|
||||
ok(false, "Item for " + name + " was not listed");
|
||||
}
|
||||
|
||||
function confirm_install(window) {
|
||||
items = window.document.getElementById("itemList").childNodes;
|
||||
is(items.length, 2, "Should be 2 items listed in the confirmation dialog");
|
||||
|
||||
let item = get_item(items, "XPI Test");
|
||||
if (item) {
|
||||
is(item.signed, "false", "Should not have listed the item as signed");
|
||||
is(item.icon, "", "Should have listed no icon for the item");
|
||||
}
|
||||
|
||||
item = get_item(items, "Signed XPI Test");
|
||||
if (item) {
|
||||
is(item.cert, "(Object Signer)", "Should have seen the signer");
|
||||
is(item.signed, "true", "Should have listed the item as signed");
|
||||
is(item.icon, "", "Should have listed no icon for the item");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function install_ended(install, addon) {
|
||||
install.cancel();
|
||||
}
|
||||
|
||||
function finish_test(count) {
|
||||
is(count, 2, "2 Add-ons should have been successfully installed");
|
||||
gBrowser.removeCurrentTab();
|
||||
Harness.finish();
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
BIN
toolkit/mozapps/extensions/test/xpinstall/multipackage.xpi
Normal file
BIN
toolkit/mozapps/extensions/test/xpinstall/multipackage.xpi
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user