Add support for special exception filter `#@#+js()`

The purpose is to wholly disable scriptlet injection
for a given site without having to create exceptions
for all matching scriptlet injection filters.

The following exception filter will cause scriptlet
injection to be wholly disable for `example.com`:

    `example.com#@#+js()`

Or to disable scriptlet injection everywhere:

    `#@#+js()`

The following form is meaningless and will be
ignored:

    `example.com##+js()`
This commit is contained in:
Raymond Hill 2019-08-17 08:38:48 -04:00
parent 1ac016bed7
commit bf3c92574e
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
2 changed files with 86 additions and 46 deletions

View File

@ -1127,41 +1127,39 @@ FilterContainer.prototype.getFilterCount = function() {
/******************************************************************************/ /******************************************************************************/
FilterContainer.prototype.benchmark = function() { FilterContainer.prototype.benchmark = async function() {
µb.loadBenchmarkDataset().then(requests => { const requests = await µb.loadBenchmarkDataset();
if ( Array.isArray(requests) === false || requests.length === 0 ) { if ( Array.isArray(requests) === false || requests.length === 0 ) {
console.info('No requests found to benchmark'); console.info('No requests found to benchmark');
return; return;
} }
console.info(`Benchmarking cosmeticFilteringEngine.matchString()...`); console.info('Benchmarking cosmeticFilteringEngine.retrieveSpecificSelectors()...');
const details = { const details = {
tabId: undefined, tabId: undefined,
frameId: undefined, frameId: undefined,
hostname: '', hostname: '',
domain: '', domain: '',
entity: '', entity: '',
}; };
const options = { const options = {
noCosmeticFiltering: false, noCosmeticFiltering: false,
noGenericCosmeticFiltering: false, noGenericCosmeticFiltering: false,
}; };
let count = 0; let count = 0;
const t0 = self.performance.now(); const t0 = self.performance.now();
for ( let i = 0; i < requests.length; i++ ) { for ( let i = 0; i < requests.length; i++ ) {
const request = requests[i]; const request = requests[i];
if ( request.cpt !== 'document' ) { continue; } if ( request.cpt !== 'document' ) { continue; }
count += 1; count += 1;
details.hostname = µb.URI.hostnameFromURI(request.url); details.hostname = µb.URI.hostnameFromURI(request.url);
details.domain = µb.URI.domainFromHostname(details.hostname); details.domain = µb.URI.domainFromHostname(details.hostname);
details.entity = µb.URI.entityFromDomain(details.domain); details.entity = µb.URI.entityFromDomain(details.domain);
void this.retrieveSpecificSelectors(details, options); void this.retrieveSpecificSelectors(details, options);
} }
const t1 = self.performance.now(); const t1 = self.performance.now();
const dur = t1 - t0; const dur = t1 - t0;
console.info(`Evaluated ${count} requests in ${dur.toFixed(0)} ms`); console.info(`Evaluated ${count} requests in ${dur.toFixed(0)} ms`);
console.info(`\tAverage: ${(dur / count).toFixed(3)} ms per request`); console.info(`\tAverage: ${(dur / count).toFixed(3)} ms per request`);
});
return 'ok';
}; };
/******************************************************************************/ /******************************************************************************/

View File

@ -27,8 +27,6 @@
const µb = µBlock, const µb = µBlock,
duplicates = new Set(), duplicates = new Set(),
scriptletCache = new µb.MRUCache(32), scriptletCache = new µb.MRUCache(32),
scriptletsRegister = new Map(),
exceptionsRegister = new Set(),
reEscapeScriptArg = /[\\'"]/g; reEscapeScriptArg = /[\\'"]/g;
let acceptedCount = 0, let acceptedCount = 0,
@ -289,6 +287,11 @@
// Only exception filters are allowed to be global. // Only exception filters are allowed to be global.
const normalized = normalizeRawFilter(parsed.suffix); const normalized = normalizeRawFilter(parsed.suffix);
// Tokenless is meaningful only for exception filters.
if ( normalized === '+js()' && parsed.exception === false ) {
return;
}
if ( parsed.hostnames.length === 0 ) { if ( parsed.hostnames.length === 0 ) {
if ( parsed.exception ) { if ( parsed.exception ) {
writer.push([ 32, '', 1, normalized ]); writer.push([ 32, '', 1, normalized ]);
@ -358,7 +361,7 @@
} }
const scriptlets = new Set(); const scriptlets = new Set();
const exceptions = exceptionsRegister; const exceptions = new Set();
scriptletDB.retrieve( scriptletDB.retrieve(
hostname, hostname,
@ -370,17 +373,27 @@
[ scriptlets, exceptions ] [ scriptlets, exceptions ]
); );
} }
if ( scriptlets.size === 0 ) { return; }
for ( const rawToken of scriptlets ) { const loggerEnabled = µb.logger.enabled;
lookupScriptlet(rawToken, reng, scriptletsRegister);
// Wholly disable scriptlet injection?
if ( exceptions.has('') ) {
if ( loggerEnabled ) {
logOne(true, '', request);
}
return;
} }
if ( scriptletsRegister.size === 0 ) { return; } const scriptletToCodeMap = new Map();
for ( const rawToken of scriptlets ) {
lookupScriptlet(rawToken, reng, scriptletToCodeMap);
}
if ( scriptletToCodeMap.size === 0 ) { return; }
// Return an array of scriptlets, and log results if needed. // Return an array of scriptlets, and log results if needed.
const out = []; const out = [];
const loggerEnabled = µb.logger.enabled; for ( const [ rawToken, code ] of scriptletToCodeMap ) {
for ( const [ rawToken, code ] of scriptletsRegister ) {
const isException = exceptions.has(rawToken); const isException = exceptions.has(rawToken);
if ( isException === false ) { if ( isException === false ) {
out.push(code); out.push(code);
@ -390,9 +403,6 @@
} }
} }
scriptletsRegister.clear();
exceptionsRegister.clear();
if ( out.length === 0 ) { return; } if ( out.length === 0 ) { return; }
if ( µb.hiddenSettings.debugScriptlets ) { if ( µb.hiddenSettings.debugScriptlets ) {
@ -454,6 +464,38 @@
scriptletDB = new µb.staticExtFilteringEngine.HostnameBasedDB(1, selfie); scriptletDB = new µb.staticExtFilteringEngine.HostnameBasedDB(1, selfie);
}; };
api.benchmark = async function() {
const requests = await µb.loadBenchmarkDataset();
if ( Array.isArray(requests) === false || requests.length === 0 ) {
console.info('No requests found to benchmark');
return;
}
console.info('Benchmarking scriptletFilteringEngine.retrieve()...');
const details = {
domain: '',
entity: '',
hostname: '',
tabId: 0,
url: '',
};
let count = 0;
const t0 = self.performance.now();
for ( let i = 0; i < requests.length; i++ ) {
const request = requests[i];
if ( request.cpt !== 'document' ) { continue; }
count += 1;
details.url = request.url;
details.hostname = µb.URI.hostnameFromURI(request.url);
details.domain = µb.URI.domainFromHostname(details.hostname);
details.entity = µb.URI.entityFromDomain(details.domain);
void this.retrieve(details);
}
const t1 = self.performance.now();
const dur = t1 - t0;
console.info(`Evaluated ${count} requests in ${dur.toFixed(0)} ms`);
console.info(`\tAverage: ${(dur / count).toFixed(3)} ms per request`);
};
return api; return api;
})(); })();