DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (5b81998bb7ab)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
/* 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/. */

"use strict";

this.EXPORTED_SYMBOLS = ["Sandbox"];

const {classes: Cc, interfaces: Ci, utils: Cu} = Components;

const XHTML_NS = "http://www.w3.org/1999/xhtml";

Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");

XPCOMUtils.defineLazyModuleGetter(this,
                                  "Logger",
                                  "resource://gre/modules/identity/LogUtils.jsm");

/**
 * An object that represents a sandbox in an iframe loaded with aURL. The
 * callback provided to the constructor will be invoked when the sandbox is
 * ready to be used. The callback will receive this object as its only argument.
 *
 * You must call free() when you are finished with the sandbox to explicitly
 * free up all associated resources.
 *
 * @param aURL
 *        (string) URL to load in the sandbox.
 *
 * @param aCallback
 *        (function) Callback to be invoked with a Sandbox, when ready.
 */
this.Sandbox = function Sandbox(aURL, aCallback) {
  // Normalize the URL so the comparison in _makeSandboxContentLoaded works
  this._url = Services.io.newURI(aURL, null, null).spec;
  this._log("Creating sandbox for:", this._url);
  this._createFrame();
  this._createSandbox(aCallback);
};

this.Sandbox.prototype = {

  /**
   * Use the outer window ID as the identifier of the sandbox.
   */
  get id() {
    return this._frame.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
               .getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
  },

  /**
   * Reload the URL in the sandbox. This is useful to reuse a Sandbox (same
   * id and URL).
   */
  reload: function Sandbox_reload(aCallback) {
    this._log("reload:", this.id, ":", this._url);
    this._createSandbox(function createdSandbox(aSandbox) {
      this._log("reloaded sandbox id:", aSandbox.id);
      aCallback(aSandbox);
    }.bind(this));
  },

  /**
   * Frees the sandbox and releases the iframe created to host it.
   */
  free: function Sandbox_free() {
    this._log("free:", this.id);
    this._container.removeChild(this._frame);
    this._frame = null;
    this._container = null;
    this._url = null;
  },

  /**
   * Creates an empty, hidden iframe and sets it to the _frame
   * property of this object.
   */
  _createFrame: function Sandbox__createFrame() {
    let hiddenWindow = Services.appShell.hiddenDOMWindow;
    let doc = hiddenWindow.document;

    // Insert iframe in to create docshell.
    let frame = doc.createElementNS(XHTML_NS, "iframe");
    frame.setAttribute("mozframetype", "content");
    frame.sandbox = "allow-forms allow-scripts allow-same-origin";
    frame.style.visibility = "collapse";
    doc.documentElement.appendChild(frame);

    let docShell = frame.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                                      .getInterface(Ci.nsIWebNavigation)
                                      .QueryInterface(Ci.nsIInterfaceRequestor)
                                      .getInterface(Ci.nsIDocShell);

    // Stop about:blank from being loaded.
    docShell.stop(Ci.nsIWebNavigation.STOP_NETWORK);

    // Disable some types of content
    docShell.allowAuth = false;
    docShell.allowPlugins = false;
    docShell.allowImages = false;
    docShell.allowMedia = false;
    docShell.allowWindowControl = false;

    // Disable stylesheet loading since the document is not visible.
    let markupDocViewer = docShell.contentViewer
                                  .QueryInterface(Ci.nsIMarkupDocumentViewer);
    markupDocViewer.authorStyleDisabled = true;

    // Set instance properties.
    this._frame = frame;
    this._container = doc.documentElement;
  },

  _createSandbox: function Sandbox__createSandbox(aCallback) {
    let self = this;
    function _makeSandboxContentLoaded(event) {
      self._log("_makeSandboxContentLoaded:", self.id,
                event.target.location.toString());
      if (event.target != self._frame.contentDocument) {
        return;
      }
      self._frame.removeEventListener(
        "DOMWindowCreated", _makeSandboxContentLoaded, true
      );

      aCallback(self);
    };

    this._frame.addEventListener("DOMWindowCreated",
                                 _makeSandboxContentLoaded,
                                 true);

    // Load the iframe.
    let webNav = this._frame.contentWindow
                            .QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIWebNavigation);

    webNav.loadURI(
      this._url,
      Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE,
      null, // referrer
      null, // postData
      null  // headers
    );

  },

  _log: function Sandbox__log(...aMessageArgs) {
    Logger.log.apply(Logger, ["sandbox"].concat(aMessageArgs));
  },

};