[mv3] Various approach to minimize DNR ruleset file

Related issue:
https://github.com/mozilla/addons-server/issues/4717
This commit is contained in:
Raymond Hill 2023-08-11 20:42:03 -04:00
parent 9d696998c7
commit a9a78d415d
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
1 changed files with 82 additions and 1 deletions

View File

@ -249,6 +249,54 @@ const isGood = rule =>
/******************************************************************************/ /******************************************************************************/
// Two distinct hostnames:
// www.example.com
// example.com
// Can be reduced to a single one:
// example.com
// Since if example.com matches, then www.example.com (or any other subdomain
// of example.com) will always match.
function pruneHostnameArray(hostnames) {
const rootMap = new Map();
for ( const hostname of hostnames ) {
const labels = hostname.split('.');
let currentMap = rootMap;
let i = labels.length;
while ( i-- ) {
const label = labels[i];
let nextMap = currentMap.get(label);
if ( nextMap === null ) { break; }
if ( nextMap === undefined ) {
if ( i === 0 ) {
currentMap.set(label, (nextMap = null));
} else {
currentMap.set(label, (nextMap = new Map()));
}
} else if ( i === 0 ) {
currentMap.set(label, null);
}
currentMap = nextMap;
}
}
const assemble = (currentMap, currentHostname, out) => {
for ( const [ label, nextMap ] of currentMap ) {
const nextHostname = currentHostname === ''
? label
: `${label}.${currentHostname}`;
if ( nextMap === null ) {
out.push(nextHostname);
} else {
assemble(nextMap, nextHostname, out);
}
}
return out;
};
return assemble(rootMap, '', []);
}
/******************************************************************************/
async function processNetworkFilters(assetDetails, network) { async function processNetworkFilters(assetDetails, network) {
const replacer = (k, v) => { const replacer = (k, v) => {
if ( k.startsWith('_') ) { return; } if ( k.startsWith('_') ) { return; }
@ -271,6 +319,37 @@ async function processNetworkFilters(assetDetails, network) {
log(`\tRejected filter count: ${network.rejectedFilterCount}`); log(`\tRejected filter count: ${network.rejectedFilterCount}`);
log(`Output rule count: ${rules.length}`); log(`Output rule count: ${rules.length}`);
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/declarativeNetRequest/RuleCondition#browser_compatibility
// isUrlFilterCaseSensitive is false by default in Firefox. It will be
// false by default in Chromium 118+.
if ( platform === 'firefox' ) {
for ( const rule of rules ) {
if ( rule.condition === undefined ) { continue; }
if ( rule.condition.urlFilter === undefined ) {
if ( rule.condition.regexFilter === undefined ) { continue; }
}
if ( rule.condition.isUrlFilterCaseSensitive === undefined ) {
rule.condition.isUrlFilterCaseSensitive = true;
} else if ( rule.condition.isUrlFilterCaseSensitive === false ) {
rule.condition.isUrlFilterCaseSensitive = undefined;
}
}
}
// Minimize requestDomains arrays
for ( const rule of rules ) {
const condition = rule.condition;
if ( condition === undefined ) { continue; }
const requestDomains = condition.requestDomains;
if ( requestDomains === undefined ) { continue; }
const beforeCount = requestDomains.length;
condition.requestDomains = pruneHostnameArray(requestDomains);
const afterCount = condition.requestDomains.length;
if ( afterCount !== beforeCount ) {
log(`\tPruning requestDomains: from ${beforeCount} to ${afterCount}`);
}
}
const plainGood = rules.filter(rule => isGood(rule) && isRegex(rule) === false); const plainGood = rules.filter(rule => isGood(rule) && isRegex(rule) === false);
log(`\tPlain good: ${plainGood.length}`); log(`\tPlain good: ${plainGood.length}`);
log(plainGood log(plainGood
@ -314,9 +393,11 @@ async function processNetworkFilters(assetDetails, network) {
log(`\tUnsupported: ${bad.length}`); log(`\tUnsupported: ${bad.length}`);
log(bad.map(rule => rule._error.map(v => `\t\t${v}`)).join('\n'), true); log(bad.map(rule => rule._error.map(v => `\t\t${v}`)).join('\n'), true);
const jsonIndent = platform !== 'firefox' ? 1 : undefined;
writeFile( writeFile(
`${rulesetDir}/main/${assetDetails.id}.json`, `${rulesetDir}/main/${assetDetails.id}.json`,
`${JSON.stringify(plainGood, replacer, 1)}\n` `${JSON.stringify(plainGood, replacer, jsonIndent)}\n`
); );
if ( regexes.length !== 0 ) { if ( regexes.length !== 0 ) {