Skip to content

Commit

Permalink
fix regression in 8f05a2f (related issue: #3683)
Browse files Browse the repository at this point in the history
  • Loading branch information
gorhill committed Dec 16, 2018
1 parent 08d4604 commit d3a3505
Showing 1 changed file with 96 additions and 83 deletions.
179 changes: 96 additions & 83 deletions src/js/static-ext-filtering.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@
};

const compileProceduralSelector = (function() {
var reProceduralOperator = new RegExp([
const reProceduralOperator = new RegExp([
'^(?:',
[
'-abp-contains',
Expand All @@ -165,17 +165,17 @@
')\\('
].join(''));

var reEscapeRegex = /[.*+?^${}()|[\]\\]/g,
const reEscapeRegex = /[.*+?^${}()|[\]\\]/g,
reNeedScope = /^\s*[+>~]/,
reIsDanglingSelector = /(?:[+>~]\s*|\s+)$/;

var lastProceduralSelector = '',
lastProceduralSelectorCompiled,
regexToRawValue = new Map();
const regexToRawValue = new Map();
let lastProceduralSelector = '',
lastProceduralSelectorCompiled;

var compileText = function(s) {
var regexDetails,
match = reParseRegexLiteral.exec(s);
const compileText = function(s) {
const match = reParseRegexLiteral.exec(s);
let regexDetails;
if ( match !== null ) {
regexDetails = match[1];
if ( isBadRegex(regexDetails) ) { return; }
Expand All @@ -189,13 +189,13 @@
return regexDetails;
};

var compileCSSDeclaration = function(s) {
var name, value, regexDetails,
pos = s.indexOf(':');
const compileCSSDeclaration = function(s) {
const pos = s.indexOf(':');
if ( pos === -1 ) { return; }
name = s.slice(0, pos).trim();
value = s.slice(pos + 1).trim();
var match = reParseRegexLiteral.exec(value);
const name = s.slice(0, pos).trim();
const value = s.slice(pos + 1).trim();
const match = reParseRegexLiteral.exec(value);
let regexDetails;
if ( match !== null ) {
regexDetails = match[1];
if ( isBadRegex(regexDetails) ) { return; }
Expand All @@ -209,10 +209,7 @@
return { name: name, value: regexDetails };
};

var compileConditionalSelector = function(s) {
if ( isValidCSSSelector(s) ) {
return { selector: s, tasks: [] };
}
const compileConditionalSelector = function(s) {
// https://github.com/AdguardTeam/ExtendedCss/issues/31#issuecomment-302391277
// Prepend `:scope ` if needed.
if ( reNeedScope.test(s) ) {
Expand All @@ -221,7 +218,17 @@
return compile(s);
};

var compileXpathExpression = function(s) {
const compileNotSelector = function(s) {
// https://github.com/uBlockOrigin/uBlock-issues/issues/341#issuecomment-447603588
// Reject instances of :not() filters for which the argument is
// a valid CSS selector, otherwise we would be adversely
// changing the behavior of CSS4's :not().
if ( isValidCSSSelector(s) === false ) {
return compileConditionalSelector(s);
}
};

const compileXpathExpression = function(s) {
try {
document.createExpression(s, null);
} catch (e) {
Expand All @@ -231,21 +238,21 @@
};

// https://github.com/gorhill/uBlock/issues/2793
var normalizedOperators = new Map([
const normalizedOperators = new Map([
[ ':-abp-contains', ':has-text' ],
[ ':-abp-has', ':has' ],
[ ':contains', ':has-text' ],
]);

var compileArgument = new Map([
const compileArgument = new Map([
[ ':has', compileConditionalSelector ],
[ ':has-text', compileText ],
[ ':if', compileConditionalSelector ],
[ ':if-not', compileConditionalSelector ],
[ ':matches-css', compileCSSDeclaration ],
[ ':matches-css-after', compileCSSDeclaration ],
[ ':matches-css-before', compileCSSDeclaration ],
[ ':not', compileConditionalSelector ],
[ ':not', compileNotSelector ],
[ ':xpath', compileXpathExpression ]
]);

Expand All @@ -256,15 +263,14 @@
// to other blockers.
// The normalized string version is what is reported in the logger,
// by design.
var decompile = function(compiled) {
var tasks = compiled.tasks;
const decompile = function(compiled) {
const tasks = compiled.tasks;
if ( Array.isArray(tasks) === false ) {
return compiled.selector;
}
var raw = [ compiled.selector ],
value;
for ( var i = 0, n = tasks.length, task; i < n; i++ ) {
task = tasks[i];
const raw = [ compiled.selector ];
let value;
for ( let task of tasks ) {
switch ( task[0] ) {
case ':xpath':
raw.push(task[0], '(', task[1], ')');
Expand Down Expand Up @@ -306,14 +312,15 @@
return raw.join('');
};

var compile = function(raw) {
const compile = function(raw) {
if ( raw === '' ) { return; }
var prefix = '',
let prefix = '',
tasks = [];
let i = 0,
n = raw.length,
opPrefixBeg = 0;
for (;;) {
var i = 0,
n = raw.length,
c, match;
let c, match;
// Advance to next operator.
while ( i < n ) {
c = raw.charCodeAt(i++);
Expand All @@ -323,14 +330,14 @@
}
}
if ( i === n ) { break; }
var opNameBeg = i - 1;
var opNameEnd = i + match[0].length - 1;
const opNameBeg = i - 1;
const opNameEnd = i + match[0].length - 1;
i += match[0].length;
// Find end of argument: first balanced closing parenthesis.
// Note: unbalanced parenthesis can be used in a regex literal
// when they are escaped using `\`.
// TODO: need to handle quoted parentheses.
var pcnt = 1;
let pcnt = 1;
while ( i < n ) {
c = raw.charCodeAt(i++);
if ( c === 0x5C /* '\\' */ ) {
Expand All @@ -345,27 +352,39 @@
// Unbalanced parenthesis? An unbalanced parenthesis is fine
// as long as the last character is a closing parenthesis.
if ( pcnt !== 0 && c !== 0x29 ) { return; }
// https://github.com/uBlockOrigin/uBlock-issues/issues/341#issuecomment-447603588
// Maybe that one operator is a valid CSS selector and if so,
// then consider it to be part of the prefix. If there is
// at least one task present, then we fail, as we do not
// support suffix CSS selectors.
// TODO: AdGuard does support suffix CSS selectors, so
// supporting this would increase compatibility with
// AdGuard filter lists.
if ( isValidCSSSelector(raw.slice(opNameBeg, i)) ) {
if ( opPrefixBeg !== 0 ) { return; }
continue;
}
// Extract and remember operator details.
var operator = raw.slice(opNameBeg, opNameEnd);
let operator = raw.slice(opNameBeg, opNameEnd);
operator = normalizedOperators.get(operator) || operator;
var args = raw.slice(opNameEnd + 1, i - 1);
let args = raw.slice(opNameEnd + 1, i - 1);
args = compileArgument.get(operator)(args);
if ( args === undefined ) { return; }
if ( tasks.length === 0 ) {
if ( opPrefixBeg === 0 ) {
prefix = raw.slice(0, opNameBeg);
} else if ( opNameBeg !== 0 ) {
} else if ( opNameBeg !== opPrefixBeg ) {
return;
}
tasks.push([ operator, args ]);
raw = raw.slice(i);
if ( i === n ) { break; }
opPrefixBeg = i;
}
// No task found: then we have a CSS selector.
// At least one task found: nothing should be left to parse.
if ( tasks.length === 0 ) {
prefix = raw;
tasks = undefined;
} else if ( raw.length !== 0 ) {
} else if ( i < n ) {
return;
}
// https://github.com/NanoAdblocker/NanoCore/issues/1#issuecomment-354394894
Expand All @@ -376,7 +395,7 @@
return { selector: prefix, tasks: tasks };
};

var entryPoint = function(raw) {
const entryPoint = function(raw) {
if ( raw === lastProceduralSelector ) {
return lastProceduralSelectorCompiled;
}
Expand All @@ -391,7 +410,7 @@
};

entryPoint.reset = function() {
regexToRawValue = new Map();
regexToRawValue.clear();
lastProceduralSelector = '';
lastProceduralSelectorCompiled = undefined;
};
Expand All @@ -403,7 +422,18 @@
// Public API
//--------------------------------------------------------------------------

var api = {};
const api = {
get acceptedCount() {
return µb.cosmeticFilteringEngine.acceptedCount +
µb.scriptletFilteringEngine.acceptedCount +
µb.htmlFilteringEngine.acceptedCount;
},
get discardedCount() {
return µb.cosmeticFilteringEngine.discardedCount +
µb.scriptletFilteringEngine.discardedCount +
µb.htmlFilteringEngine.discardedCount;
}
};

//--------------------------------------------------------------------------
// Public classes
Expand Down Expand Up @@ -464,12 +494,12 @@
};

api.HostnameBasedDB.prototype[Symbol.iterator] = (function() {
var Iter = function(db) {
const Iter = function(db) {
this.mapIter = db.values();
this.arrayIter = undefined;
};
Iter.prototype.next = function() {
var result;
let result;
if ( this.arrayIter !== undefined ) {
result = this.arrayIter.next();
if ( result.done === false ) { return result; }
Expand Down Expand Up @@ -516,11 +546,11 @@
// Based on: FNV32a
// http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-reference-source
// The rest is custom, suited for uBlock.
let i1 = token.length;
const i1 = token.length;
if ( i1 === 0 ) { return 0; }
let i2 = i1 >> 1;
let i4 = i1 >> 2;
let i8 = i1 >> 3;
const i2 = i1 >> 1;
const i4 = i1 >> 2;
const i8 = i1 >> 3;
let hval = (0x811c9dc5 ^ token.charCodeAt(0)) >>> 0;
hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
hval >>>= 0;
Expand Down Expand Up @@ -553,7 +583,7 @@
api.compileHostnameToHash = function(hostname) {
let domain;
if ( hostname.endsWith('.*') ) {
let pos = hostname.lastIndexOf('.', hostname.length - 3);
const pos = hostname.lastIndexOf('.', hostname.length - 3);
domain = pos !== -1 ? hostname.slice(pos + 1) : hostname;
} else {
domain = µb.URI.domainFromHostnameNoCache(hostname);
Expand All @@ -575,39 +605,39 @@
// Do not discard unknown pseudo-elements.

api.compileSelector = (function() {
var reAfterBeforeSelector = /^(.+?)(::?after|::?before|::[a-z-]+)$/,
reStyleSelector = /^(.+?):style\((.+?)\)$/,
reStyleBad = /url\([^)]+\)/,
reExtendedSyntax = /\[-(?:abp|ext)-[a-z-]+=(['"])(?:.+?)(?:\1)\]/,
reExtendedSyntaxParser = /\[-(?:abp|ext)-([a-z-]+)=(['"])(.+?)\2\]/,
div = document.createElement('div');

var normalizedExtendedSyntaxOperators = new Map([
const reAfterBeforeSelector = /^(.+?)(::?after|::?before|::[a-z-]+)$/;
const reStyleSelector = /^(.+?):style\((.+?)\)$/;
const reStyleBad = /url\([^)]+\)/;
const reExtendedSyntax = /\[-(?:abp|ext)-[a-z-]+=(['"])(?:.+?)(?:\1)\]/;
const reExtendedSyntaxParser = /\[-(?:abp|ext)-([a-z-]+)=(['"])(.+?)\2\]/;
const div = document.createElement('div');

const normalizedExtendedSyntaxOperators = new Map([
[ 'contains', ':has-text' ],
[ 'has', ':has' ],
[ 'matches-css', ':matches-css' ],
[ 'matches-css-after', ':matches-css-after' ],
[ 'matches-css-before', ':matches-css-before' ],
]);

var isValidStyleProperty = function(cssText) {
const isValidStyleProperty = function(cssText) {
if ( reStyleBad.test(cssText) ) { return false; }
div.style.cssText = cssText;
if ( div.style.cssText === '' ) { return false; }
div.style.cssText = '';
return true;
};

var entryPoint = function(raw) {
var extendedSyntax = reExtendedSyntax.test(raw);
const entryPoint = function(raw) {
const extendedSyntax = reExtendedSyntax.test(raw);
if ( isValidCSSSelector(raw) && extendedSyntax === false ) {
return raw;
}

// We rarely reach this point -- majority of selectors are plain
// CSS selectors.

var matches, operator;
let matches, operator;

// Supported Adguard/ABP advanced selector syntax: will translate into
// uBO's syntax before further processing.
Expand All @@ -627,7 +657,7 @@
return entryPoint(raw);
}

var selector = raw,
let selector = raw,
pseudoclass, style;

// `:style` selector?
Expand Down Expand Up @@ -664,7 +694,7 @@
}

// Procedural selector?
var compiled;
let compiled;
if ( (compiled = compileProceduralSelector(raw)) ) {
return compiled;
}
Expand Down Expand Up @@ -770,23 +800,6 @@
};
};

Object.defineProperties(api, {
acceptedCount: {
get: function() {
return µb.cosmeticFilteringEngine.acceptedCount +
µb.scriptletFilteringEngine.acceptedCount +
µb.htmlFilteringEngine.acceptedCount;
}
},
discardedCount: {
get: function() {
return µb.cosmeticFilteringEngine.discardedCount +
µb.scriptletFilteringEngine.discardedCount +
µb.htmlFilteringEngine.discardedCount;
}
}
});

api.fromSelfie = function(selfie) {
µb.cosmeticFilteringEngine.fromSelfie(selfie.cosmetic);
µb.scriptletFilteringEngine.fromSelfie(selfie.scriptlets);
Expand Down

0 comments on commit d3a3505

Please sign in to comment.