Skip to content

Commit bf3c925

Browse files
committed
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()`
1 parent 1ac016b commit bf3c925

File tree

2 files changed

+86
-46
lines changed

2 files changed

+86
-46
lines changed

src/js/cosmetic-filtering.js

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,41 +1127,39 @@ FilterContainer.prototype.getFilterCount = function() {
11271127

11281128
/******************************************************************************/
11291129

1130-
FilterContainer.prototype.benchmark = function() {
1131-
µb.loadBenchmarkDataset().then(requests => {
1132-
if ( Array.isArray(requests) === false || requests.length === 0 ) {
1133-
console.info('No requests found to benchmark');
1134-
return;
1135-
}
1136-
console.info(`Benchmarking cosmeticFilteringEngine.matchString()...`);
1137-
const details = {
1138-
tabId: undefined,
1139-
frameId: undefined,
1140-
hostname: '',
1141-
domain: '',
1142-
entity: '',
1143-
};
1144-
const options = {
1145-
noCosmeticFiltering: false,
1146-
noGenericCosmeticFiltering: false,
1147-
};
1148-
let count = 0;
1149-
const t0 = self.performance.now();
1150-
for ( let i = 0; i < requests.length; i++ ) {
1151-
const request = requests[i];
1152-
if ( request.cpt !== 'document' ) { continue; }
1153-
count += 1;
1154-
details.hostname = µb.URI.hostnameFromURI(request.url);
1155-
details.domain = µb.URI.domainFromHostname(details.hostname);
1156-
details.entity = µb.URI.entityFromDomain(details.domain);
1157-
void this.retrieveSpecificSelectors(details, options);
1158-
}
1159-
const t1 = self.performance.now();
1160-
const dur = t1 - t0;
1161-
console.info(`Evaluated ${count} requests in ${dur.toFixed(0)} ms`);
1162-
console.info(`\tAverage: ${(dur / count).toFixed(3)} ms per request`);
1163-
});
1164-
return 'ok';
1130+
FilterContainer.prototype.benchmark = async function() {
1131+
const requests = await µb.loadBenchmarkDataset();
1132+
if ( Array.isArray(requests) === false || requests.length === 0 ) {
1133+
console.info('No requests found to benchmark');
1134+
return;
1135+
}
1136+
console.info('Benchmarking cosmeticFilteringEngine.retrieveSpecificSelectors()...');
1137+
const details = {
1138+
tabId: undefined,
1139+
frameId: undefined,
1140+
hostname: '',
1141+
domain: '',
1142+
entity: '',
1143+
};
1144+
const options = {
1145+
noCosmeticFiltering: false,
1146+
noGenericCosmeticFiltering: false,
1147+
};
1148+
let count = 0;
1149+
const t0 = self.performance.now();
1150+
for ( let i = 0; i < requests.length; i++ ) {
1151+
const request = requests[i];
1152+
if ( request.cpt !== 'document' ) { continue; }
1153+
count += 1;
1154+
details.hostname = µb.URI.hostnameFromURI(request.url);
1155+
details.domain = µb.URI.domainFromHostname(details.hostname);
1156+
details.entity = µb.URI.entityFromDomain(details.domain);
1157+
void this.retrieveSpecificSelectors(details, options);
1158+
}
1159+
const t1 = self.performance.now();
1160+
const dur = t1 - t0;
1161+
console.info(`Evaluated ${count} requests in ${dur.toFixed(0)} ms`);
1162+
console.info(`\tAverage: ${(dur / count).toFixed(3)} ms per request`);
11651163
};
11661164

11671165
/******************************************************************************/

src/js/scriptlet-filtering.js

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727
const µb = µBlock,
2828
duplicates = new Set(),
2929
scriptletCache = new µb.MRUCache(32),
30-
scriptletsRegister = new Map(),
31-
exceptionsRegister = new Set(),
3230
reEscapeScriptArg = /[\\'"]/g;
3331

3432
let acceptedCount = 0,
@@ -289,6 +287,11 @@
289287
// Only exception filters are allowed to be global.
290288
const normalized = normalizeRawFilter(parsed.suffix);
291289

290+
// Tokenless is meaningful only for exception filters.
291+
if ( normalized === '+js()' && parsed.exception === false ) {
292+
return;
293+
}
294+
292295
if ( parsed.hostnames.length === 0 ) {
293296
if ( parsed.exception ) {
294297
writer.push([ 32, '', 1, normalized ]);
@@ -358,7 +361,7 @@
358361
}
359362

360363
const scriptlets = new Set();
361-
const exceptions = exceptionsRegister;
364+
const exceptions = new Set();
362365

363366
scriptletDB.retrieve(
364367
hostname,
@@ -370,17 +373,27 @@
370373
[ scriptlets, exceptions ]
371374
);
372375
}
376+
if ( scriptlets.size === 0 ) { return; }
373377

374-
for ( const rawToken of scriptlets ) {
375-
lookupScriptlet(rawToken, reng, scriptletsRegister);
378+
const loggerEnabled = µb.logger.enabled;
379+
380+
// Wholly disable scriptlet injection?
381+
if ( exceptions.has('') ) {
382+
if ( loggerEnabled ) {
383+
logOne(true, '', request);
384+
}
385+
return;
376386
}
377387

378-
if ( scriptletsRegister.size === 0 ) { return; }
388+
const scriptletToCodeMap = new Map();
389+
for ( const rawToken of scriptlets ) {
390+
lookupScriptlet(rawToken, reng, scriptletToCodeMap);
391+
}
392+
if ( scriptletToCodeMap.size === 0 ) { return; }
379393

380394
// Return an array of scriptlets, and log results if needed.
381395
const out = [];
382-
const loggerEnabled = µb.logger.enabled;
383-
for ( const [ rawToken, code ] of scriptletsRegister ) {
396+
for ( const [ rawToken, code ] of scriptletToCodeMap ) {
384397
const isException = exceptions.has(rawToken);
385398
if ( isException === false ) {
386399
out.push(code);
@@ -390,9 +403,6 @@
390403
}
391404
}
392405

393-
scriptletsRegister.clear();
394-
exceptionsRegister.clear();
395-
396406
if ( out.length === 0 ) { return; }
397407

398408
if ( µb.hiddenSettings.debugScriptlets ) {
@@ -454,6 +464,38 @@
454464
scriptletDB = new µb.staticExtFilteringEngine.HostnameBasedDB(1, selfie);
455465
};
456466

467+
api.benchmark = async function() {
468+
const requests = await µb.loadBenchmarkDataset();
469+
if ( Array.isArray(requests) === false || requests.length === 0 ) {
470+
console.info('No requests found to benchmark');
471+
return;
472+
}
473+
console.info('Benchmarking scriptletFilteringEngine.retrieve()...');
474+
const details = {
475+
domain: '',
476+
entity: '',
477+
hostname: '',
478+
tabId: 0,
479+
url: '',
480+
};
481+
let count = 0;
482+
const t0 = self.performance.now();
483+
for ( let i = 0; i < requests.length; i++ ) {
484+
const request = requests[i];
485+
if ( request.cpt !== 'document' ) { continue; }
486+
count += 1;
487+
details.url = request.url;
488+
details.hostname = µb.URI.hostnameFromURI(request.url);
489+
details.domain = µb.URI.domainFromHostname(details.hostname);
490+
details.entity = µb.URI.entityFromDomain(details.domain);
491+
void this.retrieve(details);
492+
}
493+
const t1 = self.performance.now();
494+
const dur = t1 - t0;
495+
console.info(`Evaluated ${count} requests in ${dur.toFixed(0)} ms`);
496+
console.info(`\tAverage: ${(dur / count).toFixed(3)} ms per request`);
497+
};
498+
457499
return api;
458500
})();
459501

0 commit comments

Comments
 (0)