зеркало из https://github.com/mozilla/pjs.git
Bug 550936: Make InstallTrigger support cross-process communication, r=Mossop
This commit is contained in:
Родитель
26b56a9359
Коммит
96779a16bb
|
@ -149,7 +149,6 @@ COMPONENT_LIBS += \
|
|||
nsappshell \
|
||||
txmgr \
|
||||
commandlines \
|
||||
extensions \
|
||||
toolkitcomps \
|
||||
pipboot \
|
||||
pipnss \
|
||||
|
|
|
@ -265,7 +265,6 @@
|
|||
STORAGE_MODULE \
|
||||
PLACES_MODULES \
|
||||
XULENABLED_MODULES \
|
||||
MODULE(AddonsModule) \
|
||||
MODULE(nsToolkitCompsModule) \
|
||||
XREMOTE_MODULES \
|
||||
JSDEBUGGER_MODULES \
|
||||
|
|
|
@ -41,14 +41,8 @@ VPATH = @srcdir@
|
|||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = extensions
|
||||
LIBRARY_NAME = extensions
|
||||
SHORT_LIBNAME = extnsion
|
||||
IS_COMPONENT = 1
|
||||
MODULE_NAME = AddonsModule
|
||||
GRE_MODULE = 1
|
||||
LIBXUL_LIBRARY = 1
|
||||
EXPORT_LIBRARY = 1
|
||||
MODULE = extensions
|
||||
XPIDL_MODULE = extensions
|
||||
|
||||
XPIDLSRCS = \
|
||||
amIInstallTrigger.idl \
|
||||
|
@ -56,10 +50,6 @@ XPIDLSRCS = \
|
|||
amIWebInstaller.idl \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
amInstallTrigger.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_PP_COMPONENTS = \
|
||||
extensions.manifest \
|
||||
nsBlocklistService.js \
|
||||
|
|
|
@ -3836,6 +3836,49 @@ var XPIDatabase = {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -4307,8 +4350,6 @@ AddonInstall.prototype = {
|
|||
* 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)) {
|
||||
|
@ -4366,13 +4407,10 @@ AddonInstall.prototype = {
|
|||
listener.init(this, this.stream);
|
||||
try {
|
||||
this.channel = NetUtil.newChannel(this.sourceURI);
|
||||
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.notificationCallbacks =
|
||||
new XPINotificationCallbacks(this.window, !this.hash);
|
||||
this.channel.QueryInterface(Ci.nsIHttpChannelInternal)
|
||||
.forceAllowThirdPartyCookie = true;
|
||||
this.channel.asyncOpen(listener, null);
|
||||
|
||||
Services.obs.addObserver(this, "network:offline-about-to-go-offline", false);
|
||||
|
@ -4408,11 +4446,6 @@ AddonInstall.prototype = {
|
|||
* @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 {
|
||||
|
|
|
@ -57,12 +57,27 @@ 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);
|
||||
}
|
||||
|
||||
amManager.prototype = {
|
||||
|
@ -167,6 +182,52 @@ amManager.prototype = {
|
|||
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,
|
||||
{ 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) {
|
||||
|
|
|
@ -1,380 +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):
|
||||
* 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(¶ms);
|
||||
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;
|
|
@ -1,65 +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):
|
||||
* 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;
|
||||
};
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
# ***** 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";
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/**
|
||||
* 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 InstallTriggerChild() {
|
||||
addEventListener("DOMWindowCreated", this, false);
|
||||
}
|
||||
|
||||
var that = this;
|
||||
|
||||
InstallTriggerChild.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;
|
||||
|
||||
// The public object which web scripts can see (limited by
|
||||
// the __exposedProps__ defined below)
|
||||
window.wrappedJSObject.InstallTrigger = {
|
||||
__exposedProps__: {
|
||||
SKIN: "r",
|
||||
LOCALE: "r",
|
||||
CONTENT: "r",
|
||||
PACKAGE: "r",
|
||||
enabled: "r",
|
||||
updateEnabled: "r",
|
||||
install: "r",
|
||||
installChrome: "r",
|
||||
startSoftwareUpdate: "r",
|
||||
},
|
||||
|
||||
// == 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: window.location.href
|
||||
})[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* @see amIInstallTriggerInstaller.idl
|
||||
*/
|
||||
updateEnabled: function() {
|
||||
return this.enabled();
|
||||
},
|
||||
|
||||
/**
|
||||
* @see amIInstallTriggerInstaller.idl
|
||||
*/
|
||||
install: function(aArgs, aCallback) {
|
||||
var params = {
|
||||
mimetype: "application/x-xpinstall",
|
||||
referer: 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 = Services.io.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;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 callbackId, the ID of the callback.
|
||||
*
|
||||
*/
|
||||
receiveMessage: function(aMessage) {
|
||||
var payload = aMessage.json;
|
||||
var callbackId = payload.callbackId;
|
||||
var url = payload.url;
|
||||
var status = payload.status;
|
||||
var callbackObj = this.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)
|
||||
this.callbacks[callbackId] = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 Services.io.newURI(aUrl, null,
|
||||
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 = window.content.document.nodePrincipal;
|
||||
try {
|
||||
secman.checkLoadURIWithPrincipal(principal, aUri,
|
||||
Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
|
||||
return true;
|
||||
}
|
||||
catch(e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
addMessageListener(MSG_INSTALL_CALLBACK,
|
||||
window.wrappedJSObject.InstallTrigger);
|
||||
},
|
||||
};
|
||||
|
||||
new InstallTriggerChild();
|
||||
|
|
@ -5,6 +5,7 @@ toolkit.jar:
|
|||
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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче