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 ) { if ( details.tabId ) {
details.tabId = parseInt(tabId, 10);
// update doesn't accept index, must use move // update doesn't accept index, must use move
chrome.tabs.update(details.tabId, _details, function(tab) { chrome.tabs.update(details.tabId, _details, function(tab) {
// if the tab doesn't exist // if the tab doesn't exist
@ -203,7 +205,7 @@ vAPI.tabs.remove = function(tabId) {
if ( vAPI.lastError() ) { 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 ) { if ( tabId ) {
tabid = parseInt(tabId, 10);
chrome.tabs.executeScript(tabId, details, onScriptExecuted); chrome.tabs.executeScript(tabId, details, onScriptExecuted);
} else { } else {
chrome.tabs.executeScript(details, onScriptExecuted); chrome.tabs.executeScript(details, onScriptExecuted);
@ -243,6 +246,7 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
// anymore, so this ensures it does still exist. // anymore, so this ensures it does still exist.
vAPI.setIcon = function(tabId, img, badge) { vAPI.setIcon = function(tabId, img, badge) {
tabId = parseInt(tabId, 10);
var onIconReady = function() { var onIconReady = function() {
if ( vAPI.lastError() ) { if ( vAPI.lastError() ) {
return; 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 */ /* globals Services, sendAsyncMessage, addMessageListener, removeMessageListener */
(function() {
'use strict'; 'use strict';
let appName = 'ublock'; let appName = 'ublock';
let contentBaseURI = 'chrome://' + appName + '/content/js/';
let listeners = {}; let listeners = {};
let frameModule = Components.utils['import']('chrome://' + appName + '/content/frameModule.js', {});
let _addMessageListener = function(id, fn) { this.ublock_addMessageListener = function(id, fn) {
_removeMessageListener(id); ublock_removeMessageListener(id);
listeners[id] = function(msg) { listeners[id] = function(msg) {
fn(msg.data); fn(msg.data);
}; };
addMessageListener(id, listeners[id]); addMessageListener(id, listeners[id]);
}; };
let _removeMessageListener = function(id) { this.ublock_removeMessageListener = function(id) {
if (listeners[id]) { if (listeners[id]) {
removeMessageListener(id, listeners[id]); removeMessageListener(id, listeners[id]);
} }
@ -29,72 +27,3 @@ addMessageListener(appName + ':broadcast', function(msg) {
listeners[id](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 Home: https://github.com/gorhill/uBlock
*/ */
/* global Services, XPCOMUtils */ /* global Services */
// For background page // For background page
@ -34,7 +34,6 @@
const {classes: Cc, interfaces: Ci, utils: Cu} = Components; const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu['import']('resource://gre/modules/Services.jsm'); Cu['import']('resource://gre/modules/Services.jsm');
Cu['import']('resource://gre/modules/XPCOMUtils.jsm');
/******************************************************************************/ /******************************************************************************/
@ -236,7 +235,7 @@ var windowWatcher = {
onTabClose: function(e) { onTabClose: function(e) {
vAPI.tabs.onClosed(vAPI.tabs.getTabId(e.target)); vAPI.tabs.onClosed(vAPI.tabs.getTabId(e.target));
}, },
onTabSelect: function(e) { onTabSelect: function() {
// vAPI.setIcon(); // vAPI.setIcon();
}, },
onLoad: function(e) { onLoad: function(e) {
@ -338,7 +337,7 @@ vAPI.tabs.getTabId = function(target) {
var i = gBrowser.browsers.indexOf(target); var i = gBrowser.browsers.indexOf(target);
if (i !== -1) { if (i !== -1) {
i = this.getTabId(gBrowser.tabs[i]); i = gBrowser.tabs[i].linkedPanel.slice(6);
} }
return i; 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 = {};
/******************************************************************************/ /******************************************************************************/
vAPI.net.registerListeners = function() { vAPI.net.registerListeners = function() {
conentPolicy.registrar.registerFactory( var types = {
conentPolicy.classID, 2: 'script',
conentPolicy.classDescription, 3: 'image',
conentPolicy.contractID, 4: 'stylesheet',
conentPolicy 5: 'object',
); 7: 'sub_frame',
conentPolicy.catManager.addCategoryEntry( 11: 'xmlhttprequest'
'content-policy', };
conentPolicy.contractID,
conentPolicy.contractID, var onBeforeRequest = this.onBeforeRequest;
false,
true 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() { vAPI.net.unregisterListeners = function() {
conentPolicy.registrar.unregisterFactory(conentPolicy.classID, conentPolicy); vAPI.messaging.gmm.removeMessageListener(
conentPolicy.catManager.deleteCategoryEntry( vAPI.app.cleanName + ':onBeforeRequest',
'content-policy', this.onBeforeRequest
conentPolicy.contractID,
false
); );
}; };
/******************************************************************************/ /******************************************************************************/
vAPI.lastError = function() {
return null;
};
/******************************************************************************/
// clean up when the extension is disabled // clean up when the extension is disabled
window.addEventListener('unload', function() { window.addEventListener('unload', function() {
@ -773,14 +708,21 @@ window.addEventListener('unload', function() {
vAPI.messaging.unload(); vAPI.messaging.unload();
vAPI.net.unregisterListeners(); 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 // 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 (win of vAPI.tabs.getWindows()) {
for (tab of win.gBrowser.tabs) { 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); win.gBrowser.removeTab(tab);
} }
} }

View File

@ -179,7 +179,7 @@ vAPI.storage = {
vAPI.tabs = { vAPI.tabs = {
stack: {}, stack: {},
stackID: 1 stackId: 1
}; };
/******************************************************************************/ /******************************************************************************/
@ -374,21 +374,17 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
j = wins[i].tabs.length; j = wins[i].tabs.length;
while (j--) { 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) { safari.application.addEventListener('open', function(e) {
// ignore windows // ignore windows
if (e.target instanceof SafariBrowserTab) { if (e.target instanceof SafariBrowserTab) {
vAPI.tabs.stack[vAPI.tabs.stackID++] = e.target; vAPI.tabs.stack[vAPI.tabs.stackId++] = e.target;
} }
}, true); }, true);
@ -402,7 +398,7 @@ safari.application.addEventListener('close', function(e) {
var tabId = vAPI.tabs.getTabId(e.target); var tabId = vAPI.tabs.getTabId(e.target);
if (tabId > -1) { if (tabId !== -1) {
// to not add another listener, put this here // to not add another listener, put this here
// instead of vAPI.tabs.registerListeners // instead of vAPI.tabs.registerListeners
if (typeof vAPI.tabs.onClosed === 'function') { 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/vapi-*.js $DES/js/
cp platform/firefox/bootstrap.js $DES/ cp platform/firefox/bootstrap.js $DES/
cp platform/firefox/frameScript.js $DES/ cp platform/firefox/frameScript.js $DES/
cp platform/firefox/frameModule.js $DES/
cp platform/firefox/chrome.manifest $DES/ cp platform/firefox/chrome.manifest $DES/
cp platform/firefox/install.rdf $DES/ cp platform/firefox/install.rdf $DES/