1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-11-26 04:12:50 +01:00

Firefox: blocking and content scripts for e10s

This commit is contained in:
Deathamns 2014-12-09 21:56:17 +01:00
parent 0f771e94d1
commit e4329b7dfe
6 changed files with 245 additions and 204 deletions

View File

@ -140,6 +140,8 @@ vAPI.tabs.open = function(details) {
};
if ( details.tabId ) {
details.tabId = parseInt(tabId, 10);
// update doesn't accept index, must use move
chrome.tabs.update(details.tabId, _details, function(tab) {
// if the tab doesn't exist
@ -203,7 +205,7 @@ vAPI.tabs.remove = function(tabId) {
if ( vAPI.lastError() ) {
}
};
chrome.tabs.remove(tabId, onTabRemoved);
chrome.tabs.remove(parseInt(tabId, 10), onTabRemoved);
};
/******************************************************************************/
@ -227,6 +229,7 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
}
};
if ( tabId ) {
tabid = parseInt(tabId, 10);
chrome.tabs.executeScript(tabId, details, onScriptExecuted);
} else {
chrome.tabs.executeScript(details, onScriptExecuted);
@ -243,6 +246,7 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
// anymore, so this ensures it does still exist.
vAPI.setIcon = function(tabId, img, badge) {
tabId = parseInt(tabId, 10);
var onIconReady = function() {
if ( vAPI.lastError() ) {
return;

View File

@ -0,0 +1,169 @@
/* global Services, Components, XPCOMUtils */
/* exported EXPORTED_SYMBOLS, isTabbed */
'use strict';
var EXPORTED_SYMBOLS = ['contentPolicy', 'docObserver'];
Components.utils['import']('resource://gre/modules/Services.jsm');
Components.utils['import']('resource://gre/modules/XPCOMUtils.jsm');
const Ci = Components.interfaces, appName = 'ublock';
let getMessager = function(win) {
try {
// e10s
return win
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
} catch (ex) {
return win
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
}
};
let contentPolicy = {
classDescription: 'ContentPolicy implementation',
classID: Components.ID('{e6d173c8-8dbf-4189-a6fd-189e8acffd27}'),
contractID: '@ublock/content-policy;1',
ACCEPT: Ci.nsIContentPolicy.ACCEPT,
REJECT: Ci.nsIContentPolicy.REJECT_REQUEST,
get componentRegistrar() {
return Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
},
get categoryManager() {
return Components.classes['@mozilla.org/categorymanager;1']
.getService(Ci.nsICategoryManager);
},
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIFactory,
Ci.nsIContentPolicy,
Ci.nsISupportsWeakReference
]),
createInstance: function(outer, iid) {
if (outer) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(iid);
},
register: function() {
this.componentRegistrar.registerFactory(
this.classID,
this.classDescription,
this.contractID,
this
);
this.categoryManager.addCategoryEntry(
'content-policy',
this.contractID,
this.contractID,
false,
true
);
},
unregister: function() {
this.componentRegistrar.unregisterFactory(this.classID, this);
this.categoryManager.deleteCategoryEntry(
'content-policy',
this.contractID,
false
);
},
shouldLoad: function(type, location, origin, context) {
if (type === 6 || !context || !/^https?$/.test(location.scheme)) {
return this.ACCEPT;
}
let win = (context.ownerDocument || context).defaultView;
if (!win) {
return this.ACCEPT;
}
let result = getMessager(win).sendSyncMessage('ublock:onBeforeRequest', {
url: location.spec,
type: type,
tabId: -1,
frameId: win === win.top ? 0 : 1,
parentFrameId: win === win.top ? -1 : 0
})[0];
return result === true ? this.REJECT : this.ACCEPT;
}/*,
shouldProcess: function() {
return this.ACCEPT;
}*/
};
let docObserver = {
contentBaseURI: 'chrome://ublock/content/js/',
initContext: function(win, sandbox) {
let messager = getMessager(win);
if (sandbox) {
win = Components.utils.Sandbox([win], {
sandboxPrototype: win,
wantComponents: false,
wantXHRConstructor: false
});
}
win.sendAsyncMessage = messager.sendAsyncMessage;
win.addMessageListener = messager.ublock_addMessageListener;
win.removeMessageListener = messager.ublock_removeMessageListener;
return win;
},
register: function() {
Services.obs.addObserver(this, 'document-element-inserted', false);
},
unregister: function() {
Services.obs.removeObserver(this, 'document-element-inserted');
},
observe: function(doc) {
let win = doc.defaultView;
if (!win) {
return;
}
if (!/^https?:$/.test(win.location.protocol)) {
if (win.location.protocol === 'chrome:'
&& win.location.host === appName) {
this.initContext(win);
}
return;
}
let lss = Services.scriptloader.loadSubScript;
win = this.initContext(win, true);
lss(this.contentBaseURI + 'vapi-client.js', win);
lss(this.contentBaseURI + 'contentscript-start.js', win);
if (doc.readyState === 'interactive' || doc.readyState === 'complete') {
lss(this.contentBaseURI + 'contentscript-end.js', win);
}
else {
let docReady = function(e) {
this.removeEventListener(e.type, docReady, true);
lss(docObserver.contentBaseURI + 'contentscript-end.js', win);
};
doc.addEventListener('DOMContentLoaded', docReady, true);
}
}
};
contentPolicy.register();
docObserver.register();

View File

@ -1,22 +1,20 @@
/* globals Services, sendAsyncMessage, addMessageListener, removeMessageListener, content */
(function() {
/* globals Services, sendAsyncMessage, addMessageListener, removeMessageListener */
'use strict';
let appName = 'ublock';
let contentBaseURI = 'chrome://' + appName + '/content/js/';
let listeners = {};
let frameModule = Components.utils['import']('chrome://' + appName + '/content/frameModule.js', {});
let _addMessageListener = function(id, fn) {
_removeMessageListener(id);
this.ublock_addMessageListener = function(id, fn) {
ublock_removeMessageListener(id);
listeners[id] = function(msg) {
fn(msg.data);
};
addMessageListener(id, listeners[id]);
};
let _removeMessageListener = function(id) {
this.ublock_removeMessageListener = function(id) {
if (listeners[id]) {
removeMessageListener(id, listeners[id]);
}
@ -29,72 +27,3 @@ addMessageListener(appName + ':broadcast', function(msg) {
listeners[id](msg);
}
});
let initContext = function(win, sandbox) {
if (sandbox) {
win = Components.utils.Sandbox([win], {
sandboxPrototype: win,
wantComponents: false,
wantXHRConstructor: false
});
}
win.sendAsyncMessage = sendAsyncMessage;
win.addMessageListener = _addMessageListener;
win.removeMessageListener = _removeMessageListener;
return win;
};
let observer = {
observe: function(win) {
if (!win || win.top !== content) {
return;
}
if (!(win.document instanceof win.HTMLDocument
&& (/^https?:$/.test(win.location.protocol)))) {
return;
}
let lss = Services.scriptloader.loadSubScript;
win = initContext(win, true);
lss(contentBaseURI + 'vapi-client.js', win);
lss(contentBaseURI + 'contentscript-start.js', win);
let readyState = win.document.readyState;
if (readyState === "interactive" || readyState === "complete") {
lss(contentBaseURI + 'contentscript-end.js', win);
}
else {
let docReady = function(e) {
this.removeEventListener(e.type, docReady, true);
lss(contentBaseURI + 'contentscript-end.js', win);
};
win.document.addEventListener('DOMContentLoaded', docReady, true);
}
}
};
Services.obs.addObserver(observer, 'content-document-global-created', false);
let DOMReady = function(e) {
let win = e.target.defaultView;
// inject the message handlers for the options page
if (win.location.protocol === 'chrome:' && win.location.host === appName) {
initContext(win);
}
};
addEventListener('DOMContentLoaded', DOMReady, true);
addEventListener('unload', function() {
Services.obs.removeObserver(observer, 'content-document-global-created');
observer = listeners = null;
}, false);
})();

View File

@ -19,7 +19,7 @@
Home: https://github.com/gorhill/uBlock
*/
/* global Services, XPCOMUtils */
/* global Services */
// For background page
@ -34,7 +34,6 @@
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu['import']('resource://gre/modules/Services.jsm');
Cu['import']('resource://gre/modules/XPCOMUtils.jsm');
/******************************************************************************/
@ -236,7 +235,7 @@ var windowWatcher = {
onTabClose: function(e) {
vAPI.tabs.onClosed(vAPI.tabs.getTabId(e.target));
},
onTabSelect: function(e) {
onTabSelect: function() {
// vAPI.setIcon();
},
onLoad: function(e) {
@ -338,7 +337,7 @@ vAPI.tabs.getTabId = function(target) {
var i = gBrowser.browsers.indexOf(target);
if (i !== -1) {
i = this.getTabId(gBrowser.tabs[i]);
i = gBrowser.tabs[i].linkedPanel.slice(6);
}
return i;
@ -638,133 +637,69 @@ vAPI.messaging.unload = function() {
/******************************************************************************/
vAPI.lastError = function() {
return null;
};
/******************************************************************************/
var conentPolicy = {
classDescription: vAPI.app.name + ' ContentPolicy',
classID: Components.ID('{e6d173c8-8dbf-4189-a6fd-189e8acffd27}'),
contractID: '@' + vAPI.app.cleanName + '/content-policy;1',
ACCEPT: Ci.nsIContentPolicy.ACCEPT,
REJECT: Ci.nsIContentPolicy.REJECT_REQUEST,
types: {
7: 'sub_frame',
4: 'stylesheet',
2: 'script',
3: 'image',
5: 'object',
11: 'xmlhttprequest'
},
get registrar() {
return Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
},
get catManager() {
return Cc['@mozilla.org/categorymanager;1']
.getService(Ci.nsICategoryManager);
},
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIFactory,
Ci.nsIContentPolicy,
Ci.nsISupportsWeakReference
]),
createInstance: function(outer, iid) {
if (outer) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(iid);
},
shouldLoad: function(type, location, origin, context) {
if (type === 6 || !context || !/^https?$/.test(location.scheme)) {
return this.ACCEPT;
}
var win = (context.ownerDocument || context).defaultView;
if (!win) {
return this.ACCEPT;
}
var block = vAPI.net.onBeforeRequest;
type = this.types[type] || 'other';
if (block.types.indexOf(type) === -1) {
return this.ACCEPT;
}
var browser = win.top.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
if (!browser) {
return this.ACCEPT;
}
block = block.callback({
url: location.spec,
type: type,
tabId: vAPI.tabs.getTabId(browser),
frameId: win === win.top ? 0 : 1,
parentFrameId: win === win.top ? -1 : 0
});
if (block && typeof block === 'object') {
if (block.cancel === true) {
return this.REJECT;
}
else if (block.redirectURL) {
location.spec = block.redirectURL;
return this.REJECT;
}
}
return this.ACCEPT;
},/*
shouldProcess: function() {
return this.ACCEPT;
}*/
};
/******************************************************************************/
vAPI.net = {};
/******************************************************************************/
vAPI.net.registerListeners = function() {
conentPolicy.registrar.registerFactory(
conentPolicy.classID,
conentPolicy.classDescription,
conentPolicy.contractID,
conentPolicy
);
conentPolicy.catManager.addCategoryEntry(
'content-policy',
conentPolicy.contractID,
conentPolicy.contractID,
false,
true
var types = {
2: 'script',
3: 'image',
4: 'stylesheet',
5: 'object',
7: 'sub_frame',
11: 'xmlhttprequest'
};
var onBeforeRequest = this.onBeforeRequest;
this.onBeforeRequest = function(e) {
var details = e.data;
details.type = types[details.type] || 'other';
details.tabId = vAPI.tabs.getTabId(e.target);
if (onBeforeRequest.types.indexOf(details.type) === -1) {
return false;
}
var block = onBeforeRequest.callback(details);
if (block && typeof block === 'object') {
if (block.cancel === true) {
return true;
}
else if (block.redirectURL) {
return block.redirectURL;
}
}
return false;
};
vAPI.messaging.gmm.addMessageListener(
vAPI.app.cleanName + ':onBeforeRequest',
this.onBeforeRequest
);
};
/******************************************************************************/
vAPI.net.unregisterListeners = function() {
conentPolicy.registrar.unregisterFactory(conentPolicy.classID, conentPolicy);
conentPolicy.catManager.deleteCategoryEntry(
'content-policy',
conentPolicy.contractID,
false
vAPI.messaging.gmm.removeMessageListener(
vAPI.app.cleanName + ':onBeforeRequest',
this.onBeforeRequest
);
};
/******************************************************************************/
vAPI.lastError = function() {
return null;
};
/******************************************************************************/
// clean up when the extension is disabled
window.addEventListener('unload', function() {
@ -773,14 +708,21 @@ window.addEventListener('unload', function() {
vAPI.messaging.unload();
vAPI.net.unregisterListeners();
var URI = vAPI.messaging.frameScript.replace('Script.', 'Module.');
var frameModule = {};
Cu['import'](URI, frameModule);
frameModule.contentPolicy.unregister();
frameModule.docObserver.unregister();
Cu.unload(URI);
// close extension tabs
var extURI, win, tab, host = vAPI.app.cleanName;
var win, tab, host = vAPI.app.cleanName;
for (win of vAPI.tabs.getWindows()) {
for (tab of win.gBrowser.tabs) {
extURI = tab.linkedBrowser.currentURI;
URI = tab.linkedBrowser.currentURI;
if (extURI.scheme === 'chrome' && extURI.host === host) {
if (URI.scheme === 'chrome' && URI.host === host) {
win.gBrowser.removeTab(tab);
}
}

View File

@ -179,7 +179,7 @@ vAPI.storage = {
vAPI.tabs = {
stack: {},
stackID: 1
stackId: 1
};
/******************************************************************************/
@ -374,21 +374,17 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
j = wins[i].tabs.length;
while (j--) {
tabs.push(wins[i].tabs[j]);
vAPI.tabs.stack[vAPI.tabs.stackId++] = wins[i].tabs[j];
}
}
return tabs;
})().forEach(function(tab) {
vAPI.tabs.stack[vAPI.tabs.stackID++] = tab;
});
})();
/******************************************************************************/
safari.application.addEventListener('open', function(e) {
// ignore windows
if (e.target instanceof SafariBrowserTab) {
vAPI.tabs.stack[vAPI.tabs.stackID++] = e.target;
vAPI.tabs.stack[vAPI.tabs.stackId++] = e.target;
}
}, true);
@ -402,7 +398,7 @@ safari.application.addEventListener('close', function(e) {
var tabId = vAPI.tabs.getTabId(e.target);
if (tabId > -1) {
if (tabId !== -1) {
// to not add another listener, put this here
// instead of vAPI.tabs.registerListeners
if (typeof vAPI.tabs.onClosed === 'function') {

View File

@ -19,6 +19,7 @@ cp src/img/icon_128.png $DES/icon.png
cp platform/firefox/vapi-*.js $DES/js/
cp platform/firefox/bootstrap.js $DES/
cp platform/firefox/frameScript.js $DES/
cp platform/firefox/frameModule.js $DES/
cp platform/firefox/chrome.manifest $DES/
cp platform/firefox/install.rdf $DES/