diff options
Diffstat (limited to 'dom/base/nsIMessageManager.idl')
-rw-r--r-- | dom/base/nsIMessageManager.idl | 550 |
1 files changed, 550 insertions, 0 deletions
diff --git a/dom/base/nsIMessageManager.idl b/dom/base/nsIMessageManager.idl new file mode 100644 index 000000000..7c64bd222 --- /dev/null +++ b/dom/base/nsIMessageManager.idl @@ -0,0 +1,550 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 mozIDOMWindowProxy; +interface nsIDocShell; +interface nsIContent; +interface nsIFrameLoader; +interface nsIPrincipal; + +/** + * Message managers provide a way for chrome-privileged JS code to + * communicate with each other, even across process boundaries. + * + * Message managers are separated into "parent side" and "child side". + * These don't always correspond to process boundaries, but can. For + * each child-side message manager, there is always exactly one + * corresponding parent-side message manager that it sends messages + * to. However, for each parent-side message manager, there may be + * either one or many child-side managers it can message. + * + * Message managers that always have exactly one "other side" are of + * type nsIMessageSender. Parent-side message managers that have many + * "other sides" are of type nsIMessageBroadcaster. + * + * Child-side message managers can send synchronous messages to their + * parent side, but not the other way around. + * + * There are two realms of message manager hierarchies. One realm + * approximately corresponds to DOM elements, the other corresponds to + * process boundaries. + * + * Message managers corresponding to DOM elements + * ============================================== + * + * In this realm of message managers, there are + * - "frame message managers" which correspond to frame elements + * - "window message managers" which correspond to top-level chrome + * windows + * - "group message managers" which correspond to named message + * managers with a specific window MM as the parent + * - the "global message manager", on the parent side. See below. + * + * The DOM-realm message managers can communicate in the ways shown by + * the following diagram. The parent side and child side can + * correspond to process boundaries, but don't always. + * + * Parent side Child side + * ------------- ------------ + * global MMg + * | + * +-->window MMw1 + * | | + * | +-->frame MMp1_1<------------>frame MMc1_1 + * | | + * | +-->frame MMp1_2<------------>frame MMc1_2 + * | | + * | +-->group MMgr1 + * | | | + * | | +-->frame MMp2_1<------->frame MMc2_1 + * | | | + * | | +-->frame MMp2_2<------->frame MMc2_2 + * | | + * | +-->group MMgr2 + * | | ... + * | | + * | ... + * | + * +-->window MMw2 + * ... + * + * For example: a message sent from MMc1_1, from the child side, is + * sent only to MMp1_1 on the parent side. However, note that all + * message managers in the hierarchy above MMp1_1, in this diagram + * MMw1 and MMg, will also notify their message listeners when the + * message arrives. + * + * A message sent from MMc2_1 will be sent to MMp2_1 and also notify + * all message managers in the hierarchy above that, including the + * group message manager MMgr1. + + * For example: a message broadcast through the global MMg on the + * parent side would be broadcast to MMw1, which would transitively + * broadcast it to MMp1_1, MM1p_2. The message would next be + * broadcast to MMgr1, which would broadcast it to MMp2_1 and MMp2_2. + * After that it would broadcast to MMgr2 and then to MMw2, and so + * on down the hierarchy. + * + * ***** PERFORMANCE AND SECURITY WARNING ***** + * Messages broadcast through the global MM and window or group MMs + * can result in messages being dispatched across many OS processes, + * and to many processes with different permissions. Great care + * should be taken when broadcasting. + * + * Interfaces + * ---------- + * + * The global MMg and window MMw's are message broadcasters implementing + * nsIMessageBroadcaster while the frame MMp's are simple message senders + * (nsIMessageSender). Their counterparts in the content processes are + * message senders implementing nsIContentFrameMessageManager. + * + * nsIMessageListenerManager + * / \ + * nsIMessageSender nsIMessageBroadcaster + * | + * nsISyncMessageSender (content process/in-process only) + * | + * nsIContentFrameMessageManager (content process/in-process only) + * | + * nsIInProcessContentFrameMessageManager (in-process only) + * + * + * Message managers in the chrome process can also be QI'ed to nsIFrameScriptLoader. + * + * + * Message managers corresponding to process boundaries + * ==================================================== + * + * The second realm of message managers is the "process message + * managers". With one exception, these always correspond to process + * boundaries. The picture looks like + * + * Parent process Child processes + * ---------------- ----------------- + * global (GPPMM) + * | + * +-->parent in-process PIPMM<-->child in-process CIPPMM + * | + * +-->parent (PPMM1)<------------------>child (CPMM1) + * | + * +-->parent (PPMM2)<------------------>child (CPMM2) + * ... + * + * Note, PIPMM and CIPPMM both run in the parent process. + * + * For example: the parent-process PPMM1 sends messages to the + * child-process CPMM1. + * + * For example: CPMM1 sends messages directly to PPMM1. The global GPPMM + * will also notify their message listeners when the message arrives. + * + * For example: messages sent through the global GPPMM will be + * dispatched to the listeners of the same-process, CIPPMM, CPMM1, + * CPMM2, etc. + * + * ***** PERFORMANCE AND SECURITY WARNING ***** + * Messages broadcast through the GPPMM can result in messages + * being dispatched across many OS processes, and to many processes + * with different permissions. Great care should be taken when + * broadcasting. + * + * Requests sent to parent-process message listeners should usually + * have replies scoped to the requesting CPMM. The following pattern + * is common + * + * const ParentProcessListener = { + * receiveMessage: function(aMessage) { + * let childMM = aMessage.target.QueryInterface(Ci.nsIMessageSender); + * switch (aMessage.name) { + * case "Foo:Request": + * // service request + * childMM.sendAsyncMessage("Foo:Response", { data }); + * } + * } + * }; + */ + +[scriptable, function, uuid(2b44eb57-a9c6-4773-9a1e-fe0818739a4c)] +interface nsIMessageListener : nsISupports +{ + /** + * This is for JS only. + * receiveMessage is called with one parameter, which has the following + * properties: + * { + * target: %the target of the message. Either an element owning + * the message manager, or message manager itself if no + * element owns it% + * name: %message name%, + * sync: %true or false%. + * data: %structured clone of the sent message data%, + * json: %same as .data, deprecated%, + * objects: %named table of jsvals/objects, or null% + * principal: %principal for the window app + * } + * + * Each listener is invoked with its own copy of the message + * parameter. + * + * When the listener is called, 'this' value is the target of the message. + * + * If the message is synchronous, the possible return value is + * returned as JSON (will be changed to use structured clones). + * When there are multiple listeners to sync messages, each + * listener's return value is sent back as an array. |undefined| + * return values show up as undefined values in the array. + */ + void receiveMessage(); +}; + +[scriptable, builtinclass, uuid(b949bfec-bb7d-47bc-b387-ac6a9b655072)] +interface nsIMessageListenerManager : nsISupports +{ + /** + * Register |listener| to receive |messageName|. All listener + * callbacks for a particular message are invoked when that message + * is received. + * + * The message manager holds a strong ref to |listener|. + * + * If the same listener registers twice for the same message, the + * second registration is ignored. + * + * Pass true for listenWhenClosed if you want to receive messages + * during the short period after a frame has been removed from the + * DOM and before its frame script has finished unloading. This + * parameter only has an effect for frame message managers in + * the main process. Default is false. + */ + void addMessageListener(in AString messageName, + in nsIMessageListener listener, + [optional] in boolean listenWhenClosed); + + /** + * Undo an |addMessageListener| call -- that is, calling this causes us to no + * longer invoke |listener| when |messageName| is received. + * + * removeMessageListener does not remove a message listener added via + * addWeakMessageListener; use removeWeakMessageListener for that. + */ + void removeMessageListener(in AString messageName, + in nsIMessageListener listener); + + /** + * This is just like addMessageListener, except the message manager holds a + * weak ref to |listener|. + * + * If you have two weak message listeners for the same message, they may be + * called in any order. + */ + void addWeakMessageListener(in AString messageName, + in nsIMessageListener listener); + + /** + * This undoes an |addWeakMessageListener| call. + */ + void removeWeakMessageListener(in AString messageName, + in nsIMessageListener listener); + + [notxpcom] boolean markForCC(); +}; + +/** + * Message "senders" have a single "other side" to which messages are + * sent. For example, a child-process message manager will send + * messages that are only delivered to its one parent-process message + * manager. + */ +[scriptable, builtinclass, uuid(bb5d79e4-e73c-45e7-9651-4d718f4b994c)] +interface nsIMessageSender : nsIMessageListenerManager +{ + /** + * Send |messageName| and |obj| to the "other side" of this message + * manager. This invokes listeners who registered for + * |messageName|. + * + * See nsIMessageListener::receiveMessage() for the format of the + * data delivered to listeners. + * @throws NS_ERROR_NOT_INITIALIZED if the sender is not initialized. For + * example, we will throw NS_ERROR_NOT_INITIALIZED if we try to send + * a message to a cross-process frame but the other process has not + * yet been set up. + * @throws NS_ERROR_FAILURE when the message receiver cannot be found. For + * example, we will throw NS_ERROR_FAILURE if we try to send a message + * to a cross-process frame whose process has crashed. + */ + [implicit_jscontext, optional_argc] + void sendAsyncMessage([optional] in AString messageName, + [optional] in jsval obj, + [optional] in jsval objects, + [optional] in nsIPrincipal principal, + [optional] in jsval transfers); + + /** + * For remote browsers there is always a corresponding process message + * manager. The intention of this attribute is to link leaf level frame + * message managers on the parent side with the corresponding process + * message managers (if there is one). For any other cases this property + * is null. + */ + readonly attribute nsIMessageSender processMessageManager; +}; + +/** + * Message "broadcasters" don't have a single "other side" that they + * send messages to, but rather a set of subordinate message managers. + * For example, broadcasting a message through a window message + * manager will broadcast the message to all frame message managers + * within its window. + */ +[scriptable, builtinclass, uuid(4d7d62ad-4725-4f39-86cf-8fb22bf9c1d8)] +interface nsIMessageBroadcaster : nsIMessageListenerManager +{ + /** + * Like |sendAsyncMessage()|, but also broadcasts this message to + * all "child" message managers of this message manager. See long + * comment above for details. + * + * WARNING: broadcasting messages can be very expensive and leak + * sensitive data. Use with extreme caution. + */ + [implicit_jscontext, optional_argc] + void broadcastAsyncMessage([optional] in AString messageName, + [optional] in jsval obj, + [optional] in jsval objects); + + /** + * Number of subordinate message managers. + */ + readonly attribute unsigned long childCount; + + /** + * Return a single subordinate message manager. + */ + nsIMessageListenerManager getChildAt(in unsigned long aIndex); +}; + +[scriptable, builtinclass, uuid(0e602c9e-1977-422a-a8e4-fe0d4a4f78d0)] +interface nsISyncMessageSender : nsIMessageSender +{ + /** + * Like |sendAsyncMessage()|, except blocks the sender until all + * listeners of the message have been invoked. Returns an array + * containing return values from each listener invoked. + */ + [implicit_jscontext, optional_argc] + jsval sendSyncMessage([optional] in AString messageName, + [optional] in jsval obj, + [optional] in jsval objects, + [optional] in nsIPrincipal principal); + + /** + * Like |sendSyncMessage()|, except re-entrant. New RPC messages may be + * issued even if, earlier on the call stack, we are waiting for a reply + * to an earlier sendRpcMessage() call. + * + * Both sendSyncMessage and sendRpcMessage will block until a reply is + * received, but they may be temporarily interrupted to process an urgent + * incoming message (such as a CPOW request). + */ + [implicit_jscontext, optional_argc] + jsval sendRpcMessage([optional] in AString messageName, + [optional] in jsval obj, + [optional] in jsval objects, + [optional] in nsIPrincipal principal); +}; + +[scriptable, builtinclass, uuid(13f3555f-769e-44ea-b607-5239230c3162)] +interface nsIMessageManagerGlobal : nsISyncMessageSender +{ + /** + * Print a string to stdout. + */ + void dump(in DOMString aStr); + + /** + * If leak detection is enabled, print a note to the leak log that this + * process will intentionally crash. + */ + void privateNoteIntentionalCrash(); + + /** + * Ascii base64 data to binary data and vice versa + */ + DOMString atob(in DOMString aAsciiString); + DOMString btoa(in DOMString aBase64Data); +}; + +[scriptable, builtinclass, uuid(694e367c-aa25-4446-8499-2c527c4bd838)] +interface nsIContentFrameMessageManager : nsIMessageManagerGlobal +{ + /** + * The current top level window in the frame or null. + */ + readonly attribute mozIDOMWindowProxy content; + + /** + * The top level docshell or null. + */ + readonly attribute nsIDocShell docShell; +}; + +[uuid(b39a3324-b574-4f85-8cdb-274d04f807ef)] +interface nsIInProcessContentFrameMessageManager : nsIContentFrameMessageManager +{ + [notxpcom] nsIContent getOwnerContent(); + [notxpcom] void cacheFrameLoader(in nsIFrameLoader aFrameLoader); +}; + +[scriptable, builtinclass, uuid(6d12e467-2446-46db-9965-e4e93cb87ca5)] +interface nsIContentProcessMessageManager : nsIMessageManagerGlobal +{ + /** + * Read out a copy of the object that was initialized in the parent + * process via nsIProcessScriptLoader.initialProcessData. + */ + [implicit_jscontext] + readonly attribute jsval initialProcessData; +}; + +[scriptable, builtinclass, uuid(bf61446b-ba24-4b1d-88c7-4f94724b9ce1)] +interface nsIFrameScriptLoader : nsISupports +{ + /** + * Load a script in the (remote) frame. aURL must be the absolute URL. + * data: URLs are also supported. For example data:,dump("foo\n"); + * If aAllowDelayedLoad is true, script will be loaded when the + * remote frame becomes available. Otherwise the script will be loaded + * only if the frame is already available. + */ + void loadFrameScript(in AString aURL, in boolean aAllowDelayedLoad, + [optional] in boolean aRunInGlobalScope); + + /** + * Removes aURL from the list of scripts which support delayed load. + */ + void removeDelayedFrameScript(in AString aURL); + + /** + * Returns all delayed scripts that will be loaded once a (remote) + * frame becomes available. The return value is a list of pairs + * [<URL>, <WasLoadedInGlobalScope>]. + */ + [implicit_jscontext] + jsval getDelayedFrameScripts(); +}; + +[scriptable, builtinclass, uuid(7e1e1a20-b24f-11e4-ab27-0800200c9a66)] +interface nsIProcessScriptLoader : nsISupports +{ + /** + * Load a script in the (possibly remote) process. aURL must be the absolute URL. + * data: URLs are also supported. For example data:,dump("foo\n"); + * If aAllowDelayedLoad is true, script will be loaded when the + * remote frame becomes available. Otherwise the script will be loaded + * only if the frame is already available. + */ + void loadProcessScript(in AString aURL, in boolean aAllowDelayedLoad); + + /** + * Removes aURL from the list of scripts which support delayed load. + */ + void removeDelayedProcessScript(in AString aURL); + + /** + * Returns all delayed scripts that will be loaded once a (remote) + * frame becomes available. The return value is a list of URLs. + */ + [implicit_jscontext] + jsval getDelayedProcessScripts(); +}; + +[scriptable, builtinclass, uuid(5b390753-abb3-49b0-ae3b-b803dab58144)] +interface nsIGlobalProcessScriptLoader : nsIProcessScriptLoader +{ + /** + * Allows the parent process to set the initial process data for + * new, not-yet-created child processes. This attribute should only + * be used by the global parent process message manager. When a new + * process is created, it gets a copy of this data (via structured + * cloning). It can access the data via the initialProcessData + * attribute of its childprocessmessagemanager. + * + * This value will always be a JS object. Different users are + * expected to set properties on this object. The property name + * should be unique enough that other Gecko consumers won't + * accidentally choose it. + */ + [implicit_jscontext] + readonly attribute jsval initialProcessData; +}; + +[scriptable, builtinclass, uuid(637e8538-4f8f-4a3d-8510-e74386233e19)] +interface nsIProcessChecker : nsISupports +{ + bool killChild(); + + /** + * Return true if the "remote" process has |aPermission|. This is + * intended to be used by JS implementations of cross-process DOM + * APIs, like so + * + * recvFooRequest: function(message) { + * if (!message.target.assertPermission("foo")) { + * return false; + * } + * // service foo request + * + * This interface only returns meaningful data when our content is + * in a separate process. If it shares the same OS process as us, + * then applying this permission check doesn't add any security, + * though it doesn't hurt anything either. + * + * Note: If the remote content process does *not* have |aPermission|, + * it will be killed as a precaution. + */ + boolean assertPermission(in DOMString aPermission); + + /** + * Return true if the "remote" process has |aManifestURL|. This is + * intended to be used by JS implementations of cross-process DOM + * APIs, like so + * + * recvFooRequest: function(message) { + * if (!message.target.assertContainApp("foo")) { + * return false; + * } + * // service foo request + * + * This interface only returns meaningful data when our content is + * in a separate process. If it shares the same OS process as us, + * then applying this manifest URL check doesn't add any security, + * though it doesn't hurt anything either. + * + * Note: If the remote content process does *not* contain |aManifestURL|, + * it will be killed as a precaution. + */ + boolean assertContainApp(in DOMString aManifestURL); + + boolean assertAppHasPermission(in DOMString aPermission); + + /** + * Return true if the "remote" process' principal has an appStatus equal to + * |aStatus|. + * + * This interface only returns meaningful data when our content is + * in a separate process. If it shares the same OS process as us, + * then applying this permission check doesn't add any security, + * though it doesn't hurt anything either. + * + * Note: If the remote content process does *not* has the |aStatus|, + * it will be killed as a precaution. + */ + boolean assertAppHasStatus(in unsigned short aStatus); + +}; |