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

this addresses #184

This commit is contained in:
gorhill 2014-09-08 17:46:58 -04:00
parent 70533b93fe
commit 65775a5e27
13 changed files with 1008 additions and 244 deletions

View File

@ -380,7 +380,7 @@ var reloadAll = function(update) {
/******************************************************************************/ /******************************************************************************/
var buttonApplyHandler = function() { var buttonApplyHandler = function() {
reloadAll(); reloadAll(false);
uDom('#buttonApply').toggleClass('enabled', false); uDom('#buttonApply').toggleClass('enabled', false);
}; };

View File

@ -24,7 +24,7 @@
/******************************************************************************/ /******************************************************************************/
µBlock.abpFilters = (function(){ µBlock.netFilteringEngine = (function(){
/******************************************************************************/ /******************************************************************************/
@ -137,6 +137,19 @@ var histogram = function(label, categories) {
console.log('\tTotal buckets count: %d', total); console.log('\tTotal buckets count: %d', total);
}; };
*/ */
/******************************************************************************/
// Could be replaced with encodeURIComponent/decodeURIComponent,
// which seems faster on Firefox.
var encode = JSON.stringify;
var decode = JSON.parse;
var cachedParseInt = parseInt;
var atoi = function(s) {
return cachedParseInt(s, 10);
};
/******************************************************************************* /*******************************************************************************
Filters family tree: Filters family tree:
@ -187,10 +200,22 @@ FilterPlain.prototype.match = function(url, tokenBeg) {
return url.substr(tokenBeg - this.tokenBeg, this.s.length) === this.s; return url.substr(tokenBeg - this.tokenBeg, this.s.length) === this.s;
}; };
FilterPlain.prototype.fid = 'a';
FilterPlain.prototype.toString = function() { FilterPlain.prototype.toString = function() {
return this.s; return this.s;
}; };
FilterPlain.prototype.toSelfie = function() {
return this.s + '\t' +
this.tokenBeg;
};
FilterPlain.fromSelfie = function(s) {
var pos = s.indexOf('\t');
return new FilterPlain(s.slice(0, pos), atoi(s.slice(pos + 1)));
};
/******************************************************************************/ /******************************************************************************/
var FilterPlainHostname = function(s, tokenBeg, hostname) { var FilterPlainHostname = function(s, tokenBeg, hostname) {
@ -204,10 +229,23 @@ FilterPlainHostname.prototype.match = function(url, tokenBeg) {
url.substr(tokenBeg - this.tokenBeg, this.s.length) === this.s; url.substr(tokenBeg - this.tokenBeg, this.s.length) === this.s;
}; };
FilterPlainHostname.prototype.fid = 'ah';
FilterPlainHostname.prototype.toString = function() { FilterPlainHostname.prototype.toString = function() {
return this.s + '$domain=' + this.hostname; return this.s + '$domain=' + this.hostname;
}; };
FilterPlainHostname.prototype.toSelfie = function() {
return this.s + '\t' +
this.tokenBeg + '\t' +
this.hostname;
};
FilterPlainHostname.fromSelfie = function(s) {
var args = s.split('\t');
return new FilterPlainHostname(args[0], atoi(args[1]), args[2]);
};
/******************************************************************************/ /******************************************************************************/
var FilterPlainPrefix0 = function(s) { var FilterPlainPrefix0 = function(s) {
@ -218,10 +256,20 @@ FilterPlainPrefix0.prototype.match = function(url, tokenBeg) {
return url.substr(tokenBeg, this.s.length) === this.s; return url.substr(tokenBeg, this.s.length) === this.s;
}; };
FilterPlainPrefix0.prototype.fid = '0a';
FilterPlainPrefix0.prototype.toString = function() { FilterPlainPrefix0.prototype.toString = function() {
return this.s; return this.s;
}; };
FilterPlainPrefix0.prototype.toSelfie = function() {
return this.s;
};
FilterPlainPrefix0.fromSelfie = function(s) {
return new FilterPlainPrefix0(s);
};
/******************************************************************************/ /******************************************************************************/
var FilterPlainPrefix0Hostname = function(s, hostname) { var FilterPlainPrefix0Hostname = function(s, hostname) {
@ -234,10 +282,22 @@ FilterPlainPrefix0Hostname.prototype.match = function(url, tokenBeg) {
url.substr(tokenBeg, this.s.length) === this.s; url.substr(tokenBeg, this.s.length) === this.s;
}; };
FilterPlainPrefix0Hostname.prototype.fid = '0ah';
FilterPlainPrefix0Hostname.prototype.toString = function() { FilterPlainPrefix0Hostname.prototype.toString = function() {
return this.s + '$domain=' + this.hostname; return this.s + '$domain=' + this.hostname;
}; };
FilterPlainPrefix0Hostname.prototype.toSelfie = function() {
return this.s + '\t' +
this.hostname;
};
FilterPlainPrefix0Hostname.fromSelfie = function(s) {
var pos = s.indexOf('\t');
return new FilterPlainPrefix0Hostname(s.slice(0, pos), s.slice(pos + 1));
};
/******************************************************************************/ /******************************************************************************/
var FilterPlainPrefix1 = function(s) { var FilterPlainPrefix1 = function(s) {
@ -248,10 +308,20 @@ FilterPlainPrefix1.prototype.match = function(url, tokenBeg) {
return url.substr(tokenBeg - 1, this.s.length) === this.s; return url.substr(tokenBeg - 1, this.s.length) === this.s;
}; };
FilterPlainPrefix1.prototype.fid = '1a';
FilterPlainPrefix1.prototype.toString = function() { FilterPlainPrefix1.prototype.toString = function() {
return this.s; return this.s;
}; };
FilterPlainPrefix1.prototype.toSelfie = function() {
return this.s;
};
FilterPlainPrefix1.fromSelfie = function(s) {
return new FilterPlainPrefix1(s);
};
/******************************************************************************/ /******************************************************************************/
var FilterPlainPrefix1Hostname = function(s, hostname) { var FilterPlainPrefix1Hostname = function(s, hostname) {
@ -264,10 +334,22 @@ FilterPlainPrefix1Hostname.prototype.match = function(url, tokenBeg) {
url.substr(tokenBeg - 1, this.s.length) === this.s; url.substr(tokenBeg - 1, this.s.length) === this.s;
}; };
FilterPlainPrefix1Hostname.prototype.fid = '1ah';
FilterPlainPrefix1Hostname.prototype.toString = function() { FilterPlainPrefix1Hostname.prototype.toString = function() {
return this.s + '$domain=' + this.hostname; return this.s + '$domain=' + this.hostname;
}; };
FilterPlainPrefix1Hostname.prototype.toSelfie = function() {
return this.s + '\t' +
this.hostname;
};
FilterPlainPrefix1Hostname.fromSelfie = function(s) {
var pos = s.indexOf('\t');
return new FilterPlainPrefix1Hostname(s.slice(0, pos), s.slice(pos + 1));
};
/******************************************************************************/ /******************************************************************************/
var FilterPlainLeftAnchored = function(s) { var FilterPlainLeftAnchored = function(s) {
@ -278,10 +360,20 @@ FilterPlainLeftAnchored.prototype.match = function(url) {
return url.slice(0, this.s.length) === this.s; return url.slice(0, this.s.length) === this.s;
}; };
FilterPlainLeftAnchored.prototype.fid = '|a';
FilterPlainLeftAnchored.prototype.toString = function() { FilterPlainLeftAnchored.prototype.toString = function() {
return '|' + this.s; return '|' + this.s;
}; };
FilterPlainLeftAnchored.prototype.toSelfie = function() {
return this.s;
};
FilterPlainLeftAnchored.fromSelfie = function(s) {
return new FilterPlainLeftAnchored(s);
};
/******************************************************************************/ /******************************************************************************/
var FilterPlainLeftAnchoredHostname = function(s, hostname) { var FilterPlainLeftAnchoredHostname = function(s, hostname) {
@ -294,10 +386,22 @@ FilterPlainLeftAnchoredHostname.prototype.match = function(url) {
url.slice(0, this.s.length) === this.s; url.slice(0, this.s.length) === this.s;
}; };
FilterPlainLeftAnchoredHostname.prototype.fid = '|ah';
FilterPlainLeftAnchoredHostname.prototype.toString = function() { FilterPlainLeftAnchoredHostname.prototype.toString = function() {
return '|' + this.s + '$domain=' + this.hostname; return '|' + this.s + '$domain=' + this.hostname;
}; };
FilterPlainLeftAnchoredHostname.prototype.toSelfie = function() {
return this.s + '\t' +
this.hostname;
};
FilterPlainLeftAnchoredHostname.fromSelfie = function(s) {
var pos = s.indexOf('\t');
return new FilterPlainLeftAnchoredHostname(s.slice(0, pos), s.slice(pos + 1));
};
/******************************************************************************/ /******************************************************************************/
var FilterPlainRightAnchored = function(s) { var FilterPlainRightAnchored = function(s) {
@ -308,10 +412,20 @@ FilterPlainRightAnchored.prototype.match = function(url) {
return url.slice(-this.s.length) === this.s; return url.slice(-this.s.length) === this.s;
}; };
FilterPlainRightAnchored.prototype.fid = 'a|';
FilterPlainRightAnchored.prototype.toString = function() { FilterPlainRightAnchored.prototype.toString = function() {
return this.s + '|'; return this.s + '|';
}; };
FilterPlainRightAnchored.prototype.toSelfie = function() {
return this.s;
};
FilterPlainRightAnchored.fromSelfie = function(s) {
return new FilterPlainRightAnchored(s);
};
/******************************************************************************/ /******************************************************************************/
var FilterPlainRightAnchoredHostname = function(s, hostname) { var FilterPlainRightAnchoredHostname = function(s, hostname) {
@ -324,10 +438,22 @@ FilterPlainRightAnchoredHostname.prototype.match = function(url) {
url.slice(-this.s.length) === this.s; url.slice(-this.s.length) === this.s;
}; };
FilterPlainRightAnchoredHostname.prototype.fid = 'a|h';
FilterPlainRightAnchoredHostname.prototype.toString = function() { FilterPlainRightAnchoredHostname.prototype.toString = function() {
return this.s + '|$domain=' + this.hostname; return this.s + '|$domain=' + this.hostname;
}; };
FilterPlainRightAnchoredHostname.prototype.toSelfie = function() {
return this.s + '\t' +
this.hostname;
};
FilterPlainRightAnchoredHostname.fromSelfie = function(s) {
var pos = s.indexOf('\t');
return new FilterPlainRightAnchoredHostname(s.slice(0, pos), s.slice(pos + 1));
};
/******************************************************************************/ /******************************************************************************/
// With a single wildcard, regex is not optimal. // With a single wildcard, regex is not optimal.
@ -335,11 +461,10 @@ FilterPlainRightAnchoredHostname.prototype.toString = function() {
// http://jsperf.com/regexp-vs-indexof-abp-miss/3 // http://jsperf.com/regexp-vs-indexof-abp-miss/3
// http://jsperf.com/regexp-vs-indexof-abp-hit/3 // http://jsperf.com/regexp-vs-indexof-abp-hit/3
var FilterSingleWildcard = function(s, tokenBeg) { var FilterSingleWildcard = function(lSegment, rSegment, tokenBeg) {
this.tokenBeg = tokenBeg; this.tokenBeg = tokenBeg;
var wcOffset = s.indexOf('*'); this.lSegment = lSegment;
this.lSegment = s.slice(0, wcOffset); this.rSegment = rSegment;
this.rSegment = s.slice(wcOffset + 1);
}; };
FilterSingleWildcard.prototype.match = function(url, tokenBeg) { FilterSingleWildcard.prototype.match = function(url, tokenBeg) {
@ -348,17 +473,29 @@ FilterSingleWildcard.prototype.match = function(url, tokenBeg) {
url.indexOf(this.rSegment, tokenBeg + this.lSegment.length) > 0; url.indexOf(this.rSegment, tokenBeg + this.lSegment.length) > 0;
}; };
FilterSingleWildcard.prototype.fid = '*';
FilterSingleWildcard.prototype.toString = function() { FilterSingleWildcard.prototype.toString = function() {
return this.lSegment + '*' + this.rSegment; return this.lSegment + '*' + this.rSegment;
}; };
FilterSingleWildcard.prototype.toSelfie = function() {
return this.lSegment + '\t' +
this.rSegment + '\t' +
this.tokenBeg;
};
FilterSingleWildcard.fromSelfie = function(s) {
var args = s.split('\t');
return new FilterSingleWildcard(args[0], args[1], atoi(args[2]));
};
/******************************************************************************/ /******************************************************************************/
var FilterSingleWildcardHostname = function(s, tokenBeg, hostname) { var FilterSingleWildcardHostname = function(lSegment, rSegment, tokenBeg, hostname) {
this.tokenBeg = tokenBeg; this.tokenBeg = tokenBeg;
var wcOffset = s.indexOf('*'); this.lSegment = lSegment;
this.lSegment = s.slice(0, wcOffset); this.rSegment = rSegment;
this.rSegment = s.slice(wcOffset + 1);
this.hostname = hostname; this.hostname = hostname;
}; };
@ -369,16 +506,29 @@ FilterSingleWildcardHostname.prototype.match = function(url, tokenBeg) {
url.indexOf(this.rSegment, tokenBeg + this.lSegment.length) > 0; url.indexOf(this.rSegment, tokenBeg + this.lSegment.length) > 0;
}; };
FilterSingleWildcardHostname.prototype.fid = '*h';
FilterSingleWildcardHostname.prototype.toString = function() { FilterSingleWildcardHostname.prototype.toString = function() {
return this.lSegment + '*' + this.rSegment + '$domain=' + this.hostname; return this.lSegment + '*' + this.rSegment + '$domain=' + this.hostname;
}; };
FilterSingleWildcardHostname.prototype.toSelfie = function() {
return this.lSegment + '\t' +
this.rSegment + '\t' +
this.tokenBeg + '\t' +
this.hostname;
};
FilterSingleWildcardHostname.fromSelfie = function(s) {
var args = s.split('\t');
return new FilterSingleWildcardHostname(args[0], args[1], atoi(args[2]), args[3]);
};
/******************************************************************************/ /******************************************************************************/
var FilterSingleWildcardPrefix0 = function(s) { var FilterSingleWildcardPrefix0 = function(lSegment, rSegment) {
var wcOffset = s.indexOf('*'); this.lSegment = lSegment;
this.lSegment = s.slice(0, wcOffset); this.rSegment = rSegment;
this.rSegment = s.slice(wcOffset + 1);
}; };
FilterSingleWildcardPrefix0.prototype.match = function(url, tokenBeg) { FilterSingleWildcardPrefix0.prototype.match = function(url, tokenBeg) {
@ -386,16 +536,27 @@ FilterSingleWildcardPrefix0.prototype.match = function(url, tokenBeg) {
url.indexOf(this.rSegment, tokenBeg + this.lSegment.length) > 0; url.indexOf(this.rSegment, tokenBeg + this.lSegment.length) > 0;
}; };
FilterSingleWildcardPrefix0.prototype.fid = '0*';
FilterSingleWildcardPrefix0.prototype.toString = function() { FilterSingleWildcardPrefix0.prototype.toString = function() {
return this.lSegment + '*' + this.rSegment; return this.lSegment + '*' + this.rSegment;
}; };
FilterSingleWildcardPrefix0.prototype.toSelfie = function() {
return this.lSegment + '\t' +
this.rSegment;
};
FilterSingleWildcardPrefix0.fromSelfie = function(s) {
var pos = s.indexOf('\t');
return new FilterSingleWildcardPrefix0(s.slice(0, pos), s.slice(pos + 1));
};
/******************************************************************************/ /******************************************************************************/
var FilterSingleWildcardPrefix0Hostname = function(s, hostname) { var FilterSingleWildcardPrefix0Hostname = function(lSegment, rSegment, hostname) {
var wcOffset = s.indexOf('*'); this.lSegment = lSegment;
this.lSegment = s.slice(0, wcOffset); this.rSegment = rSegment;
this.rSegment = s.slice(wcOffset + 1);
this.hostname = hostname; this.hostname = hostname;
}; };
@ -405,21 +566,28 @@ FilterSingleWildcardPrefix0Hostname.prototype.match = function(url, tokenBeg) {
url.indexOf(this.rSegment, tokenBeg + this.lSegment.length) > 0; url.indexOf(this.rSegment, tokenBeg + this.lSegment.length) > 0;
}; };
FilterSingleWildcardPrefix0Hostname.prototype.fid = '0*h';
FilterSingleWildcardPrefix0Hostname.prototype.toString = function() { FilterSingleWildcardPrefix0Hostname.prototype.toString = function() {
return this.lSegment + '*' + this.rSegment + '$domain=' + this.hostname; return this.lSegment + '*' + this.rSegment + '$domain=' + this.hostname;
}; };
FilterSingleWildcardPrefix0Hostname.prototype.toSelfie = function() {
return this.lSegment + '\t' +
this.rSegment + '\t' +
this.hostname;
};
FilterSingleWildcardPrefix0Hostname.fromSelfie = function(s) {
var args = s.split('\t');
return new FilterSingleWildcardPrefix0Hostname(args[0], args[1], args[2]);
};
/******************************************************************************/ /******************************************************************************/
// With a single wildcard, regex is not optimal. var FilterSingleWildcardLeftAnchored = function(lSegment, rSegment) {
// See: this.lSegment = lSegment;
// http://jsperf.com/regexp-vs-indexof-abp-miss/3 this.rSegment = rSegment;
// http://jsperf.com/regexp-vs-indexof-abp-hit/3
var FilterSingleWildcardLeftAnchored = function(s) {
var wcOffset = s.indexOf('*');
this.lSegment = s.slice(0, wcOffset);
this.rSegment = s.slice(wcOffset + 1);
}; };
FilterSingleWildcardLeftAnchored.prototype.match = function(url) { FilterSingleWildcardLeftAnchored.prototype.match = function(url) {
@ -427,16 +595,27 @@ FilterSingleWildcardLeftAnchored.prototype.match = function(url) {
url.indexOf(this.rSegment, this.lSegment.length) > 0; url.indexOf(this.rSegment, this.lSegment.length) > 0;
}; };
FilterSingleWildcardLeftAnchored.prototype.fid = '|*';
FilterSingleWildcardLeftAnchored.prototype.toString = function() { FilterSingleWildcardLeftAnchored.prototype.toString = function() {
return '|' + this.lSegment + '*' + this.rSegment; return '|' + this.lSegment + '*' + this.rSegment;
}; };
FilterSingleWildcardLeftAnchored.prototype.toSelfie = function() {
return this.lSegment + '\t' +
this.rSegment;
};
FilterSingleWildcardLeftAnchored.fromSelfie = function(s) {
var pos = s.indexOf('\t');
return new FilterSingleWildcardLeftAnchored(s.slice(0, pos), s.slice(pos + 1));
};
/******************************************************************************/ /******************************************************************************/
var FilterSingleWildcardLeftAnchoredHostname = function(s, hostname) { var FilterSingleWildcardLeftAnchoredHostname = function(lSegment, rSegment, hostname) {
var wcOffset = s.indexOf('*'); this.lSegment = lSegment;
this.lSegment = s.slice(0, wcOffset); this.rSegment = rSegment;
this.rSegment = s.slice(wcOffset + 1);
this.hostname = hostname; this.hostname = hostname;
}; };
@ -446,21 +625,28 @@ FilterSingleWildcardLeftAnchoredHostname.prototype.match = function(url) {
url.indexOf(this.rSegment, this.lSegment.length) > 0; url.indexOf(this.rSegment, this.lSegment.length) > 0;
}; };
FilterSingleWildcardLeftAnchoredHostname.prototype.fid = '|*h';
FilterSingleWildcardLeftAnchoredHostname.prototype.toString = function() { FilterSingleWildcardLeftAnchoredHostname.prototype.toString = function() {
return '|' + this.lSegment + '*' + this.rSegment + '$domain=' + this.hostname; return '|' + this.lSegment + '*' + this.rSegment + '$domain=' + this.hostname;
}; };
FilterSingleWildcardLeftAnchoredHostname.prototype.toSelfie = function() {
return this.lSegment + '\t' +
this.rSegment + '\t' +
this.hostname;
};
FilterSingleWildcardLeftAnchoredHostname.fromSelfie = function(s) {
var args = s.split('\t');
return new FilterSingleWildcardLeftAnchoredHostname(args[0], args[1], args[2]);
};
/******************************************************************************/ /******************************************************************************/
// With a single wildcard, regex is not optimal. var FilterSingleWildcardRightAnchored = function(lSegment, rSegment) {
// See: this.lSegment = lSegment;
// http://jsperf.com/regexp-vs-indexof-abp-miss/3 this.rSegment = rSegment;
// http://jsperf.com/regexp-vs-indexof-abp-hit/3
var FilterSingleWildcardRightAnchored = function(s) {
var wcOffset = s.indexOf('*');
this.lSegment = s.slice(0, wcOffset);
this.rSegment = s.slice(wcOffset + 1);
}; };
FilterSingleWildcardRightAnchored.prototype.match = function(url) { FilterSingleWildcardRightAnchored.prototype.match = function(url) {
@ -468,16 +654,27 @@ FilterSingleWildcardRightAnchored.prototype.match = function(url) {
url.lastIndexOf(this.lSegment, url.length - this.rSegment.length - this.lSegment.length) >= 0; url.lastIndexOf(this.lSegment, url.length - this.rSegment.length - this.lSegment.length) >= 0;
}; };
FilterSingleWildcardRightAnchored.prototype.fid = '*|';
FilterSingleWildcardRightAnchored.prototype.toString = function() { FilterSingleWildcardRightAnchored.prototype.toString = function() {
return this.lSegment + '*' + this.rSegment + '|'; return this.lSegment + '*' + this.rSegment + '|';
}; };
FilterSingleWildcardRightAnchored.prototype.toSelfie = function() {
return this.lSegment + '\t' +
this.rSegment;
};
FilterSingleWildcardRightAnchored.fromSelfie = function(s) {
var pos = s.indexOf('\t');
return new FilterSingleWildcardRightAnchored(s.slice(0, pos), s.slice(pos + 1));
};
/******************************************************************************/ /******************************************************************************/
var FilterSingleWildcardRightAnchoredHostname = function(s, hostname) { var FilterSingleWildcardRightAnchoredHostname = function(lSegment, rSegment, hostname) {
var wcOffset = s.indexOf('*'); this.lSegment = lSegment;
this.lSegment = s.slice(0, wcOffset); this.rSegment = rSegment;
this.rSegment = s.slice(wcOffset + 1);
this.hostname = hostname; this.hostname = hostname;
}; };
@ -487,10 +684,23 @@ FilterSingleWildcardRightAnchoredHostname.prototype.match = function(url) {
url.lastIndexOf(this.lSegment, url.length - this.rSegment.length - this.lSegment.length) >= 0; url.lastIndexOf(this.lSegment, url.length - this.rSegment.length - this.lSegment.length) >= 0;
}; };
FilterSingleWildcardRightAnchoredHostname.prototype.fid = '*|h';
FilterSingleWildcardRightAnchoredHostname.prototype.toString = function() { FilterSingleWildcardRightAnchoredHostname.prototype.toString = function() {
return this.lSegment + '*' + this.rSegment + '|$domain=' + this.hostname; return this.lSegment + '*' + this.rSegment + '|$domain=' + this.hostname;
}; };
FilterSingleWildcardRightAnchoredHostname.prototype.toSelfie = function() {
return this.lSegment + '\t' +
this.rSegment + '\t' +
this.hostname;
};
FilterSingleWildcardRightAnchoredHostname.fromSelfie = function(s) {
var args = s.split('\t');
return new FilterSingleWildcardRightAnchoredHostname(args[0], args[1], args[2]);
};
/******************************************************************************/ /******************************************************************************/
// With many wildcards, a regex is best. // With many wildcards, a regex is best.
@ -509,10 +719,22 @@ FilterManyWildcards.prototype.match = function(url, tokenBeg) {
return this.re.test(url.slice(tokenBeg - this.tokenBeg)); return this.re.test(url.slice(tokenBeg - this.tokenBeg));
}; };
FilterManyWildcards.prototype.fid = '*+';
FilterManyWildcards.prototype.toString = function() { FilterManyWildcards.prototype.toString = function() {
return this.s; return this.s;
}; };
FilterManyWildcards.prototype.toSelfie = function() {
return this.s + '\t' +
this.tokenBeg;
};
FilterManyWildcards.fromSelfie = function(s) {
var pos = s.indexOf('\t');
return new FilterManyWildcards(s.slice(0, pos), atoi(s.slice(pos + 1)));
};
/******************************************************************************/ /******************************************************************************/
var FilterManyWildcardsHostname = function(s, tokenBeg, hostname) { var FilterManyWildcardsHostname = function(s, tokenBeg, hostname) {
@ -527,29 +749,90 @@ FilterManyWildcardsHostname.prototype.match = function(url, tokenBeg) {
this.re.test(url.slice(tokenBeg - this.tokenBeg)); this.re.test(url.slice(tokenBeg - this.tokenBeg));
}; };
FilterManyWildcardsHostname.prototype.fid = '*+h';
FilterManyWildcardsHostname.prototype.toString = function() { FilterManyWildcardsHostname.prototype.toString = function() {
return this.s + '$domain=' + this.hostname; return this.s + '$domain=' + this.hostname;
}; };
FilterManyWildcardsHostname.prototype.toSelfie = function() {
return this.s + '\t' +
this.tokenBeg + '\t' +
this.hostname;
};
FilterManyWildcardsHostname.fromSelfie = function(s) {
var args = s.split('\t');
return new FilterManyWildcardsHostname(args[0], atoi(args[1]), args[2]);
};
/******************************************************************************/
var FilterBucket = function(a, b) {
this.f = null;
this.filters = [];
if ( a !== undefined ) {
this.filters[0] = a;
if ( b !== undefined ) {
this.filters[1] = b;
}
}
};
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.f = filters[i];
return true;
}
}
return false;
};
FilterBucket.prototype.fid = '[]';
FilterBucket.prototype.toString = function() {
if ( this.f !== null ) {
return this.f.toString();
}
return '';
};
FilterBucket.prototype.toSelfie = function() {
return this.filters.length.toString();
};
FilterBucket.fromSelfie = function() {
return new FilterBucket();
};
/******************************************************************************/ /******************************************************************************/
var makeFilter = function(details, tokenBeg) { var makeFilter = function(details, tokenBeg) {
var s = details.f; var s = details.f;
var wcOffset = s.indexOf('*'); var wcOffset = s.indexOf('*');
if ( wcOffset > 0 ) { if ( wcOffset !== -1 ) {
if ( (/\*[^*]\*/).test(s) ) { if ( s.indexOf('*', wcOffset + 1) !== -1 ) {
return details.anchor === 0 ? new FilterManyWildcards(s, tokenBeg) : null; return details.anchor === 0 ? new FilterManyWildcards(s, tokenBeg) : null;
} }
var lSegment = s.slice(0, wcOffset);
var rSegment = s.slice(wcOffset + 1);
if ( details.anchor < 0 ) { if ( details.anchor < 0 ) {
return new FilterSingleWildcardLeftAnchored(s); return new FilterSingleWildcardLeftAnchored(lSegment, rSegment);
} }
if ( details.anchor > 0 ) { if ( details.anchor > 0 ) {
return new FilterSingleWildcardRightAnchored(s); return new FilterSingleWildcardRightAnchored(lSegment, rSegment);
} }
if ( tokenBeg === 0 ) { if ( tokenBeg === 0 ) {
return new FilterSingleWildcardPrefix0(s); return new FilterSingleWildcardPrefix0(lSegment, rSegment);
} }
return new FilterSingleWildcard(s, tokenBeg); return new FilterSingleWildcard(lSegment, rSegment, tokenBeg);
} }
if ( details.anchor < 0 ) { if ( details.anchor < 0 ) {
return new FilterPlainLeftAnchored(s); return new FilterPlainLeftAnchored(s);
@ -571,20 +854,22 @@ var makeFilter = function(details, tokenBeg) {
var makeHostnameFilter = function(details, tokenBeg, hostname) { var makeHostnameFilter = function(details, tokenBeg, hostname) {
var s = details.f; var s = details.f;
var wcOffset = s.indexOf('*'); var wcOffset = s.indexOf('*');
if ( wcOffset > 0 ) { if ( wcOffset !== -1 ) {
if ( (/\*[^*]\*/).test(s) ) { if ( s.indexOf('*', wcOffset + 1) !== -1 ) {
return details.anchor === 0 ? new FilterManyWildcardsHostname(s, tokenBeg, hostname) : null; return details.anchor === 0 ? new FilterManyWildcardsHostname(s, tokenBeg, hostname) : null;
} }
var lSegment = s.slice(0, wcOffset);
var rSegment = s.slice(wcOffset + 1);
if ( details.anchor < 0 ) { if ( details.anchor < 0 ) {
return new FilterSingleWildcardLeftAnchoredHostname(s, hostname); return new FilterSingleWildcardLeftAnchoredHostname(lSegment, rSegment, hostname);
} }
if ( details.anchor > 0 ) { if ( details.anchor > 0 ) {
return new FilterSingleWildcardRightAnchoredHostname(s, hostname); return new FilterSingleWildcardRightAnchoredHostname(lSegment, rSegment, hostname);
} }
if ( tokenBeg === 0 ) { if ( tokenBeg === 0 ) {
return new FilterSingleWildcardPrefix0Hostname(s, hostname); return new FilterSingleWildcardPrefix0Hostname(lSegment, rSegment, hostname);
} }
return new FilterSingleWildcardHostname(s, tokenBeg, hostname); return new FilterSingleWildcardHostname(lSegment, rSegment, tokenBeg, hostname);
} }
if ( details.anchor < 0 ) { if ( details.anchor < 0 ) {
return new FilterPlainLeftAnchoredHostname(s, hostname); return new FilterPlainLeftAnchoredHostname(s, hostname);
@ -613,6 +898,7 @@ var badTokens = {
'com': true, 'com': true,
'http': true, 'http': true,
'https': true, 'https': true,
'icon': true,
'images': true, 'images': true,
'img': true, 'img': true,
'js': true, 'js': true,
@ -661,6 +947,7 @@ var trimChar = function(s, c) {
return s; return s;
}; };
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
var FilterParser = function() { var FilterParser = function() {
@ -783,6 +1070,19 @@ FilterParser.prototype.parse = function(s) {
s = s.slice(2); s = s.slice(2);
} }
// options
var pos = s.indexOf('$');
if ( pos > 0 ) {
this.fopts = s.slice(pos + 1);
s = s.slice(0, pos);
}
// regex? (not supported)
if ( s.charAt(0) === '/' && s.slice(-1) === '/' ) {
this.unsupported = true;
return this;
}
// hostname anchoring // hostname anchoring
if ( s.slice(0, 2) === '||' ) { if ( s.slice(0, 2) === '||' ) {
this.hostname = true; this.hostname = true;
@ -795,13 +1095,6 @@ FilterParser.prototype.parse = function(s) {
s = s.slice(1); s = s.slice(1);
} }
// options
var pos = s.indexOf('$');
if ( pos > 0 ) {
this.fopts = s.slice(pos + 1);
s = s.slice(0, pos);
}
// right-anchored // right-anchored
if ( s.slice(-1) === '|' ) { if ( s.slice(-1) === '|' ) {
this.anchor = 1; this.anchor = 1;
@ -859,37 +1152,6 @@ FilterParser.prototype.parse = function(s) {
/******************************************************************************/ /******************************************************************************/
/******************************************************************************/ /******************************************************************************/
var FilterBucket = function(a, b) {
this.filters = [a, b];
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.f = filters[i];
return true;
}
}
return false;
};
FilterBucket.prototype.toString = function() {
if ( this.f !== null ) {
return this.f.toString();
}
return '';
};
/******************************************************************************/
/******************************************************************************/
var FilterContainer = function() { var FilterContainer = function() {
this.reAnyToken = /[%0-9a-z]+/g; this.reAnyToken = /[%0-9a-z]+/g;
this.buckets = new Array(8); this.buckets = new Array(8);
@ -908,6 +1170,7 @@ FilterContainer.prototype.reset = function() {
this.frozen = false; this.frozen = false;
this.processedFilterCount = 0; this.processedFilterCount = 0;
this.acceptedCount = 0; this.acceptedCount = 0;
this.rejectedCount = 0;
this.allowFilterCount = 0; this.allowFilterCount = 0;
this.blockFilterCount = 0; this.blockFilterCount = 0;
this.duplicateCount = 0; this.duplicateCount = 0;
@ -931,6 +1194,136 @@ FilterContainer.prototype.freeze = function() {
/******************************************************************************/ /******************************************************************************/
FilterContainer.prototype.toSelfie = function() {
var categoryToSelfie = function(dict) {
var selfie = [];
var bucket, ff, n, i, f;
for ( var k in dict ) {
if ( dict.hasOwnProperty(k) === false ) {
continue;
}
// We need to encode the key because there could be a `\n` or '\t'
// character in it, which would trip the code at parse time.
selfie.push('k2\t' + encode(k));
bucket = dict[k];
selfie.push(bucket.fid + '\t' + bucket.toSelfie());
if ( bucket.fid !== '[]' ) {
continue;
}
ff = bucket.filters;
n = ff.length;
for ( i = 0; i < n; i++ ) {
f = ff[i];
selfie.push(f.fid + '\t' + f.toSelfie());
}
}
return selfie.join('\n');
};
var categoriesToSelfie = function(dict) {
var selfie = [];
for ( var k in dict ) {
if ( dict.hasOwnProperty(k) === false ) {
continue;
}
// We need to encode the key because there could be a `\n` or '\t'
// character in it, which would trip the code at parse time.
selfie.push('k1\t' + encode(k));
selfie.push(categoryToSelfie(dict[k]));
}
return selfie.join('\n');
};
return {
processedFilterCount: this.processedFilterCount,
acceptedCount: this.acceptedCount,
rejectedCount: this.rejectedCount,
allowFilterCount: this.allowFilterCount,
blockFilterCount: this.blockFilterCount,
duplicateCount: this.duplicateCount,
categories: categoriesToSelfie(this.categories),
blockedAnyPartyHostnames: this.blockedAnyPartyHostnames.toSelfie(),
blocked3rdPartyHostnames: this.blocked3rdPartyHostnames.toSelfie()
};
};
/******************************************************************************/
FilterContainer.prototype.fromSelfie = function(selfie) {
this.frozen = true;
this.processedFilterCount = selfie.processedFilterCount;
this.acceptedCount = selfie.acceptedCount;
this.rejectedCount = selfie.rejectedCount;
this.allowFilterCount = selfie.allowFilterCount;
this.blockFilterCount = selfie.blockFilterCount;
this.duplicateCount = selfie.duplicateCount;
this.blockedAnyPartyHostnames.fromSelfie(selfie.blockedAnyPartyHostnames);
this.blocked3rdPartyHostnames.fromSelfie(selfie.blocked3rdPartyHostnames);
var factories = {
'[]': FilterBucket,
'a': FilterPlain,
'ah': FilterPlainHostname,
'0a': FilterPlainPrefix0,
'0ah': FilterPlainPrefix0Hostname,
'1a': FilterPlainPrefix1,
'1ah': FilterPlainPrefix1Hostname,
'|a': FilterPlainLeftAnchored,
'|ah': FilterPlainLeftAnchoredHostname,
'a|': FilterPlainRightAnchored,
'a|h': FilterPlainRightAnchoredHostname,
'*': FilterSingleWildcard,
'*h': FilterSingleWildcardHostname,
'0*': FilterSingleWildcardPrefix0,
'0*h': FilterSingleWildcardPrefix0Hostname,
'|*': FilterSingleWildcardLeftAnchored,
'|*h': FilterSingleWildcardLeftAnchoredHostname,
'*|': FilterSingleWildcardRightAnchored,
'*|h': FilterSingleWildcardRightAnchoredHostname,
'*+': FilterManyWildcards,
'*+h': FilterManyWildcardsHostname
};
var catKey, tokenKey;
var dict = this.categories, subdict;
var bucket = null;
var rawText = selfie.categories;
var rawEnd = rawText.length;
var lineBeg = 0, lineEnd;
var line, pos, what, factory;
while ( lineBeg < rawEnd ) {
lineEnd = rawText.indexOf('\n', lineBeg);
if ( lineEnd < 0 ) {
lineEnd = rawEnd;
}
line = rawText.slice(lineBeg, lineEnd);
lineBeg = lineEnd + 1;
pos = line.indexOf('\t');
what = line.slice(0, pos);
if ( what === 'k1' ) {
catKey = decode(line.slice(pos + 1));
subdict = dict[catKey] = {};
bucket = null;
continue;
}
if ( what === 'k2' ) {
tokenKey = decode(line.slice(pos + 1));
bucket = null;
continue;
}
factory = factories[what];
if ( bucket === null ) {
bucket = subdict[tokenKey] = factory.fromSelfie(line.slice(pos + 1));
continue;
}
// When token key is reused, it can't be anything
// else than FilterBucket
bucket.add(factory.fromSelfie(line.slice(pos + 1)));
}
};
/******************************************************************************/
FilterContainer.prototype.toDomainBits = function(domain) { FilterContainer.prototype.toDomainBits = function(domain) {
if ( domain === undefined ) { if ( domain === undefined ) {
return 0; return 0;
@ -989,6 +1382,13 @@ FilterContainer.prototype.add = function(s) {
var parsed = this.filterParser.parse(s); var parsed = this.filterParser.parse(s);
// Ignore rules with other conditions for now
if ( parsed.unsupported ) {
this.rejectedCount += 1;
// console.log('µBlock> abp-filter.js/FilterContainer.add(): unsupported filter "%s"', s);
return false;
}
// Ignore element-hiding filters // Ignore element-hiding filters
if ( parsed.elemHiding ) { if ( parsed.elemHiding ) {
return false; return false;
@ -1002,12 +1402,6 @@ FilterContainer.prototype.add = function(s) {
this.processedFilterCount += 1; this.processedFilterCount += 1;
// Ignore rules with other conditions for now
if ( parsed.unsupported ) {
// console.log('µBlock> abp-filter.js/FilterContainer.add(): unsupported filter "%s"', s);
return false;
}
// Ignore optionless hostname rules, these will be taken care of by µBlock. // Ignore optionless hostname rules, these will be taken care of by µBlock.
if ( parsed.hostname && parsed.fopts === '' && parsed.action === BlockAction && reHostnameRule.test(parsed.f) ) { if ( parsed.hostname && parsed.fopts === '' && parsed.action === BlockAction && reHostnameRule.test(parsed.f) ) {
return false; return false;
@ -1145,7 +1539,7 @@ FilterContainer.prototype.addToCategory = function(category, tokenKey, filter) {
categoryBucket[tokenKey] = filter; categoryBucket[tokenKey] = filter;
return; return;
} }
if ( filterEntry instanceof FilterBucket ) { if ( filterEntry.fid === '[]' ) {
filterEntry.add(filter); filterEntry.add(filter);
return; return;
} }

View File

@ -24,13 +24,20 @@
/******************************************************************************/ /******************************************************************************/
µBlock.abpHideFilters = (function(){ µBlock.cosmeticFilteringEngine = (function(){
/******************************************************************************/ /******************************************************************************/
var µb = µBlock; var µb = µBlock;
/******************************************************************************/
// Could be replaced with encodeURIComponent/decodeURIComponent,
// which seems faster on Firefox.
var encode = JSON.stringify;
var decode = JSON.parse;
/******************************************************************************/ /******************************************************************************/
/* /*
var histogram = function(label, buckets) { var histogram = function(label, buckets) {
@ -86,6 +93,16 @@ FilterPlain.prototype.retrieve = function(s, out) {
} }
}; };
FilterPlain.prototype.fid = '#';
FilterPlain.prototype.toSelfie = function() {
return this.s;
};
FilterPlain.fromSelfie = function(s) {
return new FilterPlain(s);
};
/******************************************************************************/ /******************************************************************************/
// Id- and class-based filters with extra selector stuff following. // Id- and class-based filters with extra selector stuff following.
@ -104,6 +121,50 @@ FilterPlainMore.prototype.retrieve = function(s, out) {
} }
}; };
FilterPlainMore.prototype.fid = '#+';
FilterPlainMore.prototype.toSelfie = function() {
return this.s;
};
FilterPlainMore.fromSelfie = function(s) {
return new FilterPlainMore(s);
};
/******************************************************************************/
var FilterBucket = function(a, b) {
this.f = null;
this.filters = [];
if ( a !== undefined ) {
this.filters[0] = a;
if ( b !== undefined ) {
this.filters[1] = b;
}
}
};
FilterBucket.prototype.add = function(a) {
this.filters.push(a);
};
FilterBucket.prototype.retrieve = function(s, out) {
var i = this.filters.length;
while ( i-- ) {
this.filters[i].retrieve(s, out);
}
};
FilterBucket.prototype.fid = '[]';
FilterBucket.prototype.toSelfie = function() {
return this.filters.length.toString();
};
FilterBucket.fromSelfie = function() {
return new FilterBucket();
};
/******************************************************************************/ /******************************************************************************/
// Any selector specific to a hostname // Any selector specific to a hostname
@ -127,6 +188,17 @@ FilterHostname.prototype.retrieve = function(hostname, out) {
} }
}; };
FilterHostname.prototype.fid = 'h';
FilterHostname.prototype.toSelfie = function() {
return encode(this.s) + '\t' + this.hostname;
};
FilterHostname.fromSelfie = function(s) {
var pos = s.indexOf('\t');
return new FilterHostname(decode(s.slice(0, pos)), s.slice(pos + 1));
};
/******************************************************************************/ /******************************************************************************/
// Any selector specific to an entity // Any selector specific to an entity
@ -144,28 +216,15 @@ FilterEntity.prototype.retrieve = function(entity, out) {
} }
}; };
/******************************************************************************/ FilterEntity.prototype.fid = 'e';
/******************************************************************************/
// TODO: evaluate the gain (if any) from avoiding the use of an array for when FilterEntity.prototype.toSelfie = function() {
// there are only two filters (or three, etc.). I suppose there is a specific return encode(this.s) + '\t' + this.entity;
// number of filters below which using an array is more of an overhead than
// using a couple of property members.
// i.e. FilterBucket2, FilterBucket3, FilterBucketN.
var FilterBucket = function(a, b) {
this.filters = [a, b];
}; };
FilterBucket.prototype.add = function(a) { FilterEntity.fromSelfie = function(s) {
this.filters.push(a); var pos = s.indexOf('\t');
}; return new FilterEntity(decode(s.slice(0, pos)), s.slice(pos + 1));
FilterBucket.prototype.retrieve = function(s, out) {
var i = this.filters.length;
while ( i-- ) {
this.filters[i].retrieve(s, out);
}
}; };
/******************************************************************************/ /******************************************************************************/
@ -419,6 +478,7 @@ FilterContainer.prototype.reset = function() {
this.hostnameDonthide = {}; this.hostnameDonthide = {};
this.entityHide = {}; this.entityHide = {};
this.entityDonthide = {}; this.entityDonthide = {};
// permanent // permanent
// [class], [id] // [class], [id]
this.lowGenericFilters = {}; this.lowGenericFilters = {};
@ -436,11 +496,12 @@ FilterContainer.prototype.reset = function() {
this.highMediumGenericDonthideCount = 0; this.highMediumGenericDonthideCount = 0;
// everything else // everything else
this.highHighGenericHide = []; this.highHighGenericHide = '';
this.highHighGenericDonthide = []; this.highHighGenericDonthide = '';
this.highHighGenericHideCount = 0; this.highHighGenericHideCount = 0;
this.highHighGenericDonthideCount = 0; this.highHighGenericDonthideCount = 0;
// hostname, entity-based filters
this.hostnameFilters = {}; this.hostnameFilters = {};
this.entityFilters = {}; this.entityFilters = {};
}; };
@ -705,6 +766,120 @@ FilterContainer.prototype.freeze = function() {
/******************************************************************************/ /******************************************************************************/
FilterContainer.prototype.toSelfie = function() {
var selfieFromDict = function(dict) {
var selfie = [];
var bucket, ff, n, i, f;
for ( var k in dict ) {
if ( dict.hasOwnProperty(k) === false ) {
continue;
}
// We need to encode the key because there could be a `\n`
// character in it, which would trip the code at parse time.
selfie.push('k\t' + encode(k));
bucket = dict[k];
selfie.push(bucket.fid + '\t' + bucket.toSelfie());
if ( bucket.fid !== '[]' ) {
continue;
}
ff = bucket.filters;
n = ff.length;
for ( i = 0; i < n; i++ ) {
f = ff[i];
selfie.push(f.fid + '\t' + f.toSelfie());
}
}
return selfie.join('\n');
};
return {
acceptedCount: this.acceptedCount,
duplicateCount: this.duplicateCount,
hostnameSpecificFilters: selfieFromDict(this.hostnameFilters),
entitySpecificFilters: selfieFromDict(this.entityFilters),
lowGenericFilters: selfieFromDict(this.lowGenericFilters),
highLowGenericHide: this.highLowGenericHide,
highLowGenericDonthide: this.highLowGenericDonthide,
highLowGenericHideCount: this.highLowGenericHideCount,
highLowGenericDonthideCount: this.highLowGenericDonthideCount,
highMediumGenericHide: this.highMediumGenericHide,
highMediumGenericDonthide: this.highMediumGenericDonthide,
highMediumGenericHideCount: this.highMediumGenericHideCount,
highMediumGenericDonthideCount: this.highMediumGenericDonthideCount,
highHighGenericHide: this.highHighGenericHide,
highHighGenericDonthide: this.highHighGenericDonthide,
highHighGenericHideCount: this.highHighGenericHideCount,
highHighGenericDonthideCount: this.highHighGenericDonthideCount
};
};
/******************************************************************************/
FilterContainer.prototype.fromSelfie = function(selfie) {
var factories = {
'[]': FilterBucket,
'#': FilterPlain,
'#+': FilterPlainMore,
'h': FilterHostname,
'e': FilterEntity
};
var dictFromSelfie = function(selfie) {
var dict = {};
var dictKey;
var bucket = null;
var rawText = selfie;
var rawEnd = rawText.length;
var lineBeg = 0, lineEnd;
var line, pos, what, factory;
while ( lineBeg < rawEnd ) {
lineEnd = rawText.indexOf('\n', lineBeg);
if ( lineEnd < 0 ) {
lineEnd = rawEnd;
}
line = rawText.slice(lineBeg, lineEnd);
lineBeg = lineEnd + 1;
pos = line.indexOf('\t');
what = line.slice(0, pos);
if ( what === 'k' ) {
dictKey = decode(line.slice(pos + 1));
bucket = null;
continue;
}
factory = factories[what];
if ( bucket === null ) {
bucket = dict[dictKey] = factory.fromSelfie(line.slice(pos + 1));
continue;
}
// When token key is reused, it can't be anything
// else than FilterBucket
bucket.add(factory.fromSelfie(line.slice(pos + 1)));
}
return dict;
};
this.frozen = true;
this.acceptedCount = selfie.acceptedCount;
this.duplicateCount = selfie.duplicateCount;
this.hostnameFilters = dictFromSelfie(selfie.hostnameSpecificFilters);
this.entityFilters = dictFromSelfie(selfie.entitySpecificFilters);
this.lowGenericFilters = dictFromSelfie(selfie.lowGenericFilters);
this.highLowGenericHide = selfie.highLowGenericHide;
this.highLowGenericDonthide = selfie.highLowGenericDonthide;
this.highLowGenericHideCount = selfie.highLowGenericHideCount;
this.highLowGenericDonthideCount = selfie.highLowGenericDonthideCount;
this.highMediumGenericHide = selfie.highMediumGenericHide;
this.highMediumGenericDonthide = selfie.highMediumGenericDonthide;
this.highMediumGenericHideCount = selfie.highMediumGenericHideCount;
this.highMediumGenericDonthideCount = selfie.highMediumGenericDonthideCount;
this.highHighGenericHide = selfie.highHighGenericHide;
this.highHighGenericDonthide = selfie.highHighGenericDonthide;
this.highHighGenericHideCount = selfie.highHighGenericHideCount;
this.highHighGenericDonthideCount = selfie.highHighGenericDonthideCount;
};
/******************************************************************************/
FilterContainer.prototype.addToSelectorCache = function(details) { FilterContainer.prototype.addToSelectorCache = function(details) {
var hostname = details.hostname; var hostname = details.hostname;
if ( typeof hostname !== 'string' || hostname === '' ) { if ( typeof hostname !== 'string' || hostname === '' ) {

View File

@ -43,16 +43,23 @@ File system structure:
/******************************************************************************/ /******************************************************************************/
var oneSecond = 1000;
var oneMinute = 60 * oneSecond;
var oneHour = 60 * oneMinute;
var oneDay = 24 * oneHour;
/******************************************************************************/
var repositoryRoot = µBlock.projectServerRoot; var repositoryRoot = µBlock.projectServerRoot;
var nullFunc = function() {}; var nullFunc = function() {};
var reIsExternalPath = /^https?:\/\/[a-z0-9]/; var reIsExternalPath = /^https?:\/\/[a-z0-9]/;
var reIsUserPath = /^assets\/user\//; var reIsUserPath = /^assets\/user\//;
var lastRepoMetaTimestamp = 0; var lastRepoMetaTimestamp = 0;
var refreshRepoMetaPeriod = 6 * 60 * 60 * 1000; var refreshRepoMetaPeriod = 5 * oneHour;
var exports = { var exports = {
autoUpdate: true, autoUpdate: true,
autoUpdateDelay: 2 * 24 * 60 * 60 * 1000 autoUpdateDelay: 4 * oneDay
}; };
/******************************************************************************/ /******************************************************************************/
@ -349,7 +356,7 @@ exports.setHomeURL = function(path, homeURL) {
entry = metadata.entries[path] = new AssetEntry(); entry = metadata.entries[path] = new AssetEntry();
} }
entry.homeURL = homeURL; entry.homeURL = homeURL;
} };
getRepoMetadata(onRepoMetadataReady); getRepoMetadata(onRepoMetadataReady);
}; };
@ -548,9 +555,9 @@ var readRepoCopyAsset = function(path, callback) {
var onCacheMetaReady = function(entries) { var onCacheMetaReady = function(entries) {
// Fetch from remote if: // Fetch from remote if:
// - Auto-update enabled AND (not in cache OR in cache but obsolete) // - Auto-update enabled AND (not in cache OR in cache but obsolete)
var timestamp = entries[path];
var homeURL = assetEntry.homeURL; var homeURL = assetEntry.homeURL;
if ( exports.autoUpdate && typeof homeURL === 'string' && homeURL !== '' ) { if ( exports.autoUpdate && typeof homeURL === 'string' && homeURL !== '' ) {
var timestamp = entries[path];
var obsolete = Date.now() - exports.autoUpdateDelay; var obsolete = Date.now() - exports.autoUpdateDelay;
if ( typeof timestamp !== 'number' || timestamp <= obsolete ) { if ( typeof timestamp !== 'number' || timestamp <= obsolete ) {
//console.log('µBlock> readRepoCopyAsset("%s") / onCacheMetaReady(): not cached or obsolete', path); //console.log('µBlock> readRepoCopyAsset("%s") / onCacheMetaReady(): not cached or obsolete', path);

View File

@ -63,6 +63,7 @@ return {
updateAssetsEvery: 75 * oneHour + 23 * oneMinute + 53 * oneSecond + 605, updateAssetsEvery: 75 * oneHour + 23 * oneMinute + 53 * oneSecond + 605,
projectServerRoot: 'https://raw.githubusercontent.com/gorhill/uBlock/master/', projectServerRoot: 'https://raw.githubusercontent.com/gorhill/uBlock/master/',
userFiltersPath: 'assets/user/filters.txt', userFiltersPath: 'assets/user/filters.txt',
pslPath: 'assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat',
// permanent lists // permanent lists
permanentLists: { permanentLists: {
@ -86,11 +87,21 @@ return {
remoteBlacklists: { remoteBlacklists: {
}, },
firstUpdateAfter: 5 * oneMinute,
nextUpdateAfter: 7 * oneHour,
selfieMagic: 'ccolmudazpvm',
selfieAfter: 7 * oneMinute,
pageStores: {}, pageStores: {},
storageQuota: chrome.storage.local.QUOTA_BYTES, storageQuota: chrome.storage.local.QUOTA_BYTES,
storageUsed: 0, storageUsed: 0,
noopFunc: function(){},
apiErrorCount: 0,
// so that I don't have to care for last comma // so that I don't have to care for last comma
dummy: 0 dummy: 0
}; };

View File

@ -19,6 +19,9 @@
Home: https://github.com/gorhill/uBlock Home: https://github.com/gorhill/uBlock
*/ */
/* jshint bitwise: false */
/* global µBlock */
/******************************************************************************/ /******************************************************************************/
µBlock.LiquidDict = (function() { µBlock.LiquidDict = (function() {
@ -94,12 +97,20 @@ LiquidDict.prototype.makeKey = function(word) {
if ( len > 255 ) { if ( len > 255 ) {
len = 255; len = 255;
} }
var i = len >> 2; var i8 = len >>> 3;
var i4 = len >>> 2;
var i2 = len >>> 1;
// Be sure the msb is not set, this will guarantee a valid unicode
// character (because 0xD800-0xDFFF).
return String.fromCharCode( return String.fromCharCode(
(word.charCodeAt( 0) & 0x03) << 14 | (word.charCodeAt( i8) & 0x01) << 14 |
(word.charCodeAt( i) & 0x03) << 12 | (word.charCodeAt( i4 ) & 0x01) << 13 |
(word.charCodeAt( i+i) & 0x03) << 10 | (word.charCodeAt( i4+i8) & 0x01) << 12 |
(word.charCodeAt(i+i+i) & 0x03) << 8 | (word.charCodeAt(i2 ) & 0x01) << 11 |
(word.charCodeAt(i2 +i8) & 0x01) << 10 |
(word.charCodeAt(i2+i4 ) & 0x01) << 9 |
(word.charCodeAt(i2+i4+i8) & 0x01) << 8 ,
len len
); );
}; };
@ -187,6 +198,26 @@ LiquidDict.prototype.reset = function() {
/******************************************************************************/ /******************************************************************************/
LiquidDict.prototype.toSelfie = function() {
return {
count: this.count,
bucketCount: this.bucketCount,
frozenBucketCount: this.frozenBucketCount,
dict: this.dict
};
};
/******************************************************************************/
LiquidDict.prototype.fromSelfie = function(selfie) {
this.count = selfie.count;
this.bucketCount = selfie.bucketCount;
this.frozenBucketCount = selfie.frozenBucketCount;
this.dict = selfie.dict;
};
/******************************************************************************/
return LiquidDict; return LiquidDict;
/******************************************************************************/ /******************************************************************************/

View File

@ -121,7 +121,7 @@ var onMessage = function(request, sender, callback) {
switch ( request.what ) { switch ( request.what ) {
case 'retrieveDomainCosmeticSelectors': case 'retrieveDomainCosmeticSelectors':
if ( pageStore && pageStore.getNetFilteringSwitch() ) { if ( pageStore && pageStore.getNetFilteringSwitch() ) {
response = µb.abpHideFilters.retrieveDomainSelectors(request); response = µb.cosmeticFilteringEngine.retrieveDomainSelectors(request);
} }
break; break;
@ -162,12 +162,12 @@ var onMessage = function(request, sender, callback) {
switch ( request.what ) { switch ( request.what ) {
case 'retrieveGenericCosmeticSelectors': case 'retrieveGenericCosmeticSelectors':
if ( pageStore && pageStore.getNetFilteringSwitch() ) { if ( pageStore && pageStore.getNetFilteringSwitch() ) {
response = µb.abpHideFilters.retrieveGenericSelectors(request); response = µb.cosmeticFilteringEngine.retrieveGenericSelectors(request);
} }
break; break;
case 'injectedSelectors': case 'injectedSelectors':
µb.abpHideFilters.addToSelectorCache(request); µb.cosmeticFilteringEngine.addToSelectorCache(request);
break; break;
case 'blockedRequests': case 'blockedRequests':
@ -250,8 +250,8 @@ var getLists = function(callback) {
available: null, available: null,
current: µb.remoteBlacklists, current: µb.remoteBlacklists,
cosmetic: µb.userSettings.parseAllABPHideFilters, cosmetic: µb.userSettings.parseAllABPHideFilters,
netFilterCount: µb.abpFilters.getFilterCount(), netFilterCount: µb.netFilteringEngine.getFilterCount(),
cosmeticFilterCount: µb.abpHideFilters.getFilterCount(), cosmeticFilterCount: µb.cosmeticFilteringEngine.getFilterCount(),
autoUpdate: µb.userSettings.autoUpdate, autoUpdate: µb.userSettings.autoUpdate,
userFiltersPath: µb.userFiltersPath, userFiltersPath: µb.userFiltersPath,
cache: null cache: null

View File

@ -40,12 +40,15 @@ var quickProfiler = (function() {
prompt = s || ''; prompt = s || '';
tstart = timer.now(); tstart = timer.now();
}; };
var stop = function() { var stop = function(period) {
if ( period === undefined ) {
period = 10000;
}
var now = timer.now(); var now = timer.now();
count += 1; count += 1;
time += (now - tstart); time += (now - tstart);
if ( (now - lastlog) > 10000 ) { if ( (now - lastlog) >= period ) {
console.log('µBlock > %s: %s ms (%d samples)', prompt, avg().toFixed(3), count); console.log('µBlock> %s: %s ms (%d samples)', prompt, avg().toFixed(3), count);
lastlog = now; lastlog = now;
} }
}; };

View File

@ -31,36 +31,76 @@
/******************************************************************************/ /******************************************************************************/
var µb = µBlock; var µb = µBlock;
var bufferTime = 0 * 60 * 1000;
var exports = {};
var jobCallback = function() { var jobCallback = function() {
// Simpler to fire restart here, and safe given how far this will happen
// in the future.
restart();
// If auto-update is disabled, check again in a while.
if ( µb.userSettings.autoUpdate !== true ) { if ( µb.userSettings.autoUpdate !== true ) {
return; return;
} }
// TODO: need smarter update, currently blindly reloading all.
µb.loadUpdatableAssets(true); var onMetadataReady = function(metadata) {
// Check PSL
var mdEntry = metadata[µb.pslPath];
if ( mdEntry.repoObsolete ) {
// console.log('µBlock.updater> updating all updatable assets');
µb.loadUpdatableAssets({ update: true });
return;
}
// Check used filter lists
var lists = µb.remoteBlacklists;
for ( var path in lists ) {
if ( lists.hasOwnProperty(path) === false ) {
continue;
}
if ( lists[path].off ) {
continue;
}
if ( metadata.hasOwnProperty(path) === false ) {
continue;
}
mdEntry = metadata[path];
if ( mdEntry.cacheObsolete || mdEntry.repoObsolete ) {
// console.log('µBlock.updater> updating only filter lists');
µb.loadUpdatableAssets({ update: true, psl: false });
return;
}
}
// console.log('µBlock.updater> all is up to date');
};
µb.assets.metadata(onMetadataReady);
}; };
// https://www.youtube.com/watch?v=cIrGQD84F1g // https://www.youtube.com/watch?v=cIrGQD84F1g
/******************************************************************************/ /******************************************************************************/
exports.restart = function() { var restart = function(after) {
if ( after === undefined ) {
after = µb.nextUpdateAfter;
}
µb.asyncJobs.add( µb.asyncJobs.add(
'autoUpdateAssets', 'autoUpdateAssets',
null, null,
jobCallback, jobCallback,
µb.updateAssetsEvery - bufferTime, after,
true false
); );
}; };
exports.restart();
/******************************************************************************/ /******************************************************************************/
return exports; return {
restart: restart
};
/******************************************************************************/
})(); })();

View File

@ -139,12 +139,18 @@
/******************************************************************************/ /******************************************************************************/
µBlock.appendUserFilters = function(content) { µBlock.appendUserFilters = function(content) {
var µb = this;
var onFiltersReady = function() {
};
var onSaved = function(details) { var onSaved = function(details) {
if ( details.error ) { if ( details.error ) {
return; return;
} }
µBlock.loadUbiquitousBlacklists(); µb.loadFilterLists(onFiltersReady);
}; };
var onLoaded = function(details) { var onLoaded = function(details) {
if ( details.error ) { if ( details.error ) {
return; return;
@ -152,8 +158,9 @@
if ( details.content.indexOf(content.trim()) !== -1 ) { if ( details.content.indexOf(content.trim()) !== -1 ) {
return; return;
} }
µBlock.saveUserFilters(details.content + '\n' + content, onSaved); µb.saveUserFilters(details.content + '\n' + content, onSaved);
}; };
if ( content.length > 0 ) { if ( content.length > 0 ) {
this.loadUserFilters(onLoaded); this.loadUserFilters(onLoaded);
} }
@ -256,15 +263,21 @@
/******************************************************************************/ /******************************************************************************/
µBlock.loadUbiquitousBlacklists = function() { µBlock.loadFilterLists = function(callback) {
var µb = this; var µb = this;
var blacklistLoadCount; var blacklistLoadCount;
if ( typeof callback !== 'function' ) {
callback = this.noopFunc;
}
var loadBlacklistsEnd = function() { var loadBlacklistsEnd = function() {
µb.abpFilters.freeze(); µb.netFilteringEngine.freeze();
µb.abpHideFilters.freeze(); µb.cosmeticFilteringEngine.freeze();
µb.messaging.announce({ what: 'loadUbiquitousBlacklistCompleted' });
chrome.storage.local.set({ 'remoteBlacklists': µb.remoteBlacklists }); chrome.storage.local.set({ 'remoteBlacklists': µb.remoteBlacklists });
µb.messaging.announce({ what: 'loadUbiquitousBlacklistCompleted' });
µb.toSelfieAsync();
callback();
}; };
var mergeBlacklist = function(details) { var mergeBlacklist = function(details) {
@ -277,10 +290,9 @@
var loadBlacklistsStart = function(lists) { var loadBlacklistsStart = function(lists) {
µb.remoteBlacklists = lists; µb.remoteBlacklists = lists;
µb.netFilteringEngine.reset();
// rhill 2013-12-10: set all existing entries to `false`. µb.cosmeticFilteringEngine.reset();
µb.abpFilters.reset(); µb.destroySelfie();
µb.abpHideFilters.reset();
var locations = Object.keys(lists); var locations = Object.keys(lists);
blacklistLoadCount = locations.length; blacklistLoadCount = locations.length;
if ( blacklistLoadCount === 0 ) { if ( blacklistLoadCount === 0 ) {
@ -322,11 +334,11 @@
// Useful references: // Useful references:
// https://adblockplus.org/en/filter-cheatsheet // https://adblockplus.org/en/filter-cheatsheet
// https://adblockplus.org/en/filters // https://adblockplus.org/en/filters
var abpFilters = this.abpFilters; var netFilteringEngine = this.netFilteringEngine;
var abpHideFilters = this.abpHideFilters; var cosmeticFilteringEngine = this.cosmeticFilteringEngine;
var parseCosmeticFilters = this.userSettings.parseAllABPHideFilters; var parseCosmeticFilters = this.userSettings.parseAllABPHideFilters;
var duplicateCount = abpFilters.duplicateCount + abpHideFilters.duplicateCount; var duplicateCount = netFilteringEngine.duplicateCount + cosmeticFilteringEngine.duplicateCount;
var acceptedCount = abpFilters.acceptedCount + abpHideFilters.acceptedCount; var acceptedCount = netFilteringEngine.acceptedCount + cosmeticFilteringEngine.acceptedCount;
var reLocalhost = /(^|\s)(localhost\.localdomain|localhost|local|broadcasthost|0\.0\.0\.0|127\.0\.0\.1|::1|fe80::1%lo0)(?=\s|$)/g; var reLocalhost = /(^|\s)(localhost\.localdomain|localhost|local|broadcasthost|0\.0\.0\.0|127\.0\.0\.1|::1|fe80::1%lo0)(?=\s|$)/g;
var reAdblockFilter = /^[^a-z0-9:]|[^a-z0-9]$|[^a-z0-9_:.-]/; var reAdblockFilter = /^[^a-z0-9:]|[^a-z0-9]$|[^a-z0-9_:.-]/;
var reAdblockHostFilter = /^\|\|([a-z0-9.-]+[a-z0-9])\^?$/; var reAdblockHostFilter = /^\|\|([a-z0-9.-]+[a-z0-9])\^?$/;
@ -360,7 +372,7 @@
// 2014-05-18: ABP element hide filters are allowed to contain space // 2014-05-18: ABP element hide filters are allowed to contain space
// characters // characters
if ( parseCosmeticFilters ) { if ( parseCosmeticFilters ) {
if ( abpHideFilters.add(line) ) { if ( cosmeticFilteringEngine.add(line) ) {
continue; continue;
} }
} }
@ -396,7 +408,7 @@
// Likely an ABP net filter? // Likely an ABP net filter?
if ( reAdblockFilter.test(line) ) { if ( reAdblockFilter.test(line) ) {
if ( abpFilters.add(line) ) { if ( netFilteringEngine.add(line) ) {
continue; continue;
} }
// rhill 2014-01-22: Transpose possible Adblock Plus-filter syntax // rhill 2014-01-22: Transpose possible Adblock Plus-filter syntax
@ -412,13 +424,13 @@
continue; continue;
} }
abpFilters.addAnyPartyHostname(line); netFilteringEngine.addAnyPartyHostname(line);
} }
// For convenience, store the number of entries for this // For convenience, store the number of entries for this
// blacklist, user might be happy to know this information. // blacklist, user might be happy to know this information.
duplicateCount = abpFilters.duplicateCount + abpHideFilters.duplicateCount - duplicateCount; duplicateCount = netFilteringEngine.duplicateCount + cosmeticFilteringEngine.duplicateCount - duplicateCount;
acceptedCount = abpFilters.acceptedCount + abpHideFilters.acceptedCount - acceptedCount; acceptedCount = netFilteringEngine.acceptedCount + cosmeticFilteringEngine.acceptedCount - acceptedCount;
this.remoteBlacklists[details.path].entryCount = acceptedCount + duplicateCount; this.remoteBlacklists[details.path].entryCount = acceptedCount + duplicateCount;
this.remoteBlacklists[details.path].entryUsedCount = acceptedCount; this.remoteBlacklists[details.path].entryUsedCount = acceptedCount;
@ -449,66 +461,192 @@
} }
// Now force reload // Now force reload
this.loadUpdatableAssets(update); this.loadUpdatableAssets({ update: update, psl: update });
}; };
/******************************************************************************/ /******************************************************************************/
µBlock.loadPublicSuffixList = function(callback) { µBlock.loadPublicSuffixList = function(callback) {
if ( typeof callback !== 'function' ) {
callback = this.noopFunc;
}
var applyPublicSuffixList = function(details) { var applyPublicSuffixList = function(details) {
// TODO: Not getting proper suffix list is a bit serious, I think // TODO: Not getting proper suffix list is a bit serious, I think
// the extension should be force-restarted if it occurs.. // the extension should be force-restarted if it occurs..
if ( !details.error ) { if ( !details.error ) {
publicSuffixList.parse(details.content, punycode.toASCII); publicSuffixList.parse(details.content, punycode.toASCII);
} }
if ( typeof callback === 'function' ) { callback();
callback();
}
}; };
this.assets.get( this.assets.get(this.pslPath, applyPublicSuffixList);
'assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat',
applyPublicSuffixList
);
}; };
/******************************************************************************/ /******************************************************************************/
// Load updatable assets // Load updatable assets
µBlock.loadUpdatableAssets = function(update) { µBlock.loadUpdatableAssets = function(details) {
var µb = this;
details = details || {};
var update = details.update !== false;
this.assets.autoUpdate = update || this.userSettings.autoUpdate; this.assets.autoUpdate = update || this.userSettings.autoUpdate;
this.assets.autoUpdateDelay = this.updateAssetsEvery; this.assets.autoUpdateDelay = this.updateAssetsEvery;
this.loadPublicSuffixList();
this.loadUbiquitousBlacklists();
// It could be a manual update, so we reset the auto-updater var onFiltersReady = function() {
if ( update ) { if ( update ) {
this.updater.restart(); µb.updater.restart();
}
};
var onPSLReady = function() {
µb.loadFilterLists(onFiltersReady);
};
if ( details.psl !== false ) {
this.loadPublicSuffixList(onPSLReady);
} else {
this.loadFilterLists(onFiltersReady);
} }
}; };
/******************************************************************************/ /******************************************************************************/
µBlock.toSelfie = function() {
var selfie = {
magic: this.selfieMagic,
publicSuffixList: publicSuffixList.toSelfie(),
filterLists: this.remoteBlacklists,
netFilteringEngine: this.netFilteringEngine.toSelfie(),
cosmeticFilteringEngine: this.cosmeticFilteringEngine.toSelfie(),
};
chrome.storage.local.set({ selfie: selfie });
// console.log('µBlock.toSelfie> made a selfie!');
};
// This is to be sure the selfie is generated in a sane manner: the selfie will
// be generated if the user doesn't change his filter lists selection for
// some set time.
µBlock.toSelfieAsync = function(after) {
if ( typeof after !== 'number' ) {
after = this.selfieAfter;
}
this.asyncJobs.add(
'toSelfie',
null,
this.toSelfie.bind(this),
after,
false
);
};
/******************************************************************************/
µBlock.fromSelfie = function(callback) {
var µb = this;
if ( typeof callback !== 'function' ) {
callback = this.noopFunc;
}
var onSelfieReady = function(store) {
var selfie = store.selfie;
if ( typeof selfie !== 'object' || selfie.magic !== µb.selfieMagic ) {
callback(false);
return;
}
if ( publicSuffixList.fromSelfie(selfie.publicSuffixList) !== true ) {
callback(false);
return;
}
// console.log('µBlock.fromSelfie> selfie looks good');
µb.remoteBlacklists = selfie.filterLists;
µb.netFilteringEngine.fromSelfie(selfie.netFilteringEngine);
µb.cosmeticFilteringEngine.fromSelfie(selfie.cosmeticFilteringEngine);
callback(true);
};
chrome.storage.local.get('selfie', onSelfieReady);
};
/******************************************************************************/
µBlock.destroySelfie = function() {
chrome.storage.local.remove('selfie');
};
/******************************************************************************/
// Load all // Load all
µBlock.load = function() { µBlock.load = function() {
var µb = this; var µb = this;
// User whitelist directives and filters need the Public Suffix List to be // Final initialization steps after all needed assets are in memory
// available -- because the way they are stored internally. var onAllDone = function(wasAutoUpdated) {
// Initialize internal state with maybe already existing tabs
var bindToTabs = function(tabs) {
var scriptStart = function(tabId) {
var scriptEnd = function() {
chrome.tabs.executeScript(tabId, {
file: 'js/contentscript-end.js',
allFrames: true,
runAt: 'document_idle'
});
};
chrome.tabs.executeScript(tabId, {
file: 'js/contentscript-start.js',
allFrames: true,
runAt: 'document_idle'
}, scriptEnd);
};
var i = tabs.length, tab;
while ( i-- ) {
tab = tabs[i];
µb.bindTabToPageStats(tab.id, tab.url);
// https://github.com/gorhill/uBlock/issues/129
scriptStart(tab.id);
}
};
chrome.tabs.query({ url: 'http://*/*' }, bindToTabs);
chrome.tabs.query({ url: 'https://*/*' }, bindToTabs);
// https://github.com/gorhill/uBlock/issues/184
// If we restored a selfie, check for updates not too far
// in the future.
µb.updater.restart(wasAutoUpdated ? µb.nextUpdateAfter : µb.firstUpdateAfter);
};
// Filters are in memory
var onFiltersReady = function() {
onAllDone(µb.userSettings.autoUpdate);
};
// Load order because dependencies:
// User settings -> PSL -> [filter lists, user whitelist]
var onPSLReady = function() { var onPSLReady = function() {
µb.loadWhitelist(); µb.loadWhitelist();
µb.loadUbiquitousBlacklists(); µb.loadFilterLists(onFiltersReady);
}; };
// Public Suffix List loader needs the user settings need to be available // If no selfie available, take the long way, i.e. load and parse
// because we need to know whether to auto-update the list or not. // raw data.
var onUserSettingsReady = function() { var onSelfieReady = function(success) {
µb.assets.autoUpdate = µb.userSettings.autoUpdate || true; if ( success === true ) {
onAllDone(false);
return;
}
µb.assets.autoUpdate = µb.userSettings.autoUpdate;
µb.loadPublicSuffixList(onPSLReady); µb.loadPublicSuffixList(onPSLReady);
}; };
this.loadUserSettings(onUserSettingsReady);
// User settings are in memory
var onUserSettingsReady = function() {
µb.fromSelfie(onSelfieReady);
};
this.loadUserSettings(onUserSettingsReady);
this.loadLocalSettings(); this.loadLocalSettings();
this.getBytesInUse(); this.getBytesInUse();
}; };

View File

@ -59,41 +59,6 @@
chrome.tabs.onRemoved.addListener(onTabRemoved); chrome.tabs.onRemoved.addListener(onTabRemoved);
})(); })();
/******************************************************************************/
// Initialize internal state with maybe already existing tabs
// This needs to be executed once, hence it has its own scope, which will
// allow the code to be flushed once completed.
(function(){
var µb = µBlock;
var bindToTabs = function(tabs) {
var scriptStart = function(tabId) {
var scriptEnd = function() {
chrome.tabs.executeScript(tabId, {
file: 'js/contentscript-end.js',
allFrames: true,
runAt: 'document_idle'
});
};
chrome.tabs.executeScript(tabId, {
file: 'js/contentscript-start.js',
allFrames: true,
runAt: 'document_idle'
}, scriptEnd);
};
var i = tabs.length, tab;
while ( i-- ) {
tab = tabs[i];
µb.bindTabToPageStats(tab.id, tab.url);
// https://github.com/gorhill/uBlock/issues/129
scriptStart(tab.id);
}
};
chrome.tabs.query({ url: 'http://*/*' }, bindToTabs);
chrome.tabs.query({ url: 'https://*/*' }, bindToTabs);
})();
/******************************************************************************/ /******************************************************************************/
/******************************************************************************/ /******************************************************************************/

View File

@ -80,7 +80,7 @@ var onBeforeRequest = function(details) {
var reason = false; var reason = false;
if ( pageStore.getNetFilteringSwitch() ) { if ( pageStore.getNetFilteringSwitch() ) {
reason = µb.abpFilters.matchString(requestContext, requestURL, requestType, requestHostname); reason = µb.netFilteringEngine.matchString(requestContext, requestURL, requestType, requestHostname);
} }
// Record what happened. // Record what happened.
pageStore.recordRequest(requestType, requestURL, reason); pageStore.recordRequest(requestType, requestURL, reason);
@ -168,7 +168,7 @@ var onBeforeSendHeaders = function(details) {
// in multiple tabs. // in multiple tabs.
var reason = false; var reason = false;
if ( pageStore.getNetFilteringSwitch() ) { if ( pageStore.getNetFilteringSwitch() ) {
reason = µb.abpFilters.matchStringExactType( reason = µb.netFilteringEngine.matchStringExactType(
pageDetails, pageDetails,
requestURL, requestURL,
'popup', 'popup',

View File

@ -1,17 +1,17 @@
/*! Home: https://github.com/gorhill/publicsuffixlist.js */ /*! Home: https://github.com/gorhill/publicsuffixlist.js */
;(function(f){var b={};var h={};var a=480; /* Minified using http://refresh-sf.com/yui/ */
var g=/[^a-z0-9.-]/;function i(k){if(!k||k.charAt(0)==="."){return""}k=k.toLowerCase();var l=c(k);if(l===k){return"" ;(function(i){var d={};var k={};var g="iscjsfsaolnm";var b=480;
}var m=k.lastIndexOf(".",k.lastIndexOf(".",k.length-l.length)-1);if(m<=0){return k}return k.slice(m+1) var j=/[^a-z0-9.-]/;function l(n){if(!n||n.charAt(0)==="."){return""}n=n.toLowerCase();var o=e(n);if(o===n){return""}var p=n.lastIndexOf(".",n.lastIndexOf(".",n.length-o.length)-1);
}function c(k){if(!k){return""}var l;while(true){l=k.indexOf(".");if(l<0){return k}if(j(b,k)){return k.slice(l+1) if(p<=0){return n}return n.slice(p+1)}function e(n){if(!n){return""}var o;while(true){o=n.indexOf(".");if(o<0){return n}if(m(d,n)){return n.slice(o+1)
}if(j(h,k)){return k}if(j(h,"*"+k.slice(l))){return k}k=k.slice(l+1)}}function j(t,r){var q=r.lastIndexOf("."); }if(m(k,n)){return n}if(m(k,"*"+n.slice(o))){return n}n=n.slice(o+1)}}function m(v,t){var s=t.lastIndexOf(".");var o,x;if(s<0){o=t;
var m,v;if(q<0){m=r;v=r}else{m=r.slice(q+1);v=r.slice(0,q)}var s=t[m];if(!s){return false}if(typeof s==="string"){return s.indexOf(" "+v+" ")>=0 x=t}else{o=t.slice(s+1);x=t.slice(0,s)}var u=v[o];if(!u){return false}if(typeof u==="string"){return u.indexOf(" "+x+" ")>=0
}var n=v.length;var w=s[n];if(!w){return false}var k=0;var u=Math.floor(w.length/n+0.5);var p,o;while(k<u){p=k+u>>1; }var p=x.length;var y=u[p];if(!y){return false}var n=0;var w=Math.floor(y.length/p+0.5);var r,q;while(n<w){r=n+w>>1;q=y.substr(p*r,p);
o=w.substr(n*p,n);if(v<o){u=p}else{if(v>o){k=p+1}else{return true}}}return false}function d(r,p){b={}; if(x<q){w=r}else{if(x>q){n=r+1}else{return true}}}return false}function f(u,s){d={};k={};u=u.toLowerCase();var r=0,o;var p=u.length;
h={};r=r.toLowerCase();var o=0,l;var m=r.length;var s,q,n,k;while(o<m){l=r.indexOf("\n",o);if(l<0){l=m var v,t,q,n;while(r<p){o=u.indexOf("\n",r);if(o<0){o=u.indexOf("\r",r);if(o<0){o=p}}v=u.slice(r,o).trim();r=o+1;if(v.length===0){continue
}s=r.slice(o,l);o=l+1;if(s.length===0){continue}n=s.indexOf("//");if(n>=0){s=s.slice(0,n)}s=s.trim(); }q=v.indexOf("//");if(q>=0){v=v.slice(0,q)}v=v.trim();if(!v){continue}if(j.test(v)){v=s(v)}if(v.charAt(0)==="!"){t=d;v=v.slice(1)
if(!s){continue}if(g.test(s)){s=p(s)}if(s.charAt(0)==="!"){q=b;s=s.slice(1)}else{q=h}n=s.lastIndexOf("."); }else{t=k}q=v.lastIndexOf(".");if(q<0){n=v}else{n=v.slice(q+1);v=v.slice(0,q)}if(!t.hasOwnProperty(n)){t[n]=[]}if(v){t[n].push(v)
if(n<0){k=s}else{k=s.slice(n+1);s=s.slice(0,n)}if(!q[k]){q[k]=[]}if(s){q[k].push(s)}}e(b);e(h)}function e(m){var o,q,p,k; }}h(d);h(k)}function h(o){var q,s,r,n;for(var p in o){if(!o.hasOwnProperty(p)){continue}q=o[p].join(" ");if(!q){o[p]="";continue
for(var n in m){if(!m.hasOwnProperty(n)){continue}o=m[n].join(" ");if(!o){m[n]="";continue}if(o.length<a){m[n]=" "+o+" "; }if(q.length<b){o[p]=" "+q+" ";continue}r=o[p].length;q=[];while(r--){s=o[p][r];n=s.length;if(!q[n]){q[n]=[]}q[n].push(s)
continue}p=m[n].length;o=[];while(p--){q=m[n][p];k=q.length;if(!o[k]){o[k]=[]}o[k].push(q)}k=o.length; }n=q.length;while(n--){if(q[n]){q[n]=q[n].sort().join("")}}o[p]=q}return o}function c(){return{magic:g,rules:k,exceptions:d}
while(k--){if(o[k]){o[k]=o[k].sort().join("")}}m[n]=o}return m}f.publicSuffixList={version:"1.0",parse:d,getDomain:i,getPublicSuffix:c} }function a(n){if(typeof n!=="object"||typeof n.magic!=="string"||n.magic!==g){return false}k=n.rules;d=n.exceptions;return true
})(this); }i=i||window;i.publicSuffixList={version:"1.0",parse:f,getDomain:l,getPublicSuffix:e,toSelfie:c,fromSelfie:a}})(this);