diff --git a/src/js/background.js b/src/js/background.js index 6aa6df696..1c86e1470 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -139,8 +139,8 @@ const µBlock = (( ) => { // jshint ignore:line // Read-only systemSettings: { - compiledMagic: 30, // Increase when compiled format changes - selfieMagic: 30, // Increase when selfie format changes + compiledMagic: 31, // Increase when compiled format changes + selfieMagic: 31, // Increase when selfie format changes }, // https://github.com/uBlockOrigin/uBlock-issues/issues/759#issuecomment-546654501 diff --git a/src/js/logger-ui.js b/src/js/logger-ui.js index 7a13b4d14..f76ff5925 100644 --- a/src/js/logger-ui.js +++ b/src/js/logger-ui.js @@ -302,7 +302,13 @@ const processLoggerEntries = function(response) { if ( autoDeleteVoidedRows ) { continue; } parsed.voided = true; } - if ( parsed.type === 'main_frame' && parsed.aliased === false ) { + if ( + parsed.type === 'main_frame' && + parsed.aliased === false && ( + parsed.filter === undefined || + parsed.filter.source !== 'redirect' + ) + ) { const separator = createLogSeparator(parsed, unboxed.url); loggerEntries.unshift(separator); if ( rowFilterer.filterOne(separator) ) { diff --git a/src/js/pagestore.js b/src/js/pagestore.js index f5e7e7acd..d9827a6b9 100644 --- a/src/js/pagestore.js +++ b/src/js/pagestore.js @@ -647,22 +647,9 @@ const PageStore = class { // Redirect non-blocked request? if ( (fctxt.itype & fctxt.INLINE_ANY) === 0 ) { if ( result === 1 ) { - if ( µb.hiddenSettings.ignoreRedirectFilters !== true ) { - const redirectURL = µb.redirectEngine.toURL(fctxt); - if ( redirectURL !== undefined ) { - fctxt.redirectURL = redirectURL; - this.internalRedirectionCount += 1; - fctxt.pushFilter({ - source: 'redirect', - raw: µb.redirectEngine.resourceNameRegister - }); - } - } + this.redirectBlockedRequest(fctxt); } else if ( snfe.hasQuery(fctxt) ) { - const directives = snfe.filterQuery(fctxt); - if ( directives !== undefined && loggerEnabled ) { - fctxt.pushFilters(directives.map(a => a.logData())); - } + this.redirectNonBlockedRequest(fctxt); } } @@ -675,6 +662,32 @@ const PageStore = class { return result; } + redirectBlockedRequest(fctxt) { + if ( µb.hiddenSettings.ignoreRedirectFilters === true ) { return; } + const directive = µb.staticNetFilteringEngine.redirectRequest(fctxt); + if ( directive === undefined ) { return; } + this.internalRedirectionCount += 1; + if ( µb.logger.enabled !== true ) { return; } + fctxt.pushFilter(directive.logData()); + if ( fctxt.redirectURL === undefined ) { return; } + fctxt.pushFilter({ + source: 'redirect', + raw: µb.redirectEngine.resourceNameRegister + }); + } + + redirectNonBlockedRequest(fctxt) { + const directives = µb.staticNetFilteringEngine.filterQuery(fctxt); + if ( directives === undefined ) { return; } + if ( µb.logger.enabled !== true ) { return; } + fctxt.pushFilters(directives.map(a => a.logData())); + if ( fctxt.redirectURL === undefined ) { return; } + fctxt.pushFilter({ + source: 'redirect', + raw: fctxt.redirectURL + }); + } + filterCSPReport(fctxt) { if ( µb.sessionSwitches.evaluateZ( diff --git a/src/js/redirect-engine.js b/src/js/redirect-engine.js index d24067847..6204189b9 100644 --- a/src/js/redirect-engine.js +++ b/src/js/redirect-engine.js @@ -275,24 +275,13 @@ const RedirectEngine = function() { this.aliases = new Map(); this.resources = new Map(); this.reset(); + this.modifyTime = Date.now(); this.resourceNameRegister = ''; }; /******************************************************************************/ RedirectEngine.prototype.reset = function() { - this.rules = new Map(); - this.ruleSources = new Set(); - this.ruleDestinations = new Set(); - this.resetCache(); - this.modifyTime = Date.now(); -}; - -RedirectEngine.prototype.resetCache = function() { - this._src = ''; - this._srcAll = [ '*' ]; - this._des = ''; - this._desAll = [ '*' ]; }; /******************************************************************************/ @@ -302,301 +291,25 @@ RedirectEngine.prototype.freeze = function() { /******************************************************************************/ -RedirectEngine.prototype.toBroaderHostname = function(hostname) { - const pos = hostname.indexOf('.'); - if ( pos !== -1 ) { - return hostname.slice(pos + 1); - } - return hostname !== '*' ? '*' : ''; -}; - -/******************************************************************************/ - -RedirectEngine.prototype.decomposeHostname = function(hn, dict, out) { - let i = 0; - for (;;) { - if ( dict.has(hn) ) { - out[i] = hn; i += 1; - } - hn = this.toBroaderHostname(hn); - if ( hn === '' ) { break; } - } - out.length = i; -}; - -/******************************************************************************/ - -RedirectEngine.prototype.lookup = function(fctxt) { - const src = fctxt.getDocHostname(); - const des = fctxt.getHostname(); - const type = fctxt.type; - if ( src !== this._src ) { - this._src = src; - this.decomposeHostname(src, this.ruleSources, this._srcAll); - } - if ( this._srcAll.length === 0 ) { return; } - if ( des !== this._des ) { - this._des = des; - this.decomposeHostname(des, this.ruleDestinations, this._desAll); - } - if ( this._desAll.length === 0 ) { return; } - const reqURL = fctxt.url; - for ( const src of this._srcAll ) { - for ( const des of this._desAll ) { - let entries = this.rules.get(`${src} ${des} ${type}`); - if ( entries !== undefined ) { - const rule = this.lookupRule(entries, reqURL); - if ( rule !== undefined ) { return rule; } - } - entries = this.rules.get(`${src} ${des} *`); - if ( entries !== undefined ) { - const rule = this.lookupRule(entries, reqURL); - if ( rule !== undefined ) { return rule; } - } - } - } -}; - -RedirectEngine.prototype.lookupRule = function(entries, reqURL) { - for ( const entry of entries ) { - if ( entry.pat instanceof RegExp === false ) { - entry.pat = new RegExp(entry.pat, 'i'); - } - if ( entry.pat.test(reqURL) ) { - return entry; - } - } -}; - -/******************************************************************************/ - -RedirectEngine.prototype.toURL = function(fctxt) { - const rule = this.lookup(fctxt); - if ( rule === undefined ) { return; } - let token = this.resourceNameRegister = rule.tok; +RedirectEngine.prototype.tokenToURL = function(fctxt, token) { const asDataURI = token.charCodeAt(0) === 0x25 /* '%' */; if ( asDataURI ) { token = token.slice(1); } const entry = this.resources.get(this.aliases.get(token) || token); - if ( entry !== undefined ) { - return entry.toURL(fctxt, asDataURI); - } + if ( entry === undefined ) { return; } + this.resourceNameRegister = token; + return entry.toURL(fctxt, asDataURI); }; /******************************************************************************/ -RedirectEngine.prototype.addRule = function(src, des, type, pattern, redirect) { - this.ruleSources.add(src); - this.ruleDestinations.add(des); - const key = `${src} ${des} ${type}`, - entries = this.rules.get(key); - if ( entries === undefined ) { - this.rules.set(key, [ { tok: redirect, pat: pattern } ]); - this.modifyTime = Date.now(); - return; - } - let entry; - for ( var i = 0, n = entries.length; i < n; i++ ) { - entry = entries[i]; - if ( redirect === entry.tok ) { break; } - } - if ( i === n ) { - entries.push({ tok: redirect, pat: pattern }); - return; - } - let p = entry.pat; - if ( p instanceof RegExp ) { - p = p.source; - } - // Duplicate? - let pos = p.indexOf(pattern); - if ( pos !== -1 ) { - if ( pos === 0 || p.charAt(pos - 1) === '|' ) { - pos += pattern.length; - if ( pos === p.length || p.charAt(pos) === '|' ) { return; } - } - } - entry.pat = p + '|' + pattern; +RedirectEngine.prototype.toSelfie = async function() { }; /******************************************************************************/ -RedirectEngine.prototype.fromCompiledRule = function(line) { - const fields = line.split('\t'); - if ( fields.length !== 5 ) { return; } - this.addRule(fields[0], fields[1], fields[2], fields[3], fields[4]); -}; - -/******************************************************************************/ - -RedirectEngine.prototype.compileRuleFromStaticFilter = function(line) { - const matches = this.reFilterParser.exec(line); - if ( matches === null || matches.length !== 4 ) { return; } - - const des = matches[1] || ''; - - // https://github.com/uBlockOrigin/uBlock-issues/issues/572 - // Extract best possible hostname. - let deshn = des; - let pos = deshn.lastIndexOf('*'); - if ( pos !== -1 ) { - deshn = deshn.slice(pos + 1); - pos = deshn.indexOf('.'); - if ( pos !== -1 ) { - deshn = deshn.slice(pos + 1); - } else { - deshn = ''; - } - } - - const path = matches[2] || ''; - let pattern = - des - .replace(/\*/g, '[\\w.%-]*') - .replace(/\./g, '\\.') + - path - .replace(/\|$/, '$') - .replace(/[.+?{}()|[\]\/\\]/g, '\\$&') - .replace(/\^/g, '[^\\w.%-]') - .replace(/\*/g, '.*?'); - if ( pattern === '' ) { - pattern = '^'; - } - - let type, - redirect = '', - srchns = []; - for ( const option of matches[3].trim().split(/,/) ) { - if ( option.startsWith('redirect=') ) { - redirect = option.slice(9); - continue; - } - if ( option.startsWith('redirect-rule=') ) { - redirect = option.slice(14); - continue; - } - if ( option === 'empty' ) { - redirect = 'empty'; - continue; - } - if ( option === 'mp4' ) { - redirect = 'noopmp4-1s'; - continue; - } - if ( option.startsWith('domain=') ) { - srchns = option.slice(7).split('|'); - continue; - } - if ( (option === 'first-party' || option === '1p') && deshn !== '' ) { - srchns.push(µBlock.URI.domainFromHostname(deshn) || deshn); - continue; - } - // One and only one type must be specified. - if ( this.supportedTypes.has(option) ) { - if ( type !== undefined ) { return; } - type = this.supportedTypes.get(option); - continue; - } - } - - // Need a resource token. - if ( redirect === '' ) { return; } - - // Need one single type -- not negated. - if ( type === undefined ) { - if ( redirect === 'empty' ) { - type = '*'; - } else if ( redirect === 'noopmp4-1s' ) { - type = 'media'; - } else { - return; - } - } - - if ( deshn === '' ) { - deshn = '*'; - } - - if ( srchns.length === 0 ) { - srchns.push('*'); - } - - const out = []; - for ( const srchn of srchns ) { - if ( srchn === '' ) { continue; } - if ( srchn.startsWith('~') ) { continue; } - out.push(`${srchn}\t${deshn}\t${type}\t${pattern}\t${redirect}`); - } - - if ( out.length === 0 ) { return; } - - return out; -}; - -/******************************************************************************/ - -RedirectEngine.prototype.reFilterParser = /^(?:\|\|([^\/:?#^]+)|\*?)([^$]+)?\$([^$]+)$/; - -RedirectEngine.prototype.supportedTypes = new Map([ - [ 'css', 'stylesheet' ], - [ 'font', 'font' ], - [ 'image', 'image' ], - [ 'media', 'media' ], - [ 'object', 'object' ], - [ 'script', 'script' ], - [ 'stylesheet', 'stylesheet' ], - [ 'frame', 'sub_frame' ], - [ 'subdocument', 'sub_frame' ], - [ 'xhr', 'xmlhttprequest' ], - [ 'xmlhttprequest', 'xmlhttprequest' ], -]); - -/******************************************************************************/ - -RedirectEngine.prototype.toSelfie = function(path) { - // Because rules may contains RegExp instances, we need to manually - // convert it to a serializable format. The serialized format must be - // suitable to be used as an argument to the Map() constructor. - const rules = []; - for ( const item of this.rules ) { - const rule = [ item[0], [] ]; - const entries = item[1]; - let i = entries.length; - while ( i-- ) { - const entry = entries[i]; - rule[1].push({ - tok: entry.tok, - pat: entry.pat instanceof RegExp ? entry.pat.source : entry.pat - }); - } - rules.push(rule); - } - return µBlock.assets.put( - `${path}/main`, - JSON.stringify({ - rules: rules, - ruleSources: Array.from(this.ruleSources), - ruleDestinations: Array.from(this.ruleDestinations) - }) - ); -}; - -/******************************************************************************/ - -RedirectEngine.prototype.fromSelfie = async function(path) { - const result = await µBlock.assets.get(`${path}/main`); - let selfie; - try { - selfie = JSON.parse(result.content); - } catch (ex) { - } - if ( selfie instanceof Object === false ) { return false; } - this.rules = new Map(selfie.rules); - this.ruleSources = new Set(selfie.ruleSources); - this.ruleDestinations = new Set(selfie.ruleDestinations); - this.resetCache(); - this.modifyTime = Date.now(); +RedirectEngine.prototype.fromSelfie = async function() { return true; }; @@ -851,9 +564,6 @@ RedirectEngine.prototype.resourcesFromSelfie = async function() { RedirectEngine.prototype.invalidateResourcesSelfie = function() { µBlock.assets.remove('compiled/redirectEngine/resources'); - - // TODO: obsolete, remove eventually - µBlock.cacheStorage.remove('resourcesSelfie'); }; /******************************************************************************/ diff --git a/src/js/static-filtering-parser.js b/src/js/static-filtering-parser.js index 098a99e5b..b7410e87f 100644 --- a/src/js/static-filtering-parser.js +++ b/src/js/static-filtering-parser.js @@ -2069,8 +2069,8 @@ const netOptionTokenDescriptors = new Map([ [ 'popunder', OPTTokenPopunder | OPTType ], [ 'popup', OPTTokenPopup | OPTType | OPTCanNegate ], [ 'queryprune', OPTTokenQueryprune | OPTMustAssign | OPTAllowMayAssign | OPTModifierType ], - [ 'redirect', OPTTokenRedirect | OPTMustAssign | OPTBlockOnly | OPTRedirectType | OPTModifierType ], - [ 'redirect-rule', OPTTokenRedirectRule | OPTMustAssign | OPTBlockOnly | OPTRedirectType | OPTModifierType ], + [ 'redirect', OPTTokenRedirect | OPTMustAssign | OPTAllowMayAssign | OPTModifierType | OPTRedirectType ], + [ 'redirect-rule', OPTTokenRedirectRule | OPTMustAssign | OPTAllowMayAssign | OPTModifierType | OPTRedirectType ], [ 'script', OPTTokenScript | OPTCanNegate | OPTType | OPTNetworkType | OPTModifiableType ], [ 'shide', OPTTokenShide | OPTType ], [ 'specifichide', OPTTokenShide | OPTType ], diff --git a/src/js/static-net-filtering.js b/src/js/static-net-filtering.js index 5356cf34d..f083b37b5 100644 --- a/src/js/static-net-filtering.js +++ b/src/js/static-net-filtering.js @@ -2267,7 +2267,6 @@ const FilterParser = class { this.denyallowOpt = ''; this.isPureHostname = false; this.isRegex = false; - this.redirect = 0; this.token = '*'; this.tokenHash = this.noTokenHash; this.tokenBeg = 0; @@ -2355,6 +2354,7 @@ const FilterParser = class { this.badFilter = true; break; case parser.OPTTokenCsp: + if ( this.modifyType !== undefined ) { return false; } this.modifyType = parser.OPTTokenCsp; if ( val !== undefined ) { if ( this.reBadCSP.test(val) ) { return false; } @@ -2391,14 +2391,20 @@ const FilterParser = class { // Used by Adguard: // https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#empty-modifier case parser.OPTTokenEmpty: + if ( this.modifyType !== undefined ) { return false; } + this.modifyType = parser.OPTTokenRedirect; + this.modifyValue = 'empty'; + break; case parser.OPTTokenMp4: - case parser.OPTTokenRedirect: - case parser.OPTTokenRedirectRule: - if ( this.redirect !== 0 ) { return false; } - this.redirect = id === parser.OPTTokenRedirectRule ? 2 : 1; + if ( this.modifyType !== undefined ) { return false; } + this.modifyType = parser.OPTTokenRedirect; + this.modifyValue = 'noopmp4-1s'; break; case parser.OPTTokenQueryprune: - this.modifyType = parser.OPTTokenQueryprune; + case parser.OPTTokenRedirect: + case parser.OPTTokenRedirectRule: + if ( this.modifyType !== undefined ) { return false; } + this.modifyType = id; if ( val !== undefined ) { this.modifyValue = val; } else if ( this.action === AllowAction ) { @@ -2748,7 +2754,6 @@ FilterContainer.prototype.reset = function() { FilterContainer.prototype.freeze = function() { const filterBucketId = FilterBucket.fid; - const redirectTypeValue = typeNameToTypeValue.redirect; const unserialize = µb.CompiledLineIO.unserialize; const units = filterUnits; @@ -2763,13 +2768,6 @@ FilterContainer.prototype.freeze = function() { const args = unserialize(line); const bits = args[0]; - // Special cases: delegate to more specialized engines. - // Redirect engine. - if ( (bits & TypeBitsMask) === redirectTypeValue ) { - µb.redirectEngine.fromCompiledRule(args[1]); - continue; - } - // Plain static filters. const tokenHash = args[1]; const fdata = args[2]; @@ -2994,21 +2992,6 @@ FilterContainer.prototype.compile = function(parser, writer) { return false; } - // Redirect rule - if ( parsed.redirect !== 0 ) { - const result = this.compileRedirectRule(parser.raw, parsed.badFilter, writer); - if ( result === false ) { - const who = writer.properties.get('assetKey') || '?'; - µb.logger.writeOne({ - realm: 'message', - type: 'error', - text: `Invalid redirect rule in ${who}: ${parser.raw}` - }); - return false; - } - if ( parsed.redirect === 2 ) { return true; } - } - // Pure hostnames, use more efficient dictionary lookup // https://github.com/chrisaljoudi/uBlock/issues/665 // Create a dict keyed on request type etc. @@ -3099,8 +3082,20 @@ FilterContainer.prototype.compile = function(parser, writer) { units.push(FilterDenyAllow.compile(parsed)); } - // Data + // Modifier if ( parsed.modifyType !== undefined ) { + // A block filter is implicit with `redirect=` modifier + if ( + parsed.modifyType === parser.OPTTokenRedirect && + (parsed.action & ActionBitsMask) !== AllowAction + ) { + this.compileToAtomicFilter( + parsed, + FilterCompositeAll.compile(units), + writer + ); + parsed.modifyType = parser.OPTTokenRedirectRule; + } units.push(FilterModifier.compile(parsed)); parsed.action = ModifyAction; parsed.important = 0; @@ -3109,7 +3104,6 @@ FilterContainer.prototype.compile = function(parser, writer) { const fdata = units.length === 1 ? units[0] : FilterCompositeAll.compile(units); - this.compileToAtomicFilter(parsed, fdata, writer); return true; @@ -3158,19 +3152,6 @@ FilterContainer.prototype.compileToAtomicFilter = function( /******************************************************************************/ -FilterContainer.prototype.compileRedirectRule = function(raw, badFilter, writer) { - const redirects = µb.redirectEngine.compileRuleFromStaticFilter(raw); - if ( Array.isArray(redirects) === false ) { return false; } - writer.select(badFilter ? 1 : 0); - const type = typeNameToTypeValue.redirect; - for ( const redirect of redirects ) { - writer.push([ type, redirect ]); - } - return true; -}; - -/******************************************************************************/ - FilterContainer.prototype.fromCompiledContent = function(reader) { // 0 = network filters reader.select(0); @@ -3192,18 +3173,6 @@ FilterContainer.prototype.fromCompiledContent = function(reader) { /******************************************************************************/ -// TODO: -// Evaluate converting redirect directives in redirect engine into -// modifiers in static network filtering engine. -// -// Advantages: no more syntax quirks, gain all performance benefits, ability -// to reverse-lookup list of redirect directive in logger. -// -// Challenges: need to figure a way to calculate specificity so that the -// most specific redirect directive out of many can be -// identified (possibly based on total number of hostname labels -// seen at compile time). - FilterContainer.prototype.matchAndFetchModifiers = function( fctxt, modifierType @@ -3554,6 +3523,54 @@ FilterContainer.prototype.matchString = function(fctxt, modifiers = 0) { /******************************************************************************/ +FilterContainer.prototype.redirectRequest = function(fctxt) { + const directives = this.matchAndFetchModifiers(fctxt, 'redirect-rule'); + if ( directives === undefined ) { return; } + let winningDirective; + let winningPriority = 0; + for ( const directive of directives ) { + const modifier = directive.modifier; + const isException = (directive.bits & ActionBitsMask) === AllowAction; + if ( isException && modifier.value === '' ) { + winningDirective = directive; + break; + } + if ( modifier.cache === undefined ) { + const rawToken = modifier.value; + let token = rawToken; + let priority = 0; + const match = /:(\d+)$/.exec(rawToken); + if ( match !== null ) { + token = rawToken.slice(0, match.index); + priority = parseInt(match[1], 10); + } + modifier.cache = { token, priority }; + } + if ( + winningDirective === undefined || + modifier.cache.priority > winningPriority + ) { + winningDirective = directive; + winningPriority = modifier.cache.priority; + } + } + if ( winningDirective === undefined ) { return; } + if ( (winningDirective.bits & ActionBitsMask) !== AllowAction ) { + fctxt.redirectURL = µb.redirectEngine.tokenToURL( + fctxt, + winningDirective.modifier.cache.token + ); + } + return winningDirective; +}; + +FilterContainer.prototype.hasQuery = function(fctxt) { + urlTokenizer.setURL(fctxt.url); + return urlTokenizer.hasQuery(); +}; + +/******************************************************************************/ + FilterContainer.prototype.filterQuery = function(fctxt) { const directives = this.matchAndFetchModifiers(fctxt, 'queryprune'); if ( directives === undefined ) { return; } @@ -3564,6 +3581,11 @@ FilterContainer.prototype.filterQuery = function(fctxt) { const out = []; for ( const directive of directives ) { const modifier = directive.modifier; + const isException = (directive.bits & ActionBitsMask) === AllowAction; + if ( isException && modifier.value === '' ) { + out.push(directive); + break; + } if ( modifier.cache === undefined ) { let retext = modifier.value; if ( retext.startsWith('|') ) { retext = `^${retext.slice(1)}`; } @@ -3574,7 +3596,9 @@ FilterContainer.prototype.filterQuery = function(fctxt) { let filtered = false; for ( const [ key, value ] of params ) { if ( re.test(`${key}=${value}`) === false ) { continue; } - params.delete(key); + if ( isException === false ) { + params.delete(key); + } filtered = true; } if ( filtered ) { @@ -3699,11 +3723,15 @@ FilterContainer.prototype.benchmark = async function(action, target) { print(`\turl=${fctxt.url}`); print(`\tdocOrigin=${fctxt.getDocOrigin()}`); } - if ( r !== 1 && this.hasQuery(fctxt) ) { - this.filterQuery(fctxt, 'queryprune'); - } - if ( r !== 1 && fctxt.type === 'main_frame' || fctxt.type === 'sub_frame' ) { - this.matchAndFetchModifiers(fctxt, 'csp'); + if ( r !== 1 ) { + if ( this.hasQuery(fctxt) ) { + this.filterQuery(fctxt, 'queryprune'); + } + if ( fctxt.type === 'main_frame' || fctxt.type === 'sub_frame' ) { + this.matchAndFetchModifiers(fctxt, 'csp'); + } + } else { + this.redirectRequest(fctxt); } } const t1 = self.performance.now(); diff --git a/src/js/traffic.js b/src/js/traffic.js index 4d2e53c4e..34b44711a 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -205,25 +205,19 @@ const onBeforeRootFrameRequest = function(fctxt) { } const pageStore = µb.bindTabToPageStats(fctxt.tabId, 'beforeRequest'); - if ( pageStore ) { + if ( pageStore !== null ) { pageStore.journalAddRootFrame('uncommitted', requestURL); pageStore.journalAddRequest(requestHostname, result); } - // Log if ( loggerEnabled ) { - fctxt.setRealm('network').setFilter(logData); + fctxt.setFilter(logData); } - // Modifier(s)? - // A modifier is an action which transform the original network request. // https://github.com/uBlockOrigin/uBlock-issues/issues/760 // Redirect non-blocked request? - if ( result === 0 && snfe.hasQuery(fctxt) ) { - const directives = snfe.filterQuery(fctxt); - if ( directives !== undefined && loggerEnabled ) { - fctxt.pushFilters(directives.map(a => a.logData())); - } + if ( result === 0 && pageStore !== null && snfe.hasQuery(fctxt) ) { + pageStore.redirectNonBlockedRequest(fctxt); } if ( loggerEnabled ) {