diff --git a/src/js/dynamic-net-filtering.js b/src/js/dynamic-net-filtering.js index 0e6199907..bb58ff19c 100644 --- a/src/js/dynamic-net-filtering.js +++ b/src/js/dynamic-net-filtering.js @@ -70,41 +70,9 @@ var nameToActionMap = { /******************************************************************************/ // For performance purpose, as simple tests as possible -var reHostnameVeryCoarse = /[g-z_-]/; -var reIPv4VeryCoarse = /\.\d+$/; var reBadHostname = /[^0-9a-z_.\[\]:%-]/; var reNotASCII = /[^\x20-\x7F]/; -// http://tools.ietf.org/html/rfc5952 -// 4.3: "MUST be represented in lowercase" -// Also: http://en.wikipedia.org/wiki/IPv6_address#Literal_IPv6_addresses_in_network_resource_identifiers - -var isIPAddress = function(hostname) { - if ( reHostnameVeryCoarse.test(hostname) ) { - return false; - } - if ( reIPv4VeryCoarse.test(hostname) ) { - return true; - } - return hostname.startsWith('['); -}; - -var toBroaderHostname = function(hostname) { - var pos = hostname.indexOf('.'); - if ( pos !== -1 ) { - return hostname.slice(pos + 1); - } - return hostname !== '*' && hostname !== '' ? '*' : ''; -}; - -var toBroaderIPAddress = function(ipaddress) { - return ipaddress !== '*' && ipaddress !== '' ? '*' : ''; -}; - -var selectHostnameBroadener = function(hostname) { - return isIPAddress(hostname) ? toBroaderIPAddress : toBroaderHostname; -}; - /******************************************************************************/ Matrix.prototype.reset = function() { @@ -114,6 +82,8 @@ Matrix.prototype.reset = function() { this.z = ''; this.rules = new Map(); this.changed = false; + this.decomposedSource = []; + this.decomposedDestination = []; }; /******************************************************************************/ @@ -291,14 +261,13 @@ var domainFromHostname = µBlock.URI.domainFromHostname; /******************************************************************************/ -Matrix.prototype.evaluateCellZ = function(srcHostname, desHostname, type, broadener) { +Matrix.prototype.evaluateCellZ = function(srcHostname, desHostname, type) { + µBlock.decomposeHostname(srcHostname, this.decomposedSource); this.type = type; - var bitOffset = typeBitOffsets[type]; - var s = srcHostname; - var v; - for (;;) { - this.z = s; - v = this.rules.get(s + ' ' + desHostname); + let bitOffset = typeBitOffsets[type]; + for ( let shn of this.decomposedSource ) { + this.z = shn; + let v = this.rules.get(shn + ' ' + desHostname); if ( v !== undefined ) { v = v >>> bitOffset & 3; if ( v !== 0 ) { @@ -306,8 +275,6 @@ Matrix.prototype.evaluateCellZ = function(srcHostname, desHostname, type, broade return v; } } - s = broadener(s); - if ( s === '' ) { break; } } // srcHostname is '*' at this point this.r = 0; @@ -318,29 +285,24 @@ Matrix.prototype.evaluateCellZ = function(srcHostname, desHostname, type, broade Matrix.prototype.evaluateCellZY = function(srcHostname, desHostname, type) { // Pathological cases. - var d = desHostname; - if ( d === '' ) { + if ( desHostname === '' ) { this.r = 0; return 0; } - // Prepare broadening handlers -- depends on whether we are dealing with - // a hostname or IP address. - var broadenSource = selectHostnameBroadener(srcHostname), - broadenDestination = selectHostnameBroadener(desHostname); - // Precedence: from most specific to least specific // Specific-destination, any party, any type - while ( d !== '*' ) { - this.y = d; - if ( this.evaluateCellZ(srcHostname, d, '*', broadenSource) !== 0 ) { + µBlock.decomposeHostname(desHostname, this.decomposedDestination); + for ( let dhn of this.decomposedDestination ) { + if ( dhn === '*' ) { break; } + this.y = dhn; + if ( this.evaluateCellZ(srcHostname, dhn, '*') !== 0 ) { return this.r; } - d = broadenDestination(d); } - var thirdParty = is3rdParty(srcHostname, desHostname); + let thirdParty = is3rdParty(srcHostname, desHostname); // Any destination this.y = '*'; @@ -349,34 +311,34 @@ Matrix.prototype.evaluateCellZY = function(srcHostname, desHostname, type) { if ( thirdParty ) { // 3rd-party, specific type if ( type === 'script' ) { - if ( this.evaluateCellZ(srcHostname, '*', '3p-script', broadenSource) !== 0 ) { + if ( this.evaluateCellZ(srcHostname, '*', '3p-script') !== 0 ) { return this.r; } } else if ( type === 'sub_frame' ) { - if ( this.evaluateCellZ(srcHostname, '*', '3p-frame', broadenSource) !== 0 ) { + if ( this.evaluateCellZ(srcHostname, '*', '3p-frame') !== 0 ) { return this.r; } } // 3rd-party, any type - if ( this.evaluateCellZ(srcHostname, '*', '3p', broadenSource) !== 0 ) { + if ( this.evaluateCellZ(srcHostname, '*', '3p') !== 0 ) { return this.r; } } else if ( type === 'script' ) { // 1st party, specific type - if ( this.evaluateCellZ(srcHostname, '*', '1p-script', broadenSource) !== 0 ) { + if ( this.evaluateCellZ(srcHostname, '*', '1p-script') !== 0 ) { return this.r; } } // Any destination, any party, specific type if ( supportedDynamicTypes.hasOwnProperty(type) ) { - if ( this.evaluateCellZ(srcHostname, '*', type, broadenSource) !== 0 ) { + if ( this.evaluateCellZ(srcHostname, '*', type) !== 0 ) { return this.r; } } // Any destination, any party, any type - if ( this.evaluateCellZ(srcHostname, '*', '*', broadenSource) !== 0 ) { + if ( this.evaluateCellZ(srcHostname, '*', '*') !== 0 ) { return this.r; } diff --git a/src/js/hnswitches.js b/src/js/hnswitches.js index abf8bb79b..53f517937 100644 --- a/src/js/hnswitches.js +++ b/src/js/hnswitches.js @@ -60,40 +60,12 @@ var nameToSwitchStateMap = { /******************************************************************************/ // For performance purpose, as simple tests as possible -var reHostnameVeryCoarse = /[g-z_-]/; -var reIPv4VeryCoarse = /\.\d+$/; var reNotASCII = /[^\x20-\x7F]/; // http://tools.ietf.org/html/rfc5952 // 4.3: "MUST be represented in lowercase" // Also: http://en.wikipedia.org/wiki/IPv6_address#Literal_IPv6_addresses_in_network_resource_identifiers -var isIPAddress = function(hostname) { - if ( reHostnameVeryCoarse.test(hostname) ) { - return false; - } - if ( reIPv4VeryCoarse.test(hostname) ) { - return true; - } - return hostname.startsWith('['); -}; - -var toBroaderHostname = function(hostname) { - var pos = hostname.indexOf('.'); - if ( pos !== -1 ) { - return hostname.slice(pos + 1); - } - return hostname !== '*' && hostname !== '' ? '*' : ''; -}; - -var toBroaderIPAddress = function(ipaddress) { - return ipaddress !== '*' && ipaddress !== '' ? '*' : ''; -}; - -var selectHostnameBroadener = function(hostname) { - return isIPAddress(hostname) ? toBroaderIPAddress : toBroaderHostname; -}; - /******************************************************************************/ HnSwitches.prototype.reset = function() { @@ -102,6 +74,7 @@ HnSwitches.prototype.reset = function() { this.z = ''; this.r = 0; this.changed = true; + this.decomposedSource = []; }; /******************************************************************************/ @@ -220,21 +193,17 @@ HnSwitches.prototype.evaluateZ = function(switchName, hostname) { return false; } this.n = switchName; - var bits, - hn = hostname, - broadenSource = selectHostnameBroadener(hn); - for (;;) { - bits = this.switches.get(hn); + µBlock.decomposeHostname(hostname, this.decomposedSource); + for ( let shn of this.decomposedSource ) { + let bits = this.switches.get(shn); if ( bits !== undefined ) { bits = bits >>> bitOffset & 3; if ( bits !== 0 ) { - this.z = hn; + this.z = shn; this.r = bits; return bits === 1; } } - hn = broadenSource(hn); - if ( hn === '' ) { break; } } this.r = 0; return false; diff --git a/src/js/url-net-filtering.js b/src/js/url-net-filtering.js index 7ba9c56ec..c7da817c4 100644 --- a/src/js/url-net-filtering.js +++ b/src/js/url-net-filtering.js @@ -137,6 +137,7 @@ URLNetFiltering.prototype.reset = function() { this.type = ''; this.r = 0; this.changed = false; + this.decomposedSource = []; }; /******************************************************************************/ @@ -207,32 +208,31 @@ URLNetFiltering.prototype.evaluateZ = function(context, target, type) { if ( this.rules.size === 0 ) { return 0; } - var entries, pos, i, entry; - for (;;) { - this.context = context; - if ( (entries = this.rules.get(context + ' ' + type)) ) { - i = indexOfMatch(entries, target); + µBlock.decomposeHostname(context, this.decomposedSource); + for ( let shn of this.decomposedSource ) { + this.context = shn; + let entries = this.rules.get(shn + ' ' + type); + if ( entries !== undefined ) { + let i = indexOfMatch(entries, target); if ( i !== -1 ) { - entry = entries[i]; + let entry = entries[i]; this.url = entry.url; this.type = type; this.r = entry.action; return this.r; } } - if ( (entries = this.rules.get(context + ' *')) ) { - i = indexOfMatch(entries, target); + entries = this.rules.get(shn + ' *'); + if ( entries !== undefined ) { + let i = indexOfMatch(entries, target); if ( i !== -1 ) { - entry = entries[i]; + let entry = entries[i]; this.url = entry.url; this.type = '*'; this.r = entry.action; return this.r; } } - if ( context === '*' ) { break; } - pos = context.indexOf('.'); - context = pos !== -1 ? context.slice(pos + 1) : '*'; } return 0; }; diff --git a/src/js/utils.js b/src/js/utils.js index 305d36803..89e2c4e0e 100644 --- a/src/js/utils.js +++ b/src/js/utils.js @@ -416,3 +416,48 @@ }; /******************************************************************************/ + +µBlock.decomposeHostname = (function() { + // For performance purpose, as simple tests as possible + let reHostnameVeryCoarse = /[g-z_-]/; + let reIPv4VeryCoarse = /\.\d+$/; + + let isIPAddress = function(hostname) { + if ( reHostnameVeryCoarse.test(hostname) ) { + return false; + } + if ( reIPv4VeryCoarse.test(hostname) ) { + return true; + } + return hostname.startsWith('['); + }; + + let toBroaderHostname = function(hostname) { + let pos = hostname.indexOf('.'); + if ( pos !== -1 ) { + return hostname.slice(pos + 1); + } + return hostname !== '*' && hostname !== '' ? '*' : ''; + }; + + let toBroaderIPAddress = function(ipaddress) { + return ipaddress !== '*' && ipaddress !== '' ? '*' : ''; + }; + + return function decomposeHostname(hostname, decomposed) { + if ( decomposed.length === 0 || decomposed[0] !== hostname ) { + let broaden = isIPAddress(hostname) ? + toBroaderIPAddress : + toBroaderHostname; + decomposed[0] = hostname; + let i = 1; + for (;;) { + hostname = broaden(hostname); + if ( hostname === '' ) { break; } + decomposed[i++] = hostname; + } + decomposed.length = i; + } + return decomposed; + }; +})();