Improve reporting of matching `redirect=` rules in logger

All matching `redirect-rule` directives will now be reported
in the logger, instead of just the effective one.

The highest-ranked redirect directive will be the one
effectively used for redirection. This way filter list
authors can see whether a lower priority redirect is
being overriden by a higher priority one.

The default priority has been changed to 10, so as to allow
more leeway to create lower ranked redirect directives.

Additonally, rendering of redirect directives with explicit
priority has been fixed in the logger, they will no longer
be rendered as unknown redirect tokens.
This commit is contained in:
Raymond Hill 2020-12-01 09:29:40 -05:00
parent e08f8cb001
commit cf2c638d8e
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
4 changed files with 42 additions and 46 deletions

View File

@ -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;
}

View File

@ -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',

View File

@ -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 }; }

View File

@ -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) {