Skip to content

Commit 227782c

Browse files
author
Paul Ellenbogen
committed
Introduce a Link that allows console messages and breaking with the debugger.
1 parent 6b410b9 commit 227782c

File tree

4 files changed

+75
-67
lines changed

4 files changed

+75
-67
lines changed

Gruntfile.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ module.exports = function(grunt) {
5353
FILES.lib
5454
.concat(promise_lib)
5555
.concat(FILES.srcCore)
56-
.concat("src/tab-link.js")
56+
.concat("src/backgroundframe-link.js")
5757
.concat('providers/*.js')
5858
}
5959
}

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ Or in classic firefox extensions use:
1818
Components.utils.import(PATH TO .jsm);
1919

2020

21-
This will define the function `setupFreedom` in the current scope. `setupFreedom` takes three arguments:
22-
- manifest: the path to the freedom manifest file.
23-
- debug: true for debugging output.
24-
- freedomcfg: the freedomcfg function for defining new freedom apis.
21+
This will define the function `setupFreedom` in the current scope. `setupFreedom` takes two arguments:
22+
- manifest: the path to the freedom manifest file.
23+
- options: an dictionary mapping various options
24+
- debug: true for debugging output.
25+
- freedomcfg: the freedomcfg function for defining new freedom apis.
26+
- portType: Type of port. Default is Worker. BackgroundFrame is available for debugging purposes.
2527

2628
`setupFreedom` returns a freedom object.
2729

Lines changed: 49 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,56 +6,59 @@ if (typeof fdom === 'undefined') {
66
fdom.link = fdom.link || {};
77

88
/**
9-
* A port providing message transport between two freedom contexts via iTabs.
10-
* @class link.Tab
9+
* A port providing message transport between two freedom contexts via iBackgroundFrames.
10+
* @class link.BackgroundFrame
1111
* @extends Link
1212
* @uses handleEvents
1313
* @constructor
1414
*/
15-
fdom.link.Tab = function() {
15+
fdom.link.BackgroundFrame = function() {
1616
fdom.Link.call(this);
17+
if (typeof hiddenWindow !== 'undefined') {
18+
this.document = hiddenWindow.document;
19+
}
1720
};
1821

1922
/**
20-
* Start this port by listening or creating a tab.
23+
* Start this port by listening or creating a frame.
2124
* @method start
2225
* @private
2326
*/
24-
fdom.link.Tab.prototype.start = function() {
27+
fdom.link.BackgroundFrame.prototype.start = function() {
2528
if (this.config.moduleContext) {
2629
this.config.global.DEBUG = true;
2730
this.setupListener();
2831
this.src = 'in';
2932
} else {
30-
this.setupTab();
33+
this.setupBackgroundFrame();
3134
this.src = 'out';
3235
}
3336
};
3437

3538
/**
36-
* Stop this port by deleting the tab.
39+
* Stop this port by deleting the frame.
3740
* @method stop
3841
* @private
3942
*/
40-
fdom.link.Tab.prototype.stop = function() {
41-
// Function is determined by setupListener or setupTab as appropriate.
43+
fdom.link.BackgroundFrame.prototype.stop = function() {
44+
// Function is determined by setupListener or setupBackgroundFrame as appropriate.
4245
};
4346

4447
/**
4548
* Get the textual description of this port.
4649
* @method toString
4750
* @return {String} the description of this port.
4851
*/
49-
fdom.link.Tab.prototype.toString = function() {
50-
return "[Tab" + this.id + "]";
52+
fdom.link.BackgroundFrame.prototype.toString = function() {
53+
return "[BackgroundFrame" + this.id + "]";
5154
};
5255

5356
/**
5457
* Set up a global listener to handle incoming messages to this
5558
* freedom.js context.
5659
* @method setupListener
5760
*/
58-
fdom.link.Tab.prototype.setupListener = function() {
61+
fdom.link.BackgroundFrame.prototype.setupListener = function() {
5962
var onMsg = function(msg) {
6063
if (msg.data.src !== 'in') {
6164
this.emitMessage(msg.data.flow, msg.data.message);
@@ -71,72 +74,66 @@ fdom.link.Tab.prototype.setupListener = function() {
7174
};
7275

7376
/**
74-
* Set up an iTab with an isolated freedom.js context inside.
75-
* @method setupTab
77+
* Set up an iBackgroundFrame with an isolated freedom.js context inside.
78+
* @method setupBackgroundFrame
7679
*/
77-
fdom.link.Tab.prototype.setupTab = function() {
78-
var worker, onMsg;
79-
worker = this.makeTab(this.config.src, this.config.inject);
80+
fdom.link.BackgroundFrame.prototype.setupBackgroundFrame = function() {
81+
var frame, onMsg;
82+
frame = this.makeBackgroundFrame(this.config.src, this.config.inject);
8083

81-
onMsg = function(tab, msg) {
84+
if (!this.document.body) {
85+
this.document.appendChild(this.document.createElement("body"));
86+
}
87+
this.document.body.appendChild(frame);
88+
89+
onMsg = function(frame, msg) {
8290
if (!this.obj) {
83-
this.obj = tab;
91+
this.obj = frame;
8492
this.emit('started');
8593
}
8694
if (msg.data.src !== 'out') {
8795
this.emitMessage(msg.data.flow, msg.data.message);
8896
}
89-
}.bind(this, worker);
97+
}.bind(this, frame.contentWindow);
9098

91-
worker.port.on('message', onMsg);
99+
frame.contentWindow.addEventListener('message', onMsg, true);
92100
this.stop = function() {
93-
worker.destroy();
101+
frame.contentWindow.removeEventListener('message', onMsg, true);
94102
if (this.obj) {
95103
delete this.obj;
96104
}
105+
frame.src = "about:blank";
106+
this.document.body.removeChild(frame);
97107
};
98108
};
99109

100-
// The toString version of this function will be used as a content script
101-
fdom.link.contentScript = function contentScript() {
102-
var window = unsafeWindow;
103-
window.addEventListener("message", self.port.emit.bind(self.port, "message"));
104-
self.port.on("message", function(message) {
105-
window.postMessage(message, "*");
106-
});
107-
};
108-
109110
/**
110-
* Make tabs to replicate freedom isolation without web-workers.
111-
* iTab isolation is non-standardized, and access to the DOM within tabs
111+
* Make frames to replicate freedom isolation without web-workers.
112+
* iBackgroundFrame isolation is non-standardized, and access to the DOM within frames
112113
* means that they are insecure. However, debugging of webworkers is
113114
* painful enough that this mode of execution can be valuable for debugging.
114-
* @method makeTab
115+
* @method makeBackgroundFrame
115116
*/
116-
fdom.link.Tab.prototype.makeTab = function(src) {
117-
debugger;
118-
var tab,
117+
fdom.link.BackgroundFrame.prototype.makeBackgroundFrame = function(src, inject) {
118+
var frame = this.document.createElement('iframe'),
119119
extra = '',
120120
loader,
121-
worker,
122121
blob;
123122
// TODO(willscott): add sandboxing protection.
124123

125124
// TODO(willscott): survive name mangling.
126-
src = src.replace('portType: "Worker"', 'portType: "Tab"');
125+
src = src.replace('portType: "Worker"', 'portType: "BackgroundFrame"');
126+
if (inject) {
127+
extra = '<script src="' + inject + '" onerror="' +
128+
'throw new Error(\'Injection of ' + inject +' Failed!\');' +
129+
'"></script>';
130+
}
127131
loader = '<html>' + extra + '<script src="' +
128132
fdom.util.forceModuleContext(src) + '"></script></html>';
129133
blob = fdom.util.getBlob(loader, 'text/html');
130-
tab = fftabs.open({url: fdom.util.getURL(blob),
131-
onLoad: function onLoad(tab) {
132-
worker = tab.attach({
133-
contentScript: "(" +
134-
fdom.link.contentScript.toString() +
135-
")()"
136-
});
137-
}});
138-
139-
return worker;
134+
frame.src = fdom.util.getURL(blob);
135+
136+
return frame;
140137
};
141138

142139
/**
@@ -146,15 +143,9 @@ fdom.link.Tab.prototype.makeTab = function(src) {
146143
* @param {String} flow the channel/flow of the message.
147144
* @param {Object} message The Message.
148145
*/
149-
fdom.link.Tab.prototype.deliverMessage = function(flow, message) {
150-
if (this.obj.port) { // We are in the root context
146+
fdom.link.BackgroundFrame.prototype.deliverMessage = function(flow, message) {
147+
if (this.obj) {
151148
//fdom.debug.log('message sent to worker: ', flow, message);
152-
this.obj.port.emit("message", {
153-
src: this.src,
154-
flow: flow,
155-
message: message
156-
});
157-
} else if(this.obj.postMessage) { // We are in a module
158149
this.obj.postMessage({
159150
src: this.src,
160151
flow: flow,
@@ -164,3 +155,4 @@ fdom.link.Tab.prototype.deliverMessage = function(flow, message) {
164155
this.once('started', this.onMessage.bind(this, flow, message));
165156
}
166157
};
158+

src/firefox-preamble.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ Components.utils.import('resource://gre/modules/Services.jsm');
44
// This module does not support all of es6 promise functionality.
55
// Components.utils.import("resource://gre/modules/Promise.jsm");
66
const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1", "nsIXMLHttpRequest");
7-
Components.utils.importGlobalProperties(['URL']);
7+
88

99
var hiddenWindow = Services.appShell.hiddenDOMWindow;
1010
var mozRTCPeerConnection = hiddenWindow.mozRTCPeerConnection;
1111
var mozRTCSessionDescription = hiddenWindow.mozRTCSessionDescription;
1212
var mozRTCIceCandidate = hiddenWindow.mozRTCIceCandidate;
13-
1413
// Replace Blob with blob that has prototype defined.
1514
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1007318
1615
var Blob = hiddenWindow.Blob;
@@ -23,21 +22,36 @@ var location = {
2322
protocol: "resource:"
2423
};
2524

26-
function setupFreedom(manifest, debug, freedomcfg, fftabs) {
25+
function setupFreedom(manifest, options) {
26+
debugger;
2727
if (this.freedom) {
2828
return this.freedom;
2929
}
3030

31+
options = options || {};
32+
var freedomcfg = options.freedomcfg;
33+
34+
35+
if (options.portType === "BackgroundFrame") {
36+
// If we are using iframes on the background page, we need to
37+
// generate blob URLs from the URL object on the page. We get a
38+
// privledge error if we try to load a blob given a url by the
39+
// Cu.importGlobalProperties(['URL']) version of URL.
40+
var URL = hiddenWindow.URL;
41+
} else {
42+
Components.utils.importGlobalProperties(['URL']);
43+
}
44+
3145
var lastSlash = manifest.lastIndexOf("/");
3246
var manifestLocation = manifest.substring(0, lastSlash + 1);
3347
//var manifestFilename = manifest.substring(lastSlash + 1);
3448
firefox_config = {
3549
isApp: false,
3650
manifest: manifest,
37-
portType: 'Tab',
51+
portType: options.portType || 'Worker',
3852
stayLocal: true,
3953
location: manifestLocation,
40-
debug: debug || false,
54+
debug: options.debug || false,
4155
isModule: false
4256
};
4357

0 commit comments

Comments
 (0)