mirror of https://github.com/gorhill/uBlock.git
Fine tune various static filtering code
Notably, make `queryprune` option available only to filter list authors, until there are guards against bad filters in some future and until the option syntax and behavior is fully settled. Instances of `queryprune` in filter lists will be compiled, however instances of `queryprune` in _"My filters"_ will be ignored unless users indicated they are a filter list author.
This commit is contained in:
parent
525d7b1b3b
commit
2cfeaddbed
|
@ -57,6 +57,7 @@ vAPI.messaging.send('dashboard', {
|
|||
if ( mode.setHints instanceof Function ) {
|
||||
mode.setHints(response);
|
||||
}
|
||||
mode.parser.expertMode = response.expertMode !== false;
|
||||
});
|
||||
|
||||
let cachedUserFilters = '';
|
||||
|
|
|
@ -364,6 +364,9 @@ CodeMirror.defineMode('ubo-static-filtering', function() {
|
|||
preparseDirectiveHints.push(...details.preparseDirectiveHints);
|
||||
initHints();
|
||||
},
|
||||
get parser() {
|
||||
return parser;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -1184,6 +1184,7 @@ const onMessage = function(request, sender, callback) {
|
|||
redirectResources: µb.redirectEngine.getResourceDetails(),
|
||||
preparseDirectiveTokens: µb.preparseDirectives.getTokens(),
|
||||
preparseDirectiveHints: µb.preparseDirectives.getHints(),
|
||||
expertMode: µb.hiddenSettings.filterAuthorMode,
|
||||
};
|
||||
break;
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@ const Parser = class {
|
|||
this.netOptionsIterator = new NetOptionsIterator(this);
|
||||
this.extOptionsIterator = new ExtOptionsIterator(this);
|
||||
this.maxTokenLength = Number.MAX_SAFE_INTEGER;
|
||||
this.expertMode = options.expertMode !== false;
|
||||
this.reIsLocalhostRedirect = /(?:0\.0\.0\.0|(?:broadcast|local)host|local|ip6-\w+)(?:[^\w.-]|$)/;
|
||||
this.reHostname = /^[^\x00-\x24\x26-\x29\x2B\x2C\x2F\x3A-\x40\x5B-\x5E\x60\x7B-\x7F]+/;
|
||||
this.reHostsSink = /^[\w-.:\[\]]+$/;
|
||||
|
@ -2281,14 +2282,19 @@ const NetOptionsIterator = class {
|
|||
if (
|
||||
descriptor === undefined ||
|
||||
hasBits(descriptor, OPTNotSupported) ||
|
||||
ltok !== lopt && hasNoBits(descriptor, OPTCanNegate) ||
|
||||
this.exception && hasBits(descriptor, OPTBlockOnly) ||
|
||||
this.exception === false && hasBits(descriptor, OPTAllowOnly) ||
|
||||
assigned && hasNoBits(descriptor, OPTMustAssign) ||
|
||||
assigned === false && hasBits(descriptor, OPTMustAssign) && (
|
||||
this.exception === false ||
|
||||
hasNoBits(descriptor, OPTAllowMayAssign)
|
||||
)
|
||||
ltok !== lopt &&
|
||||
hasNoBits(descriptor, OPTCanNegate) ||
|
||||
this.exception &&
|
||||
hasBits(descriptor, OPTBlockOnly) ||
|
||||
this.exception === false &&
|
||||
hasBits(descriptor, OPTAllowOnly) ||
|
||||
assigned &&
|
||||
hasNoBits(descriptor, OPTMustAssign) ||
|
||||
assigned === false &&
|
||||
hasBits(descriptor, OPTMustAssign) && (
|
||||
this.exception === false ||
|
||||
hasNoBits(descriptor, OPTAllowMayAssign)
|
||||
)
|
||||
) {
|
||||
descriptor = OPTTokenInvalid;
|
||||
}
|
||||
|
@ -2398,7 +2404,10 @@ const NetOptionsIterator = class {
|
|||
{
|
||||
const i = this.tokenPos[OPTTokenQueryprune];
|
||||
if ( i !== -1 ) {
|
||||
if ( hasBits(allBits, OPTNonNetworkType) ) {
|
||||
if (
|
||||
this.parser.expertMode === false ||
|
||||
hasBits(allBits, OPTNonNetworkType)
|
||||
) {
|
||||
optSlices[i] = OPTTokenInvalid;
|
||||
if ( this.interactive ) {
|
||||
this.parser.errorSlices(optSlices[i+1], optSlices[i+5]);
|
||||
|
|
|
@ -2660,6 +2660,17 @@ const FilterParser = class {
|
|||
return i === 1 ? out[0] : out.join('|');
|
||||
}
|
||||
|
||||
parseModifierOption(modifier, value) {
|
||||
if ( this.modifyType !== undefined ) { return false; }
|
||||
this.modifyType = modifier;
|
||||
if ( value !== undefined ) {
|
||||
this.modifyValue = value;
|
||||
} else if ( this.action === AllowAction ) {
|
||||
this.modifyValue = '';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
parseOptions(parser) {
|
||||
for ( let { id, val, not } of parser.netOptions() ) {
|
||||
switch ( id ) {
|
||||
|
@ -2677,13 +2688,11 @@ const FilterParser = class {
|
|||
this.badFilter = true;
|
||||
break;
|
||||
case parser.OPTTokenCsp:
|
||||
if ( this.modifyType !== undefined ) { return false; }
|
||||
this.modifyType = parser.OPTTokenCsp;
|
||||
if ( val !== undefined ) {
|
||||
if ( this.reBadCSP.test(val) ) { return false; }
|
||||
this.modifyValue = val;
|
||||
} else if ( this.action === AllowAction ) {
|
||||
this.modifyValue = '';
|
||||
if ( this.parseModifierOption(id, val) === false ) {
|
||||
return false;
|
||||
}
|
||||
if ( val !== undefined && this.reBadCSP.test(val) ) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
// https://github.com/gorhill/uBlock/issues/2294
|
||||
|
@ -2725,15 +2734,10 @@ const FilterParser = class {
|
|||
this.modifyValue = 'noopmp4-1s';
|
||||
break;
|
||||
case parser.OPTTokenQueryprune:
|
||||
// TODO: validate value
|
||||
case parser.OPTTokenRedirect:
|
||||
case parser.OPTTokenRedirectRule:
|
||||
if ( this.modifyType !== undefined ) { return false; }
|
||||
this.modifyType = id;
|
||||
if ( val !== undefined ) {
|
||||
this.modifyValue = val;
|
||||
} else if ( this.action === AllowAction ) {
|
||||
this.modifyValue = '';
|
||||
if ( this.parseModifierOption(id, val) === false ) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case parser.OPTTokenInvalid:
|
||||
|
@ -2877,7 +2881,7 @@ const FilterParser = class {
|
|||
if ( this.isRegex ) {
|
||||
return this.extractTokenFromRegex();
|
||||
}
|
||||
const match = this.findGoodToken(parser);
|
||||
const match = this.extractTokenFromPattern(parser);
|
||||
if ( match === null ) { return; }
|
||||
this.token = match.token;
|
||||
this.tokenHash = urlTokenizer.tokenHashFromString(this.token);
|
||||
|
@ -2885,15 +2889,15 @@ const FilterParser = class {
|
|||
}
|
||||
|
||||
// Note: a one-char token is better than a documented bad token.
|
||||
findGoodToken(parser) {
|
||||
extractTokenFromPattern(parser) {
|
||||
let bestMatch = null;
|
||||
let bestBadness = 0;
|
||||
let bestBadness = 0x7FFFFFFF;
|
||||
for ( const match of parser.patternTokens() ) {
|
||||
const badness = match.token.length > 1
|
||||
? this.badTokens.get(match.token) || 0
|
||||
: 1;
|
||||
if ( badness === 0 ) { return match; }
|
||||
if ( bestBadness === 0 || badness < bestBadness ) {
|
||||
if ( badness < bestBadness ) {
|
||||
bestMatch = match;
|
||||
bestBadness = badness;
|
||||
}
|
||||
|
@ -2910,7 +2914,7 @@ const FilterParser = class {
|
|||
extractTokenFromRegex() {
|
||||
this.reRegexToken.lastIndex = 0;
|
||||
const s = this.pattern;
|
||||
let bestBadness = 0;
|
||||
let bestBadness = 0x7FFFFFFF;
|
||||
for (;;) {
|
||||
const matches = this.reRegexToken.exec(s);
|
||||
if ( matches === null ) { break; }
|
||||
|
@ -2941,7 +2945,7 @@ const FilterParser = class {
|
|||
const badness = token.length > 1
|
||||
? this.badTokens.get(token) || 0
|
||||
: 1;
|
||||
if ( bestBadness === 0 || badness < bestBadness ) {
|
||||
if ( badness < bestBadness ) {
|
||||
this.token = token.toLowerCase();
|
||||
this.tokenHash = urlTokenizer.tokenHashFromString(this.token);
|
||||
this.tokenBeg = matches.index;
|
||||
|
@ -3170,6 +3174,8 @@ FilterContainer.prototype.freeze = function() {
|
|||
/******************************************************************************/
|
||||
|
||||
FilterContainer.prototype.optimize = function() {
|
||||
const t0 = Date.now();
|
||||
|
||||
for ( let bits = 0, n = this.categories.length; bits < n; bits++ ) {
|
||||
const bucket = this.categories[bits];
|
||||
if ( bucket === undefined ) { continue; }
|
||||
|
@ -3192,6 +3198,8 @@ FilterContainer.prototype.optimize = function() {
|
|||
for ( let i = filterUnitWritePtr, n = filterUnits.length; i < n; i++ ) {
|
||||
filterUnits[i] = null;
|
||||
}
|
||||
|
||||
log.info(`staticNetFilteringEngine.optimize() took ${Date.now()-t0} ms`);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -768,10 +768,9 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
// fetch the compiled content in case it has become available.
|
||||
const compiledDetails = await this.assets.get(compiledPath);
|
||||
if ( compiledDetails.content === '' ) {
|
||||
compiledDetails.content = this.compileFilters(
|
||||
rawDetails.content,
|
||||
{ assetKey: assetKey }
|
||||
);
|
||||
compiledDetails.content = this.compileFilters(rawDetails.content, {
|
||||
assetKey
|
||||
});
|
||||
this.assets.put(compiledPath, compiledDetails.content);
|
||||
}
|
||||
|
||||
|
@ -830,24 +829,24 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.compileFilters = function(rawText, details) {
|
||||
µBlock.compileFilters = function(rawText, details = {}) {
|
||||
const writer = new this.CompiledLineIO.Writer();
|
||||
|
||||
// Populate the writer with information potentially useful to the
|
||||
// client compilers.
|
||||
if ( details ) {
|
||||
if ( details.assetKey ) {
|
||||
writer.properties.set('assetKey', details.assetKey);
|
||||
}
|
||||
if ( details.assetKey ) {
|
||||
writer.properties.set('assetKey', details.assetKey);
|
||||
}
|
||||
|
||||
const expertMode =
|
||||
details.assetKey !== this.userFiltersPath ||
|
||||
this.hiddenSettings.filterAuthorMode !== false;
|
||||
// Useful references:
|
||||
// https://adblockplus.org/en/filter-cheatsheet
|
||||
// https://adblockplus.org/en/filters
|
||||
const staticNetFilteringEngine = this.staticNetFilteringEngine;
|
||||
const staticExtFilteringEngine = this.staticExtFilteringEngine;
|
||||
const lineIter = new this.LineIterator(this.preparseDirectives.prune(rawText));
|
||||
const parser = new vAPI.StaticFilteringParser();
|
||||
const parser = new vAPI.StaticFilteringParser({ expertMode });
|
||||
|
||||
parser.setMaxTokenLength(staticNetFilteringEngine.MAX_TOKEN_LENGTH);
|
||||
|
||||
|
@ -1386,10 +1385,9 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
if ( this.badLists.has(details.assetKey) === false ) {
|
||||
this.assets.put(
|
||||
'compiled/' + details.assetKey,
|
||||
this.compileFilters(
|
||||
details.content,
|
||||
{ assetKey: details.assetKey }
|
||||
)
|
||||
this.compileFilters(details.content, {
|
||||
assetKey: details.assetKey
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue