Backed out changeset c8dc4dd369ee
authorKyle Huey <me@kylehuey.com>
Tue, 17 Aug 2010 01:07:56 -0400
changeset 50710 fafc537889901eff93e3a287bbbeb646e6764684
parent 50685 c8dc4dd369ee9b8668685d3a2011473cde7390f1
child 50711 6b6187bfe4fece3d87a49093a366366fefb59dd1
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone2.0b4pre
backs outc8dc4dd369ee9b8668685d3a2011473cde7390f1
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
Backed out changeset c8dc4dd369ee
toolkit/library/libxul-config.mk
toolkit/library/nsStaticXULComponents.cpp
toolkit/mozapps/extensions/Makefile.in
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/extensions/addonManager.js
toolkit/mozapps/extensions/amInstallTrigger.cpp
toolkit/mozapps/extensions/amInstallTrigger.h
toolkit/mozapps/extensions/content/extensions-content.js
toolkit/mozapps/extensions/jar.mn
--- a/toolkit/library/libxul-config.mk
+++ b/toolkit/library/libxul-config.mk
@@ -144,16 +144,17 @@ COMPONENT_LIBS += \
 	imglib2 \
 	gklayout \
 	docshell \
 	embedcomponents \
 	webbrwsr \
 	nsappshell \
 	txmgr \
 	commandlines \
+	extensions \
 	toolkitcomps \
 	pipboot \
 	pipnss \
 	appcomps \
 	$(NULL)
 
 ifdef MOZ_IPC
 COMPONENT_LIBS +=  jetpack_s
--- a/toolkit/library/nsStaticXULComponents.cpp
+++ b/toolkit/library/nsStaticXULComponents.cpp
@@ -260,16 +260,17 @@
     COMPOSER_MODULE                          \
     MODULE(application)                      \
     MODULE(Apprunner)                        \
     MODULE(CommandLineModule)                \
     FILEVIEW_MODULE                          \
     STORAGE_MODULE                           \
     PLACES_MODULES                           \
     XULENABLED_MODULES                       \
+    MODULE(AddonsModule)                     \
     MODULE(nsToolkitCompsModule)             \
     XREMOTE_MODULES                          \
     JSDEBUGGER_MODULES                       \
     MODULE(BOOT)                             \
     MODULE(NSS)                              \
     SYSTEMPREF_MODULES                       \
     SPELLCHECK_MODULE                        \
     LAYOUT_DEBUG_MODULE                      \
--- a/toolkit/mozapps/extensions/Makefile.in
+++ b/toolkit/mozapps/extensions/Makefile.in
@@ -36,25 +36,35 @@
 
 DEPTH     = ../../..
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-MODULE       = extensions
-XPIDL_MODULE = extensions
+MODULE         = extensions
+LIBRARY_NAME   = extensions
+SHORT_LIBNAME  = extnsion
+IS_COMPONENT   = 1
+MODULE_NAME    = AddonsModule
+GRE_MODULE     = 1
+LIBXUL_LIBRARY = 1
+EXPORT_LIBRARY = 1
 
 XPIDLSRCS = \
   amIInstallTrigger.idl \
   amIWebInstallListener.idl \
   amIWebInstaller.idl \
   $(NULL)
 
+CPPSRCS		= \
+  amInstallTrigger.cpp \
+  $(NULL)
+
 EXTRA_PP_COMPONENTS = \
   extensions.manifest \
   nsBlocklistService.js \
   addonManager.js \
   amContentHandler.js \
   amWebInstallListener.js \
   $(NULL)
 
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -3832,59 +3832,16 @@ var XPIDatabase = {
     fos.write(text, text.length);
     FileUtils.closeSafeFileOutputStream(fos);
 
     Services.prefs.setCharPref(PREF_EM_ENABLED_ADDONS, enabledAddons.join(","));
   }
 };
 
 /**
- * Handles callbacks for HTTP channels of XPI downloads. We support
- * prompting for auth dialogs and, optionally, to ignore bad certs.
- *
- * @param  aWindow
- *         An optional DOM Element related to the request
- * @param  aNeedBadCertHandling
- *         Whether we should handle bad certs or not
- */
-function XPINotificationCallbacks(aWindow, aNeedBadCertHandling) {
-  this.window = aWindow;
-
-  // Verify that we don't end up on an insecure channel if we haven't got a
-  // hash to verify with (see bug 537761 for discussion)
-  this.needBadCertHandling = aNeedBadCertHandling;
-
-  if (this.needBadCertHandling) {
-    Components.utils.import("resource://gre/modules/CertUtils.jsm");
-    this.badCertHandler = new BadCertHandler();
-  }
-}
-
-XPINotificationCallbacks.prototype = {
-  QueryInterface: function(iid) {
-    if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIInterfaceRequestor))
-      return this;
-    throw Components.results.NS_ERROR_NO_INTERFACE;
-  },
-
-  getInterface: function(iid) {
-    if (iid.equals(Components.interfaces.nsIAuthPrompt2)) {
-      var factory = Cc["@mozilla.org/prompter;1"].
-                    getService(Ci.nsIPromptFactory);
-      return factory.getPrompt(this.window, Ci.nsIAuthPrompt);
-    }
-
-    if (this.needBadCertHandling)
-      return this.badCertHandler.getInterface(iid);
-
-    throw Components.results.NS_ERROR_NO_INTERFACE;
-  },
-};
-
-/**
  * Instantiates an AddonInstall and passes the new object to a callback when
  * it is complete.
  *
  * @param  aCallback
  *         The callback to pass the AddonInstall to
  * @param  aInstallLocation
  *         The install location the add-on will be installed into
  * @param  aUrl
@@ -4345,16 +4302,18 @@ AddonInstall.prototype = {
     // Network is going offline
     this.cancel();
   },
 
   /**
    * Starts downloading the add-on's XPI file.
    */
   startDownload: function AI_startDownload() {
+    Components.utils.import("resource://gre/modules/CertUtils.jsm");
+
     this.state = AddonManager.STATE_DOWNLOADING;
     if (!AddonManagerPrivate.callInstallListeners("onDownloadStarted",
                                                   this.listeners, this.wrapper)) {
       this.state = AddonManager.STATE_CANCELLED;
       XPIProvider.removeActiveInstall(this);
       AddonManagerPrivate.callInstallListeners("onDownloadCancelled",
                                                this.listeners, this.wrapper)
       return;
@@ -4402,20 +4361,23 @@ AddonInstall.prototype = {
       return;
     }
 
     let listener = Cc["@mozilla.org/network/stream-listener-tee;1"].
                    createInstance(Ci.nsIStreamListenerTee);
     listener.init(this, this.stream);
     try {
       this.channel = NetUtil.newChannel(this.sourceURI);
-      this.channel.notificationCallbacks =
-        new XPINotificationCallbacks(this.window, !this.hash);
-      this.channel.QueryInterface(Ci.nsIHttpChannelInternal)
-                  .forceAllowThirdPartyCookie = true;
+      if (this.loadGroup)
+        this.channel.loadGroup = this.loadGroup;
+
+      // Verify that we don't end up on an insecure channel if we haven't got a
+      // hash to verify with (see bug 537761 for discussion)
+      if (!this.hash)
+        this.channel.notificationCallbacks = new BadCertHandler();
       this.channel.asyncOpen(listener, null);
 
       Services.obs.addObserver(this, "network:offline-about-to-go-offline", false);
     }
     catch (e) {
       WARN("Failed to start download: " + e);
       this.state = AddonManager.STATE_DOWNLOAD_FAILED;
       this.error = AddonManager.ERROR_NETWORK_FAILURE;
@@ -4441,16 +4403,21 @@ AddonInstall.prototype = {
   },
 
   /**
    * This is the first chance to get at real headers on the channel.
    *
    * @see nsIStreamListener
    */
   onStartRequest: function AI_onStartRequest(aRequest, aContext) {
+    // We must remove the request from the load group otherwise if the user
+    // closes the page that triggered it the download will be cancelled
+    if (this.loadGroup)
+      this.loadGroup.removeRequest(aRequest, null, Cr.NS_BINDING_RETARGETED);
+
     this.progress = 0;
     if (aRequest instanceof Ci.nsIChannel) {
       try {
         this.maxProgress = aRequest.contentLength;
       }
       catch (e) {
       }
       LOG("Download started for " + this.sourceURI.spec + " to file " +
--- a/toolkit/mozapps/extensions/addonManager.js
+++ b/toolkit/mozapps/extensions/addonManager.js
@@ -52,37 +52,22 @@ const PREF_EM_UPDATE_INTERVAL = "extensi
 // The old XPInstall error codes
 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_CALLBACK = "WebInstallerInstallCallback";
-
-const CHILD_SCRIPT =
-  "chrome://mozapps/content/extensions/extensions-content.js";
-
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-Components.utils.import("resource://gre/modules/Services.jsm");
 
 var gSingleton = null;
 
 function amManager() {
   Components.utils.import("resource://gre/modules/AddonManager.jsm");
-
-  var messageManager = Cc["@mozilla.org/globalmessagemanager;1"].
-                       getService(Ci.nsIChromeFrameMessageManager);
-
-  messageManager.addMessageListener(MSG_INSTALL_ENABLED, this);
-  messageManager.addMessageListener(MSG_INSTALL_ADDONS, this);
-  messageManager.loadFrameScript(CHILD_SCRIPT, true, true);
 }
 
 amManager.prototype = {
   observe: function AMC_observe(aSubject, aTopic, aData) {
     let os = Cc["@mozilla.org/observer-service;1"].
              getService(Ci.nsIObserverService);
 
     switch (aTopic) {
@@ -177,63 +162,16 @@ amManager.prototype = {
 
     return retval;
   },
 
   notify: function AMC_notify(aTimer) {
     AddonManagerPrivate.backgroundUpdateCheck();
   },
 
-  /**
-   * messageManager callback function.
-   *
-   * Listens to requests from child processes for InstallTrigger
-   * activity, and sends back callbacks.
-   */
-  receiveMessage: function(aMessage) {
-    var payload = aMessage.json;
-    var referer = Services.io.newURI(payload.referer, null, null);
-    switch (aMessage.name) {
-      case MSG_INSTALL_ENABLED:
-        return this.isInstallEnabled(payload.mimetype, referer);
-
-      case MSG_INSTALL_ADDONS:
-        var callback = null;
-        if (payload.callbackId != -1) {
-          callback = {
-            onInstallEnded: function ITP_callback(url, status) {
-              // Doing it this way, instead of aMessage.target.messageManager,
-              // ensures it works in Firefox and not only Fennec. See bug
-              // 578172. TODO: Clean up this code once that bug is fixed
-              var flo = aMessage.target.QueryInterface(Ci.nsIFrameLoaderOwner);
-              var returnMessageManager = flo.frameLoader.messageManager;
-              returnMessageManager.sendAsyncMessage(MSG_INSTALL_CALLBACK,
-                { installerId: payload.installerId,
-                  callbackId: payload.callbackId, url: url, status: status }
-              );
-            },
-          };
-        }
-        var window;
-        try {
-          // Normal approach for single-process mode
-          window = aMessage.target.docShell
-                           .QueryInterface(Ci.nsIInterfaceRequestor)
-                           .getInterface(Ci.nsIDOMWindow).content;
-        } catch (e) {
-          // Fallback for multiprocess (e10s) mode. Appears to work but has
-          // not had a full suite of automated tests run on it.
-          window = aMessage.target.ownerDocument.defaultView;
-        }
-        return this.installAddonsFromWebpage(payload.mimetype,
-          window, referer, payload.uris, payload.hashes, payload.names,
-          payload.icons, callback, payload.uris.length);
-    }
-  },
-
   classID: Components.ID("{4399533d-08d1-458c-a87a-235f74451cfa}"),
   _xpcom_factory: {
     createInstance: function(aOuter, aIid) {
       if (aOuter != null)
         throw Cr.NS_ERROR_NO_AGGREGATION;
   
       if (!gSingleton)
         gSingleton = new amManager();
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/amInstallTrigger.cpp
@@ -0,0 +1,380 @@
+/* ***** 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) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dave Townsend <dtownsend@oxymoronical.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "amInstallTrigger.h"
+#include "nsIClassInfoImpl.h"
+#include "nsIComponentManager.h"
+#include "nsICategoryManager.h"
+#include "nsServiceManagerUtils.h"
+#include "nsXPIDLString.h"
+#include "nsIScriptNameSpaceManager.h"
+#include "nsDOMJSUtils.h"
+#include "nsIXPConnect.h"
+#include "nsContentUtils.h"
+#include "nsIDocument.h"
+#include "nsIDOMDocument.h"
+#include "nsNetUtil.h"
+#include "nsIScriptSecurityManager.h"
+#include "mozilla/ModuleUtils.h"
+
+//
+// Helper function for URI verification
+//
+static nsresult
+CheckLoadURIFromScript(JSContext *aCx, const nsACString& aUriStr)
+{
+  nsresult rv;
+  nsCOMPtr<nsIScriptSecurityManager> secman(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // get the script principal
+  nsCOMPtr<nsIPrincipal> principal;
+  rv = secman->GetSubjectPrincipal(getter_AddRefs(principal));
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!principal)
+    return NS_ERROR_FAILURE;
+
+  // convert the requested URL string to a URI
+  // Note that we use a null base URI here, since that's what we use when we
+  // actually convert the string into a URI to load.
+  nsCOMPtr<nsIURI> uri;
+  rv = NS_NewURI(getter_AddRefs(uri), aUriStr);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // are we allowed to load this one?
+  rv = secman->CheckLoadURIWithPrincipal(principal, uri,
+                  nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL);
+  return rv;
+}
+
+NS_IMPL_CLASSINFO(amInstallTrigger, NULL, nsIClassInfo::DOM_OBJECT,
+                  AM_InstallTrigger_CID)
+NS_IMPL_ISUPPORTS1_CI(amInstallTrigger, amIInstallTrigger)
+
+amInstallTrigger::amInstallTrigger()
+{
+  mManager = do_GetService("@mozilla.org/addons/integration;1");
+}
+
+amInstallTrigger::~amInstallTrigger()
+{
+}
+
+JSContext*
+amInstallTrigger::GetJSContext()
+{
+  nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
+
+  // get the xpconnect native call context
+  nsAXPCNativeCallContext *cc = nsnull;
+  xpc->GetCurrentNativeCallContext(&cc);
+  if (!cc)
+    return nsnull;
+
+  // Get JSContext of current call
+  JSContext* cx;
+  nsresult rv = cc->GetJSContext(&cx);
+  if (NS_FAILED(rv))
+    return nsnull;
+
+  return cx;
+}
+
+already_AddRefed<nsIDOMWindowInternal>
+amInstallTrigger::GetOriginatingWindow(JSContext* aCx)
+{
+  nsIScriptGlobalObject *globalObject = nsnull;
+  nsIScriptContext *scriptContext = GetScriptContextFromJSContext(aCx);
+  if (!scriptContext)
+    return nsnull;
+
+  globalObject = scriptContext->GetGlobalObject();
+  if (!globalObject)
+    return nsnull;
+
+  nsCOMPtr<nsIDOMWindowInternal> window = do_QueryInterface(globalObject);
+  return window.forget();
+}
+
+already_AddRefed<nsIURI>
+amInstallTrigger::GetOriginatingURI(nsIDOMWindowInternal* aWindow)
+{
+  if (!aWindow)
+    return nsnull;
+
+  nsCOMPtr<nsIDOMDocument> domdoc;
+  aWindow->GetDocument(getter_AddRefs(domdoc));
+  nsCOMPtr<nsIDocument> doc(do_QueryInterface(domdoc));
+  nsIURI* uri = doc->GetDocumentURI();
+  NS_IF_ADDREF(uri);
+  return uri;
+}
+
+/* boolean updateEnabled (); */
+NS_IMETHODIMP
+amInstallTrigger::UpdateEnabled(PRBool *_retval NS_OUTPARAM)
+{
+  return Enabled(_retval);
+}
+
+/* boolean enabled (); */
+NS_IMETHODIMP
+amInstallTrigger::Enabled(PRBool *_retval NS_OUTPARAM)
+{
+  nsCOMPtr<nsIDOMWindowInternal> window = GetOriginatingWindow(GetJSContext());
+  nsCOMPtr<nsIURI> referer = GetOriginatingURI(window);
+
+  return mManager->IsInstallEnabled(NS_LITERAL_STRING("application/x-xpinstall"), referer, _retval);
+}
+
+/* boolean install (in nsIVariant args, [optional] in amIInstallCallback callback); */
+NS_IMETHODIMP
+amInstallTrigger::Install(nsIVariant *aArgs,
+                          amIInstallCallback *aCallback,
+                          PRBool *_retval NS_OUTPARAM)
+{
+  JSContext *cx = GetJSContext();
+  nsCOMPtr<nsIDOMWindowInternal> window = GetOriginatingWindow(cx);
+  nsCOMPtr<nsIURI> referer = GetOriginatingURI(window);
+
+  jsval params;
+  nsresult rv = aArgs->GetAsJSVal(&params);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!JSVAL_IS_OBJECT(params) || !JSVAL_TO_OBJECT(params))
+    return NS_ERROR_INVALID_ARG;
+
+  JSIdArray *ida = JS_Enumerate(cx, JSVAL_TO_OBJECT(params));
+  if (!ida)
+    return NS_ERROR_FAILURE;
+
+  PRUint32 count = ida->length;
+
+  nsTArray<const PRUnichar*> names;
+  nsTArray<const PRUnichar*> uris;
+  nsTArray<const PRUnichar*> icons;
+  nsTArray<const PRUnichar*> hashes;
+
+  jsval v;
+  for (PRUint32 i = 0; i < count; i++ ) {
+    JS_IdToValue(cx, ida->vector[i], &v);
+    JSString *str = JS_ValueToString(cx, v);
+    if (!str) {
+      JS_DestroyIdArray(cx, ida);
+      return NS_ERROR_FAILURE;
+    }
+
+    const PRUnichar* name = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str));
+    const PRUnichar* uri = nsnull;
+    const PRUnichar* icon = nsnull;
+    const PRUnichar* hash = nsnull;
+
+    JS_GetUCProperty(cx, JSVAL_TO_OBJECT(params), reinterpret_cast<const jschar*>(name), nsCRT::strlen(name), &v);
+    if (JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v)) {
+      jsval v2;
+      if (JS_GetProperty(cx, JSVAL_TO_OBJECT(v), "URL", &v2) && !JSVAL_IS_VOID(v2)) {
+        JSString *str = JS_ValueToString(cx, v2);
+        if (!str) {
+          JS_DestroyIdArray(cx, ida);
+          return NS_ERROR_FAILURE;
+        }
+        uri = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str));
+      }
+
+      if (JS_GetProperty(cx, JSVAL_TO_OBJECT(v), "IconURL", &v2) && !JSVAL_IS_VOID(v2)) {
+        JSString *str = JS_ValueToString(cx, v2);
+        if (!str) {
+          JS_DestroyIdArray(cx, ida);
+          return NS_ERROR_FAILURE;
+        }
+        icon = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str));
+      }
+
+      if (JS_GetProperty(cx, JSVAL_TO_OBJECT(v), "Hash", &v2) && !JSVAL_IS_VOID(v2)) {
+        JSString *str = JS_ValueToString(cx, v2);
+        if (!str) {
+          JS_DestroyIdArray(cx, ida);
+          return NS_ERROR_FAILURE;
+        }
+        hash = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str));
+      }
+    }
+    else {
+      uri = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(JS_ValueToString(cx, v)));
+    }
+
+    if (!uri) {
+      JS_DestroyIdArray(cx, ida);
+      return NS_ERROR_FAILURE;
+    }
+
+    nsCString tmpURI = NS_ConvertUTF16toUTF8(uri);
+    // Get relative URL to load
+    if (referer) {
+      rv = referer->Resolve(tmpURI, tmpURI);
+      if (NS_FAILED(rv)) {
+        JS_DestroyIdArray(cx, ida);
+        return rv;
+      }
+    }
+
+    rv = CheckLoadURIFromScript(cx, tmpURI);
+    if (NS_FAILED(rv)) {
+      JS_DestroyIdArray(cx, ida);
+      return rv;
+    }
+    uri = UTF8ToNewUnicode(tmpURI);
+
+    if (icon) {
+      nsCString tmpIcon = NS_ConvertUTF16toUTF8(icon);
+      if (referer) {
+        rv = referer->Resolve(tmpIcon, tmpIcon);
+        if (NS_FAILED(rv)) {
+          JS_DestroyIdArray(cx, ida);
+          return rv;
+        }
+      }
+
+      // If the page can't load the icon then just ignore it
+      rv = CheckLoadURIFromScript(cx, tmpIcon);
+      if (NS_FAILED(rv))
+        icon = nsnull;
+      else
+        icon = UTF8ToNewUnicode(tmpIcon);
+    }
+
+    names.AppendElement(name);
+    uris.AppendElement(uri);
+    icons.AppendElement(icon);
+    hashes.AppendElement(hash);
+  }
+
+  JS_DestroyIdArray(cx, ida);
+
+  rv = mManager->InstallAddonsFromWebpage(NS_LITERAL_STRING("application/x-xpinstall"),
+                                          window, referer, uris.Elements(),
+                                          hashes.Elements(), names.Elements(),
+                                          icons.Elements(), aCallback, count,
+                                          _retval);
+
+  for (PRUint32 i = 0; i < uris.Length(); i++) {
+    NS_Free(const_cast<PRUnichar*>(uris[i]));
+    if (icons[i])
+      NS_Free(const_cast<PRUnichar*>(icons[i]));
+  }
+
+  return rv;
+}
+
+/* boolean installChrome (in PRUint32 type, in AString url, in AString skin); */
+NS_IMETHODIMP
+amInstallTrigger::InstallChrome(PRUint32 aType,
+                                const nsAString & aUrl,
+                                const nsAString & aSkin,
+                                PRBool *_retval NS_OUTPARAM)
+{
+  return StartSoftwareUpdate(aUrl, 0, _retval);
+}
+
+/* boolean startSoftwareUpdate (in AString url, [optional] in PRInt32 flags); */
+NS_IMETHODIMP
+amInstallTrigger::StartSoftwareUpdate(const nsAString & aUrl,
+                                      PRInt32 aFlags,
+                                      PRBool *_retval NS_OUTPARAM)
+{
+  nsresult rv;
+
+  JSContext *cx = GetJSContext();
+  nsCOMPtr<nsIDOMWindowInternal> window = GetOriginatingWindow(cx);
+  nsCOMPtr<nsIURI> referer = GetOriginatingURI(window);
+
+  nsTArray<const PRUnichar*> names;
+  nsTArray<const PRUnichar*> uris;
+  nsTArray<const PRUnichar*> icons;
+  nsTArray<const PRUnichar*> hashes;
+
+  nsCString tmpURI = NS_ConvertUTF16toUTF8(aUrl);
+  // Get relative URL to load
+  if (referer) {
+    rv = referer->Resolve(tmpURI, tmpURI);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  rv = CheckLoadURIFromScript(cx, tmpURI);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  names.AppendElement((PRUnichar*)nsnull);
+  uris.AppendElement(UTF8ToNewUnicode(tmpURI));
+  icons.AppendElement((PRUnichar*)nsnull);
+  hashes.AppendElement((PRUnichar*)nsnull);
+
+  rv = mManager->InstallAddonsFromWebpage(NS_LITERAL_STRING("application/x-xpinstall"),
+                                          window, referer, uris.Elements(),
+                                          hashes.Elements(), names.Elements(),
+                                          icons.Elements(), nsnull, 1, _retval);
+
+  NS_Free(const_cast<PRUnichar*>(uris[0]));
+  return rv;
+}
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(amInstallTrigger)
+
+NS_DEFINE_NAMED_CID(AM_InstallTrigger_CID);
+
+static const mozilla::Module::CIDEntry kInstallTriggerCIDs[] = {
+  { &kAM_InstallTrigger_CID, false, NULL, amInstallTriggerConstructor },
+  { NULL }
+};
+
+static const mozilla::Module::ContractIDEntry kInstallTriggerContracts[] = {
+  { AM_INSTALLTRIGGER_CONTRACTID, &kAM_InstallTrigger_CID },
+  { NULL }
+};
+
+static const mozilla::Module::CategoryEntry kInstallTriggerCategories[] = {
+  { JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY, "InstallTrigger", AM_INSTALLTRIGGER_CONTRACTID },
+  { NULL }
+};
+
+static const mozilla::Module kInstallTriggerModule = {
+  mozilla::Module::kVersion,
+  kInstallTriggerCIDs,
+  kInstallTriggerContracts,
+  kInstallTriggerCategories
+};
+
+NSMODULE_DEFN(AddonsModule) = &kInstallTriggerModule;
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/amInstallTrigger.h
@@ -0,0 +1,65 @@
+/* ***** 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) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dave Townsend <dtownsend@oxymoronical.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "jscntxt.h"
+#include "amIInstallTrigger.h"
+#include "nsIDOMWindowInternal.h"
+#include "nsIURI.h"
+#include "amIWebInstaller.h"
+#include "nsCOMPtr.h"
+
+#define AM_InstallTrigger_CID \
+ {0xfcfcdf1e, 0xe9ef, 0x4141, {0x90, 0xd8, 0xd5, 0xff, 0x84, 0xc1, 0x7c, 0xce}}
+#define AM_INSTALLTRIGGER_CONTRACTID "@mozilla.org/addons/installtrigger;1"
+
+class amInstallTrigger : public amIInstallTrigger
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_AMIINSTALLTRIGGER
+
+  amInstallTrigger();
+
+private:
+  ~amInstallTrigger();
+
+  JSContext* GetJSContext();
+  already_AddRefed<nsIDOMWindowInternal> GetOriginatingWindow(JSContext* aCx);
+  already_AddRefed<nsIURI> GetOriginatingURI(nsIDOMWindowInternal* aWindow);
+
+  nsCOMPtr<amIWebInstaller> mManager;
+};
deleted file mode 100644
--- a/toolkit/mozapps/extensions/content/extensions-content.js
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
-# ***** 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) 2010
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#   Alon Zakai <azakai@mozilla.com>
-#
-# 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 *****
-*/
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-const MSG_INSTALL_ENABLED  = "WebInstallerIsInstallEnabled";
-const MSG_INSTALL_ADDONS   = "WebInstallerInstallAddonsFromWebpage";
-const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback";
-
-var gIoService = Components.classes["@mozilla.org/network/io-service;1"]
-                           .getService(Components.interfaces.nsIIOService);
-
-function InstallTrigger(installerId, window) {
-  this.installerId = installerId;
-  this.window = window;
-}
-
-InstallTrigger.prototype = {
-  __exposedProps__: {
-    SKIN: "r",
-    LOCALE: "r",
-    CONTENT: "r",
-    PACKAGE: "r",
-    enabled: "r",
-    updateEnabled: "r",
-    install: "r",
-    installChrome: "r",
-    startSoftwareUpdate: "r",
-    toSource: "r", // XXX workaround for bug 582100
-  },
-
-  // == Public interface ==
-
-  SKIN: Ci.amIInstallTrigger.SKIN,
-  LOCALE: Ci.amIInstallTrigger.LOCALE,
-  CONTENT: Ci.amIInstallTrigger.CONTENT,
-  PACKAGE: Ci.amIInstallTrigger.PACKAGE,
-
-  /**
-   * @see amIInstallTriggerInstaller.idl
-   */
-  enabled: function() {
-    return sendSyncMessage(MSG_INSTALL_ENABLED, {
-      mimetype: "application/x-xpinstall", referer: this.window.location.href
-    })[0];
-  },
-
-  /**
-   * @see amIInstallTriggerInstaller.idl
-   */
-  updateEnabled: function() {
-    return this.enabled();
-  },
-
-  /**
-   * @see amIInstallTriggerInstaller.idl
-   */
-  install: function(aArgs, aCallback) {
-    var params = {
-      installerId: this.installerId,
-      mimetype: "application/x-xpinstall",
-      referer: this.window.location.href,
-      uris: [],
-      hashes: [],
-      names: [],
-      icons: [],
-    };
-
-    for (var name in aArgs) {
-      var item = aArgs[name];
-      if (typeof item === 'string') {
-        item = { URL: item };
-      } else if (!("URL" in item)) {
-        throw new Error("Missing URL property for '" + name + "'");
-      }
-
-      // Resolve and validate urls
-      var url = this.resolveURL(item.URL);
-      if (!this.checkLoadURIFromScript(url))
-        throw new Error("insufficient permissions to install: " + url);
-
-      var iconUrl = null;
-      if ("IconURL" in item) {
-        iconUrl = this.resolveURL(item.IconURL);
-        if (!this.checkLoadURIFromScript(iconUrl)) {
-          iconUrl = null; // If page can't load the icon, just ignore it
-        }
-      }
-      params.uris.push(url.spec);
-      params.hashes.push("Hash" in item ? item.Hash : null);
-      params.names.push(name);
-      params.icons.push(iconUrl ? iconUrl.spec : null);
-    }
-    // Add callback Id, done here, so only if we actually got here
-    params.callbackId = this.addCallback(aCallback, params.uris);
-    // Send message
-    return sendSyncMessage(MSG_INSTALL_ADDONS, params)[0];
-  },
-
-  /**
-   * @see amIInstallTriggerInstaller.idl
-   */
-  startSoftwareUpdate: function(aUrl, aFlags) {
-    var url = gIoService.newURI(aUrl, null, null)
-                        .QueryInterface(Ci.nsIURL).filename;
-    var object = {};
-    object[url] = { "URL": aUrl };
-    return this.install(object);
-  },
-
-  /**
-   * @see amIInstallTriggerInstaller.idl
-   */
-  installChrome: function(aType, aUrl, aSkin) {
-    return this.startSoftwareUpdate(aUrl);
-  },
-
-  // == Internal, hidden machinery ==
-
-  callbacks: {},
-
-  /**
-   * Adds a callback to the list of callbacks we may receive messages
-   * about from the parent process. We save them here; only callback IDs
-   * are sent over IPC.
-   *
-   * @param  callback
-   *         The callback function
-   * @param  urls
-   *         The urls this callback function will receive responses for.
-   *         After all the callbacks have arrived, we can forget about the
-   *         callback.
-   *
-   * @return The callback ID, an integer identifying this callback.
-   */
-  addCallback: function(aCallback, aUrls) {
-    if (!aCallback)
-      return -1;
-    var callbackId = 0;
-    while (callbackId in this.callbacks)
-      callbackId++;
-    this.callbacks[callbackId] = {
-      callback: aCallback,
-      urls: aUrls.slice(0), // Clone the urls for our own use (it lets
-                            // us know when no further callbacks will
-                            // occur)
-    };
-    return callbackId;
-  },
-
-  /**
-   * Resolves a URL in the context of our current window. We need to do
-   * this before sending URLs to the parent process.
-   *
-   * @param  aUrl
-   *         The url to resolve.
-   *
-   * @return A resolved, absolute nsURI object.
-   */
-  resolveURL: function(aUrl) {
-    return gIoService.newURI(aUrl, null,
-                             this.window.document.documentURIObject);
-  },
-
-  /**
-   * @see amInstallTrigger.cpp
-   * TODO: When e10s lands on m-c, consider removing amInstallTrigger.cpp
-   *       See bug 571166
-   */
-  checkLoadURIFromScript: function(aUri) {
-    var secman = Cc["@mozilla.org/scriptsecuritymanager;1"].
-                 getService(Ci.nsIScriptSecurityManager);
-    var principal = this.window.content.document.nodePrincipal;
-    try {
-      secman.checkLoadURIWithPrincipal(principal, aUri,
-        Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
-      return true;
-    }
-    catch(e) {
-      return false;
-    }
-  },
-};
-
-/**
- * Child part of InstallTrigger e10s handling.
- *
- * Sets up InstallTriggers on newly-created windows,
- * that will relay messages for InstallTrigger
- * activity. We also process the parameters for
- * the InstallTrigger to proper parameters for
- * amIWebInstaller.
- */
-function InstallTriggerManager() {
-  this.installerIds = [];
-  this.nextInstallerId = 0;
-
-  addMessageListener(MSG_INSTALL_CALLBACK, this);
-
-  addEventListener("DOMWindowCreated", this, false);
-
-  var self = this;
-  addEventListener("unload", function() {
-    // Clean up all references, to help gc work quickly
-    for (var installerId in self.installerIds) {
-      self.installerIds[installerId].callbacks = null;
-      self.installerIds[installerId] = null;
-    }
-    self.installerIds = null;
-  }, false);
-}
-
-InstallTriggerManager.prototype = {
-  handleEvent: function handleEvent(aEvent) {
-    var window = aEvent.originalTarget.defaultView.content;
-
-    // Need to make sure we are called on what we care about -
-    // content windows. DOMWindowCreated is called on *all* HTMLDocuments,
-    // some of which belong to ChromeWindows or lack defaultView.content
-    // altogether.
-    //
-    // Note about the syntax used here: |"wrappedJSObject" in window|
-    // will silently fail, without even letting us catch it as an
-    // exception, and checking in the way that we do check in some
-    // cases still throws an exception; see bug 582108 about both.
-    try {
-      if (!window || !window.wrappedJSObject) {
-        return;
-      }
-    }
-    catch(e) {
-      return;
-    }
-
-    // This event happens for each HTMLDocument, so it can happen more than
-    // once per Window. We only need to work once per Window though.
-    if (window.wrappedJSObject.InstallTrigger)
-        return;
-
-    // Create the public object which web scripts can see
-    var installerId = this.nextInstallerId ++;
-    var installTrigger = new InstallTrigger(installerId, window);
-    this.installerIds[installerId] = installTrigger;
-    window.wrappedJSObject.InstallTrigger = installTrigger;
-  },
-
-  /**
-   * Receives a message about a callback. Performs the actual callback
-   * (for the callback with the ID we are given). When
-   * all URLs are exhausted, can free the callbackId and linked stuff.
-   *
-   * @param  message
-   *         The IPC message. Contains IDs of the installer and the
-   *         callback.
-   *
-   */
-  receiveMessage: function(aMessage) {
-    var payload = aMessage.json;
-    var installer = this.installerIds[payload.installerId];
-    var callbackId = payload.callbackId;
-    var url = payload.url;
-    var status = payload.status;
-    var callbackObj = installer.callbacks[callbackId];
-    if (!callbackObj)
-      return;
-    try {
-      callbackObj.callback(url, status);
-    }
-    catch (e) {
-      dump("InstallTrigger callback threw an exception: " + e + "\n");
-    }
-    callbackObj.urls.splice(callbackObj.urls.indexOf(url), 1);
-    if (callbackObj.urls.length == 0)
-      installer.callbacks[callbackId] = null;
-  },
-};
-
-new InstallTriggerManager();
-
--- a/toolkit/mozapps/extensions/jar.mn
+++ b/toolkit/mozapps/extensions/jar.mn
@@ -1,16 +1,15 @@
 toolkit.jar:
 % content mozapps %content/mozapps/
   content/mozapps/extensions/extensions.xul                     (content/extensions.xul)
   content/mozapps/extensions/extensions.css                     (content/extensions.css)
   content/mozapps/extensions/extensions.js                      (content/extensions.js)
   content/mozapps/extensions/extensions.xml                     (content/extensions.xml)
   content/mozapps/extensions/updateinfo.xsl                     (content/updateinfo.xsl)
-  content/mozapps/extensions/extensions-content.js              (content/extensions-content.js)
 * content/mozapps/extensions/about.xul                          (content/about.xul)
 * content/mozapps/extensions/about.js                           (content/about.js)
 * content/mozapps/extensions/list.xul                           (content/list.xul)
 * content/mozapps/extensions/list.js                            (content/list.js)
 * content/mozapps/extensions/blocklist.xul                      (content/blocklist.xul)
 * content/mozapps/extensions/blocklist.js                       (content/blocklist.js)
 * content/mozapps/extensions/blocklist.css                      (content/blocklist.css)
 * content/mozapps/extensions/blocklist.xml                      (content/blocklist.xml)