Ignore `!#include` directives within inactive `!#if`/`!#endif` blocks

Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/1113
This commit is contained in:
Raymond Hill 2020-07-03 08:43:40 -04:00
parent ae57affea5
commit aab3812089
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
2 changed files with 99 additions and 78 deletions

View File

@ -244,6 +244,7 @@ api.fetchFilterList = async function(mainlistURL) {
const sublistURLs = new Set();
// https://github.com/uBlockOrigin/uBlock-issues/issues/1113
const processIncludeDirectives = function(results) {
const out = [];
const reInclude = /^!#include +(\S+)/gm;
@ -254,28 +255,36 @@ api.fetchFilterList = async function(mainlistURL) {
}
if ( result instanceof Object === false ) { continue; }
const content = result.content;
let lastIndex = 0;
for (;;) {
if ( rootDirectoryURL === undefined ) { break; }
const match = reInclude.exec(content);
if ( match === null ) { break; }
if ( toParsedURL(match[1]) !== undefined ) { continue; }
if ( match[1].indexOf('..') !== -1 ) { continue; }
// Compute nested list path relative to parent list path
const pos = result.url.lastIndexOf('/');
if ( pos === -1 ) { continue; }
const subURL = result.url.slice(0, pos + 1) + match[1];
if ( sublistURLs.has(subURL) ) { continue; }
sublistURLs.add(subURL);
out.push(
content.slice(lastIndex, match.index),
`! >>>>>>>> ${subURL}`,
api.fetchText(subURL),
`! <<<<<<<< ${subURL}`
);
lastIndex = reInclude.lastIndex;
const slices = µBlock.processDirectives.split(content);
for ( let i = 0, n = slices.length - 1; i < n; i++ ) {
const slice = content.slice(slices[i+0], slices[i+1]);
if ( (i & 1) !== 0 ) {
out.push(slice);
continue;
}
let lastIndex = 0;
for (;;) {
if ( rootDirectoryURL === undefined ) { break; }
const match = reInclude.exec(slice);
if ( match === null ) { break; }
if ( toParsedURL(match[1]) !== undefined ) { continue; }
if ( match[1].indexOf('..') !== -1 ) { continue; }
// Compute nested list path relative to parent list path
const pos = result.url.lastIndexOf('/');
if ( pos === -1 ) { continue; }
const subURL = result.url.slice(0, pos + 1) + match[1];
if ( sublistURLs.has(subURL) ) { continue; }
sublistURLs.add(subURL);
out.push(
slice.slice(lastIndex, match.index),
`! >>>>>>>> ${subURL}`,
api.fetchText(subURL),
`! <<<<<<<< ${subURL}`
);
lastIndex = reInclude.lastIndex;
}
out.push(lastIndex === 0 ? slice : slice.slice(lastIndex));
}
out.push(lastIndex === 0 ? content : content.slice(lastIndex));
}
return out;
};

View File

@ -799,7 +799,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
// https://adblockplus.org/en/filters
const staticNetFilteringEngine = this.staticNetFilteringEngine;
const staticExtFilteringEngine = this.staticExtFilteringEngine;
const lineIter = new this.LineIterator(this.processDirectives(rawText));
const lineIter = new this.LineIterator(this.processDirectives.prune(rawText));
const parser = new vAPI.StaticFilteringParser();
parser.setMaxTokenLength(this.urlTokenizer.MAX_TOKEN_LENGTH);
@ -854,69 +854,81 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
// https://github.com/AdguardTeam/AdguardBrowserExtension/issues/917
µBlock.processDirectives = function(content) {
const reIf = /^!#(if|endif)\b([^\n]*)/gm;
const stack = [];
const shouldDiscard = ( ) => stack.some(v => v);
const parts = [];
let beg = 0, discard = false;
µBlock.processDirectives = {
// This method returns an array of indices, corresponding to position in
// the content string which should alternatively be parsed and discarded.
split: function(content) {
const reIf = /^!#(if|endif)\b([^\n]*)(?:[\n\r]+|$)/gm;
const stack = [];
const shouldDiscard = ( ) => stack.some(v => v);
const parts = [ 0 ];
let discard = false;
while ( beg < content.length ) {
const match = reIf.exec(content);
if ( match === null ) { break; }
for (;;) {
const match = reIf.exec(content);
if ( match === null ) { break; }
switch ( match[1] ) {
case 'if':
let expr = match[2].trim();
const target = expr.charCodeAt(0) === 0x21 /* '!' */;
if ( target ) { expr = expr.slice(1); }
const token = this.processDirectives.tokens.get(expr);
const startDiscard =
token === 'false' &&
target === false ||
token !== undefined &&
vAPI.webextFlavor.soup.has(token) === target;
if ( discard === false && startDiscard ) {
parts.push(content.slice(beg, match.index));
discard = true;
switch ( match[1] ) {
case 'if':
let expr = match[2].trim();
const target = expr.charCodeAt(0) === 0x21 /* '!' */;
if ( target ) { expr = expr.slice(1); }
const token = this.tokens.get(expr);
const startDiscard =
token === 'false' &&
target === false ||
token !== undefined &&
vAPI.webextFlavor.soup.has(token) === target;
if ( discard === false && startDiscard ) {
parts.push(match.index);
discard = true;
}
stack.push(startDiscard);
break;
case 'endif':
stack.pop();
const stopDiscard = shouldDiscard() === false;
if ( discard && stopDiscard ) {
parts.push(match.index + match[0].length);
discard = false;
}
break;
default:
break;
}
stack.push(startDiscard);
break;
case 'endif':
stack.pop();
const stopDiscard = shouldDiscard() === false;
if ( discard && stopDiscard ) {
beg = match.index + match[0].length + 1;
discard = false;
}
break;
default:
break;
}
}
if ( stack.length === 0 && parts.length !== 0 ) {
parts.push(content.slice(beg));
content = parts.join('\n');
}
return content.trim();
parts.push(content.length);
return parts;
},
prune: function(content) {
const parts = this.split(content);
const out = [];
for ( let i = 0, n = parts.length - 1; i < n; i += 2 ) {
const beg = parts[i+0];
const end = parts[i+1];
out.push(content.slice(beg, end));
}
return out.join('\n');
},
tokens: new Map([
[ 'ext_ublock', 'ublock' ],
[ 'env_chromium', 'chromium' ],
[ 'env_edge', 'edge' ],
[ 'env_firefox', 'firefox' ],
[ 'env_legacy', 'legacy' ],
[ 'env_mobile', 'mobile' ],
[ 'env_safari', 'safari' ],
[ 'cap_html_filtering', 'html_filtering' ],
[ 'cap_user_stylesheet', 'user_stylesheet' ],
[ 'false', 'false' ],
]),
};
µBlock.processDirectives.tokens = new Map([
[ 'ext_ublock', 'ublock' ],
[ 'env_chromium', 'chromium' ],
[ 'env_edge', 'edge' ],
[ 'env_firefox', 'firefox' ],
[ 'env_legacy', 'legacy' ],
[ 'env_mobile', 'mobile' ],
[ 'env_safari', 'safari' ],
[ 'cap_html_filtering', 'html_filtering' ],
[ 'cap_user_stylesheet', 'user_stylesheet' ],
[ 'false', 'false' ],
]);
/******************************************************************************/
µBlock.loadRedirectResources = async function() {