diff --git a/src/js/codemirror/ubo-static-filtering.js b/src/js/codemirror/ubo-static-filtering.js index 79dc3618b..976554a20 100644 --- a/src/js/codemirror/ubo-static-filtering.js +++ b/src/js/codemirror/ubo-static-filtering.js @@ -192,11 +192,12 @@ CodeMirror.defineMode('ubo-static-filtering', function() { parser.commentSpan.i, parser.BITComma ); - const token = parser.strFromSlices(parserSlot, end - 3); + const raw = parser.strFromSlices(parserSlot, end - 3); + const { token } = StaticFilteringParser.parseRedirectValue(raw); if ( redirectNames.has(token) === false ) { style += ' warning'; } - stream.pos += token.length; + stream.pos += raw.length; parserSlot = end; return style; } diff --git a/src/js/pagestore.js b/src/js/pagestore.js index 505fe2a2a..037c84875 100644 --- a/src/js/pagestore.js +++ b/src/js/pagestore.js @@ -716,10 +716,10 @@ const PageStore = class { redirectBlockedRequest(fctxt) { if ( µb.hiddenSettings.ignoreRedirectFilters === true ) { return; } - const directive = µb.staticNetFilteringEngine.redirectRequest(fctxt); - if ( directive === undefined ) { return; } + const directives = µb.staticNetFilteringEngine.redirectRequest(fctxt); + if ( directives === undefined ) { return; } if ( µb.logger.enabled !== true ) { return; } - fctxt.pushFilter(directive.logData()); + fctxt.pushFilters(directives.map(a => a.logData())); if ( fctxt.redirectURL === undefined ) { return; } fctxt.pushFilter({ source: 'redirect', diff --git a/src/js/static-filtering-parser.js b/src/js/static-filtering-parser.js index dbe64875b..cd2732628 100644 --- a/src/js/static-filtering-parser.js +++ b/src/js/static-filtering-parser.js @@ -1162,6 +1162,17 @@ const Parser = class { ); } + static parseRedirectValue(arg) { + let token = arg.trim(); + let priority = 10; + const match = /:\d+$/.exec(token); + if ( match !== null ) { + token = token.slice(0, match.index); + priority = parseInt(token.slice(match.index + 1), 10); + } + return { token, priority }; + } + static parseQueryPruneValue(arg) { let s = arg.trim(); if ( s === '' ) { return { all: true }; } diff --git a/src/js/static-net-filtering.js b/src/js/static-net-filtering.js index 8245b6d0e..b5f83382b 100644 --- a/src/js/static-net-filtering.js +++ b/src/js/static-net-filtering.js @@ -4236,57 +4236,41 @@ FilterContainer.prototype.redirectRequest = function(fctxt) { const directives = this.matchAndFetchModifiers(fctxt, 'redirect-rule'); // No directive is the most common occurrence. if ( directives === undefined ) { return; } - // A single directive should be the next most common occurrence. - if ( directives.length === 1 ) { - const directive = directives[0]; - if ( (directive.bits & AllowAction) !== 0 ) { return directive; } - const modifier = directive.modifier; - const { token } = this.parseRedirectRequestValue(modifier); + // More than a single directive means more work. + if ( directives.length !== 1 ) { + directives.sort(FilterContainer.compareRedirectRequests); + } + // Redirect to highest-ranked directive + const directive = directives[directives.length - 1]; + if ( (directive.bits & AllowAction) === 0 ) { + const { token } = + FilterContainer.parseRedirectRequestValue(directive.modifier); fctxt.redirectURL = µb.redirectEngine.tokenToURL(fctxt, token); if ( fctxt.redirectURL === undefined ) { return; } - return directive; } - // Multiple directives mean more work to do. - let winningDirective; - let winningPriority = 0; - for ( const directive of directives ) { - const modifier = directive.modifier; - const isException = (directive.bits & AllowAction) !== 0; - if ( isException && modifier.value === '' ) { - winningDirective = directive; - break; - } - const { token, priority } = this.parseRedirectRequestValue(modifier); - if ( µb.redirectEngine.hasToken(token) === false ) { continue; } - if ( winningDirective === undefined || priority > winningPriority ) { - winningDirective = directive; - winningPriority = priority; - } - } - if ( winningDirective === undefined ) { return; } - if ( (winningDirective.bits & AllowAction) === 0 ) { - fctxt.redirectURL = µb.redirectEngine.tokenToURL( - fctxt, - winningDirective.modifier.cache.token - ); - } - return winningDirective; + return directives; }; -FilterContainer.prototype.parseRedirectRequestValue = function(modifier) { +FilterContainer.parseRedirectRequestValue = function(modifier) { if ( modifier.cache === undefined ) { - let token = modifier.value; - let priority = 1; - const match = /:(\d+)$/.exec(token); - if ( match !== null ) { - token = token.slice(0, match.index); - priority = parseInt(match[1], 10); - } - modifier.cache = { token, priority }; + modifier.cache = + vAPI.StaticFilteringParser.parseRedirectValue(modifier.value); } return modifier.cache; }; +FilterContainer.compareRedirectRequests = function(a, b) { + if ( (a.bits & AllowAction) !== 0 ) { return -1; } + if ( (b.bits & AllowAction) !== 0 ) { return 1; } + const { token: atok, priority: aint } = + FilterContainer.parseRedirectRequestValue(a.modifier); + if ( µb.redirectEngine.hasToken(atok) === false ) { return -1; } + const { token: btok, priority: bint } = + FilterContainer.parseRedirectRequestValue(b.modifier); + if ( µb.redirectEngine.hasToken(btok) === false ) { return 1; } + return aint - bint; +}; + /******************************************************************************/ FilterContainer.prototype.filterQuery = function(fctxt) {