This commit is contained in:
gorhill 2016-09-24 14:36:08 -04:00
parent 40f574537b
commit 95ec573141
9 changed files with 190 additions and 83 deletions

View File

@ -19,12 +19,18 @@
Home: https://github.com/gorhill/uBlock
*/
/* exported processObserver */
'use strict';
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/800
this.EXPORTED_SYMBOLS = ['contentObserver', 'LocationChangeListener'];
this.EXPORTED_SYMBOLS = [
'contentObserver',
'processObserver',
'LocationChangeListener'
];
const {interfaces: Ci, utils: Cu} = Components;
const {Services} = Cu.import('resource://gre/modules/Services.jsm', null);
@ -64,20 +70,94 @@ const getMessageManager = function(win) {
/******************************************************************************/
const getChildProcessMessageManager = function() {
var svc = Services;
if ( !svc ) {
return;
}
var cpmm = svc.cpmm;
if ( cpmm ) {
return cpmm;
}
cpmm = Components.classes['@mozilla.org/childprocessmessagemanager;1'];
if ( cpmm ) {
return cpmm.getService(Ci.nsISyncMessageSender);
}
};
// https://github.com/gorhill/uBlock/issues/2014
// Have a dictionary of hostnames for which there are script tag filters. This
// allow for coarse-testing before firing a synchronous message to the
// parent process. Script tag filters are not very common, so this allows
// to skip the blocking of the child process most of the time.
var scriptTagFilterer = (function() {
var scriptTagHostnames;
var getCpmm = function() {
var svc = Services;
if ( !svc ) { return; }
var cpmm = svc.cpmm;
if ( cpmm ) { return cpmm; }
cpmm = Components.classes['@mozilla.org/childprocessmessagemanager;1'];
if ( cpmm ) { return cpmm.getService(Ci.nsISyncMessageSender); }
};
var listener = function(message) {
var details;
try {
details = JSON.parse(message.data);
} catch (ex) {
}
if ( !details || !details.msg ) { return; }
if (details.msg.what === 'staticFilteringDataChanged' ) {
reset();
}
};
var getScriptTagHostnames = function() {
if ( scriptTagHostnames ) {
return scriptTagHostnames;
}
var cpmm = getCpmm();
if ( !cpmm ) { return; }
var r = cpmm.sendSyncMessage(rpcEmitterName, { fnName: 'getScriptTagHostnames' });
if ( Array.isArray(r) && Array.isArray(r[0]) ) {
scriptTagHostnames = new Set(r[0]);
}
return scriptTagHostnames;
};
var getScriptTagFilters = function(details) {
let cpmm = getCpmm();
if ( !cpmm ) { return; }
let r = cpmm.sendSyncMessage(rpcEmitterName, {
fnName: 'getScriptTagFilters',
rootURL: details.rootURL,
frameURL: details.frameURL,
frameHostname: details.frameHostname
});
if ( Array.isArray(r) ) {
return r[0];
}
};
var regexFromHostname = function(details) {
// If target hostname has no script tag filter, no point querying
// chrome process.
var hostnames = getScriptTagHostnames();
if ( !hostnames ) { return; }
var hn = details.frameHostname, pos, entity;
for (;;) {
if ( hostnames.has(hn) ) {
return getScriptTagFilters(details);
}
pos = hn.indexOf('.');
if ( pos === -1 ) { break; }
entity = hn.slice(0, pos) + '.*';
if ( hostnames.has(entity) ) {
return getScriptTagFilters(details);
}
hn = hn.slice(pos + 1);
if ( hn === '' ) { break; }
}
};
var reset = function() {
scriptTagHostnames = undefined;
};
return {
get: regexFromHostname,
listener: listener,
reset: reset
};
})();
/******************************************************************************/
@ -305,18 +385,9 @@ var contentObserver = {
wantXHRConstructor: false
});
if ( getChildProcessMessageManager() ) {
sandbox.rpc = function(details) {
var cpmm = getChildProcessMessageManager();
if ( !cpmm ) { return; }
var r = cpmm.sendSyncMessage(rpcEmitterName, details);
if ( Array.isArray(r) ) {
return r[0];
}
};
} else {
sandbox.rpc = function() {};
}
sandbox.getScriptTagFilters = function(details) {
return scriptTagFilterer.get(details);
};
sandbox.injectScript = function(script) {
let svc = Services;
@ -344,6 +415,8 @@ var contentObserver = {
}
};
sandbox.topContentScript = win === win.top;
// The goal is to have content scripts removed from web pages. This
// helps remove traces of uBlock from memory when disabling/removing
// the addon.
@ -353,15 +426,15 @@ var contentObserver = {
sandbox.outerShutdown = function() {
sandbox.removeMessageListener();
sandbox.addMessageListener =
sandbox.getScriptTagFilters =
sandbox.injectCSS =
sandbox.injectScript =
sandbox.outerShutdown =
sandbox.removeCSS =
sandbox.removeMessageListener =
sandbox.rpc =
sandbox.sendAsyncMessage = function(){};
sandbox.vAPI = {};
messager = null;
messager = sandbox = null;
};
}
else {
@ -380,13 +453,21 @@ var contentObserver = {
callback(message.data);
};
sandbox._broadcastListener_ = function(message) {
// https://github.com/gorhill/uBlock/issues/2014
if ( sandbox.topContentScript ) {
scriptTagFilterer.listener(message);
}
callback(message.data);
};
messager.addMessageListener(
sandbox._sandboxId_,
sandbox._messageListener_
);
messager.addMessageListener(
hostName + ':broadcast',
sandbox._messageListener_
sandbox._broadcastListener_
);
};
@ -401,13 +482,13 @@ var contentObserver = {
);
messager.removeMessageListener(
hostName + ':broadcast',
sandbox._messageListener_
sandbox._broadcastListener_
);
} catch (ex) {
// It throws sometimes, mostly when the popup closes
}
sandbox._messageListener_ = null;
sandbox._messageListener_ = sandbox._broadcastListener_ = null;
};
return sandbox;
@ -498,6 +579,14 @@ var contentObserver = {
/******************************************************************************/
var processObserver = {
start: function() {
scriptTagFilterer.reset();
}
};
/******************************************************************************/
var LocationChangeListener = function(docShell, webProgress) {
var mm = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);

View File

@ -23,21 +23,16 @@
// https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Frame_script_environment
(function() {
(function(context) {
'use strict';
let {LocationChangeListener} = Components.utils.import(
Components.stack.filename.replace('Script', 'Module'),
null
);
if ( !this.docShell ) {
if ( !context.docShell ) {
return;
}
let webProgress = this.docShell
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebProgress);
let webProgress = context.docShell
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebProgress);
if ( !webProgress ) {
return;
}
@ -49,11 +44,19 @@
return;
}
let {LocationChangeListener} = Components.utils.import(
Components.stack.filename.replace('Script', 'Module'),
null
);
// https://github.com/gorhill/uBlock/issues/1444
// Apparently, on older versions of Firefox (31 and less), the same context
// is used for all extensions, hence we must use a unique variable name to
// ensure no collision.
this.ublock0LocationChangeListener = new LocationChangeListener(this.docShell, webProgress);
}).call(this);
// is used for all frame scripts, hence we must use a unique variable name
// to ensure no collision.
context.ublock0LocationChangeListener = new LocationChangeListener(
context.docShell,
webProgress
);
})(this);
/******************************************************************************/

View File

@ -1760,16 +1760,15 @@ vAPI.messaging.setup = function(defaultHandler) {
}
this.defaultHandler = defaultHandler;
this.globalMessageManager.addMessageListener(
var gmm = this.globalMessageManager;
gmm.addMessageListener(
location.host + ':background',
this.onMessage
);
this.globalMessageManager.loadFrameScript(this.frameScriptURL, true);
gmm.loadFrameScript(this.frameScriptURL, true);
cleanupTasks.push(function() {
var gmm = vAPI.messaging.globalMessageManager;
gmm.broadcastAsyncMessage(
location.host + ':broadcast',
JSON.stringify({
@ -1778,13 +1777,11 @@ vAPI.messaging.setup = function(defaultHandler) {
msg: { cmd: 'shutdownSandbox' }
})
);
gmm.removeDelayedFrameScript(vAPI.messaging.frameScriptURL);
gmm.removeMessageListener(
location.host + ':background',
vAPI.messaging.onMessage
);
vAPI.messaging.defaultHandler = null;
});
};
@ -1820,8 +1817,9 @@ vAPI.messaging.broadcast = function(message) {
// https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Message_Manager/Message_manager_overview#Content_frame_message_manager
vAPI.rpcReceiver = (function() {
var calls = Object.create(null);
var childProcessMessageName = location.host + ':child-process-message';
var calls = Object.create(null),
childProcessMessageName = location.host + ':child-process-message',
processScriptURL = vAPI.getURL('processScript.js');
var onChildProcessMessage = function(ev) {
var msg = ev.data;
@ -1838,22 +1836,31 @@ vAPI.rpcReceiver = (function() {
if ( ppmm ) {
ppmm = ppmm.getService(Ci.nsIMessageListenerManager);
}
if ( !ppmm ) {
return calls;
}
}
if ( ppmm ) {
ppmm.addMessageListener(
// https://github.com/gorhill/uBlock/issues/2014
// Not supported on older versions of Firefox.
if ( ppmm.loadProcessScript instanceof Function ) {
ppmm.loadProcessScript(processScriptURL, true);
}
ppmm.addMessageListener(
childProcessMessageName,
onChildProcessMessage
);
cleanupTasks.push(function() {
if ( ppmm.removeDelayedProcessScript instanceof Function ) {
ppmm.removeDelayedProcessScript(processScriptURL);
}
ppmm.removeMessageListener(
childProcessMessageName,
onChildProcessMessage
);
}
cleanupTasks.push(function() {
if ( ppmm ) {
ppmm.removeMessageListener(
childProcessMessageName,
onChildProcessMessage
);
}
});
return calls;

View File

@ -45,13 +45,6 @@ if ( document instanceof HTMLDocument === false ) {
/******************************************************************************/
// Not all sandboxes are given an rpc function, so assign a dummy one if it is
// missing -- this avoids the need for testing before use.
self.rpc = self.rpc || function(){};
/******************************************************************************/
var vAPI = self.vAPI = self.vAPI || {};
/******************************************************************************/
@ -154,12 +147,14 @@ vAPI.shutdown = (function() {
/******************************************************************************/
(function() {
if ( !self.getScriptTagFilters ) {
return;
}
var hostname = location.hostname;
if ( !hostname ) {
return;
}
var filters = self.rpc({
fnName: 'getScriptTagFilters',
var filters = self.getScriptTagFilters({
rootURL: self.location.href,
frameURL: self.location.href,
frameHostname: hostname

View File

@ -42,7 +42,7 @@ var hasCachedContent = false;
var onMessage = function(msg) {
switch ( msg.what ) {
case 'allFilterListsReloaded':
case 'staticFilteringDataChanged':
renderFilterLists();
break;

View File

@ -1237,6 +1237,12 @@ FilterContainer.prototype.createScriptTagFilter = function(hash, hostname, selec
/******************************************************************************/
FilterContainer.prototype.retrieveScriptTagHostnames = function() {
return Object.keys(this.scriptTagFilters);
};
/******************************************************************************/
FilterContainer.prototype.retrieveScriptTagRegex = function(domain, hostname) {
if ( this.scriptTagFilterCount === 0 ) {
return;

View File

@ -1,7 +1,7 @@
/*******************************************************************************
uBlock Origin - a browser extension to block requests.
Copyright (C) 2015 Raymond Hill
Copyright (C) 2015-2016 Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,14 +19,12 @@
Home: https://github.com/gorhill/uBlock
*/
/* global vAPI, µBlock */
'use strict';
/******************************************************************************/
(function() {
'use strict';
/******************************************************************************/
if ( typeof vAPI.rpcReceiver !== 'object' ) {
@ -35,12 +33,19 @@ if ( typeof vAPI.rpcReceiver !== 'object' ) {
/******************************************************************************/
vAPI.rpcReceiver.getScriptTagHostnames = function() {
var µb = µBlock;
var cfe = µb.cosmeticFilteringEngine;
if ( !cfe ) { return; }
return cfe.retrieveScriptTagHostnames();
};
/******************************************************************************/
vAPI.rpcReceiver.getScriptTagFilters = function(details) {
var µb = µBlock;
var cfe = µb.cosmeticFilteringEngine;
if ( !cfe ) {
return;
}
if ( !cfe ) { return; }
// Fetching the script tag filters first: assuming it is faster than
// checking whether the site is whitelisted.
var hostname = details.frameHostname;

View File

@ -406,7 +406,8 @@
//quickProfiler.stop(0);
vAPI.messaging.broadcast({ what: 'allFilterListsReloaded' });
vAPI.messaging.broadcast({ what: 'staticFilteringDataChanged' });
callback();
µb.selfieManager.create();

View File

@ -25,6 +25,7 @@ cp platform/firefox/css/* $DES/css/
cp platform/firefox/polyfill.js $DES/js/
cp platform/firefox/vapi-*.js $DES/js/
cp platform/firefox/bootstrap.js $DES/
cp platform/firefox/processScript.js $DES/
cp platform/firefox/frame*.js $DES/
cp -R platform/firefox/img $DES/
cp platform/firefox/chrome.manifest $DES/