Skip to content

Commit

Permalink
Add ability to directly evaluate static network filtering engine
Browse files Browse the repository at this point in the history
Related issue:
uBlockOrigin/uBlock-issues#3362

There used to be a way to test URL against the network filtering engine,
but this was removed in a distant past during refactoring.

The ability has been brought back through uBO's own developer tools,
accessible through the _More_ button in the _Support_ pane in the
dashboard.

To query the static network filtering engine, enter the following
in the text editor:

snfe?url-to-test [type] [url-of-context]

`snfe?` is a prompt indicating the intent to query the static network
filtering engine.

At a minimum there must be a URL to test.

Optionally the type of the resource to match, default to `xhr` if
none specified. Also optionally, the context from within which the
request is made. Example:

Enter:
snfe?https://www.google-analytics.com/analytics.js

Result:
url: https://www.google-analytics.com/analytics.js
blocked: ||google-analytics.com^

Enter:
snfe?https://www.google-analytics.com/analytics.js script

Result:
url: https://www.google-analytics.com/analytics.js
type: script
blocked: ||google-analytics.com^
modified: ||google-analytics.com/analytics.js$script,redirect-rule=google-analytics_analytics.js:5

Enter:
snfe?https://example.com/

Result:
url: https://example.com/
not blocked

Enter:
snfe?https://example.com/ ping

Result:
url: https://example.com/
type: ping
blocked: *$ping,3p
  • Loading branch information
gorhill committed Sep 2, 2024
1 parent eef99e9 commit b7ed3b4
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 78 deletions.
1 change: 1 addition & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ rules:
- error
- 4
- ignoredNodes:
- Program > BlockStatement
- Program > IfStatement > BlockStatement
- Program > ExpressionStatement > CallExpression > ArrowFunctionExpression > BlockStatement
- Program > ExpressionStatement > CallExpression > FunctionExpression > BlockStatement
Expand Down
50 changes: 23 additions & 27 deletions src/js/benchmarks.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,22 @@
Home: https://github.com/gorhill/uBlock
*/

'use strict';

/******************************************************************************/

import cosmeticFilteringEngine from './cosmetic-filtering.js';
import io from './assets.js';
import scriptletFilteringEngine from './scriptlet-filtering.js';
import staticNetFilteringEngine from './static-net-filtering.js';
import µb from './background.js';
import webRequest from './traffic.js';
import { FilteringContext } from './filtering-context.js';
import { LineIterator } from './text-utils.js';
import { sessionFirewall } from './filtering-engines.js';

import {
domainFromHostname,
entityFromDomain,
hostnameFromURI,
} from './uri-utils.js';

import { FilteringContext } from './filtering-context.js';
import { LineIterator } from './text-utils.js';
import cosmeticFilteringEngine from './cosmetic-filtering.js';
import io from './assets.js';
import scriptletFilteringEngine from './scriptlet-filtering.js';
import { sessionFirewall } from './filtering-engines.js';
import { default as sfne } from './static-net-filtering.js';
import webRequest from './traffic.js';
import µb from './background.js';

/******************************************************************************/

// The requests.json.gz file can be downloaded from:
Expand Down Expand Up @@ -155,13 +151,13 @@ export async function benchmarkStaticNetFiltering(options = {}) {
fctxt.setURL(request.url);
fctxt.setDocOriginFromURL(request.frameUrl);
fctxt.setType(request.cpt);
const r = staticNetFilteringEngine.matchRequest(fctxt);
const r = sfne.matchRequest(fctxt);
console.info(`Result=${r}:`);
console.info(`\ttype=${fctxt.type}`);
console.info(`\turl=${fctxt.url}`);
console.info(`\tdocOrigin=${fctxt.getDocOrigin()}`);
if ( r !== 0 ) {
console.info(staticNetFilteringEngine.toLogData());
console.info(sfne.toLogData());
}
return;
}
Expand All @@ -180,34 +176,34 @@ export async function benchmarkStaticNetFiltering(options = {}) {
fctxt.setURL(request.url);
fctxt.setDocOriginFromURL(request.frameUrl);
fctxt.setType(request.cpt);
staticNetFilteringEngine.redirectURL = undefined;
const r = staticNetFilteringEngine.matchRequest(fctxt);
sfne.redirectURL = undefined;
const r = sfne.matchRequest(fctxt);
matchCount += 1;
if ( r === 1 ) { blockCount += 1; }
else if ( r === 2 ) { allowCount += 1; }
if ( r !== 1 ) {
if ( staticNetFilteringEngine.transformRequest(fctxt) ) {
if ( sfne.transformRequest(fctxt) ) {
redirectCount += 1;
}
if ( fctxt.redirectURL !== undefined && staticNetFilteringEngine.hasQuery(fctxt) ) {
if ( staticNetFilteringEngine.filterQuery(fctxt, 'removeparam') ) {
if ( fctxt.redirectURL !== undefined && sfne.hasQuery(fctxt) ) {
if ( sfne.filterQuery(fctxt, 'removeparam') ) {
removeparamCount += 1;
}
}
if ( fctxt.type === 'main_frame' || fctxt.type === 'sub_frame' ) {
if ( staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'csp') ) {
if ( sfne.matchAndFetchModifiers(fctxt, 'csp') ) {
cspCount += 1;
}
if ( staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'permissions') ) {
if ( sfne.matchAndFetchModifiers(fctxt, 'permissions') ) {
permissionsCount += 1;
}
}
staticNetFilteringEngine.matchHeaders(fctxt, []);
if ( staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'replace') ) {
sfne.matchHeaders(fctxt, []);
if ( sfne.matchAndFetchModifiers(fctxt, 'replace') ) {
replaceCount += 1;
}
} else if ( redirectEngine !== undefined ) {
if ( staticNetFilteringEngine.redirectRequest(redirectEngine, fctxt) ) {
if ( sfne.redirectRequest(redirectEngine, fctxt) ) {
redirectCount += 1;
}
}
Expand Down Expand Up @@ -254,7 +250,7 @@ export async function tokenHistogramsfunction() {
fctxt.setURL(request.url);
fctxt.setDocOriginFromURL(request.frameUrl);
fctxt.setType(request.cpt);
const r = staticNetFilteringEngine.matchRequest(fctxt);
const r = sfne.matchRequest(fctxt);
for ( let [ keyword ] of request.url.toLowerCase().matchAll(reTokens) ) {
const token = keyword.slice(0, 7);
if ( r === 0 ) {
Expand Down
43 changes: 41 additions & 2 deletions src/js/devtools.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@

/* global CodeMirror, uBlockDashboard */

'use strict';

import { dom, qs$ } from './dom.js';

/******************************************************************************/
Expand Down Expand Up @@ -212,3 +210,44 @@ vAPI.messaging.send('dashboard', {
});

/******************************************************************************/

async function snfeQuery(lineNo, query) {
const doc = cmEditor.getDoc();
const lineHandle = doc.getLineHandle(lineNo)
const result = await vAPI.messaging.send('devTools', {
what: 'snfeQuery',
query
});
if ( typeof result !== 'string' ) { return; }
cmEditor.startOperation();
const nextLineNo = doc.getLineNumber(lineHandle) + 1;
doc.replaceRange(`${result}\n`, { line: nextLineNo, ch: 0 });
cmEditor.endOperation();
}

cmEditor.on('beforeChange', (cm, details) => {
if ( details.origin !== '+input' ) { return; }
if ( details.text.length !== 2 ) { return; }
if ( details.text[1] !== '' ) { return; }
const lineNo = details.from.line;
const line = cm.getLine(lineNo);
if ( details.from.ch !== line.length ) { return; }
if ( line.startsWith('snfe?') === false ) { return; }
const fields = line.slice(5).split(/\s+/);
const query = {};
for ( const field of fields ) {
if ( /[/.]/.test(field) ) {
if ( query.url === undefined ) {
query.url = field;
} else if ( query.from === undefined ) {
query.from = field;
}
} else if ( query.type === undefined ) {
query.type = field;
}
}
if ( query.url === undefined ) { return; }
snfeQuery(lineNo, query);
});

/******************************************************************************/
90 changes: 47 additions & 43 deletions src/js/messaging.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,53 +19,50 @@
Home: https://github.com/gorhill/uBlock
*/

/* globals browser */

'use strict';
import * as s14e from './s14e-serializer.js';
import * as sfp from './static-filtering-parser.js';

/******************************************************************************/
import {
domainFromHostname,
domainFromURI,
entityFromDomain,
hostnameFromURI,
isNetworkURI,
} from './uri-utils.js';

import publicSuffixList from '../lib/publicsuffixlist/publicsuffixlist.js';
import punycode from '../lib/punycode.js';
import {
permanentFirewall,
permanentSwitches,
permanentURLFiltering,
sessionFirewall,
sessionSwitches,
sessionURLFiltering,
} from './filtering-engines.js';

import { filteringBehaviorChanged } from './broadcast.js';
import cacheStorage from './cachestorage.js';
import cosmeticFilteringEngine from './cosmetic-filtering.js';
import { denseBase64 } from './base64-custom.js';
import { dnrRulesetFromRawLists } from './static-dnr-filtering.js';
import { filteringBehaviorChanged } from './broadcast.js';
import htmlFilteringEngine from './html-filtering.js';
import { i18n$ } from './i18n.js';
import io from './assets.js';
import logger from './logger.js';
import lz4Codec from './lz4.js';
import io from './assets.js';
import publicSuffixList from '../lib/publicsuffixlist/publicsuffixlist.js';
import punycode from '../lib/punycode.js';
import { redirectEngine } from './redirect-engine.js';
import scriptletFilteringEngine from './scriptlet-filtering.js';
import staticFilteringReverseLookup from './reverselookup.js';
import staticNetFilteringEngine from './static-net-filtering.js';
import µb from './background.js';
import webRequest from './traffic.js';
import { denseBase64 } from './base64-custom.js';
import { dnrRulesetFromRawLists } from './static-dnr-filtering.js';
import { i18n$ } from './i18n.js';
import { redirectEngine } from './redirect-engine.js';
import * as sfp from './static-filtering-parser.js';
import * as s14e from './s14e-serializer.js';

import {
permanentFirewall,
sessionFirewall,
permanentSwitches,
sessionSwitches,
permanentURLFiltering,
sessionURLFiltering,
} from './filtering-engines.js';

import {
domainFromHostname,
domainFromURI,
entityFromDomain,
hostnameFromURI,
isNetworkURI,
} from './uri-utils.js';
import µb from './background.js';

/******************************************************************************/

const hasOwnProperty = (o, p) =>
Object.prototype.hasOwnProperty.call(o, p);

// https://github.com/uBlockOrigin/uBlock-issues/issues/710
// Listeners have a name and a "privileged" status.
// The nameless default handler is always deemed "privileged".
Expand Down Expand Up @@ -807,7 +804,7 @@ const onMessage = function(request, sender, callback) {
});
break;

case 'shouldRenderNoscriptTags':
case 'shouldRenderNoscriptTags': {
if ( pageStore === null ) { break; }
const fctxt = µb.filteringContext.fromTabId(sender.tabId);
if ( pageStore.filterScripting(fctxt, undefined) ) {
Expand All @@ -818,7 +815,7 @@ const onMessage = function(request, sender, callback) {
});
}
break;

}
case 'retrieveGenericCosmeticSelectors':
request.tabId = sender.tabId;
request.frameId = sender.frameId;
Expand Down Expand Up @@ -1098,7 +1095,7 @@ const restoreUserData = async function(request) {
// Discard unknown setting or setting with default value.
for ( const key in hiddenSettings ) {
if (
µb.hiddenSettingsDefault.hasOwnProperty(key) === false ||
hasOwnProperty(µb.hiddenSettingsDefault, key) === false ||
hiddenSettings[key] === µb.hiddenSettingsDefault[key]
) {
delete hiddenSettings[key];
Expand Down Expand Up @@ -1128,7 +1125,7 @@ const restoreUserData = async function(request) {
});
µb.saveUserFilters(userData.userFilters);
if ( Array.isArray(userData.selectedFilterLists) ) {
await µb.saveSelectedFilterLists(userData.selectedFilterLists);
await µb.saveSelectedFilterLists(userData.selectedFilterLists);
}

vAPI.app.restart();
Expand All @@ -1150,7 +1147,7 @@ const resetUserData = async function() {
// Filter lists
const prepListEntries = function(entries) {
for ( const k in entries ) {
if ( entries.hasOwnProperty(k) === false ) { continue; }
if ( hasOwnProperty(entries, k) === false ) { continue; }
const entry = entries[k];
if ( typeof entry.supportURL === 'string' && entry.supportURL !== '' ) {
entry.supportName = hostnameFromURI(entry.supportURL);
Expand Down Expand Up @@ -1338,7 +1335,7 @@ const getSupportData = async function() {
let addedListset = {};
let removedListset = {};
for ( const listKey in lists ) {
if ( lists.hasOwnProperty(listKey) === false ) { continue; }
if ( hasOwnProperty(lists, listKey) === false ) { continue; }
const list = lists[listKey];
if ( list.content !== 'filters' ) { continue; }
const used = µb.selectedFilterLists.includes(listKey);
Expand Down Expand Up @@ -1755,7 +1752,7 @@ const onMessage = (request, sender, callback) => {
// Sync
let response;
switch ( request.what ) {
case 'getInspectorArgs':
case 'getInspectorArgs': {
const bc = new globalThis.BroadcastChannel('contentInspectorChannel');
bc.postMessage({
what: 'contentInspectorChannel',
Expand All @@ -1768,6 +1765,7 @@ const onMessage = (request, sender, callback) => {
),
};
break;
}
default:
return vAPI.messaging.UNHANDLED;
}
Expand Down Expand Up @@ -2004,6 +2002,12 @@ const onMessage = function(request, sender, callback) {
response = staticNetFilteringEngine.dump();
break;

case 'snfeQuery':
response = staticNetFilteringEngine.test(
Object.assign({ redirectEngine }, request.query)
);
break;

case 'cfeDump':
response = cosmeticFilteringEngine.dump();
break;
Expand Down Expand Up @@ -2181,7 +2185,7 @@ const onMessage = function(request, sender, callback) {
}
break;

case 'subscribeTo':
case 'subscribeTo': {
// https://github.com/uBlockOrigin/uBlock-issues/issues/1797
if ( /^(file|https?):\/\//.test(request.location) === false ) { break; }
const url = encodeURIComponent(request.location);
Expand All @@ -2194,8 +2198,8 @@ const onMessage = function(request, sender, callback) {
select: true,
});
break;

case 'updateLists':
}
case 'updateLists': {
const listkeys = request.listkeys.split(',').filter(s => s !== '');
if ( listkeys.length === 0 ) { return; }
if ( listkeys.includes('all') ) {
Expand All @@ -2211,7 +2215,7 @@ const onMessage = function(request, sender, callback) {
});
µb.scheduleAssetUpdater({ now: true, fetchDelay: 100, auto: request.auto });
break;

}
default:
return vAPI.messaging.UNHANDLED;
}
Expand Down
Loading

0 comments on commit b7ed3b4

Please sign in to comment.