2014-06-24 00:42:43 +02:00
|
|
|
|
/*******************************************************************************
|
|
|
|
|
|
2016-06-27 03:15:18 +02:00
|
|
|
|
uBlock Origin - a browser extension to block requests.
|
2018-02-26 20:08:16 +01:00
|
|
|
|
Copyright (C) 2014-2018 Raymond Hill
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
|
|
|
|
|
|
|
|
|
Home: https://github.com/gorhill/uBlock
|
|
|
|
|
*/
|
|
|
|
|
|
2015-12-29 17:34:41 +01:00
|
|
|
|
/* jshint bitwise: false */
|
2017-11-02 20:49:11 +01:00
|
|
|
|
/* global punycode, HNTrieBuilder */
|
2014-10-19 17:10:31 +02:00
|
|
|
|
|
2016-06-27 03:15:18 +02:00
|
|
|
|
'use strict';
|
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2014-12-28 16:07:43 +01:00
|
|
|
|
µBlock.staticNetFilteringEngine = (function(){
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2014-09-14 22:20:40 +02:00
|
|
|
|
var µb = µBlock;
|
|
|
|
|
|
2014-07-14 17:24:59 +02:00
|
|
|
|
// fedcba9876543210
|
2017-05-25 23:46:59 +02:00
|
|
|
|
// | | | |||
|
|
|
|
|
// | | | |||
|
|
|
|
|
// | | | |||
|
|
|
|
|
// | | | |||
|
|
|
|
|
// | | | ||+---- bit 0: [BlockAction | AllowAction]
|
|
|
|
|
// | | | |+----- bit 1: `important`
|
|
|
|
|
// | | | +------ bit 2- 3: party [0 - 3]
|
|
|
|
|
// | | +-------- bit 4- 8: type [0 - 31]
|
|
|
|
|
// | +------------- bit 9-14: unused
|
|
|
|
|
// +------------------- bit 15: bad filter
|
2014-09-20 16:44:04 +02:00
|
|
|
|
|
2015-03-03 12:09:35 +01:00
|
|
|
|
var BlockAction = 0 << 0;
|
|
|
|
|
var AllowAction = 1 << 0;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var Important = 1 << 1;
|
|
|
|
|
var AnyParty = 0 << 2;
|
|
|
|
|
var FirstParty = 1 << 2;
|
|
|
|
|
var ThirdParty = 2 << 2;
|
2017-05-25 23:46:59 +02:00
|
|
|
|
var BadFilter = 1 << 15;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
2015-03-26 00:28:22 +01:00
|
|
|
|
var AnyType = 0 << 4;
|
2014-09-21 02:06:55 +02:00
|
|
|
|
var typeNameToTypeValue = {
|
2016-08-31 11:19:16 +02:00
|
|
|
|
'no_type': 0 << 4,
|
2015-03-26 00:28:22 +01:00
|
|
|
|
'stylesheet': 1 << 4,
|
|
|
|
|
'image': 2 << 4,
|
|
|
|
|
'object': 3 << 4,
|
2017-11-03 21:51:28 +01:00
|
|
|
|
'object_subrequest': 3 << 4,
|
2015-03-26 00:28:22 +01:00
|
|
|
|
'script': 4 << 4,
|
|
|
|
|
'xmlhttprequest': 5 << 4,
|
|
|
|
|
'sub_frame': 6 << 4,
|
2015-04-05 16:38:47 +02:00
|
|
|
|
'font': 7 << 4,
|
2016-03-07 01:16:46 +01:00
|
|
|
|
'media': 8 << 4,
|
|
|
|
|
'websocket': 9 << 4,
|
|
|
|
|
'other': 10 << 4,
|
2017-05-12 16:35:11 +02:00
|
|
|
|
'popup': 11 << 4, // start of behavorial filtering
|
|
|
|
|
'popunder': 12 << 4,
|
|
|
|
|
'main_frame': 13 << 4, // start of 1st-party-only behavorial filtering
|
|
|
|
|
'generichide': 14 << 4,
|
2017-09-16 13:49:43 +02:00
|
|
|
|
'inline-font': 15 << 4,
|
|
|
|
|
'inline-script': 16 << 4,
|
|
|
|
|
'data': 17 << 4, // special: a generic data holder
|
|
|
|
|
'redirect': 18 << 4,
|
|
|
|
|
'webrtc': 19 << 4,
|
|
|
|
|
'unsupported': 20 << 4
|
2014-09-21 02:06:55 +02:00
|
|
|
|
};
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var otherTypeBitValue = typeNameToTypeValue.other;
|
2014-09-21 02:06:55 +02:00
|
|
|
|
|
2015-06-09 16:27:08 +02:00
|
|
|
|
var typeValueToTypeName = {
|
|
|
|
|
1: 'stylesheet',
|
|
|
|
|
2: 'image',
|
|
|
|
|
3: 'object',
|
|
|
|
|
4: 'script',
|
|
|
|
|
5: 'xmlhttprequest',
|
2015-07-13 14:49:58 +02:00
|
|
|
|
6: 'subdocument',
|
2015-06-09 16:27:08 +02:00
|
|
|
|
7: 'font',
|
2016-03-07 01:16:46 +01:00
|
|
|
|
8: 'media',
|
|
|
|
|
9: 'websocket',
|
|
|
|
|
10: 'other',
|
2017-05-12 16:35:11 +02:00
|
|
|
|
11: 'popup',
|
|
|
|
|
12: 'popunder',
|
|
|
|
|
13: 'document',
|
|
|
|
|
14: 'generichide',
|
2017-09-16 13:49:43 +02:00
|
|
|
|
15: 'inline-font',
|
|
|
|
|
16: 'inline-script',
|
|
|
|
|
17: 'data',
|
|
|
|
|
18: 'redirect',
|
|
|
|
|
19: 'webrtc',
|
|
|
|
|
20: 'unsupported'
|
2015-06-09 16:27:08 +02:00
|
|
|
|
};
|
|
|
|
|
|
2015-03-03 12:09:35 +01:00
|
|
|
|
var BlockAnyTypeAnyParty = BlockAction | AnyType | AnyParty;
|
|
|
|
|
var BlockAnyType = BlockAction | AnyType;
|
|
|
|
|
var BlockAnyParty = BlockAction | AnyParty;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
2015-03-03 12:09:35 +01:00
|
|
|
|
var AllowAnyTypeAnyParty = AllowAction | AnyType | AnyParty;
|
|
|
|
|
var AllowAnyType = AllowAction | AnyType;
|
|
|
|
|
var AllowAnyParty = AllowAction | AnyParty;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
2016-11-08 13:13:26 +01:00
|
|
|
|
var genericHideException = AllowAction | AnyParty | typeNameToTypeValue.generichide,
|
|
|
|
|
genericHideImportant = BlockAction | AnyParty | typeNameToTypeValue.generichide | Important;
|
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
// ABP filters: https://adblockplus.org/en/filters
|
|
|
|
|
// regex tester: http://regex101.com/
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
2014-09-21 20:03:41 +02:00
|
|
|
|
|
2015-02-05 00:06:31 +01:00
|
|
|
|
// See the following as short-lived registers, used during evaluation. They are
|
|
|
|
|
// valid until the next evaluation.
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var pageHostnameRegister = '',
|
|
|
|
|
requestHostnameRegister = '';
|
2015-03-30 23:42:12 +02:00
|
|
|
|
//var filterRegister = null;
|
|
|
|
|
//var categoryRegister = '';
|
2015-02-05 00:06:31 +01:00
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2014-09-21 20:03:41 +02:00
|
|
|
|
var histogram = function() {};
|
2014-06-24 00:42:43 +02:00
|
|
|
|
/*
|
2014-09-21 20:03:41 +02:00
|
|
|
|
histogram = function(label, categories) {
|
2014-06-24 00:42:43 +02:00
|
|
|
|
var h = [],
|
|
|
|
|
categoryBucket;
|
|
|
|
|
for ( var k in categories ) {
|
2014-09-21 15:40:54 +02:00
|
|
|
|
// No need for hasOwnProperty() here: there is no prototype chain.
|
2014-06-24 00:42:43 +02:00
|
|
|
|
categoryBucket = categories[k];
|
|
|
|
|
for ( var kk in categoryBucket ) {
|
2014-09-21 15:40:54 +02:00
|
|
|
|
// No need for hasOwnProperty() here: there is no prototype chain.
|
2014-06-24 00:42:43 +02:00
|
|
|
|
filterBucket = categoryBucket[kk];
|
|
|
|
|
h.push({
|
2014-09-21 20:03:41 +02:00
|
|
|
|
k: k.charCodeAt(0).toString(2) + ' ' + kk,
|
2014-06-24 00:42:43 +02:00
|
|
|
|
n: filterBucket instanceof FilterBucket ? filterBucket.filters.length : 1
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('Histogram %s', label);
|
|
|
|
|
|
|
|
|
|
var total = h.length;
|
|
|
|
|
h.sort(function(a, b) { return b.n - a.n; });
|
|
|
|
|
|
|
|
|
|
// Find indices of entries of interest
|
|
|
|
|
var target = 2;
|
|
|
|
|
for ( var i = 0; i < total; i++ ) {
|
|
|
|
|
if ( h[i].n === target ) {
|
|
|
|
|
console.log('\tEntries with only %d filter(s) start at index %s (key = "%s")', target, i, h[i].k);
|
|
|
|
|
target -= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
h = h.slice(0, 50);
|
|
|
|
|
|
|
|
|
|
h.forEach(function(v) {
|
|
|
|
|
console.log('\tkey=%s count=%d', v.k, v.n);
|
|
|
|
|
});
|
|
|
|
|
console.log('\tTotal buckets count: %d', total);
|
|
|
|
|
};
|
|
|
|
|
*/
|
2014-09-08 23:46:58 +02:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2015-06-09 23:01:31 +02:00
|
|
|
|
// Local helpers
|
|
|
|
|
|
2016-07-25 14:18:17 +02:00
|
|
|
|
// Be sure to not confuse 'example.com' with 'anotherexample.com'
|
2015-12-15 16:40:40 +01:00
|
|
|
|
var isFirstParty = function(domain, hostname) {
|
|
|
|
|
return hostname.endsWith(domain) &&
|
|
|
|
|
(hostname.length === domain.length ||
|
2017-05-12 16:35:11 +02:00
|
|
|
|
hostname.charCodeAt(hostname.length - domain.length - 1) === 0x2E /* '.' */);
|
2014-10-07 22:30:40 +02:00
|
|
|
|
};
|
|
|
|
|
|
2016-01-17 02:21:17 +01:00
|
|
|
|
var normalizeRegexSource = function(s) {
|
2015-10-26 16:23:56 +01:00
|
|
|
|
try {
|
2016-01-17 02:21:17 +01:00
|
|
|
|
var re = new RegExp(s);
|
|
|
|
|
return re.source;
|
2015-10-26 16:23:56 +01:00
|
|
|
|
} catch (ex) {
|
2016-01-17 02:21:17 +01:00
|
|
|
|
normalizeRegexSource.message = ex.toString();
|
2015-10-26 16:23:56 +01:00
|
|
|
|
}
|
2016-01-17 02:21:17 +01:00
|
|
|
|
return '';
|
2015-10-26 16:23:56 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var rawToRegexStr = function(s, anchor) {
|
|
|
|
|
var me = rawToRegexStr;
|
2015-07-04 23:34:18 +02:00
|
|
|
|
// https://www.loggly.com/blog/five-invaluable-techniques-to-improve-regex-performance/
|
2015-03-17 14:39:03 +01:00
|
|
|
|
// https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions
|
2016-07-01 21:15:58 +02:00
|
|
|
|
// Also: remove leading/trailing wildcards -- there is no point.
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var reStr = s.replace(me.escape1, '\\$&')
|
|
|
|
|
.replace(me.escape2, '(?:[^%.0-9a-z_-]|$)')
|
|
|
|
|
.replace(me.escape3, '')
|
|
|
|
|
.replace(me.escape4, '[^ ]*?');
|
|
|
|
|
if ( anchor & 0x4 ) {
|
2017-08-31 20:17:55 +02:00
|
|
|
|
reStr = (
|
|
|
|
|
reStr.startsWith('\\.') ?
|
|
|
|
|
rawToRegexStr.reTextHostnameAnchor2 :
|
|
|
|
|
rawToRegexStr.reTextHostnameAnchor1
|
|
|
|
|
) + reStr;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
} else if ( anchor & 0x2 ) {
|
2015-03-05 01:36:09 +01:00
|
|
|
|
reStr = '^' + reStr;
|
|
|
|
|
}
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( anchor & 0x1 ) {
|
|
|
|
|
reStr += '$';
|
2016-08-23 16:33:28 +02:00
|
|
|
|
}
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return reStr;
|
2015-03-02 16:41:51 +01:00
|
|
|
|
};
|
2017-05-12 16:35:11 +02:00
|
|
|
|
rawToRegexStr.escape1 = /[.+?${}()|[\]\\]/g;
|
|
|
|
|
rawToRegexStr.escape2 = /\^/g;
|
|
|
|
|
rawToRegexStr.escape3 = /^\*|\*$/g;
|
|
|
|
|
rawToRegexStr.escape4 = /\*/g;
|
2017-08-31 20:17:55 +02:00
|
|
|
|
rawToRegexStr.reTextHostnameAnchor1 = '^[a-z-]+://(?:[^/?#]+\\.)?';
|
|
|
|
|
rawToRegexStr.reTextHostnameAnchor2 = '^[a-z-]+://(?:[^/?#]+)?';
|
2015-03-02 16:41:51 +01:00
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
var filterFingerprinter = µb.CompiledLineWriter.fingerprint;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
|
2017-05-19 14:45:19 +02:00
|
|
|
|
var toLogDataInternal = function(categoryBits, tokenHash, filter) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( filter === null ) { return undefined; }
|
|
|
|
|
var logData = filter.logData();
|
2017-05-25 23:46:59 +02:00
|
|
|
|
logData.compiled = filterFingerprinter([ categoryBits, tokenHash, logData.compiled ]);
|
2017-05-19 14:45:19 +02:00
|
|
|
|
if ( categoryBits & 0x001 ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
logData.raw = '@@' + logData.raw;
|
|
|
|
|
}
|
|
|
|
|
var opts = [];
|
2017-05-19 14:45:19 +02:00
|
|
|
|
if ( categoryBits & 0x002 ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
opts.push('important');
|
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
if ( categoryBits & 0x008 ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
opts.push('third-party');
|
2017-05-19 14:45:19 +02:00
|
|
|
|
} else if ( categoryBits & 0x004 ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
opts.push('first-party');
|
|
|
|
|
}
|
2017-09-16 13:49:43 +02:00
|
|
|
|
var type = categoryBits & 0x1F0;
|
|
|
|
|
if ( type !== 0 && type !== typeNameToTypeValue.data ) {
|
|
|
|
|
opts.push(typeValueToTypeName[type >>> 4]);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
}
|
|
|
|
|
if ( logData.opts !== undefined ) {
|
|
|
|
|
opts.push(logData.opts);
|
|
|
|
|
}
|
|
|
|
|
if ( opts.length !== 0 ) {
|
|
|
|
|
logData.raw += '$' + opts.join(',');
|
|
|
|
|
}
|
|
|
|
|
return logData;
|
2015-06-09 23:01:31 +02:00
|
|
|
|
};
|
|
|
|
|
|
2016-08-23 16:33:28 +02:00
|
|
|
|
// First character of match must be within the hostname part of the url.
|
|
|
|
|
var isHnAnchored = function(url, matchStart) {
|
|
|
|
|
var hnStart = url.indexOf('://');
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( hnStart === -1 ) { return false; }
|
2016-08-23 16:33:28 +02:00
|
|
|
|
hnStart += 3;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( matchStart <= hnStart ) { return true; }
|
2016-08-23 16:33:28 +02:00
|
|
|
|
if ( reURLPostHostnameAnchors.test(url.slice(hnStart, matchStart)) ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// https://github.com/gorhill/uBlock/issues/1929
|
|
|
|
|
// Match only hostname label boundaries.
|
|
|
|
|
return url.charCodeAt(matchStart - 1) === 0x2E;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var reURLPostHostnameAnchors = /[\/?#]/;
|
|
|
|
|
|
2017-05-27 02:00:21 +02:00
|
|
|
|
var arrayStrictEquals = function(a, b) {
|
|
|
|
|
var n = a.length;
|
|
|
|
|
if ( n !== b.length ) { return false; }
|
|
|
|
|
var isArray, x, y;
|
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
|
|
|
|
x = a[i]; y = b[i];
|
|
|
|
|
isArray = Array.isArray(x);
|
|
|
|
|
if ( isArray !== Array.isArray(y) ) { return false; }
|
|
|
|
|
if ( isArray === true ) {
|
|
|
|
|
if ( arrayStrictEquals(x, y) === false ) { return false; }
|
|
|
|
|
} else {
|
|
|
|
|
if ( x !== y ) { return false; }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
/*******************************************************************************
|
2015-08-22 18:15:16 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
Each filter class will register itself in the map. A filter class
|
|
|
|
|
id MUST always stringify to ONE single character.
|
2015-08-22 18:15:16 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
IMPORTANT: any change which modifies the mapping will have to be
|
|
|
|
|
reflected with µBlock.systemSettings.compiledMagic.
|
2017-01-06 18:39:37 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
**/
|
2015-08-22 18:15:16 +02:00
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
var filterClasses = [],
|
2017-05-12 16:35:11 +02:00
|
|
|
|
filterClassIdGenerator = 0;
|
2015-08-22 18:15:16 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var registerFilterClass = function(ctor) {
|
|
|
|
|
var fid = filterClassIdGenerator++;
|
2017-05-25 23:46:59 +02:00
|
|
|
|
ctor.fid = ctor.prototype.fid = fid;
|
|
|
|
|
filterClasses[fid] = ctor;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
//console.log(ctor.name, fid);
|
2015-08-22 18:15:16 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
var filterFromCompiledData = function(args) {
|
|
|
|
|
//filterClassHistogram.set(fid, (filterClassHistogram.get(fid) || 0) + 1);
|
|
|
|
|
return filterClasses[args[0]].load(args);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//var filterClassHistogram = new Map();
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
/******************************************************************************/
|
2017-01-06 18:39:37 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterTrue = function() {
|
2015-08-22 03:52:16 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterTrue.prototype.match = function() {
|
|
|
|
|
return true;
|
2015-08-22 03:52:16 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterTrue.prototype.logData = function() {
|
|
|
|
|
return {
|
|
|
|
|
raw: '*',
|
|
|
|
|
regex: '^',
|
|
|
|
|
compiled: this.compile(),
|
|
|
|
|
};
|
2015-08-22 18:15:16 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterTrue.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid ];
|
2015-08-22 18:15:16 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterTrue.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterTrue.fid ];
|
2015-08-22 18:15:16 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterTrue.load = function() {
|
|
|
|
|
return new FilterTrue();
|
|
|
|
|
};
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterTrue);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
var FilterPlain = function(s, tokenBeg) {
|
|
|
|
|
this.s = s;
|
|
|
|
|
this.tokenBeg = tokenBeg;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterPlain.prototype.match = function(url, tokenBeg) {
|
2015-12-15 16:40:40 +01:00
|
|
|
|
return url.startsWith(this.s, tokenBeg - this.tokenBeg);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlain.prototype.logData = function() {
|
|
|
|
|
return {
|
|
|
|
|
raw: this.s,
|
|
|
|
|
regex: rawToRegexStr(this.s),
|
|
|
|
|
compiled: this.compile()
|
|
|
|
|
};
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlain.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid, this.s, this.tokenBeg ];
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlain.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterPlain.fid, details.f, details.tokenBeg ];
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterPlain.load = function(args) {
|
|
|
|
|
return new FilterPlain(args[1], args[2]);
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterPlain);
|
2014-09-08 23:46:58 +02:00
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
var FilterPlainPrefix0 = function(s) {
|
|
|
|
|
this.s = s;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterPlainPrefix0.prototype.match = function(url, tokenBeg) {
|
2015-12-15 16:40:40 +01:00
|
|
|
|
return url.startsWith(this.s, tokenBeg);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainPrefix0.prototype.logData = function() {
|
|
|
|
|
return {
|
|
|
|
|
raw: this.s,
|
|
|
|
|
regex: rawToRegexStr(this.s),
|
|
|
|
|
compiled: this.compile()
|
|
|
|
|
};
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainPrefix0.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid, this.s ];
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainPrefix0.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterPlainPrefix0.fid, details.f ];
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterPlainPrefix0.load = function(args) {
|
|
|
|
|
return new FilterPlainPrefix0(args[1]);
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterPlainPrefix0);
|
2014-09-08 23:46:58 +02:00
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
var FilterPlainPrefix1 = function(s) {
|
|
|
|
|
this.s = s;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterPlainPrefix1.prototype.match = function(url, tokenBeg) {
|
2015-12-15 16:40:40 +01:00
|
|
|
|
return url.startsWith(this.s, tokenBeg - 1);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainPrefix1.prototype.logData = function() {
|
|
|
|
|
return {
|
|
|
|
|
raw: this.s,
|
|
|
|
|
regex: rawToRegexStr(this.s),
|
|
|
|
|
compiled: this.compile()
|
|
|
|
|
};
|
|
|
|
|
};
|
2014-09-08 23:46:58 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainPrefix1.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid, this.s ];
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2015-02-24 00:31:29 +01:00
|
|
|
|
FilterPlainPrefix1.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterPlainPrefix1.fid, details.f ];
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterPlainPrefix1.load = function(args) {
|
|
|
|
|
return new FilterPlainPrefix1(args[1]);
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterPlainPrefix1);
|
|
|
|
|
|
2014-08-28 15:59:05 +02:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterPlainHostname = function(s) {
|
2014-06-24 00:42:43 +02:00
|
|
|
|
this.s = s;
|
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainHostname.prototype.match = function() {
|
|
|
|
|
var haystack = requestHostnameRegister, needle = this.s;
|
|
|
|
|
if ( haystack.endsWith(needle) === false ) { return false; }
|
|
|
|
|
var offset = haystack.length - needle.length;
|
|
|
|
|
return offset === 0 || haystack.charCodeAt(offset - 1) === 0x2E /* '.' */;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainHostname.prototype.logData = function() {
|
|
|
|
|
return {
|
|
|
|
|
raw: '||' + this.s + '^',
|
2017-08-31 20:17:55 +02:00
|
|
|
|
regex: rawToRegexStr(this.s + '^'),
|
2017-05-12 16:35:11 +02:00
|
|
|
|
compiled: this.compile()
|
|
|
|
|
};
|
|
|
|
|
};
|
2014-08-28 15:59:05 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainHostname.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid, this.s ];
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainHostname.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterPlainHostname.fid, details.f ];
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterPlainHostname.load = function(args) {
|
|
|
|
|
return new FilterPlainHostname(args[1]);
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterPlainHostname);
|
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
var FilterPlainLeftAnchored = function(s) {
|
|
|
|
|
this.s = s;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterPlainLeftAnchored.prototype.match = function(url) {
|
2015-12-15 16:40:40 +01:00
|
|
|
|
return url.startsWith(this.s);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainLeftAnchored.prototype.logData = function() {
|
|
|
|
|
return {
|
|
|
|
|
raw: '|' + this.s,
|
|
|
|
|
regex: rawToRegexStr(this.s, 0x2),
|
|
|
|
|
compiled: this.compile()
|
|
|
|
|
};
|
|
|
|
|
};
|
2014-08-28 15:59:05 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainLeftAnchored.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid, this.s ];
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2015-02-24 00:31:29 +01:00
|
|
|
|
FilterPlainLeftAnchored.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterPlainLeftAnchored.fid, details.f ];
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterPlainLeftAnchored.load = function(args) {
|
|
|
|
|
return new FilterPlainLeftAnchored(args[1]);
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterPlainLeftAnchored);
|
|
|
|
|
|
2014-08-28 15:59:05 +02:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterPlainRightAnchored = function(s) {
|
2014-06-24 00:42:43 +02:00
|
|
|
|
this.s = s;
|
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainRightAnchored.prototype.match = function(url) {
|
|
|
|
|
return url.endsWith(this.s);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainRightAnchored.prototype.logData = function() {
|
|
|
|
|
return {
|
|
|
|
|
raw: this.s + '|',
|
|
|
|
|
regex: rawToRegexStr(this.s, 0x1),
|
|
|
|
|
compiled: this.compile()
|
|
|
|
|
};
|
|
|
|
|
};
|
2014-08-28 15:59:05 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainRightAnchored.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid, this.s ];
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainRightAnchored.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterPlainRightAnchored.fid, details.f ];
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterPlainRightAnchored.load = function(args) {
|
|
|
|
|
return new FilterPlainRightAnchored(args[1]);
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterPlainRightAnchored);
|
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-10-09 15:28:28 +02:00
|
|
|
|
var FilterExactMatch = function(s) {
|
|
|
|
|
this.s = s;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterExactMatch.prototype.match = function(url) {
|
|
|
|
|
return url === this.s;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterExactMatch.prototype.logData = function() {
|
|
|
|
|
return {
|
|
|
|
|
raw: '|' + this.s + '|',
|
|
|
|
|
regex: rawToRegexStr(this.s, 0x3),
|
|
|
|
|
compiled: this.compile()
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterExactMatch.prototype.compile = function() {
|
|
|
|
|
return [ this.fid, this.s ];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterExactMatch.compile = function(details) {
|
|
|
|
|
return [ FilterExactMatch.fid, details.f ];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterExactMatch.load = function(args) {
|
|
|
|
|
return new FilterExactMatch(args[1]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
registerFilterClass(FilterExactMatch);
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterPlainHnAnchored = function(s) {
|
2014-06-24 00:42:43 +02:00
|
|
|
|
this.s = s;
|
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainHnAnchored.prototype.match = function(url, tokenBeg) {
|
|
|
|
|
return url.startsWith(this.s, tokenBeg) &&
|
|
|
|
|
isHnAnchored(url, tokenBeg);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainHnAnchored.prototype.logData = function() {
|
|
|
|
|
return {
|
|
|
|
|
raw: '||' + this.s,
|
|
|
|
|
regex: rawToRegexStr(this.s),
|
|
|
|
|
compiled: this.compile()
|
|
|
|
|
};
|
|
|
|
|
};
|
2014-08-28 15:59:05 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainHnAnchored.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid, this.s ];
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterPlainHnAnchored.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterPlainHnAnchored.fid, details.f ];
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterPlainHnAnchored.load = function(args) {
|
|
|
|
|
return new FilterPlainHnAnchored(args[1]);
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterPlainHnAnchored);
|
|
|
|
|
|
2014-08-28 15:59:05 +02:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterGeneric = function(s, anchor) {
|
2014-06-24 00:42:43 +02:00
|
|
|
|
this.s = s;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.anchor = anchor;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterGeneric.prototype.re = null;
|
|
|
|
|
|
|
|
|
|
FilterGeneric.prototype.match = function(url) {
|
|
|
|
|
if ( this.re === null ) {
|
|
|
|
|
this.re = new RegExp(rawToRegexStr(this.s, this.anchor));
|
|
|
|
|
}
|
|
|
|
|
return this.re.test(url);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterGeneric.prototype.logData = function() {
|
|
|
|
|
var out = {
|
|
|
|
|
raw: this.s,
|
|
|
|
|
regex: this.re.source,
|
|
|
|
|
compiled: this.compile()
|
|
|
|
|
};
|
|
|
|
|
if ( this.anchor & 0x2 ) {
|
|
|
|
|
out.raw = '|' + out.raw;
|
|
|
|
|
}
|
|
|
|
|
if ( this.anchor & 0x1 ) {
|
|
|
|
|
out.raw += '|';
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
};
|
2014-08-28 15:59:05 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterGeneric.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid, this.s, this.anchor ];
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterGeneric.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterGeneric.fid, details.f, details.anchor ];
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterGeneric.load = function(args) {
|
|
|
|
|
return new FilterGeneric(args[1], args[2]);
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterGeneric);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
/******************************************************************************/
|
2014-09-19 16:59:44 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterGenericHnAnchored = function(s) {
|
2014-09-19 16:59:44 +02:00
|
|
|
|
this.s = s;
|
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterGenericHnAnchored.prototype.re = null;
|
|
|
|
|
FilterGenericHnAnchored.prototype.anchor = 0x4;
|
|
|
|
|
|
|
|
|
|
FilterGenericHnAnchored.prototype.match = function(url) {
|
|
|
|
|
if ( this.re === null ) {
|
|
|
|
|
this.re = new RegExp(rawToRegexStr(this.s, this.anchor));
|
|
|
|
|
}
|
2017-08-31 01:03:02 +02:00
|
|
|
|
return this.re.test(url);
|
2014-09-19 16:59:44 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterGenericHnAnchored.prototype.logData = function() {
|
|
|
|
|
var out = {
|
|
|
|
|
raw: '||' + this.s,
|
2017-08-31 20:17:55 +02:00
|
|
|
|
regex: rawToRegexStr(this.s, this.anchor & ~0x4),
|
2017-05-12 16:35:11 +02:00
|
|
|
|
compiled: this.compile()
|
|
|
|
|
};
|
|
|
|
|
return out;
|
|
|
|
|
};
|
2014-09-19 16:59:44 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterGenericHnAnchored.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid, this.s ];
|
2014-09-19 16:59:44 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterGenericHnAnchored.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterGenericHnAnchored.fid, details.f ];
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterGenericHnAnchored.load = function(args) {
|
|
|
|
|
return new FilterGenericHnAnchored(args[1]);
|
2014-09-19 16:59:44 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterGenericHnAnchored);
|
2014-09-19 16:59:44 +02:00
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterGenericHnAndRightAnchored = function(s) {
|
|
|
|
|
FilterGenericHnAnchored.call(this, s);
|
2015-04-27 21:09:19 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterGenericHnAndRightAnchored.prototype = Object.create(
|
|
|
|
|
FilterGenericHnAnchored.prototype,
|
|
|
|
|
{
|
|
|
|
|
constructor: {
|
|
|
|
|
value: FilterGenericHnAndRightAnchored
|
|
|
|
|
},
|
|
|
|
|
anchor: {
|
|
|
|
|
value: 0x5
|
|
|
|
|
},
|
|
|
|
|
logData: {
|
|
|
|
|
value: function() {
|
|
|
|
|
var out = FilterGenericHnAnchored.prototype.logData.call(this);
|
|
|
|
|
out.raw += '|';
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
compile: {
|
|
|
|
|
value: function() {
|
|
|
|
|
return [ this.fid, this.s ];
|
|
|
|
|
}
|
2017-05-12 16:35:11 +02:00
|
|
|
|
}
|
2017-05-25 23:46:59 +02:00
|
|
|
|
}
|
|
|
|
|
);
|
2015-04-27 21:09:19 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterGenericHnAndRightAnchored.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterGenericHnAndRightAnchored.fid, details.f ];
|
2015-04-27 21:09:19 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterGenericHnAndRightAnchored.load = function(args) {
|
|
|
|
|
return new FilterGenericHnAndRightAnchored(args[1]);
|
2015-04-27 21:09:19 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterGenericHnAndRightAnchored);
|
2015-04-27 21:09:19 +02:00
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterRegex = function(s) {
|
2017-07-11 18:21:08 +02:00
|
|
|
|
this.re = s;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterRegex.prototype.match = function(url) {
|
2017-07-11 18:21:08 +02:00
|
|
|
|
if ( typeof this.re === 'string' ) {
|
|
|
|
|
this.re = new RegExp(this.re, 'i');
|
|
|
|
|
}
|
2015-03-05 01:36:09 +01:00
|
|
|
|
return this.re.test(url);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterRegex.prototype.logData = function() {
|
2017-07-11 18:21:08 +02:00
|
|
|
|
var s = typeof this.re === 'string' ? this.re : this.re.source;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return {
|
2017-07-11 18:21:08 +02:00
|
|
|
|
raw: '/' + s + '/',
|
|
|
|
|
regex: s,
|
2017-05-12 16:35:11 +02:00
|
|
|
|
compiled: this.compile()
|
|
|
|
|
};
|
|
|
|
|
};
|
2014-09-08 23:46:58 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterRegex.prototype.compile = function() {
|
2017-07-11 18:21:08 +02:00
|
|
|
|
return [
|
|
|
|
|
this.fid,
|
|
|
|
|
typeof this.re === 'string' ? this.re : this.re.source
|
|
|
|
|
];
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterRegex.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterRegex.fid, details.f ];
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterRegex.load = function(args) {
|
|
|
|
|
return new FilterRegex(args[1]);
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterRegex);
|
|
|
|
|
|
2014-09-08 23:46:58 +02:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
// Filtering according to the origin.
|
2014-08-28 15:59:05 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterOrigin = function() {
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterOrigin.prototype.wrapped = {
|
|
|
|
|
compile: function() {
|
|
|
|
|
return '';
|
|
|
|
|
},
|
|
|
|
|
logData: function() {
|
|
|
|
|
return {
|
|
|
|
|
compiled: ''
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
match: function() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterOrigin.prototype.matchOrigin = function() {
|
|
|
|
|
return true;
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterOrigin.prototype.match = function(url, tokenBeg) {
|
|
|
|
|
return this.matchOrigin() && this.wrapped.match(url, tokenBeg);
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterOrigin.prototype.logData = function() {
|
|
|
|
|
var out = this.wrapped.logData(),
|
|
|
|
|
domainOpt = this.toDomainOpt();
|
2017-05-25 23:46:59 +02:00
|
|
|
|
out.compiled = [ this.fid, domainOpt, out.compiled ];
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( out.opts === undefined ) {
|
|
|
|
|
out.opts = 'domain=' + domainOpt;
|
|
|
|
|
} else {
|
|
|
|
|
out.opts += ',domain=' + domainOpt;
|
|
|
|
|
}
|
|
|
|
|
return out;
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterOrigin.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid, this.toDomainOpt(), this.wrapped.compile() ];
|
2017-05-12 16:35:11 +02:00
|
|
|
|
};
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
// *** start of specialized origin matchers
|
2015-03-02 16:41:51 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterOriginHit = function(domainOpt) {
|
|
|
|
|
FilterOrigin.call(this);
|
|
|
|
|
this.hostname = domainOpt;
|
2015-03-02 16:41:51 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterOriginHit.prototype = Object.create(FilterOrigin.prototype, {
|
|
|
|
|
constructor: {
|
|
|
|
|
value: FilterOriginHit
|
|
|
|
|
},
|
|
|
|
|
toDomainOpt: {
|
|
|
|
|
value: function() {
|
|
|
|
|
return this.hostname;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
matchOrigin: {
|
|
|
|
|
value: function() {
|
|
|
|
|
var needle = this.hostname, haystack = pageHostnameRegister;
|
|
|
|
|
if ( haystack.endsWith(needle) === false ) { return false; }
|
|
|
|
|
var offset = haystack.length - needle.length;
|
|
|
|
|
return offset === 0 || haystack.charCodeAt(offset - 1) === 0x2E /* '.' */;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
});
|
2015-03-02 16:41:51 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
//
|
2015-03-02 16:41:51 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterOriginMiss = function(domainOpt) {
|
|
|
|
|
FilterOrigin.call(this);
|
|
|
|
|
this.hostname = domainOpt.slice(1);
|
2015-03-02 16:41:51 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterOriginMiss.prototype = Object.create(FilterOrigin.prototype, {
|
|
|
|
|
constructor: {
|
|
|
|
|
value: FilterOriginMiss
|
|
|
|
|
},
|
|
|
|
|
toDomainOpt: {
|
|
|
|
|
value: function() {
|
|
|
|
|
return '~' + this.hostname;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
matchOrigin: {
|
|
|
|
|
value: function() {
|
|
|
|
|
var needle = this.hostname, haystack = pageHostnameRegister;
|
|
|
|
|
if ( haystack.endsWith(needle) === false ) { return true; }
|
|
|
|
|
var offset = haystack.length - needle.length;
|
|
|
|
|
return offset !== 0 && haystack.charCodeAt(offset - 1) !== 0x2E /* '.' */;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
});
|
2015-03-02 16:41:51 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
var FilterOriginHitSet = function(domainOpt) {
|
|
|
|
|
FilterOrigin.call(this);
|
2017-05-27 02:00:21 +02:00
|
|
|
|
this.domainOpt = domainOpt.length < 128
|
|
|
|
|
? domainOpt
|
|
|
|
|
: µb.stringDeduplicater.lookup(domainOpt);
|
2015-03-02 16:41:51 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterOriginHitSet.prototype = Object.create(FilterOrigin.prototype, {
|
|
|
|
|
constructor: {
|
|
|
|
|
value: FilterOriginHitSet
|
|
|
|
|
},
|
|
|
|
|
oneOf: {
|
|
|
|
|
value: null,
|
|
|
|
|
writable: true
|
|
|
|
|
},
|
|
|
|
|
toDomainOpt: {
|
|
|
|
|
value: function() {
|
|
|
|
|
return this.domainOpt;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
matchOrigin: {
|
|
|
|
|
value: function() {
|
|
|
|
|
if ( this.oneOf === null ) {
|
2017-11-02 20:49:11 +01:00
|
|
|
|
this.oneOf = HNTrieBuilder.fromDomainOpt(this.domainOpt);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
}
|
2017-11-02 20:49:11 +01:00
|
|
|
|
return this.oneOf.matches(pageHostnameRegister);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//
|
2015-03-02 16:41:51 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterOriginMissSet = function(domainOpt) {
|
|
|
|
|
FilterOrigin.call(this);
|
2017-05-27 02:00:21 +02:00
|
|
|
|
this.domainOpt = domainOpt.length < 128
|
|
|
|
|
? domainOpt
|
|
|
|
|
: µb.stringDeduplicater.lookup(domainOpt);
|
2015-03-02 22:22:23 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterOriginMissSet.prototype = Object.create(FilterOrigin.prototype, {
|
|
|
|
|
constructor: {
|
|
|
|
|
value: FilterOriginMissSet
|
|
|
|
|
},
|
|
|
|
|
noneOf: {
|
|
|
|
|
value: null,
|
|
|
|
|
writable: true
|
|
|
|
|
},
|
|
|
|
|
toDomainOpt: {
|
|
|
|
|
value: function() {
|
|
|
|
|
return this.domainOpt;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
matchOrigin: {
|
|
|
|
|
value: function() {
|
|
|
|
|
if ( this.noneOf === null ) {
|
2017-11-02 20:49:11 +01:00
|
|
|
|
this.noneOf = HNTrieBuilder.fromDomainOpt(this.domainOpt.replace(/~/g, ''));
|
2017-05-12 16:35:11 +02:00
|
|
|
|
}
|
2017-11-02 20:49:11 +01:00
|
|
|
|
return this.noneOf.matches(pageHostnameRegister) === false;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
var FilterOriginMixedSet = function(domainOpt) {
|
|
|
|
|
FilterOrigin.call(this);
|
2017-05-27 02:00:21 +02:00
|
|
|
|
this.domainOpt = domainOpt.length < 128
|
|
|
|
|
? domainOpt
|
|
|
|
|
: µb.stringDeduplicater.lookup(domainOpt);
|
2015-03-02 22:22:23 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterOriginMixedSet.prototype = Object.create(FilterOrigin.prototype, {
|
|
|
|
|
constructor: {
|
|
|
|
|
value: FilterOriginMixedSet
|
|
|
|
|
},
|
|
|
|
|
oneOf: {
|
|
|
|
|
value: null,
|
|
|
|
|
writable: true
|
|
|
|
|
},
|
|
|
|
|
noneOf: {
|
|
|
|
|
value: null,
|
|
|
|
|
writable: true
|
|
|
|
|
},
|
|
|
|
|
init: {
|
|
|
|
|
value: function() {
|
|
|
|
|
var oneOf = [], noneOf = [],
|
|
|
|
|
hostnames = this.domainOpt.split('|'),
|
|
|
|
|
i = hostnames.length,
|
|
|
|
|
hostname;
|
|
|
|
|
while ( i-- ) {
|
2018-01-13 14:31:13 +01:00
|
|
|
|
hostname = hostnames[i];
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( hostname.charCodeAt(0) === 0x7E /* '~' */ ) {
|
|
|
|
|
noneOf.push(hostname.slice(1));
|
|
|
|
|
} else {
|
|
|
|
|
oneOf.push(hostname);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-11-02 20:49:11 +01:00
|
|
|
|
this.oneOf = HNTrieBuilder.fromIterable(oneOf);
|
|
|
|
|
this.noneOf = HNTrieBuilder.fromIterable(noneOf);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
toDomainOpt: {
|
|
|
|
|
value: function() {
|
|
|
|
|
return this.domainOpt;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
matchOrigin: {
|
|
|
|
|
value: function() {
|
|
|
|
|
if ( this.oneOf === null ) { this.init(); }
|
|
|
|
|
var needle = pageHostnameRegister;
|
2017-11-02 20:49:11 +01:00
|
|
|
|
return this.oneOf.matches(needle) &&
|
|
|
|
|
this.noneOf.matches(needle) === false;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// *** end of specialized origin matchers
|
|
|
|
|
|
|
|
|
|
// The optimal test function is picked according to the content of the
|
|
|
|
|
// `domain=` filter option.
|
|
|
|
|
// Re-factored in light of:
|
|
|
|
|
// - https://gorhill.github.io/obj-vs-set-vs-map/set-vs-regexp.html
|
|
|
|
|
// The re-factoring made possible to reuse instances of a matcher. As of
|
|
|
|
|
// writing, I observed that just with EasyList, there were ~1,200 reused
|
|
|
|
|
// instances out of ~2,800.
|
2015-03-02 22:22:23 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterOrigin.matcherFactory = function(domainOpt) {
|
|
|
|
|
// One hostname
|
|
|
|
|
if ( domainOpt.indexOf('|') === -1 ) {
|
|
|
|
|
if ( domainOpt.charCodeAt(0) === 0x7E /* '~' */ ) {
|
|
|
|
|
return new FilterOriginMiss(domainOpt);
|
|
|
|
|
}
|
|
|
|
|
return new FilterOriginHit(domainOpt);
|
|
|
|
|
}
|
|
|
|
|
// Many hostnames.
|
|
|
|
|
// Must be in set (none negated).
|
|
|
|
|
if ( domainOpt.indexOf('~') === -1 ) {
|
|
|
|
|
return new FilterOriginHitSet(domainOpt);
|
|
|
|
|
}
|
|
|
|
|
// Must not be in set (all negated).
|
|
|
|
|
if ( FilterOrigin.reAllNegated.test(domainOpt) ) {
|
|
|
|
|
return new FilterOriginMissSet(domainOpt);
|
|
|
|
|
}
|
|
|
|
|
// Must be in one set, but not in the other.
|
|
|
|
|
return new FilterOriginMixedSet(domainOpt);
|
2015-03-02 22:22:23 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterOrigin.reAllNegated = /^~(?:[^|~]+\|~)+[^|~]+$/;
|
|
|
|
|
|
|
|
|
|
FilterOrigin.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterOrigin.fid, details.domainOpt ];
|
2015-03-02 22:22:23 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterOrigin.load = function(args) {
|
|
|
|
|
var f = FilterOrigin.matcherFactory(args[1]);
|
|
|
|
|
f.wrapped = filterFromCompiledData(args[2]);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return f;
|
2015-03-02 22:22:23 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterOrigin);
|
2015-03-02 22:22:23 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
/******************************************************************************/
|
2015-01-23 17:32:49 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var FilterDataHolder = function(dataType, dataStr) {
|
|
|
|
|
this.dataType = dataType;
|
|
|
|
|
this.dataStr = dataStr;
|
|
|
|
|
this.wrapped = undefined;
|
2015-01-23 17:32:49 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterDataHolder.prototype.match = function(url, tokenBeg) {
|
|
|
|
|
return this.wrapped.match(url, tokenBeg);
|
2015-01-23 17:32:49 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterDataHolder.prototype.logData = function() {
|
|
|
|
|
var out = this.wrapped.logData();
|
2017-05-25 23:46:59 +02:00
|
|
|
|
out.compiled = [ this.fid, this.dataType, this.dataStr, out.compiled ];
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var opt = this.dataType;
|
|
|
|
|
if ( this.dataStr !== '' ) {
|
|
|
|
|
opt += '=' + this.dataStr;
|
|
|
|
|
}
|
|
|
|
|
if ( out.opts === undefined ) {
|
|
|
|
|
out.opts = opt;
|
|
|
|
|
} else {
|
|
|
|
|
out.opts = opt + ',' + out.opts;
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
};
|
2015-01-23 17:32:49 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterDataHolder.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid, this.dataType, this.dataStr, this.wrapped.compile() ];
|
2015-01-23 17:32:49 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterDataHolder.compile = function(details) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ FilterDataHolder.fid, details.dataType, details.dataStr ];
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterDataHolder.load = function(args) {
|
|
|
|
|
var f = new FilterDataHolder(args[1], args[2]);
|
|
|
|
|
f.wrapped = filterFromCompiledData(args[3]);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return f;
|
2015-01-23 17:32:49 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterDataHolder);
|
2015-01-23 17:32:49 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
// Helper class for storing instances of FilterDataHolder.
|
2015-01-23 17:32:49 +01:00
|
|
|
|
|
2017-05-19 14:45:19 +02:00
|
|
|
|
var FilterDataHolderEntry = function(categoryBits, tokenHash, fdata) {
|
|
|
|
|
this.categoryBits = categoryBits;
|
|
|
|
|
this.tokenHash = tokenHash;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.filter = filterFromCompiledData(fdata);
|
|
|
|
|
this.next = undefined;
|
2015-01-23 17:32:49 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterDataHolderEntry.prototype.logData = function() {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
return toLogDataInternal(this.categoryBits, this.tokenHash, this.filter);
|
2015-02-24 00:31:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterDataHolderEntry.prototype.compile = function() {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.categoryBits, this.tokenHash, this.filter.compile() ];
|
2015-01-23 17:32:49 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterDataHolderEntry.load = function(data) {
|
|
|
|
|
return new FilterDataHolderEntry(data[0], data[1], data[2]);
|
2015-01-23 17:32:49 +01:00
|
|
|
|
};
|
|
|
|
|
|
2014-09-08 23:46:58 +02:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2015-02-05 00:06:31 +01:00
|
|
|
|
// Dictionary of hostnames
|
2015-02-05 14:45:29 +01:00
|
|
|
|
//
|
2015-02-05 00:06:31 +01:00
|
|
|
|
var FilterHostnameDict = function() {
|
|
|
|
|
this.h = ''; // short-lived register
|
2016-09-12 16:22:25 +02:00
|
|
|
|
this.dict = new Set();
|
2015-02-05 00:06:31 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-03-20 20:54:41 +01:00
|
|
|
|
Object.defineProperty(FilterHostnameDict.prototype, 'size', {
|
|
|
|
|
get: function() {
|
|
|
|
|
return this.dict.size;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2015-02-05 00:06:31 +01:00
|
|
|
|
FilterHostnameDict.prototype.add = function(hn) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
if ( this.dict.has(hn) === true ) { return false; }
|
2016-09-12 16:22:25 +02:00
|
|
|
|
this.dict.add(hn);
|
2015-02-24 00:31:29 +01:00
|
|
|
|
return true;
|
2015-02-05 00:06:31 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-03-20 20:54:41 +01:00
|
|
|
|
FilterHostnameDict.prototype.remove = function(hn) {
|
|
|
|
|
return this.dict.delete(hn);
|
|
|
|
|
};
|
|
|
|
|
|
2015-02-24 00:31:29 +01:00
|
|
|
|
FilterHostnameDict.prototype.match = function() {
|
2015-02-05 00:06:31 +01:00
|
|
|
|
// TODO: mind IP addresses
|
|
|
|
|
var pos,
|
|
|
|
|
hostname = requestHostnameRegister;
|
2016-09-12 16:22:25 +02:00
|
|
|
|
while ( this.dict.has(hostname) === false ) {
|
2015-02-05 00:06:31 +01:00
|
|
|
|
pos = hostname.indexOf('.');
|
|
|
|
|
if ( pos === -1 ) {
|
|
|
|
|
this.h = '';
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
hostname = hostname.slice(pos + 1);
|
|
|
|
|
}
|
2015-06-09 16:27:08 +02:00
|
|
|
|
this.h = hostname;
|
2017-05-20 03:07:37 +02:00
|
|
|
|
return true;
|
2015-02-05 00:06:31 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterHostnameDict.prototype.logData = function() {
|
|
|
|
|
return {
|
|
|
|
|
raw: '||' + this.h + '^',
|
|
|
|
|
regex: rawToRegexStr(this.h) + '(?:[^%.0-9a-z_-]|$)',
|
|
|
|
|
compiled: this.h
|
|
|
|
|
};
|
2015-02-05 00:06:31 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterHostnameDict.prototype.compile = function() {
|
2018-06-01 13:54:31 +02:00
|
|
|
|
return [ this.fid, Array.from(this.dict) ];
|
2015-02-05 00:06:31 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterHostnameDict.load = function(args) {
|
2015-02-05 00:06:31 +01:00
|
|
|
|
var f = new FilterHostnameDict();
|
2017-10-21 19:43:46 +02:00
|
|
|
|
f.dict = new Set(args[1]);
|
2015-02-05 00:06:31 +01:00
|
|
|
|
return f;
|
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterHostnameDict);
|
|
|
|
|
|
2015-02-05 00:06:31 +01:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2014-09-22 02:26:16 +02:00
|
|
|
|
// Some buckets can grow quite large, and finding a hit in these buckets
|
|
|
|
|
// may end up being expensive. After considering various solutions, the one
|
2014-10-17 21:44:19 +02:00
|
|
|
|
// retained is to promote hit filters to a smaller index, so that next time
|
2014-09-22 02:26:16 +02:00
|
|
|
|
// they can be looked-up faster.
|
2014-09-19 16:59:44 +02:00
|
|
|
|
|
2014-09-21 20:03:41 +02:00
|
|
|
|
// key= 10000 ad count=660
|
|
|
|
|
// key= 10000 ads count=433
|
|
|
|
|
// key= 10001 google count=277
|
|
|
|
|
// key=1000000 2mdn count=267
|
|
|
|
|
// key= 10000 social count=240
|
|
|
|
|
// key= 10001 pagead2 count=166
|
|
|
|
|
// key= 10000 twitter count=122
|
|
|
|
|
// key= 10000 doubleclick count=118
|
|
|
|
|
// key= 10000 facebook count=114
|
|
|
|
|
// key= 10000 share count=113
|
|
|
|
|
// key= 10000 google count=106
|
|
|
|
|
// key= 10001 code count=103
|
|
|
|
|
// key= 11000 doubleclick count=100
|
|
|
|
|
// key=1010001 g count=100
|
|
|
|
|
// key= 10001 js count= 89
|
|
|
|
|
// key= 10000 adv count= 88
|
|
|
|
|
// key= 10000 youtube count= 61
|
|
|
|
|
// key= 10000 plugins count= 60
|
|
|
|
|
// key= 10001 partner count= 59
|
|
|
|
|
// key= 10000 ico count= 57
|
|
|
|
|
// key= 110001 ssl count= 57
|
|
|
|
|
// key= 10000 banner count= 53
|
|
|
|
|
// key= 10000 footer count= 51
|
|
|
|
|
// key= 10000 rss count= 51
|
2014-09-19 16:59:44 +02:00
|
|
|
|
|
2014-09-22 02:26:16 +02:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-27 02:00:21 +02:00
|
|
|
|
var FilterPair = function(a, b) {
|
|
|
|
|
this.f1 = a;
|
|
|
|
|
this.f2 = b;
|
|
|
|
|
this.f = null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Object.defineProperty(FilterPair.prototype, 'size', {
|
|
|
|
|
get: function() {
|
|
|
|
|
if ( this.f1 === undefined && this.f2 === undefined ) { return 0; }
|
|
|
|
|
if ( this.f1 === undefined || this.f2 === undefined ) { return 1; }
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
FilterPair.prototype.remove = function(fdata) {
|
|
|
|
|
if ( arrayStrictEquals(this.f2.compile(), fdata) === true ) {
|
|
|
|
|
this.f2 = undefined;
|
|
|
|
|
}
|
|
|
|
|
if ( arrayStrictEquals(this.f1.compile(), fdata) === true ) {
|
|
|
|
|
this.f1 = this.f2;
|
|
|
|
|
}
|
2018-06-24 01:15:56 +02:00
|
|
|
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/84
|
|
|
|
|
if ( this.f1 === undefined ) {
|
|
|
|
|
console.log(JSON.stringify(fdata));
|
|
|
|
|
}
|
2017-05-27 02:00:21 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterPair.prototype.match = function(url, tokenBeg) {
|
|
|
|
|
if ( this.f1.match(url, tokenBeg) === true ) {
|
|
|
|
|
this.f = this.f1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if ( this.f2.match(url, tokenBeg) === true ) {
|
|
|
|
|
this.f = this.f2;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterPair.prototype.logData = function() {
|
|
|
|
|
return this.f.logData();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterPair.prototype.compile = function() {
|
|
|
|
|
return [ this.fid, this.f1.compile(), this.f2.compile() ];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterPair.prototype.upgrade = function(a) {
|
|
|
|
|
var bucket = new FilterBucket(this.f1, this.f2, a);
|
2018-06-24 01:15:56 +02:00
|
|
|
|
this.f1 = this.f2 = undefined;
|
|
|
|
|
this.f = null;
|
2017-05-27 02:00:21 +02:00
|
|
|
|
FilterPair.available = this;
|
|
|
|
|
return bucket;
|
|
|
|
|
};
|
|
|
|
|
|
2018-06-24 01:15:56 +02:00
|
|
|
|
FilterPair.prototype.downgrade = function() {
|
|
|
|
|
if ( this.f2 !== undefined ) { return this; }
|
|
|
|
|
if ( this.f1 !== undefined ) { return this.f1; }
|
|
|
|
|
};
|
|
|
|
|
|
2017-05-27 02:00:21 +02:00
|
|
|
|
FilterPair.load = function(args) {
|
|
|
|
|
var f1 = filterFromCompiledData(args[1]),
|
|
|
|
|
f2 = filterFromCompiledData(args[2]),
|
|
|
|
|
pair = FilterPair.available;
|
|
|
|
|
if ( pair === null ) {
|
|
|
|
|
return new FilterPair(f1, f2);
|
|
|
|
|
}
|
|
|
|
|
FilterPair.available = null;
|
|
|
|
|
pair.f1 = f1;
|
|
|
|
|
pair.f2 = f2;
|
|
|
|
|
return pair;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FilterPair.available = null;
|
|
|
|
|
|
|
|
|
|
registerFilterClass(FilterPair);
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
var FilterBucket = function(a, b, c) {
|
2014-09-08 23:46:58 +02:00
|
|
|
|
this.filters = [];
|
2017-05-25 23:46:59 +02:00
|
|
|
|
this.f = null;
|
2014-09-08 23:46:58 +02:00
|
|
|
|
if ( a !== undefined ) {
|
|
|
|
|
this.filters[0] = a;
|
2017-05-25 23:46:59 +02:00
|
|
|
|
this.filters[1] = b;
|
2017-05-27 02:00:21 +02:00
|
|
|
|
this.filters[2] = c;
|
2014-09-08 23:46:58 +02:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-05-27 02:00:21 +02:00
|
|
|
|
Object.defineProperty(FilterBucket.prototype, 'size', {
|
|
|
|
|
get: function() {
|
|
|
|
|
return this.filters.length;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterBucket.prototype.promoted = 0;
|
|
|
|
|
|
|
|
|
|
FilterBucket.prototype.add = function(fdata) {
|
|
|
|
|
this.filters[this.filters.length] = filterFromCompiledData(fdata);
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterBucket.prototype.remove = function(fdata) {
|
2017-03-11 19:55:47 +01:00
|
|
|
|
var i = this.filters.length,
|
|
|
|
|
filter;
|
|
|
|
|
while ( i-- ) {
|
|
|
|
|
filter = this.filters[i];
|
2017-05-27 02:00:21 +02:00
|
|
|
|
if ( arrayStrictEquals(filter.compile(), fdata) === true ) {
|
2017-03-11 19:55:47 +01:00
|
|
|
|
this.filters.splice(i, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-09-22 02:26:16 +02:00
|
|
|
|
// Promote hit filters so they can be found faster next time.
|
|
|
|
|
FilterBucket.prototype.promote = function(i) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
var filters = this.filters,
|
|
|
|
|
pivot = filters.length >>> 1;
|
2014-09-22 02:26:16 +02:00
|
|
|
|
while ( i < pivot ) {
|
|
|
|
|
pivot >>>= 1;
|
2017-05-25 23:46:59 +02:00
|
|
|
|
if ( pivot < 16 ) { break; }
|
2014-09-22 02:26:16 +02:00
|
|
|
|
}
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( i <= pivot ) { return; }
|
2014-09-22 02:26:16 +02:00
|
|
|
|
var j = this.promoted % pivot;
|
|
|
|
|
//console.debug('FilterBucket.promote(): promoted %d to %d', i, j);
|
|
|
|
|
var f = filters[j];
|
|
|
|
|
filters[j] = filters[i];
|
|
|
|
|
filters[i] = f;
|
|
|
|
|
this.promoted += 1;
|
|
|
|
|
};
|
|
|
|
|
|
2014-09-08 23:46:58 +02:00
|
|
|
|
FilterBucket.prototype.match = function(url, tokenBeg) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
var filters = this.filters;
|
|
|
|
|
for ( var i = 0, n = filters.length; i < n; i++ ) {
|
|
|
|
|
if ( filters[i].match(url, tokenBeg) === true ) {
|
2014-09-08 23:46:58 +02:00
|
|
|
|
this.f = filters[i];
|
2017-05-25 23:46:59 +02:00
|
|
|
|
if ( i >= 16 ) { this.promote(i); }
|
2014-09-08 23:46:58 +02:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterBucket.prototype.logData = function() {
|
|
|
|
|
return this.f.logData();
|
|
|
|
|
};
|
2014-09-08 23:46:58 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterBucket.prototype.compile = function() {
|
|
|
|
|
var compiled = [],
|
|
|
|
|
filters = this.filters;
|
|
|
|
|
for ( var i = 0, n = filters.length; i < n; i++ ) {
|
|
|
|
|
compiled[i] = filters[i].compile();
|
|
|
|
|
}
|
2017-05-25 23:46:59 +02:00
|
|
|
|
return [ this.fid, compiled ];
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-30 17:38:45 +02:00
|
|
|
|
FilterBucket.prototype.downgrade = function() {
|
2018-06-24 01:15:56 +02:00
|
|
|
|
if ( this.filters.length > 2 ) { return this; }
|
|
|
|
|
if ( this.filters.length === 2 ) {
|
|
|
|
|
return new FilterPair(this.filters[0], this.filters[1]);
|
|
|
|
|
}
|
|
|
|
|
if ( this.filters.length === 1 ) { return this.filters[0]; }
|
2017-05-30 17:38:45 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterBucket.load = function(args) {
|
2017-05-27 02:00:21 +02:00
|
|
|
|
var bucket = new FilterBucket(),
|
2017-05-25 23:46:59 +02:00
|
|
|
|
compiledFilters = args[1],
|
2017-05-27 02:00:21 +02:00
|
|
|
|
filters = bucket.filters;
|
2017-05-25 23:46:59 +02:00
|
|
|
|
for ( var i = 0, n = compiledFilters.length; i < n; i++ ) {
|
|
|
|
|
filters[i] = filterFromCompiledData(compiledFilters[i]);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
}
|
2017-05-27 02:00:21 +02:00
|
|
|
|
return bucket;
|
2015-06-09 16:27:08 +02:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
registerFilterClass(FilterBucket);
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
var FilterParser = function() {
|
2016-08-31 01:57:25 +02:00
|
|
|
|
this.cantWebsocket = vAPI.cantWebsocket;
|
2017-01-09 14:56:42 +01:00
|
|
|
|
this.reBadDomainOptChars = /[*+?^${}()[\]\\]/;
|
2016-03-12 07:25:02 +01:00
|
|
|
|
this.reHostnameRule1 = /^[0-9a-z][0-9a-z.-]*[0-9a-z]$/i;
|
2017-05-30 17:38:45 +02:00
|
|
|
|
this.reHostnameRule2 = /^[0-9a-z][0-9a-z.-]*[0-9a-z]\^?$/i;
|
|
|
|
|
this.reCleanupHostnameRule2 = /\^$/g;
|
2015-12-13 17:03:13 +01:00
|
|
|
|
this.reCanTrimCarets1 = /^[^*]*$/;
|
|
|
|
|
this.reCanTrimCarets2 = /^\^?[^^]+[^^][^^]+\^?$/;
|
2015-01-23 17:32:49 +01:00
|
|
|
|
this.reHasUppercase = /[A-Z]/;
|
2015-12-13 18:55:55 +01:00
|
|
|
|
this.reIsolateHostname = /^(\*?\.)?([^\x00-\x24\x26-\x2C\x2F\x3A-\x5E\x60\x7B-\x7F]+)(.*)/;
|
2015-02-27 00:08:42 +01:00
|
|
|
|
this.reHasUnicode = /[^\x00-\x7F]/;
|
2016-09-06 00:56:35 +02:00
|
|
|
|
this.reWebsocketAny = /^ws[s*]?(?::\/?\/?)?\*?$/;
|
2017-05-16 18:44:12 +02:00
|
|
|
|
this.reBadCSP = /(?:^|;)\s*report-(?:to|uri)\b/;
|
2015-08-22 18:15:16 +02:00
|
|
|
|
this.domainOpt = '';
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.noTokenHash = µb.urlTokenizer.tokenHashFromString('*');
|
2017-09-14 05:41:20 +02:00
|
|
|
|
this.unsupportedTypeBit = this.bitFromType('unsupported');
|
|
|
|
|
// All network request types to bitmap
|
|
|
|
|
// bring origin to 0 (from 4 -- see typeNameToTypeValue)
|
|
|
|
|
// left-shift 1 by the above-calculated value
|
|
|
|
|
// subtract 1 to set all type bits
|
|
|
|
|
this.allNetRequestTypeBits = (1 << (otherTypeBitValue >>> 4)) - 1;
|
2014-08-28 15:59:05 +02:00
|
|
|
|
this.reset();
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2016-11-06 16:49:02 +01:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/1493
|
|
|
|
|
// Transpose `ping` into `other` for now.
|
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
FilterParser.prototype.toNormalizedType = {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
'beacon': 'other',
|
2018-02-26 20:08:16 +01:00
|
|
|
|
'css': 'stylesheet',
|
2017-05-12 16:35:11 +02:00
|
|
|
|
'data': 'data',
|
|
|
|
|
'document': 'main_frame',
|
|
|
|
|
'elemhide': 'generichide',
|
2015-04-05 16:38:47 +02:00
|
|
|
|
'font': 'font',
|
2018-02-26 20:08:16 +01:00
|
|
|
|
'frame': 'sub_frame',
|
2017-09-14 23:54:59 +02:00
|
|
|
|
'genericblock': 'unsupported',
|
2017-05-12 16:35:11 +02:00
|
|
|
|
'generichide': 'generichide',
|
|
|
|
|
'image': 'image',
|
2017-09-16 13:49:43 +02:00
|
|
|
|
'inline-font': 'inline-font',
|
2017-05-12 16:35:11 +02:00
|
|
|
|
'inline-script': 'inline-script',
|
2016-03-07 01:16:46 +01:00
|
|
|
|
'media': 'media',
|
2017-05-12 16:35:11 +02:00
|
|
|
|
'object': 'object',
|
|
|
|
|
'object-subrequest': 'object',
|
2017-11-03 21:51:28 +01:00
|
|
|
|
'other': 'other',
|
2016-11-06 16:49:02 +01:00
|
|
|
|
'ping': 'other',
|
2015-12-04 17:15:09 +01:00
|
|
|
|
'popunder': 'popunder',
|
2017-05-12 16:35:11 +02:00
|
|
|
|
'popup': 'popup',
|
|
|
|
|
'script': 'script',
|
|
|
|
|
'stylesheet': 'stylesheet',
|
|
|
|
|
'subdocument': 'sub_frame',
|
2018-02-26 20:08:16 +01:00
|
|
|
|
'xhr': 'xmlhttprequest',
|
2017-05-12 16:35:11 +02:00
|
|
|
|
'xmlhttprequest': 'xmlhttprequest',
|
2017-09-14 05:41:20 +02:00
|
|
|
|
'webrtc': 'unsupported',
|
2017-05-12 16:35:11 +02:00
|
|
|
|
'websocket': 'websocket'
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
FilterParser.prototype.reset = function() {
|
|
|
|
|
this.action = BlockAction;
|
|
|
|
|
this.anchor = 0;
|
2017-05-25 23:46:59 +02:00
|
|
|
|
this.badFilter = 0;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.dataType = undefined;
|
|
|
|
|
this.dataStr = undefined;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
this.elemHiding = false;
|
|
|
|
|
this.f = '';
|
|
|
|
|
this.firstParty = false;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.thirdParty = false;
|
|
|
|
|
this.party = AnyParty;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
this.fopts = '';
|
2014-09-19 16:59:44 +02:00
|
|
|
|
this.hostnamePure = false;
|
2015-08-22 18:15:16 +02:00
|
|
|
|
this.domainOpt = '';
|
2015-01-23 17:32:49 +01:00
|
|
|
|
this.isRegex = false;
|
2015-11-24 01:18:25 +01:00
|
|
|
|
this.raw = '';
|
|
|
|
|
this.redirect = false;
|
2015-12-04 03:24:37 +01:00
|
|
|
|
this.token = '*';
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.tokenHash = this.noTokenHash;
|
2015-01-23 17:32:49 +01:00
|
|
|
|
this.tokenBeg = 0;
|
2015-01-24 03:47:56 +01:00
|
|
|
|
this.types = 0;
|
2014-08-29 21:02:31 +02:00
|
|
|
|
this.important = 0;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
this.unsupported = false;
|
|
|
|
|
return this;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2016-08-31 01:57:25 +02:00
|
|
|
|
FilterParser.prototype.bitFromType = function(type) {
|
|
|
|
|
return 1 << ((typeNameToTypeValue[type] >>> 4) - 1);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2015-04-07 03:26:05 +02:00
|
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/589
|
2015-01-24 03:47:56 +01:00
|
|
|
|
// Be ready to handle multiple negated types
|
|
|
|
|
|
2017-01-09 15:53:57 +01:00
|
|
|
|
FilterParser.prototype.parseTypeOption = function(raw, not) {
|
2016-08-31 01:57:25 +02:00
|
|
|
|
var typeBit = this.bitFromType(this.toNormalizedType[raw]);
|
2015-01-24 03:47:56 +01:00
|
|
|
|
|
|
|
|
|
if ( !not ) {
|
2015-03-26 00:28:22 +01:00
|
|
|
|
this.types |= typeBit;
|
2015-01-24 03:47:56 +01:00
|
|
|
|
return;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
2015-01-24 03:47:56 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
// Non-discrete network types can't be negated.
|
2017-09-14 05:41:20 +02:00
|
|
|
|
if ( (typeBit & this.allNetRequestTypeBits) === 0 ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-08 04:20:24 +01:00
|
|
|
|
// Negated type: set all valid network request type bits to 1
|
2016-03-15 16:18:34 +01:00
|
|
|
|
if (
|
2017-09-14 05:41:20 +02:00
|
|
|
|
(typeBit & this.allNetRequestTypeBits) !== 0 &&
|
|
|
|
|
(this.types & this.allNetRequestTypeBits) === 0
|
2016-03-15 16:18:34 +01:00
|
|
|
|
) {
|
2017-09-14 05:41:20 +02:00
|
|
|
|
this.types |= this.allNetRequestTypeBits;
|
2015-01-24 03:47:56 +01:00
|
|
|
|
}
|
2016-03-15 16:18:34 +01:00
|
|
|
|
this.types &= ~typeBit;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-01-09 15:53:57 +01:00
|
|
|
|
FilterParser.prototype.parsePartyOption = function(firstParty, not) {
|
2015-06-07 00:31:38 +02:00
|
|
|
|
if ( firstParty ) {
|
|
|
|
|
not = !not;
|
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
|
if ( not ) {
|
|
|
|
|
this.firstParty = true;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.party = this.thirdParty ? AnyParty : FirstParty;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
} else {
|
|
|
|
|
this.thirdParty = true;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.party = this.firstParty ? AnyParty : ThirdParty;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-01-09 15:53:57 +01:00
|
|
|
|
FilterParser.prototype.parseDomainOption = function(s) {
|
|
|
|
|
if ( this.reHasUnicode.test(s) ) {
|
|
|
|
|
var hostnames = s.split('|'),
|
|
|
|
|
i = hostnames.length;
|
|
|
|
|
while ( i-- ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( this.reHasUnicode.test(hostnames[i]) ) {
|
|
|
|
|
hostnames[i] = punycode.toASCII(hostnames[i]);
|
|
|
|
|
}
|
2017-01-09 15:53:57 +01:00
|
|
|
|
}
|
|
|
|
|
s = hostnames.join('|');
|
|
|
|
|
}
|
|
|
|
|
if ( this.reBadDomainOptChars.test(s) ) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2015-01-23 17:32:49 +01:00
|
|
|
|
FilterParser.prototype.parseOptions = function(s) {
|
|
|
|
|
this.fopts = s;
|
|
|
|
|
var opts = s.split(',');
|
|
|
|
|
var opt, not;
|
|
|
|
|
for ( var i = 0; i < opts.length; i++ ) {
|
|
|
|
|
opt = opts[i];
|
2015-12-15 16:40:40 +01:00
|
|
|
|
not = opt.startsWith('~');
|
2014-06-24 00:42:43 +02:00
|
|
|
|
if ( not ) {
|
2015-01-23 17:32:49 +01:00
|
|
|
|
opt = opt.slice(1);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
2018-02-26 20:08:16 +01:00
|
|
|
|
if ( opt === 'third-party' || opt === '3p' ) {
|
2017-01-09 15:53:57 +01:00
|
|
|
|
this.parsePartyOption(false, not);
|
2015-01-23 17:32:49 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-10-05 17:03:20 +02:00
|
|
|
|
// https://issues.adblockplus.org/ticket/616
|
2015-10-05 17:04:36 +02:00
|
|
|
|
// `generichide` concept already supported, just a matter of
|
2015-10-05 16:58:24 +02:00
|
|
|
|
// adding support for the new keyword.
|
2015-10-05 17:03:20 +02:00
|
|
|
|
if ( opt === 'elemhide' || opt === 'generichide' ) {
|
2016-11-08 13:13:26 +01:00
|
|
|
|
if ( not === false ) {
|
2017-01-09 15:53:57 +01:00
|
|
|
|
this.parseTypeOption('generichide', false);
|
2015-03-26 00:28:22 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
this.unsupported = true;
|
|
|
|
|
break;
|
2015-01-23 17:32:49 +01:00
|
|
|
|
}
|
2017-05-25 23:46:59 +02:00
|
|
|
|
// Test before handling all other types.
|
|
|
|
|
if ( opt.startsWith('redirect=') ) {
|
|
|
|
|
if ( this.action === BlockAction ) {
|
|
|
|
|
this.redirect = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
this.unsupported = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-01-23 17:32:49 +01:00
|
|
|
|
if ( this.toNormalizedType.hasOwnProperty(opt) ) {
|
2017-01-09 15:53:57 +01:00
|
|
|
|
this.parseTypeOption(opt, not);
|
2015-01-23 17:32:49 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-01-09 14:56:42 +01:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/2294
|
|
|
|
|
// Detect and discard filter if domain option contains nonsensical
|
|
|
|
|
// characters.
|
2015-12-15 16:40:40 +01:00
|
|
|
|
if ( opt.startsWith('domain=') ) {
|
2017-01-09 15:53:57 +01:00
|
|
|
|
this.domainOpt = this.parseDomainOption(opt.slice(7));
|
|
|
|
|
if ( this.domainOpt === '' ) {
|
2017-01-09 14:56:42 +01:00
|
|
|
|
this.unsupported = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-01-23 17:32:49 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if ( opt === 'important' ) {
|
|
|
|
|
this.important = Important;
|
|
|
|
|
continue;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
2018-02-26 20:08:16 +01:00
|
|
|
|
if ( opt === 'first-party' || opt === '1p' ) {
|
2017-01-09 15:53:57 +01:00
|
|
|
|
this.parsePartyOption(true, not);
|
2015-06-07 00:31:38 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( opt.startsWith('csp=') ) {
|
2017-05-16 18:44:12 +02:00
|
|
|
|
if ( opt.length > 4 && this.reBadCSP.test(opt) === false ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.parseTypeOption('data', not);
|
|
|
|
|
this.dataType = 'csp';
|
|
|
|
|
this.dataStr = opt.slice(4).trim();
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if ( opt === 'csp' && this.action === AllowAction ) {
|
|
|
|
|
this.parseTypeOption('data', not);
|
|
|
|
|
this.dataType = 'csp';
|
|
|
|
|
this.dataStr = '';
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-12-18 18:19:13 +01:00
|
|
|
|
// Used by Adguard, purpose is unclear -- just ignore for now.
|
|
|
|
|
if ( opt === 'empty' ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-03-11 19:55:47 +01:00
|
|
|
|
// https://github.com/uBlockOrigin/uAssets/issues/192
|
|
|
|
|
if ( opt === 'badfilter' ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
this.badFilter = BadFilter;
|
2017-03-11 19:55:47 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-11-24 05:34:03 +01:00
|
|
|
|
// Unrecognized filter option: ignore whole filter.
|
2015-01-23 17:32:49 +01:00
|
|
|
|
this.unsupported = true;
|
|
|
|
|
break;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/1943#issuecomment-243188946
|
|
|
|
|
// Convert websocket-related filter where possible to a format which
|
|
|
|
|
// can be handled using CSP injection.
|
|
|
|
|
|
|
|
|
|
FilterParser.prototype.translate = function() {
|
|
|
|
|
var dataTypeBit = this.bitFromType('data');
|
|
|
|
|
|
|
|
|
|
if ( this.cantWebsocket && this.reWebsocketAny.test(this.f) ) {
|
|
|
|
|
this.f = '*';
|
|
|
|
|
this.types = dataTypeBit;
|
|
|
|
|
this.dataType = 'csp';
|
|
|
|
|
this.dataStr = "connect-src https: http:";
|
|
|
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=669086
|
|
|
|
|
// TODO: remove when most users are beyond Chromium v56
|
2018-04-05 13:29:15 +02:00
|
|
|
|
if (
|
|
|
|
|
vAPI.webextFlavor.soup.has('chromium') &&
|
|
|
|
|
vAPI.webextFlavor.major < 57
|
|
|
|
|
) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.dataStr += '; frame-src *';
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Broad |data:-based filters.
|
|
|
|
|
if ( this.f === 'data:' ) {
|
|
|
|
|
switch ( this.types ) {
|
|
|
|
|
case 0:
|
|
|
|
|
this.f = '*';
|
|
|
|
|
this.types = dataTypeBit;
|
|
|
|
|
this.dataType = 'csp';
|
|
|
|
|
this.dataStr = "default-src 'self' * blob: 'unsafe-inline' 'unsafe-eval'";
|
|
|
|
|
break;
|
|
|
|
|
case this.bitFromType('script'):
|
|
|
|
|
this.f = '*';
|
|
|
|
|
this.types = dataTypeBit;
|
|
|
|
|
this.dataType = 'csp';
|
|
|
|
|
this.dataStr = "script-src 'self' * blob: 'unsafe-inline' 'unsafe-eval'";
|
|
|
|
|
break;
|
|
|
|
|
case this.bitFromType('sub_frame'):
|
|
|
|
|
this.f = '*';
|
|
|
|
|
this.types = dataTypeBit;
|
|
|
|
|
this.dataType = 'csp';
|
|
|
|
|
this.dataStr = "frame-src 'self' * blob:";
|
|
|
|
|
break;
|
|
|
|
|
case this.bitFromType('script') | this.bitFromType('sub_frame'):
|
|
|
|
|
this.f = '*';
|
|
|
|
|
this.types = dataTypeBit;
|
|
|
|
|
this.dataType = 'csp';
|
|
|
|
|
this.dataStr = "frame-src 'self' * blob:; script-src 'self' * blob: 'unsafe-inline' 'unsafe-eval';";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Broad |blob:-based filters.
|
|
|
|
|
if ( this.f === 'blob:' ) {
|
|
|
|
|
switch ( this.types ) {
|
|
|
|
|
case 0:
|
|
|
|
|
this.f = '*';
|
|
|
|
|
this.types = dataTypeBit;
|
|
|
|
|
this.dataType = 'csp';
|
|
|
|
|
this.dataStr = "default-src 'self' * data: 'unsafe-inline' 'unsafe-eval'";
|
|
|
|
|
break;
|
|
|
|
|
case this.bitFromType('script'):
|
|
|
|
|
this.f = '*';
|
|
|
|
|
this.types = dataTypeBit;
|
|
|
|
|
this.dataType = 'csp';
|
|
|
|
|
this.dataStr = "script-src 'self' * data: 'unsafe-inline' 'unsafe-eval'";
|
|
|
|
|
break;
|
|
|
|
|
case this.bitFromType('sub_frame'):
|
|
|
|
|
this.f = '*';
|
|
|
|
|
this.types = dataTypeBit;
|
|
|
|
|
this.dataType = 'csp';
|
|
|
|
|
this.dataStr = "frame-src 'self' * data:";
|
|
|
|
|
break;
|
|
|
|
|
case this.bitFromType('script') | this.bitFromType('sub_frame'):
|
|
|
|
|
this.f = '*';
|
|
|
|
|
this.types = dataTypeBit;
|
|
|
|
|
this.dataType = 'csp';
|
|
|
|
|
this.dataStr = "frame-src 'self' * data:; script-src 'self' * data: 'unsafe-inline' 'unsafe-eval';";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
|
|
|
|
|
|
anchor: bit vector
|
|
|
|
|
0000 (0x0): no anchoring
|
|
|
|
|
0001 (0x1): anchored to the end of the URL.
|
|
|
|
|
0010 (0x2): anchored to the start of the URL.
|
|
|
|
|
0011 (0x3): anchored to the start and end of the URL.
|
|
|
|
|
0100 (0x4): anchored to the hostname of the URL.
|
|
|
|
|
0101 (0x5): anchored to the hostname and end of the URL.
|
|
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
2015-02-27 00:08:42 +01:00
|
|
|
|
FilterParser.prototype.parse = function(raw) {
|
2014-06-24 00:42:43 +02:00
|
|
|
|
// important!
|
|
|
|
|
this.reset();
|
|
|
|
|
|
2015-11-24 01:18:25 +01:00
|
|
|
|
var s = this.raw = raw;
|
2015-02-27 00:08:42 +01:00
|
|
|
|
|
2015-12-13 18:55:55 +01:00
|
|
|
|
// plain hostname? (from HOSTS file)
|
|
|
|
|
if ( this.reHostnameRule1.test(s) ) {
|
2014-09-19 16:59:44 +02:00
|
|
|
|
this.f = s;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.hostnamePure = true;
|
|
|
|
|
this.anchor |= 0x4;
|
2014-09-19 16:59:44 +02:00
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
// element hiding filter?
|
2015-01-23 17:32:49 +01:00
|
|
|
|
var pos = s.indexOf('#');
|
|
|
|
|
if ( pos !== -1 ) {
|
|
|
|
|
var c = s.charAt(pos + 1);
|
|
|
|
|
if ( c === '#' || c === '@' ) {
|
|
|
|
|
console.error('static-net-filtering.js > unexpected cosmetic filters');
|
|
|
|
|
this.elemHiding = true;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-24 03:47:56 +01:00
|
|
|
|
// block or allow filter?
|
|
|
|
|
// Important: this must be executed before parsing options
|
2015-12-15 16:40:40 +01:00
|
|
|
|
if ( s.startsWith('@@') ) {
|
2015-01-24 03:47:56 +01:00
|
|
|
|
this.action = AllowAction;
|
|
|
|
|
s = s.slice(2);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-23 17:32:49 +01:00
|
|
|
|
// options
|
2015-11-06 16:49:09 +01:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/842
|
|
|
|
|
// - ensure sure we are not dealing with a regex-based filter.
|
|
|
|
|
// - lookup the last occurrence of `$`.
|
2015-12-15 16:40:40 +01:00
|
|
|
|
if ( s.startsWith('/') === false || s.endsWith('/') === false ) {
|
2015-11-06 16:49:09 +01:00
|
|
|
|
pos = s.lastIndexOf('$');
|
|
|
|
|
if ( pos !== -1 ) {
|
2015-11-30 20:47:56 +01:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/952
|
2017-09-14 05:41:20 +02:00
|
|
|
|
// Discard Adguard-specific `$$` filters.
|
2015-11-30 20:47:56 +01:00
|
|
|
|
if ( s.indexOf('$$') !== -1 ) {
|
|
|
|
|
this.unsupported = true;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
2015-11-06 16:49:09 +01:00
|
|
|
|
this.parseOptions(s.slice(pos + 1));
|
2017-09-14 05:41:20 +02:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/2283
|
|
|
|
|
// Abort if type is only for unsupported types, otherwise
|
|
|
|
|
// toggle off `unsupported` bit.
|
|
|
|
|
if ( this.types & this.unsupportedTypeBit ) {
|
2018-01-13 15:42:04 +01:00
|
|
|
|
this.types &= ~this.unsupportedTypeBit;
|
2017-09-14 05:41:20 +02:00
|
|
|
|
if ( this.types === 0 ) {
|
|
|
|
|
this.unsupported = true;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-11-06 16:49:09 +01:00
|
|
|
|
s = s.slice(0, pos);
|
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-01-23 17:32:49 +01:00
|
|
|
|
// regex?
|
2015-12-15 16:40:40 +01:00
|
|
|
|
if ( s.startsWith('/') && s.endsWith('/') && s.length > 2 ) {
|
2015-01-23 17:32:49 +01:00
|
|
|
|
this.isRegex = true;
|
|
|
|
|
this.f = s.slice(1, -1);
|
2016-01-17 02:21:17 +01:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/1246
|
|
|
|
|
// If the filter is valid, use the corrected version of the source
|
|
|
|
|
// string -- this ensure reverse-lookup will work fine.
|
|
|
|
|
this.f = normalizeRegexSource(this.f);
|
|
|
|
|
if ( this.f === '' ) {
|
2015-10-26 16:23:56 +01:00
|
|
|
|
console.error(
|
|
|
|
|
"uBlock Origin> discarding bad regular expression-based network filter '%s': '%s'",
|
|
|
|
|
raw,
|
2016-01-17 02:21:17 +01:00
|
|
|
|
normalizeRegexSource.message
|
2015-10-26 16:23:56 +01:00
|
|
|
|
);
|
|
|
|
|
this.unsupported = true;
|
|
|
|
|
}
|
2014-09-08 23:46:58 +02:00
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-27 00:08:42 +01:00
|
|
|
|
// hostname-anchored
|
2015-12-15 16:40:40 +01:00
|
|
|
|
if ( s.startsWith('||') ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.anchor |= 0x4;
|
2015-12-13 18:55:55 +01:00
|
|
|
|
s = s.slice(2);
|
|
|
|
|
|
2015-02-27 00:08:42 +01:00
|
|
|
|
// convert hostname to punycode if needed
|
2017-05-09 14:58:30 +02:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/2599
|
2015-02-27 00:08:42 +01:00
|
|
|
|
if ( this.reHasUnicode.test(s) ) {
|
|
|
|
|
var matches = this.reIsolateHostname.exec(s);
|
2015-12-13 18:55:55 +01:00
|
|
|
|
if ( matches ) {
|
2017-05-09 14:58:30 +02:00
|
|
|
|
s = (matches[1] !== undefined ? matches[1] : '') +
|
|
|
|
|
punycode.toASCII(matches[2]) +
|
|
|
|
|
matches[3];
|
2015-02-27 00:08:42 +01:00
|
|
|
|
//console.debug('µBlock.staticNetFilteringEngine/FilterParser.parse():', raw, '=', s);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-03-26 20:16:48 +01:00
|
|
|
|
|
2015-04-07 03:26:05 +02:00
|
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/1096
|
2015-12-15 16:40:40 +01:00
|
|
|
|
if ( s.startsWith('^') ) {
|
2015-03-26 20:16:48 +01:00
|
|
|
|
this.unsupported = true;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
2015-12-13 18:55:55 +01:00
|
|
|
|
|
|
|
|
|
// plain hostname? (from ABP filter list)
|
2016-06-27 03:15:18 +02:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/1757
|
2017-05-12 16:35:11 +02:00
|
|
|
|
// A filter can't be a pure-hostname one if there is a domain or csp
|
|
|
|
|
// option present.
|
|
|
|
|
if ( this.reHostnameRule2.test(s) ) {
|
2015-12-13 18:55:55 +01:00
|
|
|
|
this.f = s.replace(this.reCleanupHostnameRule2, '');
|
|
|
|
|
this.hostnamePure = true;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
|
|
|
|
// left-anchored
|
2017-05-12 16:35:11 +02:00
|
|
|
|
else if ( s.startsWith('|') ) {
|
|
|
|
|
this.anchor |= 0x2;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
s = s.slice(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// right-anchored
|
2015-12-15 16:40:40 +01:00
|
|
|
|
if ( s.endsWith('|') ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.anchor |= 0x1;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
s = s.slice(0, -1);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 17:38:45 +02:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/1669#issuecomment-224822448
|
|
|
|
|
// remove pointless leading *.
|
2017-09-18 19:06:36 +02:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/3034
|
|
|
|
|
// - We can remove anchoring if we need to match all at the start.
|
2017-05-30 17:38:45 +02:00
|
|
|
|
if ( s.startsWith('*') ) {
|
2018-03-07 16:37:18 +01:00
|
|
|
|
s = s.replace(/^\*+([^%0-9a-z])/i, '$1');
|
2017-09-18 19:06:36 +02:00
|
|
|
|
this.anchor &= ~0x6;
|
2017-05-30 17:38:45 +02:00
|
|
|
|
}
|
|
|
|
|
// remove pointless trailing *
|
2017-09-18 19:06:36 +02:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/3034
|
|
|
|
|
// - We can remove anchoring if we need to match all at the end.
|
2017-05-30 17:38:45 +02:00
|
|
|
|
if ( s.endsWith('*') ) {
|
2018-03-07 16:37:18 +01:00
|
|
|
|
s = s.replace(/([^%0-9a-z])\*+$/i, '$1');
|
2017-09-18 19:06:36 +02:00
|
|
|
|
this.anchor &= ~0x1;
|
2015-01-23 17:32:49 +01:00
|
|
|
|
}
|
2014-09-19 16:59:44 +02:00
|
|
|
|
|
2015-02-14 00:59:51 +01:00
|
|
|
|
// nothing left?
|
|
|
|
|
if ( s === '' ) {
|
2015-03-17 14:39:03 +01:00
|
|
|
|
s = '*';
|
2015-02-14 00:59:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-11 12:36:28 +01:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/1047
|
|
|
|
|
// Hostname-anchored makes no sense if matching all requests.
|
|
|
|
|
if ( s === '*' ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.anchor = 0;
|
2015-12-11 12:36:28 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-01-23 17:32:49 +01:00
|
|
|
|
// This might look weird but we gain memory footprint by not going through
|
|
|
|
|
// toLowerCase(), at least on Chromium. Because copy-on-write?
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
2015-01-23 17:32:49 +01:00
|
|
|
|
this.f = this.reHasUppercase.test(s) ? s.toLowerCase() : s;
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
// Convenience:
|
|
|
|
|
// Convert special broad filters for non-webRequest aware types into
|
|
|
|
|
// `csp` filters wherever possible.
|
|
|
|
|
if ( this.anchor & 0x2 && this.party === 0 ) {
|
|
|
|
|
this.translate();
|
2016-08-31 01:57:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-01-23 17:32:49 +01:00
|
|
|
|
return this;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2015-03-02 16:41:51 +01:00
|
|
|
|
// Given a string, find a good token. Tokens which are too generic, i.e. very
|
|
|
|
|
// common with a high probability of ending up as a miss, are not
|
|
|
|
|
// good. Avoid if possible. This has a *significant* positive impact on
|
|
|
|
|
// performance.
|
|
|
|
|
// These "bad tokens" are collated manually.
|
|
|
|
|
|
2015-12-04 03:24:37 +01:00
|
|
|
|
// Hostname-anchored with no wildcard always have a token index of 0.
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var reHostnameToken = /^[0-9a-z]+/;
|
2015-03-02 16:41:51 +01:00
|
|
|
|
var reGoodToken = /[%0-9a-z]{2,}/g;
|
2017-07-11 21:04:25 +02:00
|
|
|
|
var reRegexToken = /[%0-9A-Za-z]{2,}/g;
|
2017-07-13 20:34:43 +02:00
|
|
|
|
var reRegexTokenAbort = /[([]/;
|
|
|
|
|
var reRegexBadPrefix = /(^|[^\\]\.|[*?{}\\])$/;
|
|
|
|
|
var reRegexBadSuffix = /^([^\\]\.|\\[dw]|[([{}?*]|$)/;
|
2015-03-02 16:41:51 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var badTokens = new Set([
|
|
|
|
|
'com',
|
|
|
|
|
'http',
|
|
|
|
|
'https',
|
|
|
|
|
'icon',
|
|
|
|
|
'images',
|
|
|
|
|
'img',
|
|
|
|
|
'js',
|
|
|
|
|
'net',
|
|
|
|
|
'news',
|
|
|
|
|
'www'
|
|
|
|
|
]);
|
2015-03-02 16:41:51 +01:00
|
|
|
|
|
2017-07-11 19:57:31 +02:00
|
|
|
|
FilterParser.prototype.findFirstGoodToken = function() {
|
2015-03-02 16:41:51 +01:00
|
|
|
|
reGoodToken.lastIndex = 0;
|
2017-07-11 19:57:31 +02:00
|
|
|
|
var s = this.f,
|
|
|
|
|
matches, lpos,
|
2017-05-30 17:38:45 +02:00
|
|
|
|
badTokenMatch = null;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
while ( (matches = reGoodToken.exec(s)) !== null ) {
|
2015-12-03 16:06:06 +01:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/997
|
|
|
|
|
// Ignore token if preceded by wildcard.
|
|
|
|
|
lpos = matches.index;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( lpos !== 0 && s.charCodeAt(lpos - 1) === 0x2A /* '*' */ ) {
|
2015-12-03 16:06:06 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( s.charCodeAt(reGoodToken.lastIndex) === 0x2A /* '*' */ ) {
|
2015-03-02 22:22:23 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( badTokens.has(matches[0]) ) {
|
2015-12-04 03:24:37 +01:00
|
|
|
|
if ( badTokenMatch === null ) {
|
|
|
|
|
badTokenMatch = matches;
|
|
|
|
|
}
|
2015-03-02 16:41:51 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-03-02 22:22:23 +01:00
|
|
|
|
return matches;
|
|
|
|
|
}
|
2015-12-04 03:24:37 +01:00
|
|
|
|
return badTokenMatch;
|
2015-03-02 16:41:51 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-07-11 19:57:31 +02:00
|
|
|
|
FilterParser.prototype.extractTokenFromRegex = function() {
|
2017-07-11 21:04:25 +02:00
|
|
|
|
reRegexToken.lastIndex = 0;
|
2017-07-11 19:57:31 +02:00
|
|
|
|
var s = this.f,
|
2017-07-11 21:04:25 +02:00
|
|
|
|
matches, prefix;
|
|
|
|
|
while ( (matches = reRegexToken.exec(s)) !== null ) {
|
|
|
|
|
prefix = s.slice(0, matches.index);
|
|
|
|
|
if ( reRegexTokenAbort.test(prefix) ) { return; }
|
|
|
|
|
if (
|
|
|
|
|
reRegexBadPrefix.test(prefix) ||
|
|
|
|
|
reRegexBadSuffix.test(s.slice(reRegexToken.lastIndex))
|
|
|
|
|
) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
this.token = matches[0].toLowerCase();
|
|
|
|
|
this.tokenHash = µb.urlTokenizer.tokenHashFromString(this.token);
|
|
|
|
|
this.tokenBeg = matches.index;
|
|
|
|
|
if ( badTokens.has(this.token) === false ) { break; }
|
|
|
|
|
}
|
2017-07-11 19:57:31 +02:00
|
|
|
|
};
|
|
|
|
|
|
2015-03-02 22:22:23 +01:00
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-07-11 18:21:08 +02:00
|
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/1038
|
|
|
|
|
// Single asterisk will match any URL.
|
|
|
|
|
|
|
|
|
|
// https://github.com/gorhill/uBlock/issues/2781
|
|
|
|
|
// For efficiency purpose, try to extract a token from a regex-based filter.
|
|
|
|
|
|
2015-01-23 17:32:49 +01:00
|
|
|
|
FilterParser.prototype.makeToken = function() {
|
2017-07-11 18:21:08 +02:00
|
|
|
|
if ( this.isRegex ) {
|
2017-07-11 19:57:31 +02:00
|
|
|
|
this.extractTokenFromRegex();
|
2017-07-11 18:21:08 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( this.f === '*' ) { return; }
|
2015-01-23 17:32:49 +01:00
|
|
|
|
|
2017-07-11 19:57:31 +02:00
|
|
|
|
var matches = null;
|
2017-05-30 17:38:45 +02:00
|
|
|
|
if ( (this.anchor & 0x4) !== 0 && this.f.indexOf('*') === -1 ) {
|
|
|
|
|
matches = reHostnameToken.exec(this.f);
|
|
|
|
|
}
|
|
|
|
|
if ( matches === null ) {
|
2017-07-11 19:57:31 +02:00
|
|
|
|
matches = this.findFirstGoodToken();
|
2017-05-30 17:38:45 +02:00
|
|
|
|
}
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( matches !== null ) {
|
2015-12-04 03:24:37 +01:00
|
|
|
|
this.token = matches[0];
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.tokenHash = µb.urlTokenizer.tokenHashFromString(this.token);
|
2015-01-23 17:32:49 +01:00
|
|
|
|
this.tokenBeg = matches.index;
|
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
var FilterContainer = function() {
|
2015-12-05 18:25:18 +01:00
|
|
|
|
this.reIsGeneric = /[\^\*]/;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
this.filterParser = new FilterParser();
|
2015-12-29 17:34:41 +01:00
|
|
|
|
this.urlTokenizer = µb.urlTokenizer;
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.noTokenHash = this.urlTokenizer.tokenHashFromString('*');
|
|
|
|
|
this.dotTokenHash = this.urlTokenizer.tokenHashFromString('.');
|
2014-07-20 21:00:26 +02:00
|
|
|
|
this.reset();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
// Reset all, thus reducing to a minimum memory footprint of the context.
|
|
|
|
|
|
|
|
|
|
FilterContainer.prototype.reset = function() {
|
|
|
|
|
this.frozen = false;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
this.processedFilterCount = 0;
|
2014-07-16 16:43:34 +02:00
|
|
|
|
this.acceptedCount = 0;
|
2014-09-08 23:46:58 +02:00
|
|
|
|
this.rejectedCount = 0;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
this.allowFilterCount = 0;
|
|
|
|
|
this.blockFilterCount = 0;
|
2016-03-17 18:56:21 +01:00
|
|
|
|
this.discardedCount = 0;
|
2017-03-11 19:55:47 +01:00
|
|
|
|
this.badFilters = new Set();
|
2016-09-12 16:22:25 +02:00
|
|
|
|
this.duplicateBuster = new Set();
|
|
|
|
|
this.categories = new Map();
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.dataFilters = new Map();
|
2014-07-20 21:00:26 +02:00
|
|
|
|
this.filterParser.reset();
|
2015-06-09 16:27:08 +02:00
|
|
|
|
|
2017-01-06 18:39:37 +01:00
|
|
|
|
// Reuse filter instances whenever possible at load time.
|
|
|
|
|
this.fclassLast = null;
|
|
|
|
|
this.fdataLast = null;
|
|
|
|
|
this.filterLast = null;
|
|
|
|
|
|
2015-06-09 16:27:08 +02:00
|
|
|
|
// Runtime registers
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = undefined;
|
|
|
|
|
this.thRegister = undefined;
|
2015-06-09 16:27:08 +02:00
|
|
|
|
this.fRegister = null;
|
2014-07-20 21:00:26 +02:00
|
|
|
|
};
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
2014-07-20 21:00:26 +02:00
|
|
|
|
/******************************************************************************/
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
2014-07-20 21:00:26 +02:00
|
|
|
|
FilterContainer.prototype.freeze = function() {
|
2014-09-21 20:03:41 +02:00
|
|
|
|
histogram('allFilters', this.categories);
|
2017-03-11 19:55:47 +01:00
|
|
|
|
this.removeBadFilters();
|
2016-09-12 16:22:25 +02:00
|
|
|
|
this.duplicateBuster = new Set();
|
2014-07-20 21:00:26 +02:00
|
|
|
|
this.filterParser.reset();
|
2017-01-06 18:39:37 +01:00
|
|
|
|
this.fclassLast = null;
|
|
|
|
|
this.fdataLast = null;
|
|
|
|
|
this.filterLast = null;
|
2014-07-20 21:00:26 +02:00
|
|
|
|
this.frozen = true;
|
2018-06-01 13:54:31 +02:00
|
|
|
|
//console.log(JSON.stringify(Array.from(filterClassHistogram)));
|
|
|
|
|
//this.tokenHistogram = new Map(Array.from(this.tokenHistogram).sort(function(a, b) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
// return a[0].localeCompare(b[0]) || (b[1] - a[1]);
|
|
|
|
|
//}));
|
2017-01-06 18:39:37 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2014-09-08 23:46:58 +02:00
|
|
|
|
FilterContainer.prototype.toSelfie = function() {
|
2018-06-01 13:54:31 +02:00
|
|
|
|
let categoriesToSelfie = function(categoryMap) {
|
|
|
|
|
let selfie = [];
|
|
|
|
|
for ( let categoryEntry of categoryMap ) {
|
|
|
|
|
let tokenEntries = [];
|
|
|
|
|
for ( let tokenEntry of categoryEntry[1] ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
tokenEntries.push([ tokenEntry[0], tokenEntry[1].compile() ]);
|
|
|
|
|
}
|
2018-06-01 13:54:31 +02:00
|
|
|
|
selfie.push([ categoryEntry[0], tokenEntries ]);
|
2014-09-08 23:46:58 +02:00
|
|
|
|
}
|
2018-06-01 13:54:31 +02:00
|
|
|
|
return selfie;
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
2018-06-01 13:54:31 +02:00
|
|
|
|
let dataFiltersToSelfie = function(dataFilters) {
|
|
|
|
|
let selfie = [];
|
|
|
|
|
for ( let entry of dataFilters.values() ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
do {
|
|
|
|
|
selfie.push(entry.compile());
|
|
|
|
|
entry = entry.next;
|
|
|
|
|
} while ( entry !== undefined );
|
|
|
|
|
}
|
2018-06-01 13:54:31 +02:00
|
|
|
|
return selfie;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
};
|
|
|
|
|
|
2014-09-08 23:46:58 +02:00
|
|
|
|
return {
|
|
|
|
|
processedFilterCount: this.processedFilterCount,
|
|
|
|
|
acceptedCount: this.acceptedCount,
|
|
|
|
|
rejectedCount: this.rejectedCount,
|
|
|
|
|
allowFilterCount: this.allowFilterCount,
|
|
|
|
|
blockFilterCount: this.blockFilterCount,
|
2016-03-17 18:56:21 +01:00
|
|
|
|
discardedCount: this.discardedCount,
|
2017-05-12 16:35:11 +02:00
|
|
|
|
categories: categoriesToSelfie(this.categories),
|
|
|
|
|
dataFilters: dataFiltersToSelfie(this.dataFilters)
|
2014-09-08 23:46:58 +02:00
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
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;
|
2016-03-17 18:56:21 +01:00
|
|
|
|
this.discardedCount = selfie.discardedCount;
|
2014-09-08 23:46:58 +02:00
|
|
|
|
|
2018-06-01 13:54:31 +02:00
|
|
|
|
for ( let categoryEntry of selfie.categories ) {
|
|
|
|
|
let tokenMap = new Map();
|
|
|
|
|
for ( let tokenEntry of categoryEntry[1] ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
tokenMap.set(tokenEntry[0], filterFromCompiledData(tokenEntry[1]));
|
2014-09-08 23:46:58 +02:00
|
|
|
|
}
|
2018-06-01 13:54:31 +02:00
|
|
|
|
this.categories.set(categoryEntry[0], tokenMap);
|
2015-12-05 18:25:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-01 13:54:31 +02:00
|
|
|
|
for ( let dataEntry of selfie.dataFilters ) {
|
|
|
|
|
let entry = FilterDataHolderEntry.load(dataEntry);
|
|
|
|
|
let bucket = this.dataFilters.get(entry.tokenHash);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( bucket !== undefined ) {
|
|
|
|
|
entry.next = bucket;
|
2016-10-04 05:41:23 +02:00
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.dataFilters.set(entry.tokenHash, entry);
|
2015-12-05 18:25:18 +01:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterContainer.prototype.compile = function(raw, writer) {
|
2014-06-24 00:42:43 +02:00
|
|
|
|
// ORDER OF TESTS IS IMPORTANT!
|
|
|
|
|
|
|
|
|
|
// Ignore empty lines
|
2015-02-01 00:34:46 +01:00
|
|
|
|
var s = raw.trim();
|
2015-01-23 17:32:49 +01:00
|
|
|
|
if ( s.length === 0 ) {
|
2014-06-24 00:42:43 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var parsed = this.filterParser.parse(s);
|
|
|
|
|
|
2015-01-23 17:32:49 +01:00
|
|
|
|
// Ignore element-hiding filters
|
|
|
|
|
if ( parsed.elemHiding ) {
|
2014-09-08 23:46:58 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-23 17:32:49 +01:00
|
|
|
|
// Ignore filters with unsupported options
|
|
|
|
|
if ( parsed.unsupported ) {
|
2017-01-09 14:56:42 +01:00
|
|
|
|
µb.logger.writeOne('', 'error', 'Network filtering – invalid filter: ' + raw);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-28 19:49:02 +01:00
|
|
|
|
// 0 = network filters
|
|
|
|
|
writer.select(0);
|
|
|
|
|
|
2017-03-11 19:55:47 +01:00
|
|
|
|
// Pure hostnames, use more efficient dictionary lookup
|
2015-04-07 03:26:05 +02:00
|
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/665
|
2015-02-05 00:06:31 +01:00
|
|
|
|
// Create a dict keyed on request type etc.
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if (
|
|
|
|
|
parsed.hostnamePure &&
|
|
|
|
|
parsed.domainOpt === '' &&
|
|
|
|
|
parsed.dataType === undefined &&
|
2017-05-25 23:46:59 +02:00
|
|
|
|
this.compileHostnameOnlyFilter(parsed, writer)
|
2017-05-12 16:35:11 +02:00
|
|
|
|
) {
|
2015-02-05 00:06:31 +01:00
|
|
|
|
return true;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
parsed.makeToken();
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
var fdata;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( parsed.isRegex ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
fdata = FilterRegex.compile(parsed);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
} else if ( parsed.hostnamePure ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
fdata = FilterPlainHostname.compile(parsed);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
} else if ( parsed.f === '*' ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
fdata = FilterTrue.compile();
|
2017-05-12 16:35:11 +02:00
|
|
|
|
} else if ( parsed.anchor === 0x5 ) {
|
|
|
|
|
// https://github.com/gorhill/uBlock/issues/1669
|
2017-05-25 23:46:59 +02:00
|
|
|
|
fdata = FilterGenericHnAndRightAnchored.compile(parsed);
|
2017-05-30 17:38:45 +02:00
|
|
|
|
} else if ( parsed.anchor === 0x4 ) {
|
|
|
|
|
if (
|
|
|
|
|
this.reIsGeneric.test(parsed.f) === false &&
|
|
|
|
|
parsed.tokenHash !== parsed.noTokenHash &&
|
|
|
|
|
parsed.tokenBeg === 0
|
|
|
|
|
) {
|
|
|
|
|
fdata = FilterPlainHnAnchored.compile(parsed);
|
|
|
|
|
} else {
|
|
|
|
|
fdata = FilterGenericHnAnchored.compile(parsed);
|
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
} else if (
|
|
|
|
|
this.reIsGeneric.test(parsed.f) ||
|
|
|
|
|
parsed.tokenHash === parsed.noTokenHash
|
|
|
|
|
) {
|
2017-05-30 17:38:45 +02:00
|
|
|
|
fdata = FilterGeneric.compile(parsed);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
} else if ( parsed.anchor === 0x2 ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
fdata = FilterPlainLeftAnchored.compile(parsed);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
} else if ( parsed.anchor === 0x1 ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
fdata = FilterPlainRightAnchored.compile(parsed);
|
2017-10-09 15:28:28 +02:00
|
|
|
|
} else if ( parsed.anchor === 0x3 ) {
|
|
|
|
|
fdata = FilterExactMatch.compile(parsed);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
} else if ( parsed.tokenBeg === 0 ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
fdata = FilterPlainPrefix0.compile(parsed);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
} else if ( parsed.tokenBeg === 1 ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
fdata = FilterPlainPrefix1.compile(parsed);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
} else {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
fdata = FilterPlain.compile(parsed);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
var fwrapped;
|
|
|
|
|
if ( parsed.domainOpt !== '' ) {
|
|
|
|
|
fwrapped = fdata;
|
|
|
|
|
fdata = FilterOrigin.compile(parsed);
|
|
|
|
|
fdata.push(fwrapped);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( parsed.dataType !== undefined ) {
|
|
|
|
|
fwrapped = fdata;
|
|
|
|
|
fdata = FilterDataHolder.compile(parsed);
|
|
|
|
|
fdata.push(fwrapped);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.compileToAtomicFilter(fdata, parsed, writer);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
// Using fast/compact dictionary when filter is a pure hostname.
|
2015-02-05 00:06:31 +01:00
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterContainer.prototype.compileHostnameOnlyFilter = function(parsed, writer) {
|
2015-02-05 00:06:31 +01:00
|
|
|
|
// Can't fit the filter in a pure hostname dictionary.
|
2016-06-27 03:15:18 +02:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/1757
|
2016-06-27 03:16:54 +02:00
|
|
|
|
// This should no longer happen with fix to above issue.
|
2016-06-27 03:15:18 +02:00
|
|
|
|
//if ( parsed.domainOpt.length !== 0 ) {
|
|
|
|
|
// return;
|
|
|
|
|
//}
|
2015-02-05 00:06:31 +01:00
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
var descBits = parsed.action | parsed.important | parsed.party | parsed.badFilter;
|
2015-03-26 00:28:22 +01:00
|
|
|
|
|
|
|
|
|
var type = parsed.types;
|
|
|
|
|
if ( type === 0 ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
writer.push([ descBits, this.dotTokenHash, parsed.f ]);
|
2015-03-26 00:28:22 +01:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-05 00:06:31 +01:00
|
|
|
|
var bitOffset = 1;
|
2015-03-26 00:28:22 +01:00
|
|
|
|
do {
|
2015-02-05 00:06:31 +01:00
|
|
|
|
if ( type & 1 ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
writer.push([ descBits | (bitOffset << 4), this.dotTokenHash, parsed.f ]);
|
2015-02-05 00:06:31 +01:00
|
|
|
|
}
|
|
|
|
|
bitOffset += 1;
|
|
|
|
|
type >>>= 1;
|
2015-03-26 00:28:22 +01:00
|
|
|
|
} while ( type !== 0 );
|
2015-02-05 00:06:31 +01:00
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterContainer.prototype.compileToAtomicFilter = function(fdata, parsed, writer) {
|
|
|
|
|
var descBits = parsed.action | parsed.important | parsed.party | parsed.badFilter,
|
2017-03-11 19:55:47 +01:00
|
|
|
|
type = parsed.types;
|
2015-03-26 00:28:22 +01:00
|
|
|
|
if ( type === 0 ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
writer.push([ descBits, parsed.tokenHash, fdata ]);
|
2015-03-26 00:28:22 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2015-02-05 00:06:31 +01:00
|
|
|
|
var bitOffset = 1;
|
2015-03-26 00:28:22 +01:00
|
|
|
|
do {
|
2015-02-05 00:06:31 +01:00
|
|
|
|
if ( type & 1 ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
writer.push([ descBits | (bitOffset << 4), parsed.tokenHash, fdata ]);
|
2015-01-24 03:47:56 +01:00
|
|
|
|
}
|
|
|
|
|
bitOffset += 1;
|
|
|
|
|
type >>>= 1;
|
2015-03-26 00:28:22 +01:00
|
|
|
|
} while ( type !== 0 );
|
2015-11-24 01:18:25 +01:00
|
|
|
|
|
|
|
|
|
// Only static filter with an explicit type can be redirected. If we reach
|
|
|
|
|
// this point, it's because there is one or more explicit type.
|
|
|
|
|
if ( !parsed.redirect ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-11 19:55:47 +01:00
|
|
|
|
if ( parsed.badFilter ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-24 01:18:25 +01:00
|
|
|
|
var redirects = µb.redirectEngine.compileRuleFromStaticFilter(parsed.raw);
|
2015-11-25 16:05:23 +01:00
|
|
|
|
if ( Array.isArray(redirects) === false ) {
|
2017-06-07 19:20:35 +02:00
|
|
|
|
return;
|
2015-11-25 16:05:23 +01:00
|
|
|
|
}
|
2017-05-25 23:46:59 +02:00
|
|
|
|
descBits = typeNameToTypeValue.redirect;
|
2015-11-24 01:18:25 +01:00
|
|
|
|
var i = redirects.length;
|
|
|
|
|
while ( i-- ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
writer.push([ descBits, redirects[i] ]);
|
2015-11-24 01:18:25 +01:00
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
FilterContainer.prototype.fromCompiledContent = function(reader) {
|
|
|
|
|
var badFilterBit = BadFilter,
|
2017-05-27 02:00:21 +02:00
|
|
|
|
filterPairId = FilterPair.fid,
|
2017-05-25 23:46:59 +02:00
|
|
|
|
filterBucketId = FilterBucket.fid,
|
|
|
|
|
filterDataHolderId = FilterDataHolder.fid,
|
2017-09-16 13:49:43 +02:00
|
|
|
|
redirectTypeValue = typeNameToTypeValue.redirect,
|
2017-05-25 23:46:59 +02:00
|
|
|
|
args, bits, bucket, entry,
|
|
|
|
|
tokenHash, fdata, fingerprint;
|
|
|
|
|
|
2017-12-28 19:49:02 +01:00
|
|
|
|
// 0 = network filters
|
|
|
|
|
reader.select(0);
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
while ( reader.next() === true ) {
|
|
|
|
|
args = reader.args();
|
|
|
|
|
bits = args[0];
|
|
|
|
|
|
|
|
|
|
if ( (bits & badFilterBit) !== 0 ) {
|
|
|
|
|
this.badFilters.add(args);
|
2017-03-11 19:55:47 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-24 01:18:25 +01:00
|
|
|
|
// Special cases: delegate to more specialized engines.
|
|
|
|
|
// Redirect engine.
|
2017-09-16 13:49:43 +02:00
|
|
|
|
if ( (bits & 0x1F0) === redirectTypeValue ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
µb.redirectEngine.fromCompiledRule(args[1]);
|
2015-11-24 01:18:25 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-24 00:31:29 +01:00
|
|
|
|
this.acceptedCount += 1;
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
// Plain static filters.
|
|
|
|
|
fingerprint = reader.fingerprint();
|
|
|
|
|
tokenHash = args[1];
|
|
|
|
|
fdata = args[2];
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
// Special treatment: data-holding filters are stored separately
|
|
|
|
|
// because they require special matching algorithm (unlike other
|
|
|
|
|
// filters, ALL hits must be reported).
|
2017-05-25 23:46:59 +02:00
|
|
|
|
if ( fdata[0] === filterDataHolderId ) {
|
|
|
|
|
if ( this.duplicateBuster.has(fingerprint) ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
this.discardedCount += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-05-25 23:46:59 +02:00
|
|
|
|
this.duplicateBuster.add(fingerprint);
|
|
|
|
|
entry = new FilterDataHolderEntry(bits, tokenHash, fdata);
|
2017-05-19 14:45:19 +02:00
|
|
|
|
bucket = this.dataFilters.get(tokenHash);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( bucket !== undefined ) {
|
|
|
|
|
entry.next = bucket;
|
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.dataFilters.set(tokenHash, entry);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
bucket = this.categories.get(bits);
|
2015-02-24 00:31:29 +01:00
|
|
|
|
if ( bucket === undefined ) {
|
2016-09-12 16:22:25 +02:00
|
|
|
|
bucket = new Map();
|
2017-05-25 23:46:59 +02:00
|
|
|
|
this.categories.set(bits, bucket);
|
2015-02-24 00:31:29 +01:00
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
entry = bucket.get(tokenHash);
|
2015-02-24 00:31:29 +01:00
|
|
|
|
|
2017-05-19 14:45:19 +02:00
|
|
|
|
if ( tokenHash === this.dotTokenHash ) {
|
2015-02-24 00:31:29 +01:00
|
|
|
|
if ( entry === undefined ) {
|
2016-09-12 16:22:25 +02:00
|
|
|
|
entry = new FilterHostnameDict();
|
2017-05-19 14:45:19 +02:00
|
|
|
|
bucket.set(this.dotTokenHash, entry);
|
2015-02-24 00:31:29 +01:00
|
|
|
|
}
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( entry.add(fdata) === false ) {
|
2016-03-17 18:56:21 +01:00
|
|
|
|
this.discardedCount += 1;
|
2015-02-24 00:31:29 +01:00
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-25 23:46:59 +02:00
|
|
|
|
if ( this.duplicateBuster.has(fingerprint) ) {
|
2016-03-17 18:56:21 +01:00
|
|
|
|
this.discardedCount += 1;
|
2015-02-24 00:31:29 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-05-25 23:46:59 +02:00
|
|
|
|
this.duplicateBuster.add(fingerprint);
|
2015-03-05 01:36:09 +01:00
|
|
|
|
|
2015-02-24 00:31:29 +01:00
|
|
|
|
if ( entry === undefined ) {
|
2017-05-25 23:46:59 +02:00
|
|
|
|
bucket.set(tokenHash, filterFromCompiledData(fdata));
|
2015-02-24 00:31:29 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-05-25 23:46:59 +02:00
|
|
|
|
if ( entry.fid === filterBucketId ) {
|
|
|
|
|
entry.add(fdata);
|
2015-02-24 00:31:29 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-05-27 02:00:21 +02:00
|
|
|
|
if ( entry.fid === filterPairId ) {
|
|
|
|
|
bucket.set(
|
|
|
|
|
tokenHash,
|
|
|
|
|
entry.upgrade(filterFromCompiledData(fdata))
|
|
|
|
|
);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
bucket.set(
|
|
|
|
|
tokenHash,
|
|
|
|
|
new FilterPair(entry, filterFromCompiledData(fdata))
|
|
|
|
|
);
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-03-11 19:55:47 +01:00
|
|
|
|
FilterContainer.prototype.removeBadFilters = function() {
|
2017-05-27 02:00:21 +02:00
|
|
|
|
var filterPairId = FilterPair.fid,
|
|
|
|
|
filterBucketId = FilterBucket.fid,
|
|
|
|
|
filterHostnameDictId = FilterHostnameDict.fid,
|
|
|
|
|
bits, tokenHash, fdata, bucket, entry;
|
2017-05-25 23:46:59 +02:00
|
|
|
|
for ( var args of this.badFilters ) {
|
|
|
|
|
bits = args[0] & ~BadFilter;
|
|
|
|
|
bucket = this.categories.get(bits);
|
|
|
|
|
if ( bucket === undefined ) { continue; }
|
|
|
|
|
tokenHash = args[1];
|
2017-05-19 14:45:19 +02:00
|
|
|
|
entry = bucket.get(tokenHash);
|
2017-05-25 23:46:59 +02:00
|
|
|
|
if ( entry === undefined ) { continue; }
|
|
|
|
|
fdata = args[2];
|
2018-06-24 01:15:56 +02:00
|
|
|
|
if ( entry.fid === filterPairId || entry.fid === filterBucketId ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
entry.remove(fdata);
|
2018-06-24 01:15:56 +02:00
|
|
|
|
entry = entry.downgrade();
|
|
|
|
|
if ( entry !== undefined ) {
|
|
|
|
|
bucket.set(tokenHash, entry);
|
|
|
|
|
} else {
|
|
|
|
|
bucket.delete(tokenHash);
|
2017-03-11 19:55:47 +01:00
|
|
|
|
}
|
2018-06-24 01:15:56 +02:00
|
|
|
|
} else if ( entry.fid === filterHostnameDictId ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
entry.remove(fdata);
|
2017-03-21 13:23:21 +01:00
|
|
|
|
if ( entry.size === 0 ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
bucket.delete(tokenHash);
|
2017-03-21 13:23:21 +01:00
|
|
|
|
}
|
2018-06-24 01:15:56 +02:00
|
|
|
|
} else if ( arrayStrictEquals(entry.compile(), fdata) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
bucket.delete(tokenHash);
|
2018-06-24 01:15:56 +02:00
|
|
|
|
}
|
|
|
|
|
if ( bucket.size === 0 ) {
|
|
|
|
|
this.categories.delete(bits);
|
2017-03-11 19:55:47 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterContainer.prototype.matchAndFetchData = function(dataType, requestURL, out, outlog) {
|
|
|
|
|
if ( this.dataFilters.length === 0 ) { return; }
|
2015-06-09 16:27:08 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var url = this.urlTokenizer.setURL(requestURL);
|
2015-06-09 16:27:08 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
requestHostnameRegister = µb.URI.hostnameFromURI(url);
|
2015-06-09 16:27:08 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
// We need to visit ALL the matching filters.
|
|
|
|
|
var toAddImportant = new Map(),
|
|
|
|
|
toAdd = new Map(),
|
|
|
|
|
toRemove = new Map();
|
2015-06-09 16:27:08 +02:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var entry, f,
|
2017-05-19 14:45:19 +02:00
|
|
|
|
tokenHashes = this.urlTokenizer.getTokens(),
|
|
|
|
|
tokenHash, tokenOffset,
|
2017-05-12 16:35:11 +02:00
|
|
|
|
i = 0;
|
2017-05-19 14:45:19 +02:00
|
|
|
|
while ( i < 32 ) {
|
|
|
|
|
tokenHash = tokenHashes[i++];
|
|
|
|
|
if ( tokenHash === 0 ) { break; }
|
|
|
|
|
tokenOffset = tokenHashes[i++];
|
|
|
|
|
entry = this.dataFilters.get(tokenHash);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
while ( entry !== undefined ) {
|
|
|
|
|
f = entry.filter;
|
2017-05-19 14:45:19 +02:00
|
|
|
|
if ( f.match(url, tokenOffset) === true ) {
|
|
|
|
|
if ( entry.categoryBits & 0x001 ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
toRemove.set(f.dataStr, entry);
|
2017-05-19 14:45:19 +02:00
|
|
|
|
} else if ( entry.categoryBits & 0x002 ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
toAddImportant.set(f.dataStr, entry);
|
|
|
|
|
} else {
|
|
|
|
|
toAdd.set(f.dataStr, entry);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
entry = entry.next;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
entry = this.dataFilters.get(this.noTokenHash);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
while ( entry !== undefined ) {
|
|
|
|
|
f = entry.filter;
|
2017-05-19 14:45:19 +02:00
|
|
|
|
if ( f.match(url) === true ) {
|
|
|
|
|
if ( entry.categoryBits & 0x001 ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
toRemove.set(f.dataStr, entry);
|
2017-05-19 14:45:19 +02:00
|
|
|
|
} else if ( entry.categoryBits & 0x002 ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
toAddImportant.set(f.dataStr, entry);
|
|
|
|
|
} else {
|
|
|
|
|
toAdd.set(f.dataStr, entry);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
entry = entry.next;
|
2015-06-09 16:27:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( toAddImportant.size === 0 && toAdd.size === 0 ) { return; }
|
|
|
|
|
|
|
|
|
|
// Remove entries overriden by other filters.
|
2017-05-19 16:12:55 +02:00
|
|
|
|
var key;
|
|
|
|
|
for ( key of toAddImportant.keys() ) {
|
|
|
|
|
toAdd.delete(key);
|
|
|
|
|
toRemove.delete(key);
|
2015-06-09 16:27:08 +02:00
|
|
|
|
}
|
2017-05-19 16:12:55 +02:00
|
|
|
|
for ( key of toRemove.keys() ) {
|
|
|
|
|
if ( key === '' ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
toAdd.clear();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-05-19 16:12:55 +02:00
|
|
|
|
toAdd.delete(key);
|
2015-06-09 16:27:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var logData;
|
2017-05-19 16:12:55 +02:00
|
|
|
|
for ( entry of toAddImportant ) {
|
|
|
|
|
out.push(entry[0]);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( outlog === undefined ) { continue; }
|
2017-05-19 16:12:55 +02:00
|
|
|
|
logData = entry[1].logData();
|
2017-05-12 16:35:11 +02:00
|
|
|
|
logData.source = 'static';
|
|
|
|
|
logData.result = 1;
|
|
|
|
|
outlog.push(logData);
|
|
|
|
|
}
|
2017-05-19 16:12:55 +02:00
|
|
|
|
for ( entry of toAdd ) {
|
|
|
|
|
out.push(entry[0]);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
if ( outlog === undefined ) { continue; }
|
2017-05-19 16:12:55 +02:00
|
|
|
|
logData = entry[1].logData();
|
2017-05-12 16:35:11 +02:00
|
|
|
|
logData.source = 'static';
|
|
|
|
|
logData.result = 1;
|
|
|
|
|
outlog.push(logData);
|
|
|
|
|
}
|
|
|
|
|
if ( outlog !== undefined ) {
|
2017-05-19 16:12:55 +02:00
|
|
|
|
for ( entry of toRemove.values()) {
|
|
|
|
|
logData = entry.logData();
|
2017-05-12 16:35:11 +02:00
|
|
|
|
logData.source = 'static';
|
|
|
|
|
logData.result = 2;
|
|
|
|
|
outlog.push(logData);
|
|
|
|
|
}
|
2015-06-09 16:27:08 +02:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2016-09-12 16:22:25 +02:00
|
|
|
|
// bucket: Map
|
|
|
|
|
// url: string
|
|
|
|
|
|
2014-12-28 16:07:43 +01:00
|
|
|
|
FilterContainer.prototype.matchTokens = function(bucket, url) {
|
2015-02-05 00:06:31 +01:00
|
|
|
|
// Hostname-only filters
|
2017-05-19 14:45:19 +02:00
|
|
|
|
var f = bucket.get(this.dotTokenHash);
|
2017-05-20 02:22:26 +02:00
|
|
|
|
if ( f !== undefined && f.match() === true ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.thRegister = this.dotTokenHash;
|
2015-06-09 16:27:08 +02:00
|
|
|
|
this.fRegister = f;
|
|
|
|
|
return true;
|
2015-02-05 00:06:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-19 14:45:19 +02:00
|
|
|
|
var tokenHashes = this.urlTokenizer.getTokens(),
|
|
|
|
|
tokenHash, tokenOffset,
|
2017-05-12 16:35:11 +02:00
|
|
|
|
i = 0;
|
2014-09-21 20:03:41 +02:00
|
|
|
|
for (;;) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
tokenHash = tokenHashes[i++];
|
|
|
|
|
if ( tokenHash === 0 ) { break; }
|
|
|
|
|
tokenOffset = tokenHashes[i++];
|
|
|
|
|
f = bucket.get(tokenHash);
|
|
|
|
|
if ( f !== undefined && f.match(url, tokenOffset) === true ) {
|
|
|
|
|
this.thRegister = tokenHash;
|
2015-06-09 16:27:08 +02:00
|
|
|
|
this.fRegister = f;
|
|
|
|
|
return true;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-23 17:32:49 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
// Untokenizable filters
|
2017-05-19 14:45:19 +02:00
|
|
|
|
f = bucket.get(this.noTokenHash);
|
|
|
|
|
if ( f !== undefined && f.match(url) === true ) {
|
|
|
|
|
this.thRegister = this.noTokenHash;
|
2015-06-09 16:27:08 +02:00
|
|
|
|
this.fRegister = f;
|
|
|
|
|
return true;
|
2015-01-23 17:32:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2014-07-30 02:07:08 +02:00
|
|
|
|
// Specialized handlers
|
|
|
|
|
|
2016-11-08 13:13:26 +01:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/1477
|
|
|
|
|
// Special case: blocking-generichide filter ALWAYS exists, it is implicit --
|
|
|
|
|
// thus we always first check for exception filters, then for important block
|
|
|
|
|
// filter if and only if there was a hit on an exception filter.
|
|
|
|
|
// https://github.com/gorhill/uBlock/issues/2103
|
|
|
|
|
// User may want to override `generichide` exception filters.
|
|
|
|
|
|
|
|
|
|
FilterContainer.prototype.matchStringGenericHide = function(context, requestURL) {
|
|
|
|
|
var url = this.urlTokenizer.setURL(requestURL);
|
|
|
|
|
|
2016-12-08 02:18:58 +01:00
|
|
|
|
// https://github.com/gorhill/uBlock/issues/2225
|
|
|
|
|
// Important: this is used by FilterHostnameDict.match().
|
|
|
|
|
requestHostnameRegister = µb.URI.hostnameFromURI(url);
|
|
|
|
|
|
2017-05-16 16:25:00 +02:00
|
|
|
|
var bucket = this.categories.get(genericHideException);
|
2016-11-08 13:13:26 +01:00
|
|
|
|
if ( !bucket || this.matchTokens(bucket, url) === false ) {
|
|
|
|
|
this.fRegister = null;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 0;
|
2016-11-08 13:13:26 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-16 16:25:00 +02:00
|
|
|
|
bucket = this.categories.get(genericHideImportant);
|
2016-11-08 13:13:26 +01:00
|
|
|
|
if ( bucket && this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = genericHideImportant;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 1;
|
2016-11-08 13:13:26 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = genericHideException;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 2;
|
2016-11-08 13:13:26 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2015-04-07 03:26:05 +02:00
|
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/116
|
2016-11-08 13:13:26 +01:00
|
|
|
|
// Some type of requests are exceptional, they need custom handling,
|
|
|
|
|
// not the generic handling.
|
2014-07-30 03:10:00 +02:00
|
|
|
|
|
2014-12-28 16:07:43 +01:00
|
|
|
|
FilterContainer.prototype.matchStringExactType = function(context, requestURL, requestType) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
// Special cases.
|
2016-11-08 13:13:26 +01:00
|
|
|
|
if ( requestType === 'generichide' ) {
|
|
|
|
|
return this.matchStringGenericHide(context, requestURL);
|
|
|
|
|
}
|
2016-08-31 11:19:16 +02:00
|
|
|
|
var type = typeNameToTypeValue[requestType];
|
|
|
|
|
if ( type === undefined ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 0;
|
2015-03-26 00:28:22 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-29 17:34:41 +01:00
|
|
|
|
// Prime tokenizer: we get a normalized URL in return.
|
|
|
|
|
var url = this.urlTokenizer.setURL(requestURL);
|
|
|
|
|
|
|
|
|
|
// These registers will be used by various filters
|
|
|
|
|
pageHostnameRegister = context.pageHostname || '';
|
|
|
|
|
requestHostnameRegister = µb.URI.hostnameFromURI(url);
|
|
|
|
|
|
2016-11-08 13:13:26 +01:00
|
|
|
|
var party = isFirstParty(context.pageDomain, requestHostnameRegister) ? FirstParty : ThirdParty,
|
|
|
|
|
categories = this.categories,
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits, bucket;
|
2014-09-21 20:03:41 +02:00
|
|
|
|
|
2015-06-09 16:27:08 +02:00
|
|
|
|
this.fRegister = null;
|
|
|
|
|
|
2015-04-07 03:26:05 +02:00
|
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/139
|
2016-11-08 13:13:26 +01:00
|
|
|
|
// Test against important block filters
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = BlockAnyParty | Important | type;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 1;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = BlockAction | Important | type | party;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 1;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
2014-08-29 21:02:31 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-03-16 17:11:37 +01:00
|
|
|
|
// Test against block filters
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = BlockAnyParty | type;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2016-03-16 17:11:37 +01:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2016-03-16 17:11:37 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( this.fRegister === null ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = BlockAction | type | party;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2016-03-16 17:11:37 +01:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2016-03-16 17:11:37 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If there is no block filter, no need to test against allow filters
|
|
|
|
|
if ( this.fRegister === null ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 0;
|
2016-03-16 17:11:37 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-30 02:07:08 +02:00
|
|
|
|
// Test against allow filters
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = AllowAnyParty | type;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 2;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = AllowAction | type | party;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 2;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
2014-07-30 02:07:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 1;
|
2014-07-30 02:07:08 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2014-12-28 16:07:43 +01:00
|
|
|
|
FilterContainer.prototype.matchString = function(context) {
|
2015-04-07 03:26:05 +02:00
|
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/519
|
2015-01-17 13:53:19 +01:00
|
|
|
|
// Use exact type match for anything beyond `other`
|
2015-01-21 01:39:13 +01:00
|
|
|
|
// Also, be prepared to support unknown types
|
2016-08-31 04:45:24 +02:00
|
|
|
|
var type = typeNameToTypeValue[context.requestType];
|
|
|
|
|
if ( type === undefined ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
type = otherTypeBitValue;
|
|
|
|
|
} else if ( type === 0 || type > otherTypeBitValue ) {
|
2015-01-17 13:53:19 +01:00
|
|
|
|
return this.matchStringExactType(context, context.requestURL, context.requestType);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
// The logic here is simple:
|
|
|
|
|
//
|
|
|
|
|
// block = !whitelisted && blacklisted
|
|
|
|
|
// or equivalent
|
|
|
|
|
// allow = whitelisted || !blacklisted
|
|
|
|
|
|
2014-06-28 17:40:26 +02:00
|
|
|
|
// Statistically, hits on a URL in order of likelihood:
|
|
|
|
|
// 1. No hit
|
|
|
|
|
// 2. Hit on a block filter
|
|
|
|
|
// 3. Hit on an allow filter
|
|
|
|
|
//
|
|
|
|
|
// High likelihood of "no hit" means to optimize we need to reduce as much
|
|
|
|
|
// as possible the number of filters to test.
|
|
|
|
|
//
|
|
|
|
|
// Then, because of the order of probabilities, we should test only
|
2014-10-17 21:44:19 +02:00
|
|
|
|
// block filters first, and test allow filters if and only if there is a
|
2014-06-28 17:40:26 +02:00
|
|
|
|
// hit on a block filter. Since there is a high likelihood of no hit,
|
|
|
|
|
// testing allow filter by default is likely wasted work, hence allow
|
2014-06-28 17:41:49 +02:00
|
|
|
|
// filters are tested *only* if there is a (unlikely) hit on a block
|
|
|
|
|
// filter.
|
2014-06-24 00:42:43 +02:00
|
|
|
|
|
2015-12-29 17:34:41 +01:00
|
|
|
|
// Prime tokenizer: we get a normalized URL in return.
|
|
|
|
|
var url = this.urlTokenizer.setURL(context.requestURL);
|
2014-10-07 22:30:40 +02:00
|
|
|
|
|
2015-02-05 00:06:31 +01:00
|
|
|
|
// These registers will be used by various filters
|
|
|
|
|
pageHostnameRegister = context.pageHostname || '';
|
|
|
|
|
requestHostnameRegister = context.requestHostname;
|
2014-10-07 04:40:25 +02:00
|
|
|
|
|
2015-06-09 16:27:08 +02:00
|
|
|
|
this.fRegister = null;
|
2015-01-21 14:59:23 +01:00
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
var party = isFirstParty(context.pageDomain, context.requestHostname)
|
|
|
|
|
? FirstParty
|
|
|
|
|
: ThirdParty;
|
|
|
|
|
var categories = this.categories,
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits, bucket;
|
2015-06-09 23:01:31 +02:00
|
|
|
|
|
2015-04-07 03:26:05 +02:00
|
|
|
|
// https://github.com/chrisaljoudi/uBlock/issues/139
|
2014-08-29 21:02:31 +02:00
|
|
|
|
// Test against important block filters.
|
|
|
|
|
// The purpose of the `important` option 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".
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = BlockAnyTypeAnyParty | Important;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 1;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = BlockAnyType | Important | party;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 1;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = BlockAnyParty | Important | type;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 1;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = BlockAction | Important | type | party;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 1;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
2014-08-29 21:02:31 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-24 00:42:43 +02:00
|
|
|
|
// Test against block filters
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = BlockAnyTypeAnyParty;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.fRegister === null ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = BlockAnyType | party;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2015-06-09 16:27:08 +02:00
|
|
|
|
}
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.fRegister === null ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = BlockAnyParty | type;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2015-06-09 16:27:08 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( this.fRegister === null ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = BlockAction | type | party;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2015-06-09 16:27:08 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If there is no block filter, no need to test against allow filters
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.fRegister === null ) {
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 0;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test against allow filters
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = AllowAnyTypeAnyParty;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 2;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = AllowAnyType | party;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 2;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = AllowAnyParty | type;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 2;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-19 14:45:19 +02:00
|
|
|
|
catBits = AllowAction | type | party;
|
|
|
|
|
if ( (bucket = categories.get(catBits)) ) {
|
2015-06-09 16:27:08 +02:00
|
|
|
|
if ( this.matchTokens(bucket, url) ) {
|
2017-05-19 14:45:19 +02:00
|
|
|
|
this.cbRegister = catBits;
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 2;
|
2014-12-28 16:07:43 +01:00
|
|
|
|
}
|
2014-06-24 00:42:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return 1;
|
2015-06-09 16:27:08 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
2017-05-12 16:35:11 +02:00
|
|
|
|
FilterContainer.prototype.toLogData = function() {
|
|
|
|
|
if ( this.fRegister === null ) { return; }
|
2017-05-19 14:45:19 +02:00
|
|
|
|
var logData = toLogDataInternal(this.cbRegister, this.thRegister, this.fRegister);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
logData.source = 'static';
|
2017-05-19 14:45:19 +02:00
|
|
|
|
logData.tokenHash = this.thRegister;
|
|
|
|
|
logData.result = this.fRegister === null ? 0 : (this.cbRegister & 1 ? 2 : 1);
|
2017-05-12 16:35:11 +02:00
|
|
|
|
return logData;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
FilterContainer.prototype.getFilterCount = function() {
|
2016-03-17 18:56:21 +01:00
|
|
|
|
return this.acceptedCount - this.discardedCount;
|
2014-06-24 00:42:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
return new FilterContainer();
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
})();
|