Visit Mozilla.org

Code snippets:Interaction between privileged and non-privileged pages

From MDC


Contents

[edit] Sending data from unprivileged document to chrome

An easy way to send data from a web page to an extension is by using custom DOM events. In your extension's browser.xul overlay, write code which listens for a custom DOM event. Here we call the event MyExtensionEvent.

var myExtension = {
  myListener: function(evt) {
    alert("Received from web page: " +
          evt.target.getAttribute("attribute1") + "/" + 
          evt.target.getAttribute("attribute2"));
  }
}
document.addEventListener("MyExtensionEvent", function(e) { myExtension.myListener(e); }, false, true);

The data from the web page (unprivileged code) will be the values of attribute1 and attribute2. To trigger the alert() in the listener and pass the data from the web page, write code such as this in the web page:

if ("createEvent" in document) {
  var element = document.createElement("MyExtensionDataElement");
  element.setAttribute("attribute1", "foobar");
  element.setAttribute("attribute2", "hello world");
  document.documentElement.appendChild(element);

  var evt = document.createEvent("Events");
  evt.initEvent("MyExtensionEvent", true, false);
  element.dispatchEvent(evt);
}

This code creates an arbitrary element -- <MyExtensionDataElement/> -- and inserts it into the web page's DOM. Values are set for two arbitrary attributes on the element. These can also be named anything you like, but we've chosen attribute1 and attribute2. Finally, the code creates and dispatches a custom event named MyExtensionEvent -- similar to the standard DOM click event you catch with onclick handlers. The event bubbles up from the web page and reaches the extension (privileged code) where your listener catches it and reads the attribute values from the DOM element where the event originated.

In the case where your extension's overlay does not interact directly with browser.xul, such as in a sidebar, it might be easier to add the event listener to the top-level document directly as shown below (also see: accessing the elements of the top-level document from a child window).

var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                  .getInterface(Components.interfaces.nsIWebNavigation)
                  .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
                  .rootTreeItem
                  .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                  .getInterface(Components.interfaces.nsIDOMWindow);
mainWindow.document.addEventListener("MyExtensionEvent", function(e) { myExtension.myListener(e); }, false, true);

If you need to to pass lots of data, consider using CDATA sections instead of the simple attributes on a custom element.

[edit] Sending data from chrome to unprivileged document

To "answer" the web page (e.g., return code), your extension can set an attribute or attach child elements on the event target element (<MyExtensionDataElement/> in this example).

You can optionally clean up the created element, or create it once when the web page loads then re-use it each time.

Basic example of similar idea, extension passes information via attributes and fires event on div in page, here.

[edit] Security notes

  • Never invoke the web page's JavaScript functions from your extension - doing this increases the chance of creating a security hole, where a malicious web page can trick the browser to run its code with extended privileges (just like your extension) with, for example, the ability to delete local files.
  • It is highly recommended to check the source of the event (via event.target.ownerDocument.location) and make your extension ignore any events from pages not from your server.

[edit] Resources

Mozillazine Forum Discussion