Skip to content
This repository was archived by the owner on Nov 6, 2023. It is now read-only.

Commit 1f69eca

Browse files
committed
Adding https-everywhere-lib submodule, which moves much of the
functionality of `rules.js` into WASM for memory efficiency and performance.
1 parent 286dc23 commit 1f69eca

9 files changed

Lines changed: 149 additions & 51 deletions

File tree

.gitmodules

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@
22
path = translations
33
url = https://git.torproject.org/translation.git
44
branch = https_everywhere
5+
6+
[submodule "https-everywhere-lib"]
7+
path = https-everywhere-lib
8+
url = https://github.com/EFForg/https-everywhere-lib.git

chromium/.eslintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
},
2020
"globals": {
2121
"exports": true,
22-
"require": true
22+
"require": true,
23+
"wasm_bindgen": true
2324
}
2425
}

chromium/background-scripts/background.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ const rules = require('./rules'),
77
incognito = require('./incognito'),
88
util = require('./util'),
99
update = require('./update'),
10-
{ update_channels } = require('./update_channels');
10+
{ update_channels } = require('./update_channels'),
11+
wasm = require('./wasm');
1112

1213

1314
let all_rules = new rules.RuleSets();
1415

1516
async function initialize() {
17+
await wasm.initialize();
1618
await store.initialize();
1719
await store.performMigrations();
1820
await initializeStoredGlobals();

chromium/background-scripts/rules.js

Lines changed: 103 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
(function(exports) {
44

5-
const util = require('./util');
5+
const util = require('./util'),
6+
wasm = require('./wasm');
67

78
let settings = {
89
enableMixedRulesets: false,
@@ -220,6 +221,9 @@ RuleSets.prototype = {
220221
loadFromBrowserStorage: async function(store, applyStoredFunc) {
221222
this.store = store;
222223
this.ruleActiveStates = await this.store.get_promise('ruleActiveStates', {});
224+
try {
225+
this.wasm_rs = wasm.RuleSets.new();
226+
} catch(e) {}
223227
await applyStoredFunc(this);
224228
await this.loadStoredUserRules();
225229
await this.addStoredCustomRulesets();
@@ -241,11 +245,20 @@ RuleSets.prototype = {
241245

242246
addFromJson: function(ruleJson, scope) {
243247
const scope_obj = getScope(scope);
244-
for (let ruleset of ruleJson) {
245-
try {
246-
this.parseOneJsonRuleset(ruleset, scope_obj);
247-
} catch(e) {
248-
util.log(util.WARN, 'Error processing ruleset:' + e);
248+
249+
if (this.wasm_rs) {
250+
this.wasm_rs.add_all_from_js_array(
251+
ruleJson,
252+
settings.enableMixedRulesets,
253+
this.ruleActiveStates,
254+
scope);
255+
} else {
256+
for (let ruleset of ruleJson) {
257+
try {
258+
this.parseOneJsonRuleset(ruleset, scope_obj);
259+
} catch(e) {
260+
util.log(util.WARN, 'Error processing ruleset:' + e);
261+
}
249262
}
250263
}
251264
},
@@ -322,7 +335,15 @@ RuleSets.prototype = {
322335
*/
323336
addUserRule : function(params, scope) {
324337
util.log(util.INFO, 'adding new user rule for ' + JSON.stringify(params));
325-
this.parseOneJsonRuleset(params, scope);
338+
if (this.wasm_rs) {
339+
this.wasm_rs.add_all_from_js_array(
340+
[params],
341+
settings.enableMixedRulesets,
342+
this.ruleActiveStates,
343+
scope);
344+
} else {
345+
this.parseOneJsonRuleset(params, scope);
346+
}
326347

327348
// clear cache so new rule take effect immediately
328349
for (const target of params.target) {
@@ -351,11 +372,16 @@ RuleSets.prototype = {
351372
this.ruleCache.delete(ruleset.name);
352373

353374
if (src === 'popup') {
354-
const tmp = this.targets.get(ruleset.name).filter(r => !r.isEquivalentTo(ruleset))
355-
this.targets.set(ruleset.name, tmp);
356375

357-
if (this.targets.get(ruleset.name).length == 0) {
358-
this.targets.delete(ruleset.name);
376+
if (this.wasm_rs) {
377+
this.wasm_rs.remove_ruleset(ruleset);
378+
} else {
379+
const tmp = this.targets.get(ruleset.name).filter(r => !r.isEquivalentTo(ruleset))
380+
this.targets.set(ruleset.name, tmp);
381+
382+
if (this.targets.get(ruleset.name).length == 0) {
383+
this.targets.delete(ruleset.name);
384+
}
359385
}
360386
}
361387

@@ -546,51 +572,80 @@ RuleSets.prototype = {
546572
util.log(util.DBUG, "Ruleset cache miss for " + host);
547573
}
548574

549-
// Let's begin search
550-
// Copy the host targets so we don't modify them.
551-
let results = (this.targets.has(host) ?
552-
new Set([...this.targets.get(host)]) :
553-
new Set());
575+
let results;
576+
if (this.wasm_rs) {
577+
let pa = this.wasm_rs.potentially_applicable(host);
578+
results = [...pa].map(ruleset => {
579+
let rs = new RuleSet(ruleset.name, ruleset.default_state, getScope(ruleset.scope), ruleset.note);
554580

555-
// Ensure host is well-formed (RFC 1035)
556-
if (host.length <= 0 || host.length > 255 || host.indexOf("..") != -1) {
557-
util.log(util.WARN, "Malformed host passed to potentiallyApplicableRulesets: " + host);
558-
return nullIterable;
559-
}
581+
if (ruleset.cookierules) {
582+
let cookierules = ruleset.cookierules.map(cookierule => {
583+
return new CookieRule(cookierule.host, cookierule.name);
584+
});
585+
rs.cookierules = cookierules;
586+
} else {
587+
rs.cookierules = null;
588+
}
560589

561-
// Replace www.example.com with www.example.*
562-
// eat away from the right for once and only once
563-
let segmented = host.split(".");
564-
if (segmented.length > 1) {
565-
const tmp = segmented[segmented.length - 1];
566-
segmented[segmented.length - 1] = "*";
590+
let rules = ruleset.rules.map(rule => {
591+
return getRule(rule.from, rule.to);
592+
});
593+
rs.rules = rules;
567594

568-
results = (this.targets.has(segmented.join(".")) ?
569-
new Set([...results, ...this.targets.get(segmented.join("."))]) :
570-
results);
595+
if (ruleset.exclusions) {
596+
rs.exclusions = new RegExp(ruleset.exclusions);
597+
} else {
598+
rs.exclusions = null;
599+
}
600+
return rs;
601+
});
602+
} else {
603+
// Let's begin search
604+
// Copy the host targets so we don't modify them.
605+
results = (this.targets.has(host) ?
606+
new Set([...this.targets.get(host)]) :
607+
new Set());
608+
609+
// Ensure host is well-formed (RFC 1035)
610+
if (host.length <= 0 || host.length > 255 || host.indexOf("..") != -1) {
611+
util.log(util.WARN, "Malformed host passed to potentiallyApplicableRulesets: " + host);
612+
return nullIterable;
613+
}
571614

572-
segmented[segmented.length - 1] = tmp;
573-
}
615+
// Replace www.example.com with www.example.*
616+
// eat away from the right for once and only once
617+
let segmented = host.split(".");
618+
if (segmented.length > 1) {
619+
const tmp = segmented[segmented.length - 1];
620+
segmented[segmented.length - 1] = "*";
574621

575-
// now eat away from the left, with *, so that for x.y.z.google.com we
576-
// check *.y.z.google.com, *.z.google.com and *.google.com
577-
for (let i = 1; i <= segmented.length - 2; i++) {
578-
let t = "*." + segmented.slice(i, segmented.length).join(".");
622+
results = (this.targets.has(segmented.join(".")) ?
623+
new Set([...results, ...this.targets.get(segmented.join("."))]) :
624+
results);
579625

580-
results = (this.targets.has(t) ?
581-
new Set([...results, ...this.targets.get(t)]) :
582-
results);
583-
}
626+
segmented[segmented.length - 1] = tmp;
627+
}
584628

585-
// Clean the results list, which may contain duplicates or undefined entries
586-
results.delete(undefined);
629+
// now eat away from the left, with *, so that for x.y.z.google.com we
630+
// check *.y.z.google.com, *.z.google.com and *.google.com
631+
for (let i = 1; i <= segmented.length - 2; i++) {
632+
let t = "*." + segmented.slice(i, segmented.length).join(".");
587633

588-
util.log(util.DBUG,"Applicable rules for " + host + ":");
589-
if (results.size == 0) {
590-
util.log(util.DBUG, " None");
591-
results = nullIterable;
592-
} else {
593-
results.forEach(result => util.log(util.DBUG, " " + result.name));
634+
results = (this.targets.has(t) ?
635+
new Set([...results, ...this.targets.get(t)]) :
636+
results);
637+
}
638+
639+
// Clean the results list, which may contain duplicates or undefined entries
640+
results.delete(undefined);
641+
642+
util.log(util.DBUG,"Applicable rules for " + host + ":");
643+
if (results.size == 0) {
644+
util.log(util.DBUG, " None");
645+
results = nullIterable;
646+
} else {
647+
results.forEach(result => util.log(util.DBUG, " " + result.name));
648+
}
594649
}
595650

596651
// Insert results into the ruleset cache
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"use strict";
2+
3+
(function(exports) {
4+
5+
const { RuleSets } = wasm_bindgen;
6+
7+
async function initialize() {
8+
await wasm_bindgen(chrome.runtime.getURL('wasm/https_everywhere_lib_bg.wasm'));
9+
}
10+
11+
function is_enabled() {
12+
return true;
13+
}
14+
15+
Object.assign(exports, {
16+
initialize,
17+
RuleSets,
18+
is_enabled,
19+
});
20+
21+
})(typeof exports == 'undefined' ? require.scopes.wasm = {} : exports);

chromium/manifest.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
}
77
},
88
"author": "extension-devs@eff.org",
9+
"content_security_policy": "script-src 'self' 'wasm-eval'; object-src 'self'",
910
"background": {
1011
"scripts": [
1112
"background-scripts/bootstrap.js",
13+
"wasm/https_everywhere_lib.js",
14+
"background-scripts/wasm.js",
1215
"background-scripts/util.js",
1316
"background-scripts/update_channels.js",
1417
"background-scripts/update.js",
@@ -55,4 +58,4 @@
5558
"web_accessible_resources": [
5659
"/pages/cancel/index.html"
5760
]
58-
}
61+
}

chromium/test/rules_test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
'use strict'
22

3+
const text_encoding = require('text-encoding');
4+
global.TextDecoder = text_encoding.TextDecoder;
5+
global.TextEncoder = text_encoding.TextEncoder;
6+
global.self = global;
7+
require("../../https-everywhere-lib/pkg/https_everywhere_lib.js");
8+
39
const assert = require('chai').assert,
410
rules = require('../background-scripts/rules');
511

https-everywhere-lib

Submodule https-everywhere-lib added at c629516

make.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ python3.6 ../../utils/chromium-translations.py ../../translations/ _locales/
108108
python3.6 ../../utils/chromium-translations.py ../../src/chrome/locale/ _locales/
109109
do_not_ship="*.py *.xml"
110110
rm -f $do_not_ship
111+
112+
mkdir wasm
113+
cp ../../https-everywhere-lib/pkg/*.wasm wasm
114+
cp ../../https-everywhere-lib/pkg/*.js wasm
115+
111116
cd ../..
112117

113118
python3.6 ./utils/merge-rulesets.py || exit 5

0 commit comments

Comments
 (0)