summaryrefslogtreecommitdiffstats
path: root/src/js/reverselookup.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/reverselookup.js')
-rw-r--r--src/js/reverselookup.js223
1 files changed, 223 insertions, 0 deletions
diff --git a/src/js/reverselookup.js b/src/js/reverselookup.js
new file mode 100644
index 0000000..c21ca4b
--- /dev/null
+++ b/src/js/reverselookup.js
@@ -0,0 +1,223 @@
+/*******************************************************************************
+
+ uBlock Origin - a comprehensive, efficient content blocker
+ Copyright (C) 2015-present Raymond Hill
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see {http://www.gnu.org/licenses/}.
+
+ Home: https://github.com/gorhill/uBlock
+*/
+
+'use strict';
+
+/******************************************************************************/
+
+import staticNetFilteringEngine from './static-net-filtering.js';
+import µb from './background.js';
+import { CompiledListWriter } from './static-filtering-io.js';
+import { i18n$ } from './i18n.js';
+import * as sfp from './static-filtering-parser.js';
+
+import {
+ domainFromHostname,
+ hostnameFromURI,
+} from './uri-utils.js';
+
+/******************************************************************************/
+
+const pendingResponses = new Map();
+
+let worker = null;
+let needLists = true;
+let messageId = 1;
+
+const onWorkerMessage = function(e) {
+ const msg = e.data;
+ const resolver = pendingResponses.get(msg.id);
+ pendingResponses.delete(msg.id);
+ resolver(msg.response);
+};
+
+const stopWorker = function() {
+ workerTTLTimer.off();
+ if ( worker === null ) { return; }
+ worker.terminate();
+ worker = null;
+ needLists = true;
+ for ( const resolver of pendingResponses.values() ) {
+ resolver();
+ }
+ pendingResponses.clear();
+};
+
+const workerTTLTimer = vAPI.defer.create(stopWorker);
+const workerTTL = { min: 5 };
+
+const initWorker = function() {
+ if ( worker === null ) {
+ worker = new Worker('js/reverselookup-worker.js');
+ worker.onmessage = onWorkerMessage;
+ }
+
+ // The worker will be shutdown after n minutes without being used.
+ workerTTLTimer.offon(workerTTL);
+
+ if ( needLists === false ) {
+ return Promise.resolve();
+ }
+ needLists = false;
+
+ const entries = new Map();
+
+ const onListLoaded = function(details) {
+ const entry = entries.get(details.assetKey);
+
+ // https://github.com/gorhill/uBlock/issues/536
+ // Use assetKey when there is no filter list title.
+
+ worker.postMessage({
+ what: 'setList',
+ details: {
+ assetKey: details.assetKey,
+ title: entry.title || details.assetKey,
+ supportURL: entry.supportURL,
+ content: details.content
+ }
+ });
+ };
+
+ for ( const listKey in µb.availableFilterLists ) {
+ if ( µb.availableFilterLists.hasOwnProperty(listKey) === false ) {
+ continue;
+ }
+ const entry = µb.availableFilterLists[listKey];
+ if ( entry.off === true ) { continue; }
+ entries.set(listKey, {
+ title: listKey !== µb.userFiltersPath ?
+ entry.title :
+ i18n$('1pPageName'),
+ supportURL: entry.supportURL || ''
+ });
+ }
+ if ( entries.size === 0 ) {
+ return Promise.resolve();
+ }
+
+ const promises = [];
+ for ( const listKey of entries.keys() ) {
+ promises.push(
+ µb.getCompiledFilterList(listKey).then(details => {
+ onListLoaded(details);
+ })
+ );
+ }
+ return Promise.all(promises);
+};
+
+const fromNetFilter = async function(rawFilter) {
+ if ( typeof rawFilter !== 'string' || rawFilter === '' ) { return; }
+
+ const writer = new CompiledListWriter();
+ const parser = new sfp.AstFilterParser({
+ trustedSource: true,
+ maxTokenLength: staticNetFilteringEngine.MAX_TOKEN_LENGTH,
+ nativeCssHas: vAPI.webextFlavor.env.includes('native_css_has'),
+ });
+ parser.parse(rawFilter);
+
+ const compiler = staticNetFilteringEngine.createCompiler();
+ if ( compiler.compile(parser, writer) === false ) { return; }
+
+ await initWorker();
+
+ const id = messageId++;
+ worker.postMessage({
+ what: 'fromNetFilter',
+ id,
+ compiledFilter: writer.last(),
+ rawFilter,
+ });
+
+ return new Promise(resolve => {
+ pendingResponses.set(id, resolve);
+ });
+};
+
+const fromExtendedFilter = async function(details) {
+ if (
+ typeof details.rawFilter !== 'string' ||
+ details.rawFilter === ''
+ ) {
+ return;
+ }
+
+ await initWorker();
+
+ const id = messageId++;
+ const hostname = hostnameFromURI(details.url);
+
+ const parser = new sfp.AstFilterParser({
+ trustedSource: true,
+ nativeCssHas: vAPI.webextFlavor.env.includes('native_css_has'),
+ });
+ parser.parse(details.rawFilter);
+ let compiled;
+ if ( parser.isScriptletFilter() ) {
+ compiled = JSON.stringify(parser.getScriptletArgs());
+ }
+
+ worker.postMessage({
+ what: 'fromExtendedFilter',
+ id,
+ domain: domainFromHostname(hostname),
+ hostname,
+ ignoreGeneric:
+ staticNetFilteringEngine.matchRequestReverse(
+ 'generichide',
+ details.url
+ ) === 2,
+ ignoreSpecific:
+ staticNetFilteringEngine.matchRequestReverse(
+ 'specifichide',
+ details.url
+ ) === 2,
+ rawFilter: details.rawFilter,
+ compiled,
+ });
+
+ return new Promise(resolve => {
+ pendingResponses.set(id, resolve);
+ });
+};
+
+// This tells the worker that filter lists may have changed.
+
+const resetLists = function() {
+ needLists = true;
+ if ( worker === null ) { return; }
+ worker.postMessage({ what: 'resetLists' });
+};
+
+/******************************************************************************/
+
+const staticFilteringReverseLookup = {
+ fromNetFilter,
+ fromExtendedFilter,
+ resetLists,
+ shutdown: stopWorker
+};
+
+export default staticFilteringReverseLookup;
+
+/******************************************************************************/