Skip to content

Commit

Permalink
[mv3] Various approach to minimize DNR ruleset file
Browse files Browse the repository at this point in the history
  • Loading branch information
gorhill committed Aug 12, 2023
1 parent 9d69699 commit a9a78d4
Showing 1 changed file with 82 additions and 1 deletion.
83 changes: 82 additions & 1 deletion platform/mv3/make-rulesets.js
Expand Up @@ -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) {
const replacer = (k, v) => {
if ( k.startsWith('_') ) { return; }
Expand All @@ -271,6 +319,37 @@ async function processNetworkFilters(assetDetails, network) {
log(`\tRejected filter count: ${network.rejectedFilterCount}`);
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);
log(`\tPlain good: ${plainGood.length}`);
log(plainGood
Expand Down Expand Up @@ -314,9 +393,11 @@ async function processNetworkFilters(assetDetails, network) {
log(`\tUnsupported: ${bad.length}`);
log(bad.map(rule => rule._error.map(v => `\t\t${v}`)).join('\n'), true);

const jsonIndent = platform !== 'firefox' ? 1 : undefined;

writeFile(
`${rulesetDir}/main/${assetDetails.id}.json`,
`${JSON.stringify(plainGood, replacer, 1)}\n`
`${JSON.stringify(plainGood, replacer, jsonIndent)}\n`
);

if ( regexes.length !== 0 ) {
Expand Down

0 comments on commit a9a78d4

Please sign in to comment.