author | Andrew Swan <aswan@mozilla.com> |
Wed, 04 Jan 2017 10:12:53 -0800 | |
changeset 375276 | d97b2eeffc46de2ef3f9312dd60e79cce68f5208 |
parent 375275 | b14520ebf7cc599f73adba54b3d74e8b61ebf213 |
child 375277 | 308b6c4b0e8ff09723cc87229faddd3a0ed35441 |
push id | 1419 |
push user | jlund@mozilla.com |
push date | Mon, 10 Apr 2017 20:44:07 +0000 |
treeherder | mozilla-release@5e6801b73ef6 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | rhelmer |
bugs | 1323129 |
milestone | 53.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/base/content/test/general/browser_bug553455.js +++ b/browser/base/content/test/general/browser_bug553455.js @@ -465,56 +465,16 @@ function test_restartless() { Services.perms.remove(makeURI("http://example.com/"), "install"); let closePromise = waitForNotificationClose(); gBrowser.removeTab(gBrowser.selectedTab); yield closePromise; }); }, -function test_multiple() { - return Task.spawn(function* () { - let pm = Services.perms; - pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION); - - let progressPromise = waitForProgressNotification(); - let dialogPromise = waitForInstallDialog(); - let triggers = encodeURIComponent(JSON.stringify({ - "Unsigned XPI": "amosigned.xpi", - "Restartless XPI": "restartless.xpi" - })); - BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers); - let panel = yield progressPromise; - let installDialog = yield dialogPromise; - - let notificationPromise = waitForNotification("addon-install-restart"); - acceptInstallDialog(installDialog); - yield notificationPromise; - - let notification = panel.childNodes[0]; - is(notification.button.label, "Restart Now", "Should have seen the right button"); - is(notification.getAttribute("label"), - "2 add-ons will be installed after you restart " + gApp + ".", - "Should have seen the right message"); - - let installs = yield getInstalls(); - is(installs.length, 1, "Should be one pending install"); - installs[0].cancel(); - - let addon = yield new Promise(resolve => { - AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(result) { - resolve(result); - }); - }); - addon.uninstall(); - Services.perms.remove(makeURI("http://example.com/"), "install"); - yield removeTab(); - }); -}, - function test_sequential() { return Task.spawn(function* () { // This test is only relevant if using the new doorhanger UI // TODO: this subtest is disabled until multiple notification prompts are // reworked in bug 1188152 if (true || !Preferences.get("xpinstall.customConfirmationUI", false)) { return; } @@ -581,74 +541,16 @@ function test_sequential() { Services.perms.remove(makeURI("http://example.com"), "install"); let closePromise = waitForNotificationClose(); cancelInstallDialog(installDialog); yield closePromise; yield BrowserTestUtils.removeTab(gBrowser.selectedTab); }); }, -function test_someUnverified() { - return Task.spawn(function* () { - // This test is only relevant if using the new doorhanger UI and allowing - // unsigned add-ons - if (!Preferences.get("xpinstall.customConfirmationUI", false) || - Preferences.get("xpinstall.signatures.required", true) || - REQUIRE_SIGNING) { - return; - } - let pm = Services.perms; - pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION); - - let progressPromise = waitForProgressNotification(); - let dialogPromise = waitForInstallDialog(); - let triggers = encodeURIComponent(JSON.stringify({ - "Extension XPI": "restartless-unsigned.xpi", - "Theme XPI": "theme.xpi" - })); - BrowserTestUtils.openNewForegroundTab(gBrowser, TESTROOT + "installtrigger.html?" + triggers); - yield progressPromise; - let installDialog = yield dialogPromise; - - let notification = document.getElementById("addon-install-confirmation-notification"); - let message = notification.getAttribute("label"); - is(message, "Caution: This site would like to install 2 add-ons in " + gApp + - ", some of which are unverified. Proceed at your own risk.", - "Should see the right message"); - - let container = document.getElementById("addon-install-confirmation-content"); - is(container.childNodes.length, 2, "Should be two items listed"); - is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on"); - is(container.childNodes[0].lastChild.getAttribute("class"), - "addon-install-confirmation-unsigned", "Should have the unverified marker"); - is(container.childNodes[1].firstChild.getAttribute("value"), "Theme Test", "Should have the right add-on"); - is(container.childNodes[1].childNodes.length, 1, "Shouldn't have the unverified marker"); - - let notificationPromise = waitForNotification("addon-install-restart"); - acceptInstallDialog(installDialog); - yield notificationPromise; - - let [addon, theme] = yield new Promise(resolve => { - AddonManager.getAddonsByIDs(["restartless-xpi@tests.mozilla.org", - "theme-xpi@tests.mozilla.org"], - function(addons) { - resolve(addons); - }); - }); - addon.uninstall(); - // Installing a new theme tries to switch to it, switch back to the - // default theme. - theme.userDisabled = true; - theme.uninstall(); - - Services.perms.remove(makeURI("http://example.com/"), "install"); - yield removeTab(); - }); -}, - function test_allUnverified() { return Task.spawn(function* () { // This test is only relevant if using the new doorhanger UI and allowing // unsigned add-ons if (!Preferences.get("xpinstall.customConfirmationUI", false) || Preferences.get("xpinstall.signatures.required", true) || REQUIRE_SIGNING) { return;
--- a/toolkit/mozapps/extensions/AddonManager.jsm +++ b/toolkit/mozapps/extensions/AddonManager.jsm @@ -361,98 +361,87 @@ function webAPIForAddon(addon) { return result; } /** * Listens for a browser changing origin and cancels the installs that were * started by it. */ -function BrowserListener(aBrowser, aInstallingPrincipal, aInstalls) { +function BrowserListener(aBrowser, aInstallingPrincipal, aInstall) { this.browser = aBrowser; this.principal = aInstallingPrincipal; - this.installs = aInstalls; - this.installCount = aInstalls.length; + this.install = aInstall; aBrowser.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_LOCATION); Services.obs.addObserver(this, "message-manager-close", true); - for (let install of this.installs) - install.addListener(this); + aInstall.addListener(this); this.registered = true; } BrowserListener.prototype = { browser: null, - installs: null, - installCount: null, + install: null, registered: false, unregister() { if (!this.registered) return; this.registered = false; Services.obs.removeObserver(this, "message-manager-close"); // The browser may have already been detached if (this.browser.removeProgressListener) this.browser.removeProgressListener(this); - for (let install of this.installs) - install.removeListener(this); - this.installs = null; + this.install.removeListener(this); + this.install = null; }, - cancelInstalls() { - for (let install of this.installs) { - try { - install.cancel(); - } catch (e) { - // Some installs may have already failed or been cancelled, ignore these - } + cancelInstall() { + try { + this.install.cancel(); + } catch (e) { + // install may have already failed or been cancelled, ignore these } }, observe(subject, topic, data) { if (subject != this.browser.messageManager) return; // The browser's message manager has closed and so the browser is - // going away, cancel all installs - this.cancelInstalls(); + // going away, cancel the install + this.cancelInstall(); }, onLocationChange(webProgress, request, location) { if (this.browser.contentPrincipal && this.principal.subsumes(this.browser.contentPrincipal)) return; - // The browser has navigated to a new origin so cancel all installs - this.cancelInstalls(); + // The browser has navigated to a new origin so cancel the install + this.cancelInstall(); }, onDownloadCancelled(install) { - // Don't need to hear more events from this install - install.removeListener(this); - - // Once all installs have ended unregister everything - if (--this.installCount == 0) - this.unregister(); + this.unregister(); }, onDownloadFailed(install) { - this.onDownloadCancelled(install); + this.unregister(); }, onInstallFailed(install) { - this.onDownloadCancelled(install); + this.unregister(); }, onInstallEnded(install) { - this.onDownloadCancelled(install); + this.unregister(); }, QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIWebProgressListener, Ci.nsIObserver]) }; /** @@ -2021,54 +2010,49 @@ var AddonManagerInternal = { if (callProvider(provider, "supportsMimetype", false, aMimetype) && callProvider(provider, "isInstallAllowed", null, aInstallingPrincipal)) return true; } return false; }, /** - * Starts installation of an array of AddonInstalls notifying the registered + * Starts installation of an AddonInstall notifying the registered * web install listener of blocked or started installs. * * @param aMimetype * The mimetype of add-ons being installed * @param aBrowser * The optional browser element that started the installs * @param aInstallingPrincipal * The nsIPrincipal that initiated the install - * @param aInstalls - * The array of AddonInstalls to be installed + * @param aInstall + * The AddonInstall to be installed */ - installAddonsFromWebpage(aMimetype, aBrowser, - aInstallingPrincipal, aInstalls) { + installAddonFromWebpage(aMimetype, aBrowser, + aInstallingPrincipal, aInstall) { if (!gStarted) throw Components.Exception("AddonManager is not initialized", Cr.NS_ERROR_NOT_INITIALIZED); if (!aMimetype || typeof aMimetype != "string") throw Components.Exception("aMimetype must be a non-empty string", Cr.NS_ERROR_INVALID_ARG); if (aBrowser && !(aBrowser instanceof Ci.nsIDOMElement)) throw Components.Exception("aSource must be a nsIDOMElement, or null", Cr.NS_ERROR_INVALID_ARG); if (!aInstallingPrincipal || !(aInstallingPrincipal instanceof Ci.nsIPrincipal)) throw Components.Exception("aInstallingPrincipal must be a nsIPrincipal", Cr.NS_ERROR_INVALID_ARG); - if (!Array.isArray(aInstalls)) - throw Components.Exception("aInstalls must be an array", - Cr.NS_ERROR_INVALID_ARG); - if (!("@mozilla.org/addons/web-install-listener;1" in Cc)) { - logger.warn("No web installer available, cancelling all installs"); - for (let install of aInstalls) - install.cancel(); + logger.warn("No web installer available, cancelling install"); + aInstall.cancel(); return; } // When a chrome in-content UI has loaded a <browser> inside to host a // website we want to do our security checks on the inner-browser but // notify front-end that install events came from the outer-browser (the // main tab's browser). Check this by seeing if the browser we've been // passed is in a content type docshell and if so get the outer-browser. @@ -2080,56 +2064,51 @@ var AddonManagerInternal = { if (docShell.itemType == Ci.nsIDocShellTreeItem.typeContent) topBrowser = docShell.chromeEventHandler; try { let weblistener = Cc["@mozilla.org/addons/web-install-listener;1"]. getService(Ci.amIWebInstallListener); if (!this.isInstallEnabled(aMimetype)) { - for (let install of aInstalls) - install.cancel(); + aInstall.cancel(); weblistener.onWebInstallDisabled(topBrowser, aInstallingPrincipal.URI, - aInstalls, aInstalls.length); + [aInstall], 1); return; } else if (!aBrowser.contentPrincipal || !aInstallingPrincipal.subsumes(aBrowser.contentPrincipal)) { - for (let install of aInstalls) - install.cancel(); + aInstall.cancel(); if (weblistener instanceof Ci.amIWebInstallListener2) { weblistener.onWebInstallOriginBlocked(topBrowser, aInstallingPrincipal.URI, - aInstalls, aInstalls.length); + [aInstall], 1); } return; } - // The installs may start now depending on the web install listener, + // The install may start now depending on the web install listener, // listen for the browser navigating to a new origin and cancel the - // installs in that case. - new BrowserListener(aBrowser, aInstallingPrincipal, aInstalls); + // install in that case. + new BrowserListener(aBrowser, aInstallingPrincipal, aInstall); if (!this.isInstallAllowed(aMimetype, aInstallingPrincipal)) { if (weblistener.onWebInstallBlocked(topBrowser, aInstallingPrincipal.URI, - aInstalls, aInstalls.length)) { - for (let install of aInstalls) - install.install(); + [aInstall], 1)) { + aInstall.install(); } } else if (weblistener.onWebInstallRequested(topBrowser, aInstallingPrincipal.URI, - aInstalls, aInstalls.length)) { - for (let install of aInstalls) - install.install(); + [aInstall], 1)) { + aInstall.install(); } } catch (e) { // In the event that the weblistener throws during instantiation or when - // calling onWebInstallBlocked or onWebInstallRequested all of the - // installs should get cancelled. + // calling onWebInstallBlocked or onWebInstallRequested the + // install should get cancelled. logger.warn("Failure calling web installer", e); - for (let install of aInstalls) - install.cancel(); + aInstall.cancel(); } }, /** * Adds a new InstallListener if the listener is not already registered. * * @param aListener * The InstallListener to add @@ -3419,21 +3398,20 @@ this.AddonManager = { isInstallEnabled(aType) { return AddonManagerInternal.isInstallEnabled(aType); }, isInstallAllowed(aType, aInstallingPrincipal) { return AddonManagerInternal.isInstallAllowed(aType, aInstallingPrincipal); }, - installAddonsFromWebpage(aType, aBrowser, aInstallingPrincipal, - aInstalls) { - AddonManagerInternal.installAddonsFromWebpage(aType, aBrowser, - aInstallingPrincipal, - aInstalls); + installAddonFromWebpage(aType, aBrowser, aInstallingPrincipal, aInstall) { + AddonManagerInternal.installAddonFromWebpage(aType, aBrowser, + aInstallingPrincipal, + aInstall); }, installTemporaryAddon(aDirectory) { return AddonManagerInternal.installTemporaryAddon(aDirectory); }, installAddonFromSources(aDirectory) { return AddonManagerInternal.installAddonFromSources(aDirectory);
--- a/toolkit/mozapps/extensions/addonManager.js +++ b/toolkit/mozapps/extensions/addonManager.js @@ -16,17 +16,17 @@ const { classes: Cc, interfaces: Ci, uti const EXECUTION_ERROR = -203; const CANT_READ_ARCHIVE = -207; const USER_CANCELLED = -210; const DOWNLOAD_ERROR = -228; const UNSUPPORTED_TYPE = -244; const SUCCESS = 0; const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled"; -const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage"; +const MSG_INSTALL_ADDON = "WebInstallerInstallAddonFromWebpage"; const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback"; const MSG_PROMISE_REQUEST = "WebAPIPromiseRequest"; const MSG_PROMISE_RESULT = "WebAPIPromiseResult"; const MSG_INSTALL_EVENT = "WebAPIInstallEvent"; const MSG_INSTALL_CLEANUP = "WebAPICleanup"; const MSG_ADDON_EVENT_REQ = "WebAPIAddonEventRequest"; const MSG_ADDON_EVENT = "WebAPIAddonEvent"; @@ -39,17 +39,17 @@ Cu.import("resource://gre/modules/Servic var gSingleton = null; function amManager() { Cu.import("resource://gre/modules/AddonManager.jsm"); /* globals AddonManagerPrivate*/ Services.mm.loadFrameScript(CHILD_SCRIPT, true); Services.mm.addMessageListener(MSG_INSTALL_ENABLED, this); - Services.mm.addMessageListener(MSG_INSTALL_ADDONS, this); + Services.mm.addMessageListener(MSG_INSTALL_ADDON, this); Services.mm.addMessageListener(MSG_PROMISE_REQUEST, this); Services.mm.addMessageListener(MSG_INSTALL_CLEANUP, this); Services.mm.addMessageListener(MSG_ADDON_EVENT_REQ, this); Services.obs.addObserver(this, "message-manager-close", false); Services.obs.addObserver(this, "message-manager-disconnect", false); AddonManager.webAPI.setEventHandler(this.sendEvent); @@ -75,84 +75,63 @@ amManager.prototype = { /** * @see amIAddonManager.idl */ mapURIToAddonID(uri, id) { id.value = AddonManager.mapURIToAddonID(uri); return !!id.value; }, - /** - * @see amIWebInstaller.idl - */ - isInstallEnabled(aMimetype, aReferer) { - return AddonManager.isInstallEnabled(aMimetype); - }, - - /** - * @see amIWebInstaller.idl - */ - installAddonsFromWebpage(aMimetype, aBrowser, aInstallingPrincipal, - aUris, aHashes, aNames, aIcons, aCallback) { - if (aUris.length == 0) - return false; - + installAddonFromWebpage(aMimetype, aBrowser, aInstallingPrincipal, + aUri, aHash, aName, aIcon, aCallback) { let retval = true; if (!AddonManager.isInstallAllowed(aMimetype, aInstallingPrincipal)) { aCallback = null; retval = false; } - let installs = []; - function buildNextInstall() { - if (aUris.length == 0) { - AddonManager.installAddonsFromWebpage(aMimetype, aBrowser, aInstallingPrincipal, installs); + AddonManager.getInstallForURL(aUri, function(aInstall) { + function callCallback(uri, status) { + try { + aCallback.onInstallEnded(uri, status); + } catch (e) { + Components.utils.reportError(e); + } + } + + if (!aInstall) { + aCallback.onInstallEnded(aUri, UNSUPPORTED_TYPE); return; } - let uri = aUris.shift(); - AddonManager.getInstallForURL(uri, function(aInstall) { - function callCallback(aUri, aStatus) { - try { - aCallback.onInstallEnded(aUri, aStatus); - } catch (e) { - Components.utils.reportError(e); - } - } - if (aInstall) { - installs.push(aInstall); - if (aCallback) { - aInstall.addListener({ - onDownloadCancelled(aInstall) { - callCallback(uri, USER_CANCELLED); - }, + if (aCallback) { + aInstall.addListener({ + onDownloadCancelled(aInstall) { + callCallback(aUri, USER_CANCELLED); + }, - onDownloadFailed(aInstall) { - if (aInstall.error == AddonManager.ERROR_CORRUPT_FILE) - callCallback(uri, CANT_READ_ARCHIVE); - else - callCallback(uri, DOWNLOAD_ERROR); - }, - - onInstallFailed(aInstall) { - callCallback(uri, EXECUTION_ERROR); - }, + onDownloadFailed(aInstall) { + if (aInstall.error == AddonManager.ERROR_CORRUPT_FILE) + callCallback(aUri, CANT_READ_ARCHIVE); + else + callCallback(aUri, DOWNLOAD_ERROR); + }, - onInstallEnded(aInstall, aStatus) { - callCallback(uri, SUCCESS); - } - }); + onInstallFailed(aInstall) { + callCallback(aUri, EXECUTION_ERROR); + }, + + onInstallEnded(aInstall, aStatus) { + callCallback(aUri, SUCCESS); } - } else if (aCallback) { - aCallback.onInstallEnded(uri, UNSUPPORTED_TYPE); - } - buildNextInstall(); - }, aMimetype, aHashes.shift(), aNames.shift(), aIcons.shift(), null, aBrowser); - } - buildNextInstall(); + }); + } + + AddonManager.installAddonFromWebpage(aMimetype, aBrowser, aInstallingPrincipal, aInstall); + }, aMimetype, aHash, aName, aIcon, null, aBrowser); return retval; }, notify(aTimer) { AddonManagerPrivate.backgroundUpdateTimerHandler(); }, @@ -196,34 +175,34 @@ amManager.prototype = { */ receiveMessage(aMessage) { let payload = aMessage.data; switch (aMessage.name) { case MSG_INSTALL_ENABLED: return AddonManager.isInstallEnabled(payload.mimetype); - case MSG_INSTALL_ADDONS: { + case MSG_INSTALL_ADDON: { let callback = null; if (payload.callbackID != -1) { let mm = aMessage.target.messageManager; callback = { onInstallEnded(url, status) { mm.sendAsyncMessage(MSG_INSTALL_CALLBACK, { callbackID: payload.callbackID, url, status }); }, }; } - return this.installAddonsFromWebpage(payload.mimetype, - aMessage.target, payload.principalToInherit, payload.uris, - payload.hashes, payload.names, payload.icons, callback); + return this.installAddonFromWebpage(payload.mimetype, + aMessage.target, payload.principalToInherit, payload.uri, + payload.hash, payload.name, payload.icon, callback); } case MSG_PROMISE_REQUEST: { let mm = aMessage.target.messageManager; let resolve = (value) => { mm.sendAsyncMessage(MSG_PROMISE_RESULT, { callbackID: payload.callbackID, resolve: value @@ -279,15 +258,14 @@ amManager.prototype = { Cr.NS_ERROR_NO_AGGREGATION); if (!gSingleton) gSingleton = new amManager(); return gSingleton.QueryInterface(aIid); } }, QueryInterface: XPCOMUtils.generateQI([Ci.amIAddonManager, - Ci.amIWebInstaller, Ci.nsITimerCallback, Ci.nsIObserver, Ci.nsIMessageListener]) }; this.NSGetFactory = XPCOMUtils.generateNSGetFactory([amManager]);
--- a/toolkit/mozapps/extensions/amContentHandler.js +++ b/toolkit/mozapps/extensions/amContentHandler.js @@ -4,17 +4,17 @@ "use strict"; const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; const XPI_CONTENT_TYPE = "application/x-xpinstall"; -const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage"; +const MSG_INSTALL_ADDON = "WebInstallerInstallAddonFromWebpage"; Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); function amContentHandler() { } amContentHandler.prototype = { @@ -46,21 +46,21 @@ amContentHandler.prototype = { aRequest.cancel(Cr.NS_BINDING_ABORTED); let principalToInherit = aRequest.loadInfo.principalToInherit; if (!principalToInherit) { principalToInherit = aRequest.loadInfo.triggeringPrincipal; } - let installs = { - uris: [uri.spec], - hashes: [null], - names: [null], - icons: [null], + let install = { + uri: uri.spec, + hash: null, + name: null, + icon: null, mimetype: XPI_CONTENT_TYPE, principalToInherit, callbackID: -1 }; if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { // When running in the main process this might be a frame inside an // in-content UI page, walk up to find the first frame element in a chrome @@ -69,31 +69,31 @@ amContentHandler.prototype = { let ssm = Services.scriptSecurityManager; while (element && !ssm.isSystemPrincipal(element.ownerDocument.nodePrincipal)) element = element.ownerDocument.defaultView.frameElement; if (element) { let listener = Cc["@mozilla.org/addons/integration;1"]. getService(Ci.nsIMessageListener); listener.wrappedJSObject.receiveMessage({ - name: MSG_INSTALL_ADDONS, + name: MSG_INSTALL_ADDON, target: element, - data: installs, + data: install }); return; } } // Fall back to sending through the message manager let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDocShell) .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIContentFrameMessageManager); - messageManager.sendAsyncMessage(MSG_INSTALL_ADDONS, installs); + messageManager.sendAsyncMessage(MSG_INSTALL_ADDON, install); }, classID: Components.ID("{7beb3ba8-6ec3-41b4-b67c-da89b8518922}"), QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler]), log(aMsg) { let msg = "amContentHandler.js: " + (aMsg.join ? aMsg.join("") : aMsg); Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).
deleted file mode 100644 --- a/toolkit/mozapps/extensions/amIWebInstaller.idl +++ /dev/null @@ -1,82 +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/. */ - -#include "nsISupports.idl" - -interface nsIDOMElement; -interface nsIVariant; -interface nsIURI; - -/** - * A callback function used to notify webpages when a requested install has - * ended. - * - * NOTE: This is *not* the same as InstallListener. - */ -[scriptable, function, uuid(bb22f5c0-3ca1-48f6-873c-54e87987700f)] -interface amIInstallCallback : nsISupports -{ - /** - * Called when an install completes or fails. - * - * @param aUrl - * The url of the add-on being installed - * @param aStatus - * 0 if the install was successful or negative if not - */ - void onInstallEnded(in AString aUrl, in int32_t aStatus); -}; - - -/** - * This interface is used to allow webpages to start installing add-ons. - */ -[scriptable, uuid(658d6c09-15e0-4688-bee8-8551030472a9)] -interface amIWebInstaller : nsISupports -{ - /** - * Checks if installation is enabled for a webpage. - * - * @param aMimetype - * The mimetype for the add-on to be installed - * @param referer - * The URL of the webpage trying to install an add-on - * @return true if installation is enabled - */ - boolean isInstallEnabled(in AString aMimetype, in nsIURI aReferer); - - /** - * Installs an array of add-ons at the request of a webpage - * - * @param aMimetype - * The mimetype for the add-ons - * @param aBrowser - * The browser installing the add-ons. - * @param aReferer - * The URI for the webpage installing the add-ons - * @param aUris - * The URIs of add-ons to be installed - * @param aHashes - * The hashes for the add-ons to be installed - * @param aNames - * The names for the add-ons to be installed - * @param aIcons - * The icons for the add-ons to be installed - * @param aCallback - * An optional callback to notify about installation success and - * failure - * @param aInstallCount - * An optional argument including the number of add-ons to install - * @return true if the installation was successfully started - */ - boolean installAddonsFromWebpage(in AString aMimetype, - in nsIDOMElement aBrowser, - in nsIURI aReferer, - [array, size_is(aInstallCount)] in wstring aUris, - [array, size_is(aInstallCount)] in wstring aHashes, - [array, size_is(aInstallCount)] in wstring aNames, - [array, size_is(aInstallCount)] in wstring aIcons, - [optional] in amIInstallCallback aCallback, - [optional] in uint32_t aInstallCount); -};
--- a/toolkit/mozapps/extensions/amInstallTrigger.js +++ b/toolkit/mozapps/extensions/amInstallTrigger.js @@ -9,37 +9,34 @@ const {classes: Cc, interfaces: Ci, util Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Preferences.jsm"); Cu.import("resource://gre/modules/Log.jsm"); const XPINSTALL_MIMETYPE = "application/x-xpinstall"; const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled"; -const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage"; +const MSG_INSTALL_ADDON = "WebInstallerInstallAddonFromWebpage"; const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback"; var log = Log.repository.getLogger("AddonManager.InstallTrigger"); log.level = Log.Level[Preferences.get("extensions.logging.enabled", false) ? "Warn" : "Trace"]; -function CallbackObject(id, callback, urls, mediator) { +function CallbackObject(id, callback, mediator) { this.id = id; this.callback = callback; - this.urls = new Set(urls); this.callCallback = function(url, status) { try { this.callback(url, status); } catch (e) { log.warn("InstallTrigger callback threw an exception: " + e); } - this.urls.delete(url); - if (this.urls.size == 0) - mediator._callbacks.delete(id); + mediator._callbacks.delete(id); }; } function RemoteMediator(window) { window.QueryInterface(Ci.nsIInterfaceRequestor); let utils = window.getInterface(Ci.nsIDOMWindowUtils); this._windowID = utils.currentInnerWindowID; @@ -66,59 +63,59 @@ RemoteMediator.prototype = { enabled(url) { let params = { mimetype: XPINSTALL_MIMETYPE }; return this.mm.sendSyncMessage(MSG_INSTALL_ENABLED, params)[0]; }, - install(installs, principal, callback, window) { - let callbackID = this._addCallback(callback, installs.uris); + install(install, principal, callback, window) { + let callbackID = this._addCallback(callback); - installs.mimetype = XPINSTALL_MIMETYPE; - installs.principalToInherit = principal; - installs.callbackID = callbackID; + install.mimetype = XPINSTALL_MIMETYPE; + install.principalToInherit = principal; + install.callbackID = callbackID; if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { // When running in the main process this might be a frame inside an // in-content UI page, walk up to find the first frame element in a chrome // privileged document let element = window.frameElement; let ssm = Services.scriptSecurityManager; while (element && !ssm.isSystemPrincipal(element.ownerDocument.nodePrincipal)) element = element.ownerDocument.defaultView.frameElement; if (element) { let listener = Cc["@mozilla.org/addons/integration;1"]. getService(Ci.nsIMessageListener); return listener.wrappedJSObject.receiveMessage({ - name: MSG_INSTALL_ADDONS, + name: MSG_INSTALL_ADDON, target: element, - data: installs, + data: install, }); } } // Fall back to sending through the message manager let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell) .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIContentFrameMessageManager); - return messageManager.sendSyncMessage(MSG_INSTALL_ADDONS, installs)[0]; + return messageManager.sendSyncMessage(MSG_INSTALL_ADDON, install)[0]; }, - _addCallback(callback, urls) { + _addCallback(callback) { if (!callback || typeof callback != "function") return -1; let callbackID = this._windowID + "-" + ++this._lastCallbackID; - let callbackObject = new CallbackObject(callbackID, callback, urls, this); + let callbackObject = new CallbackObject(callbackID, callback, this); this._callbacks.set(callbackID, callbackObject); return callbackID; }, QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference]) }; @@ -156,50 +153,49 @@ InstallTrigger.prototype = { return this._mediator.enabled(this._url.spec); }, updateEnabled() { return this.enabled(); }, install(installs, callback) { - let installData = { - uris: [], - hashes: [], - names: [], - icons: [], - }; + let keys = Object.keys(installs); + if (keys.length > 1) { + throw new this._window.Error("Only one XPI may be installed at a time"); + } + + let item = installs[keys[0]]; - for (let name of Object.keys(installs)) { - let item = installs[name]; - if (typeof item === "string") { - item = { URL: item }; - } - if (!item.URL) { - throw new this._window.Error("Missing URL property for '" + name + "'"); - } + if (typeof item === "string") { + item = { URL: item }; + } + if (!item.URL) { + throw new this._window.Error("Missing URL property for '" + name + "'"); + } - let url = this._resolveURL(item.URL); - if (!this._checkLoadURIFromScript(url)) { - throw new this._window.Error("Insufficient permissions to install: " + url.spec); - } + let url = this._resolveURL(item.URL); + if (!this._checkLoadURIFromScript(url)) { + throw new this._window.Error("Insufficient permissions to install: " + url.spec); + } - let iconUrl = null; - if (item.IconURL) { - iconUrl = this._resolveURL(item.IconURL); - if (!this._checkLoadURIFromScript(iconUrl)) { - iconUrl = null; // If page can't load the icon, just ignore it - } + let iconUrl = null; + if (item.IconURL) { + iconUrl = this._resolveURL(item.IconURL); + if (!this._checkLoadURIFromScript(iconUrl)) { + iconUrl = null; // If page can't load the icon, just ignore it } + } - installData.uris.push(url.spec); - installData.hashes.push(item.Hash || null); - installData.names.push(name); - installData.icons.push(iconUrl ? iconUrl.spec : null); - } + let installData = { + uri: url.spec, + hash: item.Hash || null, + name: item.name, + icon: iconUrl ? iconUrl.spec : null, + }; return this._mediator.install(installData, this._principal, callback, this._window); }, startSoftwareUpdate(url, flags) { let filename = Services.io.newURI(url, null, null) .QueryInterface(Ci.nsIURL) .filename;
--- a/toolkit/mozapps/extensions/moz.build +++ b/toolkit/mozapps/extensions/moz.build @@ -10,17 +10,16 @@ if CONFIG['MOZ_BUILD_APP'] == 'mobile/an DEFINES['MOZ_FENNEC'] = True DIRS += ['internal'] TEST_DIRS += ['test'] XPIDL_SOURCES += [ 'amIAddonManager.idl', 'amIAddonPathService.idl', - 'amIWebInstaller.idl', 'amIWebInstallListener.idl', ] XPIDL_MODULE = 'extensions' EXTRA_COMPONENTS += [ 'addonManager.js', 'amContentHandler.js',
deleted file mode 100644 index 74e877f26fe36641a92e66d3c5960e7f52e39e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
--- a/toolkit/mozapps/extensions/test/xpinstall/browser.ini +++ b/toolkit/mozapps/extensions/test/xpinstall/browser.ini @@ -1,12 +1,11 @@ [DEFAULT] support-files = amosigned.xpi - amosigned2.xpi authRedirect.sjs bug540558.html bug638292.html bug645699.html concurrent_installs.html cookieRedirect.sjs corrupt.xpi empty.xpi @@ -21,17 +20,16 @@ support-files = redirect.sjs restartless.xpi restartless-unsigned.xpi signed-no-cn.xpi signed-no-o.xpi signed-tampered.xpi signed-untrusted.xpi signed.xpi - signed2.xpi slowinstall.sjs startsoftwareupdate.html theme.xpi triggerredirect.html unsigned.xpi [browser_amosigned_trigger.js] [browser_amosigned_trigger_iframe.js] @@ -45,17 +43,16 @@ support-files = [browser_badhash.js] [browser_badhashtype.js] [browser_bug540558.js] [browser_bug611242.js] [browser_bug638292.js] [browser_bug645699.js] [browser_bug672485.js] skip-if = true # disabled due to a leak. See bug 682410. -[browser_cancel.js] [browser_concurrent_installs.js] [browser_cookies.js] [browser_cookies2.js] [browser_cookies3.js] [browser_cookies4.js] skip-if = true # Bug 1084646 [browser_corrupt.js] [browser_datauri.js] @@ -78,19 +75,19 @@ skip-if = true # Bug 1084646 [browser_localfile4.js] [browser_navigateaway.js] [browser_navigateaway2.js] [browser_navigateaway3.js] skip-if = (os == "mac" || os == "win") # Bug 1198261 [browser_navigateaway4.js] [browser_offline.js] [browser_relative.js] -[browser_signed_multiple.js] +[browser_signed_no_o.js] skip-if = require_signing -[browser_signed_naming.js] +[browser_signed_no_cn.js] skip-if = require_signing [browser_signed_tampered.js] skip-if = require_signing [browser_signed_trigger.js] skip-if = require_signing [browser_signed_untrusted.js] skip-if = require_signing [browser_signed_url.js]
deleted file mode 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_cancel.js +++ /dev/null @@ -1,60 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -// ---------------------------------------------------------------------------- -// Tests that cancelling multiple installs doesn't fail -function test() { - Harness.installConfirmCallback = confirm_install; - Harness.installEndedCallback = install_ended; - Harness.installsCompletedCallback = finish_test; - Harness.setup(); - - var pm = Services.perms; - pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION); - - var triggers = encodeURIComponent(JSON.stringify({ - "Unsigned XPI": TESTROOT + "amosigned.xpi", - "Unsigned XPI 2": TESTROOT + "amosigned2.xpi", - })); - gBrowser.selectedTab = gBrowser.addTab(); - gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers); -} - -function get_item(items, url) { - for (let item of items) { - if (item.url == url) - return item; - } - ok(false, "Item for " + url + " was not listed"); - return null; -} - -function confirm_install(window) { - let items = window.document.getElementById("itemList").childNodes; - is(items.length, 2, "Should be 2 items listed in the confirmation dialog"); - let item = get_item(items, TESTROOT + "amosigned.xpi"); - if (item) { - is(item.name, "XPI Test", "Should have seen the name from the trigger list"); - is(item.signed, "false", "Should have listed the item as signed"); - } - item = get_item(items, TESTROOT + "amosigned2.xpi"); - if (item) { - is(item.name, "Signed XPI Test", "Should have seen the name from the trigger list"); - is(item.signed, "false", "Should have listed the item as signed"); - } - return false; -} - -function install_ended(install, addon) { - ok(false, "Should not have seen installs complete"); -} - -function finish_test(count) { - is(count, 0, "No add-ons should have been successfully installed"); - - Services.perms.remove(makeURI("http://example.com"), "install"); - - gBrowser.removeCurrentTab(); - Harness.finish(); -}
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_httphash6.js +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_httphash6.js @@ -58,19 +58,19 @@ function finish_failed_download() { "X-Target-Digest": "sha1:36ffb0acfd9c6e9682473aaebaab394d38b473c9", "Location": "http://example.com/browser/" + RELATIVE_DIR + "amosigned.xpi" }); // The harness expects onNewInstall events for all installs that are about to start Harness.onNewInstall(gInstall); // Restart the install as a regular webpage install so the harness tracks it - AddonManager.installAddonsFromWebpage("application/x-xpinstall", - gBrowser.selectedBrowser, - gBrowser.contentPrincipal, [gInstall]); + AddonManager.installAddonFromWebpage("application/x-xpinstall", + gBrowser.selectedBrowser, + gBrowser.contentPrincipal, gInstall); } function install_ended(install, addon) { install.cancel(); } function finish_test(count) { is(count, 1, "1 Add-on should have been successfully installed");
deleted file mode 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_signed_multiple.js +++ /dev/null @@ -1,72 +0,0 @@ -// ---------------------------------------------------------------------------- -// Tests installing two signed add-ons in the same trigger works. -// This verifies bug 453545 -function test() { - Harness.installConfirmCallback = confirm_install; - Harness.installEndedCallback = install_ended; - Harness.installsCompletedCallback = finish_test; - Harness.setup(); - - var pm = Services.perms; - pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION); - - var triggers = encodeURIComponent(JSON.stringify({ - "Signed XPI": TESTROOT + "signed.xpi", - "Signed XPI 2": TESTROOT + "signed2.xpi", - "Signed XPI 3": TESTROOT + "signed-no-o.xpi", - "Signed XPI 4": TESTROOT + "signed-no-cn.xpi", - "Signed XPI 5": TESTROOT + "unsigned.xpi" - })); - gBrowser.selectedTab = gBrowser.addTab(); - gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers); -} - -function get_item(items, url) { - for (let item of items) { - if (item.url == url) - return item; - } - ok(false, "Item for " + url + " was not listed"); - return null; -} - -function confirm_install(window) { - - var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]. - getService(Components.interfaces.nsIStringBundleService); - var bundle = sbs.createBundle("chrome://mozapps/locale/xpinstall/xpinstallConfirm.properties"); - - var expectedIntroString = bundle.formatStringFromName("itemWarnIntroMultiple", ["5"], 1); - - var introStringNode = window.document.getElementById("itemWarningIntro"); - is(introStringNode.textContent, expectedIntroString, "Should have the correct intro string"); - - var items = window.document.getElementById("itemList").childNodes; - is(items.length, 5, "Should be 5 items listed in the confirmation dialog"); - let item = get_item(items, TESTROOT + "signed.xpi"); - if (item) { - is(item.name, "Signed XPI Test", "Should have seen the name from the trigger list"); - is(item.cert, "(Object Signer)", "Should have seen the signer"); - is(item.signed, "true", "Should have listed the item as signed"); - } - item = get_item(items, TESTROOT + "signed2.xpi"); - if (item) { - is(item.name, "Signed XPI Test", "Should have seen the name from the trigger list"); - is(item.cert, "(Object Signer)", "Should have seen the signer"); - is(item.signed, "true", "Should have listed the item as signed"); - } - return true; -} - -function install_ended(install, addon) { - install.cancel(); -} - -function finish_test(count) { - is(count, 5, "5 Add-ons should have been successfully installed"); - - Services.perms.remove(makeURI("http://example.com"), "install"); - - gBrowser.removeCurrentTab(); - Harness.finish(); -}
deleted file mode 100644 --- a/toolkit/mozapps/extensions/test/xpinstall/browser_signed_naming.js +++ /dev/null @@ -1,67 +0,0 @@ -// ---------------------------------------------------------------------------- -// Tests that the correct signer is presented for combinations of O and CN present. -// The signed files have (when present) O=Mozilla Testing, CN=Object Signer -// This verifies bug 372980 -function test() { - Harness.installConfirmCallback = confirm_install; - Harness.installEndedCallback = install_ended; - Harness.installsCompletedCallback = finish_test; - Harness.setup(); - - var pm = Services.perms; - pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION); - - var triggers = encodeURIComponent(JSON.stringify({ - "Signed XPI (O and CN)": TESTROOT + "signed.xpi", - "Signed XPI (CN)": TESTROOT + "signed-no-o.xpi", - "Signed XPI (O)": TESTROOT + "signed-no-cn.xpi", - })); - gBrowser.selectedTab = gBrowser.addTab(); - gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers); -} - -function get_item(items, url) { - for (let item of items) { - if (item.url == url) - return item; - } - ok(false, "Item for " + url + " was not listed"); - return null; -} - -function confirm_install(window) { - let items = window.document.getElementById("itemList").childNodes; - is(items.length, 3, "Should be 3 items listed in the confirmation dialog"); - let item = get_item(items, TESTROOT + "signed.xpi"); - if (item) { - is(item.name, "Signed XPI Test", "Should have seen the name from the trigger list"); - is(item.cert, "(Object Signer)", "Should have seen the signer"); - is(item.signed, "true", "Should have listed the item as signed"); - } - item = get_item(items, TESTROOT + "signed-no-o.xpi"); - if (item) { - is(item.name, "Signed XPI Test (No Org)", "Should have seen the name from the trigger list"); - is(item.cert, "(Object Signer)", "Should have seen the signer"); - is(item.signed, "true", "Should have listed the item as signed"); - } - item = get_item(items, TESTROOT + "signed-no-cn.xpi"); - if (item) { - is(item.name, "Signed XPI Test (No Common Name)", "Should have seen the name from the trigger list"); - is(item.cert, "(Mozilla Testing)", "Should have seen the signer"); - is(item.signed, "true", "Should have listed the item as signed"); - } - return true; -} - -function install_ended(install, addon) { - install.cancel(); -} - -function finish_test(count) { - is(count, 3, "3 Add-ons should have been successfully installed"); - - Services.perms.remove(makeURI("http://example.com"), "install"); - - gBrowser.removeCurrentTab(); - Harness.finish(); -}
new file mode 100644 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_signed_no_cn.js @@ -0,0 +1,42 @@ +// ---------------------------------------------------------------------------- +// Tests that the correct signer is presented for combinations of O and CN present. +// The signed files have (when present) O=Mozilla Testing, CN=Object Signer +// This verifies bug 372980 +function test() { + Harness.installConfirmCallback = confirm_install; + Harness.installEndedCallback = install_ended; + Harness.installsCompletedCallback = finish_test; + Harness.setup(); + + var pm = Services.perms; + pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION); + + const trigger = encodeURIComponent(JSON.stringify({ + "Signed XPI (O)": TESTROOT + "signed-no-cn.xpi", + })); + gBrowser.selectedTab = gBrowser.addTab(); + gBrowser.loadURI(TESTROOT + "installtrigger.html?" + trigger); +} + +function confirm_install(window) { + let items = window.document.getElementById("itemList").childNodes; + is(items.length, 1, "Should be 1 item listed in the confirmation dialog"); + let item = items[0]; + is(item.name, "Signed XPI Test (No Common Name)", "Should have seen the name from the trigger list"); + is(item.cert, "(Mozilla Testing)", "Should have seen the signer"); + is(item.signed, "true", "Should have listed the item as signed"); + return true; +} + +function install_ended(install, addon) { + install.cancel(); +} + +function finish_test(count) { + is(count, 1, "1 add-on should have been successfully installed"); + + Services.perms.remove(makeURI("http://example.com"), "install"); + + gBrowser.removeCurrentTab(); + Harness.finish(); +}
new file mode 100644 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/browser_signed_no_o.js @@ -0,0 +1,42 @@ +// ---------------------------------------------------------------------------- +// Tests that the correct signer is presented for combinations of O and CN present. +// The signed files have (when present) O=Mozilla Testing, CN=Object Signer +// This verifies bug 372980 +function test() { + Harness.installConfirmCallback = confirm_install; + Harness.installEndedCallback = install_ended; + Harness.installsCompletedCallback = finish_test; + Harness.setup(); + + var pm = Services.perms; + pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION); + + const trigger = encodeURIComponent(JSON.stringify({ + "Signed XPI (CN)": TESTROOT + "signed-no-o.xpi", + })); + gBrowser.selectedTab = gBrowser.addTab(); + gBrowser.loadURI(TESTROOT + "installtrigger.html?" + trigger); +} + +function confirm_install(window) { + let items = window.document.getElementById("itemList").childNodes; + is(items.length, 1, "Should be 1 item listed in the confirmation dialog"); + let item = items[0]; + is(item.name, "Signed XPI Test (No Org)", "Should have seen the name from the trigger list"); + is(item.cert, "(Object Signer)", "Should have seen the signer"); + is(item.signed, "true", "Should have listed the item as signed"); + return true; +} + +function install_ended(install, addon) { + install.cancel(); +} + +function finish_test(count) { + is(count, 1, "1 add-on should have been successfully installed"); + + Services.perms.remove(makeURI("http://example.com"), "install"); + + gBrowser.removeCurrentTab(); + Harness.finish(); +}