1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-09-15 07:22:28 +02:00

this fixes #191 completely

This commit is contained in:
gorhill 2014-08-28 09:59:05 -04:00
parent 527817d2f2
commit fe2d761908

View File

@ -41,6 +41,7 @@
const BlockAction = 0 << 15;
const AllowAction = 1 << 15;
const ToggleAction = BlockAction ^ AllowAction;
const AnyType = 1 << 11;
@ -209,6 +210,12 @@ FilterPlain.prototype.match = function(url, tokenBeg) {
return url.substr(tokenBeg - this.tokenBeg, this.s.length) === this.s;
};
FilterPlain.prototype.toString = function() {
return this.s;
};
/******************************************************************************/
var FilterPlainHostname = function(s, tokenBeg, hostname) {
this.s = s;
this.tokenBeg = tokenBeg;
@ -221,6 +228,10 @@ FilterPlainHostname.prototype.match = function(url, tokenBeg) {
url.substr(tokenBeg - this.tokenBeg, this.s.length) === this.s;
};
FilterPlainHostname.prototype.toString = function() {
return this.s + '$domain=' + this.hostname;
};
/******************************************************************************/
var FilterPlainPrefix0 = function(s) {
@ -232,6 +243,12 @@ FilterPlainPrefix0.prototype.match = function(url, tokenBeg) {
return url.substr(tokenBeg, this.s.length) === this.s;
};
FilterPlainPrefix0.prototype.toString = function() {
return this.s;
};
/******************************************************************************/
var FilterPlainPrefix0Hostname = function(s, hostname) {
this.s = s;
this.hostname = hostname;
@ -243,6 +260,10 @@ FilterPlainPrefix0Hostname.prototype.match = function(url, tokenBeg) {
url.substr(tokenBeg, this.s.length) === this.s;
};
FilterPlainPrefix0Hostname.prototype.toString = function() {
return this.s + '$domain=' + this.hostname;
};
/******************************************************************************/
var FilterPlainPrefix1 = function(s) {
@ -254,6 +275,12 @@ FilterPlainPrefix1.prototype.match = function(url, tokenBeg) {
return url.substr(tokenBeg - 1, this.s.length) === this.s;
};
FilterPlainPrefix1.prototype.toString = function() {
return this.s;
};
/******************************************************************************/
var FilterPlainPrefix1Hostname = function(s, hostname) {
this.s = s;
this.hostname = hostname;
@ -265,6 +292,10 @@ FilterPlainPrefix1Hostname.prototype.match = function(url, tokenBeg) {
url.substr(tokenBeg - 1, this.s.length) === this.s;
};
FilterPlainPrefix1Hostname.prototype.toString = function() {
return this.s + '$domain=' + this.hostname;
};
/******************************************************************************/
var FilterPlainLeftAnchored = function(s) {
@ -276,6 +307,12 @@ FilterPlainLeftAnchored.prototype.match = function(url) {
return url.slice(0, this.s.length) === this.s;
};
FilterPlainLeftAnchored.prototype.toString = function() {
return '|' + this.s;
};
/******************************************************************************/
var FilterPlainLeftAnchoredHostname = function(s, hostname) {
this.s = s;
this.hostname = hostname;
@ -287,6 +324,10 @@ FilterPlainLeftAnchoredHostname.prototype.match = function(url) {
url.slice(0, this.s.length) === this.s;
};
FilterPlainLeftAnchoredHostname.prototype.toString = function() {
return '|' + this.s + '$domain=' + this.hostname;
};
/******************************************************************************/
var FilterPlainRightAnchored = function(s) {
@ -298,6 +339,12 @@ FilterPlainRightAnchored.prototype.match = function(url) {
return url.slice(-this.s.length) === this.s;
};
FilterPlainRightAnchored.prototype.toString = function() {
return this.s + '|';
};
/******************************************************************************/
var FilterPlainRightAnchoredHostname = function(s, hostname) {
this.s = s;
this.hostname = hostname;
@ -309,6 +356,10 @@ FilterPlainRightAnchoredHostname.prototype.match = function(url) {
url.slice(-this.s.length) === this.s;
};
FilterPlainRightAnchoredHostname.prototype.toString = function() {
return this.s + '|$domain=' + this.hostname;
};
/******************************************************************************/
// With a single wildcard, regex is not optimal.
@ -317,7 +368,6 @@ FilterPlainRightAnchoredHostname.prototype.match = function(url) {
// http://jsperf.com/regexp-vs-indexof-abp-hit/3
var FilterSingleWildcard = function(s, tokenBeg) {
this.s = s;
this.tokenBeg = tokenBeg;
var wcOffset = s.indexOf('*');
this.lSegment = s.slice(0, wcOffset);
@ -331,8 +381,13 @@ FilterSingleWildcard.prototype.match = function(url, tokenBeg) {
url.indexOf(this.rSegment, tokenBeg + this.lSegment.length) > 0;
};
FilterSingleWildcard.prototype.toString = function() {
return this.lSegment + '*' + this.rSegment;
};
/******************************************************************************/
var FilterSingleWildcardHostname = function(s, tokenBeg, hostname) {
this.s = s;
this.tokenBeg = tokenBeg;
var wcOffset = s.indexOf('*');
this.lSegment = s.slice(0, wcOffset);
@ -348,10 +403,13 @@ FilterSingleWildcardHostname.prototype.match = function(url, tokenBeg) {
url.indexOf(this.rSegment, tokenBeg + this.lSegment.length) > 0;
};
FilterSingleWildcardHostname.prototype.toString = function() {
return this.lSegment + '*' + this.rSegment + '$domain=' + this.hostname;
};
/******************************************************************************/
var FilterSingleWildcardPrefix0 = function(s) {
this.s = s;
var wcOffset = s.indexOf('*');
this.lSegment = s.slice(0, wcOffset);
this.rSegment = s.slice(wcOffset + 1);
@ -363,8 +421,13 @@ FilterSingleWildcardPrefix0.prototype.match = function(url, tokenBeg) {
url.indexOf(this.rSegment, tokenBeg + this.lSegment.length) > 0;
};
FilterSingleWildcardPrefix0.prototype.toString = function() {
return this.lSegment + '*' + this.rSegment;
};
/******************************************************************************/
var FilterSingleWildcardPrefix0Hostname = function(s, hostname) {
this.s = s;
var wcOffset = s.indexOf('*');
this.lSegment = s.slice(0, wcOffset);
this.rSegment = s.slice(wcOffset + 1);
@ -378,6 +441,10 @@ FilterSingleWildcardPrefix0Hostname.prototype.match = function(url, tokenBeg) {
url.indexOf(this.rSegment, tokenBeg + this.lSegment.length) > 0;
};
FilterSingleWildcardPrefix0Hostname.prototype.toString = function() {
return this.lSegment + '*' + this.rSegment + '$domain=' + this.hostname;
};
/******************************************************************************/
// With a single wildcard, regex is not optimal.
@ -386,7 +453,6 @@ FilterSingleWildcardPrefix0Hostname.prototype.match = function(url, tokenBeg) {
// http://jsperf.com/regexp-vs-indexof-abp-hit/3
var FilterSingleWildcardLeftAnchored = function(s) {
this.s = s;
var wcOffset = s.indexOf('*');
this.lSegment = s.slice(0, wcOffset);
this.rSegment = s.slice(wcOffset + 1);
@ -398,8 +464,13 @@ FilterSingleWildcardLeftAnchored.prototype.match = function(url) {
url.indexOf(this.rSegment, this.lSegment.length) > 0;
};
FilterSingleWildcardLeftAnchored.prototype.toString = function() {
return '|' + this.lSegment + '*' + this.rSegment;
};
/******************************************************************************/
var FilterSingleWildcardLeftAnchoredHostname = function(s, hostname) {
this.s = s;
var wcOffset = s.indexOf('*');
this.lSegment = s.slice(0, wcOffset);
this.rSegment = s.slice(wcOffset + 1);
@ -413,6 +484,10 @@ FilterSingleWildcardLeftAnchoredHostname.prototype.match = function(url) {
url.indexOf(this.rSegment, this.lSegment.length) > 0;
};
FilterSingleWildcardLeftAnchoredHostname.prototype.toString = function() {
return '|' + this.lSegment + '*' + this.rSegment + '$domain=' + this.hostname;
};
/******************************************************************************/
// With a single wildcard, regex is not optimal.
@ -421,7 +496,6 @@ FilterSingleWildcardLeftAnchoredHostname.prototype.match = function(url) {
// http://jsperf.com/regexp-vs-indexof-abp-hit/3
var FilterSingleWildcardRightAnchored = function(s) {
this.s = s;
var wcOffset = s.indexOf('*');
this.lSegment = s.slice(0, wcOffset);
this.rSegment = s.slice(wcOffset + 1);
@ -433,8 +507,13 @@ FilterSingleWildcardRightAnchored.prototype.match = function(url) {
url.lastIndexOf(this.lSegment, url.length - this.rSegment.length - this.lSegment.length) >= 0;
};
FilterSingleWildcardRightAnchored.prototype.toString = function() {
return this.lSegment + '*' + this.rSegment + '|';
};
/******************************************************************************/
var FilterSingleWildcardRightAnchoredHostname = function(s, hostname) {
this.s = s;
var wcOffset = s.indexOf('*');
this.lSegment = s.slice(0, wcOffset);
this.rSegment = s.slice(wcOffset + 1);
@ -448,6 +527,10 @@ FilterSingleWildcardRightAnchoredHostname.prototype.match = function(url) {
url.lastIndexOf(this.lSegment, url.length - this.rSegment.length - this.lSegment.length) >= 0;
};
FilterSingleWildcardRightAnchoredHostname.prototype.toString = function() {
return this.lSegment + '*' + this.rSegment + '|$domain=' + this.hostname;
};
/******************************************************************************/
// With many wildcards, a regex is best.
@ -467,6 +550,12 @@ FilterManyWildcards.prototype.match = function(url, tokenBeg) {
return this.re.test(url.slice(tokenBeg - this.tokenBeg));
};
FilterManyWildcards.prototype.toString = function() {
return this.s;
};
/******************************************************************************/
var FilterManyWildcardsHostname = function(s, tokenBeg, hostname) {
this.s = s;
this.tokenBeg = tokenBeg;
@ -480,6 +569,10 @@ FilterManyWildcardsHostname.prototype.match = function(url, tokenBeg) {
this.re.test(url.slice(tokenBeg - this.tokenBeg));
};
FilterManyWildcardsHostname.prototype.toString = function() {
return this.s + '$domain=' + this.hostname;
};
/******************************************************************************/
var makeFilter = function(details, tokenBeg) {
@ -613,20 +706,10 @@ var trimChar = function(s, c) {
/******************************************************************************/
var FilterParser = function() {
this.action = BlockAction;
this.anchor = 0;
this.domains = [];
this.elemHiding = false;
this.f = '';
this.firstParty = false;
this.fopts = '';
this.hostname = false;
this.hostnames = [];
this.notDomains = [];
this.notHostnames = [];
this.thirdParty = false;
this.types = [];
this.unsupported = false;
this.reset();
};
/******************************************************************************/
@ -648,17 +731,16 @@ FilterParser.prototype.toNormalizedType = {
FilterParser.prototype.reset = function() {
this.action = BlockAction;
this.anchor = 0;
this.domains = [];
this.domains.length = 0;
this.elemHiding = false;
this.f = '';
this.firstParty = false;
this.fopts = '';
this.hostname = false;
this.hostnames = [];
this.notDomains = [];
this.notHostnames = [];
this.hostnames.length = 0;
this.notHostname = false;
this.thirdParty = false;
this.types = [];
this.types.length = 0;
this.unsupported = false;
return this;
};
@ -710,13 +792,17 @@ FilterParser.prototype.parseOptHostnames = function(raw) {
if ( domain === '' ) {
domain = noDomainName;
}
if ( not ) {
this.notHostnames.push(hostname);
this.notDomains.push(domain);
} else {
this.hostnames.push(hostname);
this.domains.push(domain);
// https://github.com/gorhill/uBlock/issues/191
// Well it doesn't seem to make a whole lot of sense to have both
// non-negated hostnames mixed with negated hostnames.
if ( this.hostnames.length !== 0 && not !== this.notHostname ) {
console.error('FilterContainer.parseOptHostnames(): ambiguous filter syntax: "%s"', this.f);
this.unsupported = true;
return;
}
this.notHostname = not;
this.hostnames.push(hostname);
this.domains.push(domain);
}
};
@ -811,29 +897,32 @@ FilterParser.prototype.parse = function(s) {
var FilterBucket = function(a, b) {
this.filters = [a, b];
this.s = '';
this.f = null;
};
/******************************************************************************/
FilterBucket.prototype.add = function(a) {
this.filters.push(a);
};
/******************************************************************************/
FilterBucket.prototype.match = function(url, tokenBeg) {
var filters = this.filters;
var i = filters.length;
while ( i-- ) {
if ( filters[i].match(url, tokenBeg) !== false ) {
this.s = filters[i].s;
this.f = filters[i];
return true;
}
}
return false;
};
FilterBucket.prototype.toString = function() {
if ( this.f !== null ) {
return this.f.toString();
}
return '';
};
/******************************************************************************/
/******************************************************************************/
@ -996,19 +1085,12 @@ FilterContainer.prototype.addFilter = function(parsed) {
}
var tokenBeg = matches.index;
var tokenEnd = parsed.hostname ? reHostnameToken.lastIndex : reGoodToken.lastIndex;
var i, n, filter;
var filter;
// https://github.com/gorhill/uBlock/issues/191
// Well it doesn't seem to make a whole lot of sense to have both
// non-negated hostnames mixed with negated hostnames.
if ( parsed.hostnames.length && parsed.notHostnames.length ) {
console.error('FilterContainer.addFilter(): ambiguous filter syntax', parsed.f);
return false;
}
var i = parsed.hostnames.length;
if ( parsed.hostnames.length ) {
n = parsed.hostnames.length;
for ( i = 0; i < n; i++ ) {
if ( i !== 0 && !parsed.notHostname ) {
while ( i-- ) {
filter = makeHostnameFilter(parsed, tokenBeg, parsed.hostnames[i]);
if ( !filter ) {
return false;
@ -1026,24 +1108,29 @@ FilterContainer.prototype.addFilter = function(parsed) {
// https://github.com/gorhill/uBlock/issues/191
// Invert the purpose of the filter for negated hostnames
if ( parsed.notHostnames.length ) {
if ( i !== 0 && parsed.notHostname ) {
filter = makeFilter(parsed, tokenBeg);
if ( !filter ) {
return false;
}
this.addFilterEntry(filter, parsed, AnyParty, tokenBeg, tokenEnd);
// Reverse purpose of filter
parsed.action ^= (BlockAction ^ AllowAction);
n = parsed.notHostnames.length;
for ( i = 0; i < n; i++ ) {
filter = makeHostnameFilter(parsed, tokenBeg, parsed.notHostnames[i]);
parsed.action ^= ToggleAction;
while ( i-- ) {
filter = makeHostnameFilter(parsed, tokenBeg, parsed.hostnames[i]);
if ( !filter ) {
return false;
}
// https://github.com/gorhill/uBlock/issues/191#issuecomment-53654024
// If it is a block filter, we need to reverse the order of
// evaluation.
if ( parsed.action === BlockAction ) {
filter.important = true;
}
this.addFilterEntry(
filter,
parsed,
SpecificParty | this.toDomainBits(parsed.notDomains[i]),
SpecificParty | this.toDomainBits(parsed.domains[i]),
tokenBeg,
tokenEnd
);
@ -1123,49 +1210,49 @@ FilterContainer.prototype.matchTokens = function(url) {
if ( bucket0 !== undefined ) {
f = bucket0[token];
if ( f !== undefined && f.match(url, beg) !== false ) {
return f.s;
return f;
}
}
if ( bucket1 !== undefined ) {
f = bucket1[token];
if ( f !== undefined && f.match(url, beg) !== false ) {
return f.s;
return f;
}
}
if ( bucket2 !== undefined ) {
f = bucket2[token];
if ( f !== undefined && f.match(url, beg) !== false ) {
return f.s;
return f;
}
}
if ( bucket3 !== undefined ) {
f = bucket3[token];
if ( f !== undefined && f.match(url, beg) !== false ) {
return f.s;
return f;
}
}
if ( bucket4 !== undefined ) {
f = bucket4[token];
if ( f !== undefined && f.match(url, beg) !== false ) {
return f.s;
return f;
}
}
if ( bucket5 !== undefined ) {
f = bucket5[token];
if ( f !== undefined && f.match(url, beg) !== false ) {
return f.s;
return f;
}
}
if ( bucket6 !== undefined ) {
f = bucket6[token];
if ( f !== undefined && f.match(url, beg) !== false ) {
return f.s;
return f;
}
}
if ( bucket7 !== undefined ) {
f = bucket7[token];
if ( f !== undefined && f.match(url, beg) !== false ) {
return f.s;
return f;
}
}
}
@ -1251,24 +1338,31 @@ FilterContainer.prototype.matchStringExactType = function(pageDetails, requestUR
buckets[4] = categories[this.makeCategoryKey(BlockAction | type | party)];
buckets[5] = categories[this.makeCategoryKey(BlockOneParty | type | domainParty)];
buckets[7] = categories[this.makeCategoryKey(BlockOneParty | type | this.noDomainBits)];
var br = this.matchTokens(url);
var bf = this.matchTokens(url);
// If there is no block filter, no need to test against allow filters
if ( br === false ) {
if ( bf === false ) {
return false;
}
// The purpose of the `important` property is to reverse the order of
// evaluation. Normally, it is "evaluate block then evaluate allow", with
// the `important` property it is "evaluate allow then evaluate block".
if ( bf.important === true ) {
return bf.toString();
}
// Test against allow filters
buckets[3] = categories[this.makeCategoryKey(AllowAnyParty | type)];
buckets[4] = categories[this.makeCategoryKey(AllowAction | type | party)];
buckets[5] = categories[this.makeCategoryKey(AllowOneParty | type | domainParty)];
buckets[7] = categories[this.makeCategoryKey(AllowOneParty | type | this.noDomainBits)];
var ar = this.matchTokens(url);
if ( ar !== false ) {
return '@@' + ar;
var af = this.matchTokens(url);
if ( af !== false ) {
return '@@' + af.toString();
}
return br;
return bf.toString();
};
/******************************************************************************/
@ -1309,9 +1403,9 @@ FilterContainer.prototype.matchString = function(pageDetails, requestURL, reques
ThirdParty;
// Test hostname-based block filters
var br = this.matchAnyPartyHostname(requestHostname);
if ( br === false && party === ThirdParty ) {
br = this.match3rdPartyHostname(requestHostname);
var bf = this.matchAnyPartyHostname(requestHostname);
if ( bf === false && party === ThirdParty ) {
bf = this.match3rdPartyHostname(requestHostname);
}
// This will be used by hostname-based filters
@ -1323,7 +1417,7 @@ FilterContainer.prototype.matchString = function(pageDetails, requestURL, reques
var buckets = this.buckets;
// Test against block filters
if ( br === false ) {
if ( bf === false ) {
buckets[0] = categories[this.makeCategoryKey(BlockAnyTypeAnyParty)];
buckets[1] = categories[this.makeCategoryKey(BlockAnyType | party)];
buckets[2] = categories[this.makeCategoryKey(BlockAnyTypeOneParty | domainParty)];
@ -1334,14 +1428,21 @@ FilterContainer.prototype.matchString = function(pageDetails, requestURL, reques
// Test for synthetic domain as well
buckets[6] = categories[this.makeCategoryKey(BlockAnyTypeOneParty | this.noDomainBits)];
buckets[7] = categories[this.makeCategoryKey(BlockOneParty | type | this.noDomainBits)];
br = this.matchTokens(url);
bf = this.matchTokens(url);
}
// If there is no block filter, no need to test against allow filters
if ( br === false ) {
if ( bf === false ) {
return false;
}
// The purpose of the `important` property is to reverse the order of
// evaluation. Normally, it is "evaluate block then evaluate allow", with
// the `important` property it is "evaluate allow then evaluate block".
if ( bf.important === true ) {
return bf.toString();
}
// Test against allow filters
buckets[0] = categories[this.makeCategoryKey(AllowAnyTypeAnyParty)];
buckets[1] = categories[this.makeCategoryKey(AllowAnyType | party)];
@ -1353,12 +1454,12 @@ FilterContainer.prototype.matchString = function(pageDetails, requestURL, reques
// Test for synthetic domain as well
buckets[6] = categories[this.makeCategoryKey(AllowAnyTypeOneParty | this.noDomainBits)];
buckets[7] = categories[this.makeCategoryKey(AllowOneParty | type | this.noDomainBits)];
var ar = this.matchTokens(url);
if ( ar !== false ) {
return '@@' + ar;
var af = this.matchTokens(url);
if ( af !== false ) {
return '@@' + af.toString();
}
return br;
return bf.toString();
};
/******************************************************************************/