| Index: lib/matcher.js |
| =================================================================== |
| --- a/lib/matcher.js |
| +++ b/lib/matcher.js |
| @@ -17,31 +17,41 @@ |
| "use strict"; |
| /** |
| * @fileOverview Matcher class implementing matching addresses against |
| * a list of filters. |
| */ |
| -const {WhitelistFilter} = require("./filterClasses"); |
| +const {RegExpFilter, WhitelistFilter} = require("./filterClasses"); |
| /** |
| * Regular expression for matching a keyword in a filter. |
| * @type {RegExp} |
| */ |
| const keywordRegExp = /[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/; |
| /** |
| * Regular expression for matching all keywords in a filter. |
| * @type {RegExp} |
| */ |
| const allKeywordsRegExp = new RegExp(keywordRegExp, "g"); |
| /** |
| + * Bitmask for "types" that are for exception rules only, like |
| + * <code>$document</code>, <code>$elemhide</code>, and so on. |
| + * @type {number} |
| + */ |
| +const WHITELIST_ONLY_TYPES = RegExpFilter.typeMap.DOCUMENT | |
| + RegExpFilter.typeMap.ELEMHIDE | |
| + RegExpFilter.typeMap.GENERICHIDE | |
| + RegExpFilter.typeMap.GENERICBLOCK; |
| + |
| +/** |
| * Checks whether a particular filter is slow. |
| * @param {RegExpFilter} filter |
| * @returns {boolean} |
| */ |
| function isSlowFilter(filter) |
| { |
| return !filter.pattern || !keywordRegExp.test(filter.pattern); |
| } |
| @@ -315,34 +325,45 @@ |
| matchesAnyInternal(location, typeMask, docDomain, thirdParty, sitekey, |
| specificOnly) |
| { |
| let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); |
| if (candidates === null) |
| candidates = []; |
| candidates.push(""); |
| + let whitelistHit = null; |
| let blacklistHit = null; |
| - for (let i = 0, l = candidates.length; i < l; i++) |
| + |
| + // If the type mask includes no types other than whitelist-only types, we |
| + // can skip the blacklist. |
| + if ((typeMask & ~WHITELIST_ONLY_TYPES) != 0) |
| { |
| - let substr = candidates[i]; |
| - let result = this.whitelist._checkEntryMatch( |
| - substr, location, typeMask, docDomain, thirdParty, sitekey |
| - ); |
| - if (result) |
| - return result; |
| - if (blacklistHit === null) |
| + for (let i = 0, l = candidates.length; !blacklistHit && i < l; i++) |
| { |
| - blacklistHit = this.blacklist._checkEntryMatch( |
| - substr, location, typeMask, docDomain, thirdParty, sitekey, |
| - specificOnly |
| - ); |
| + blacklistHit = this.blacklist._checkEntryMatch(candidates[i], location, |
| + typeMask, docDomain, |
| + thirdParty, sitekey, |
| + specificOnly); |
| } |
| } |
| - return blacklistHit; |
| + |
| + // If the type mask includes any whitelist-only types, we need to check the |
| + // whitelist. |
| + if (blacklistHit || (typeMask & WHITELIST_ONLY_TYPES) != 0) |
| + { |
| + for (let i = 0, l = candidates.length; !whitelistHit && i < l; i++) |
| + { |
| + whitelistHit = this.whitelist._checkEntryMatch(candidates[i], location, |
| + typeMask, docDomain, |
| + thirdParty, sitekey); |
| + } |
| + } |
| + |
| + return whitelistHit || blacklistHit; |
| } |
| /** |
| * @see Matcher#matchesAny |
| * @inheritdoc |
| */ |
| matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly) |
| { |