Index: lib/matcher.js |
=================================================================== |
--- a/lib/matcher.js |
+++ b/lib/matcher.js |
@@ -216,6 +216,8 @@ |
{ |
this.blacklist = new Matcher(); |
this.whitelist = new Matcher(); |
+ this.userBlacklist = new Matcher(); |
+ this.userWhitelist = new Matcher(); |
this.resultCache = Object.create(null); |
} |
exports.CombinedMatcher = CombinedMatcher; |
@@ -241,6 +243,18 @@ |
whitelist: null, |
/** |
+ * Matcher for user-defined blocking rules. |
+ * @type Matcher |
+ */ |
+ userBlacklist: null, |
+ |
+ /** |
+ * Matcher for user-defined exception rules. |
+ * @type Matcher |
+ */ |
+ userWhitelist: null, |
+ |
+ /** |
* Lookup table of previous matchesAny results |
* @type Object |
*/ |
@@ -252,6 +266,24 @@ |
*/ |
cacheEntries: 0, |
+ _getMatcher: function(filter) |
+ { |
+ if (filter.isUserDefined) |
+ { |
+ if (filter instanceof WhitelistFilter) |
+ return this.userWhitelist; |
+ else |
+ return this.userBlacklist; |
+ } |
+ else |
+ { |
+ if (filter instanceof WhitelistFilter) |
+ return this.whitelist; |
+ else |
+ return this.blacklist; |
+ } |
+ }, |
+ |
/** |
* @see Matcher#clear |
*/ |
@@ -259,6 +291,8 @@ |
{ |
this.blacklist.clear(); |
this.whitelist.clear(); |
+ this.userBlacklist.clear(); |
+ this.userWhitelist.clear(); |
this.resultCache = Object.create(null); |
this.cacheEntries = 0; |
}, |
@@ -268,10 +302,7 @@ |
*/ |
add: function(filter) |
{ |
- if (filter instanceof WhitelistFilter) |
- this.whitelist.add(filter); |
- else |
- this.blacklist.add(filter); |
+ this._getMatcher(filter).add(filter); |
if (this.cacheEntries > 0) |
{ |
@@ -285,10 +316,7 @@ |
*/ |
remove: function(filter) |
{ |
- if (filter instanceof WhitelistFilter) |
- this.whitelist.remove(filter); |
- else |
- this.blacklist.remove(filter); |
+ this._getMatcher(filter).remove(filter); |
if (this.cacheEntries > 0) |
{ |
@@ -302,10 +330,7 @@ |
*/ |
findKeyword: function(filter) |
{ |
- if (filter instanceof WhitelistFilter) |
- return this.whitelist.findKeyword(filter); |
- else |
- return this.blacklist.findKeyword(filter); |
+ return this._getMatcher(filter).findKeyword(filter); |
}, |
/** |
@@ -313,10 +338,7 @@ |
*/ |
hasFilter: function(filter) |
{ |
- if (filter instanceof WhitelistFilter) |
- return this.whitelist.hasFilter(filter); |
- else |
- return this.blacklist.hasFilter(filter); |
+ return this._getMatcher(filter).hasFilter(filter); |
}, |
/** |
@@ -324,10 +346,7 @@ |
*/ |
getKeywordForFilter: function(filter) |
{ |
- if (filter instanceof WhitelistFilter) |
- return this.whitelist.getKeywordForFilter(filter); |
- else |
- return this.blacklist.getKeywordForFilter(filter); |
+ return this._getMatcher(filter).getKeywordForFilter(filter); |
}, |
/** |
@@ -335,7 +354,7 @@ |
*/ |
isSlowFilter: function(/**RegExpFilter*/ filter) /**Boolean*/ |
{ |
- let matcher = (filter instanceof WhitelistFilter ? this.whitelist : this.blacklist); |
+ let matcher = this._getMatcher(filter); |
if (matcher.hasFilter(filter)) |
return !matcher.getKeywordForFilter(filter); |
else |
@@ -344,28 +363,23 @@ |
/** |
* Optimized filter matching testing both whitelist and blacklist matchers |
- * simultaneously. For parameters see Matcher.matchesAny(). |
+ * simultaneously. |
* @see Matcher#matchesAny |
*/ |
- matchesAnyInternal: function(location, contentType, docDomain, thirdParty, sitekey) |
+ matchesAnyInternal: function(blacklist, whitelist, candidates, location, contentType, docDomain, thirdParty, sitekey) |
{ |
- let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); |
- if (candidates === null) |
- candidates = []; |
- candidates.push(""); |
- |
let blacklistHit = null; |
for (let i = 0, l = candidates.length; i < l; i++) |
{ |
let substr = candidates[i]; |
- if (substr in this.whitelist.filterByKeyword) |
+ if (substr in whitelist.filterByKeyword) |
{ |
- let result = this.whitelist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey); |
+ let result = whitelist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey); |
if (result) |
return result; |
} |
- if (substr in this.blacklist.filterByKeyword && blacklistHit === null) |
- blacklistHit = this.blacklist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey); |
+ if (substr in blacklist.filterByKeyword && blacklistHit === null) |
+ blacklistHit = blacklist._checkEntryMatch(substr, location, contentType, docDomain, thirdParty, sitekey); |
} |
return blacklistHit; |
}, |
@@ -379,7 +393,13 @@ |
if (key in this.resultCache) |
return this.resultCache[key]; |
- let result = this.matchesAnyInternal(location, contentType, docDomain, thirdParty, sitekey); |
+ let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); |
+ if (candidates === null) |
+ candidates = []; |
+ candidates.push(""); |
+ |
+ let result = (this.matchesAnyInternal(this.userBlacklist, this.userWhitelist, candidates, location, contentType, docDomain, thirdParty, sitekey) || |
+ this.matchesAnyInternal(this.blacklist, this.whitelist, candidates, location, contentType, docDomain, thirdParty, sitekey)); |
if (this.cacheEntries >= CombinedMatcher.maxCacheEntries) |
{ |