gecko/toolkit/identity/Sandbox.jsm
2016-02-03 17:27:36 -08:00

153 lines
4.8 KiB
JavaScript

/* 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;
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));
},
};