Left: | ||
Right: |
OLD | NEW |
---|---|
1 /* | 1 /* |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
3 * Copyright (C) 2006-present eyeo GmbH | 3 * Copyright (C) 2006-present eyeo GmbH |
4 * | 4 * |
5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
8 * | 8 * |
9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU General Public License | 14 * You should have received a copy of the GNU General Public License |
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
16 */ | 16 */ |
17 | 17 |
18 "use strict"; | 18 "use strict"; |
19 | 19 |
20 /** | 20 /** |
21 * @fileOverview Definition of Filter class and its subclasses. | 21 * @fileOverview Definition of Filter class and its subclasses. |
22 */ | 22 */ |
23 | 23 |
24 const {extend} = require("./coreUtils"); | 24 const {extend} = require("./coreUtils"); |
25 const {filterToRegExp} = require("./common"); | 25 const {filterToRegExp} = require("./common"); |
26 const {normalizeHostname, domainSuffixes} = require("./url"); | 26 const {normalizeHostname, domainSuffixes} = require("./url"); |
27 const {Cache} = require("./caching"); | |
27 const {filterNotifier} = require("./filterNotifier"); | 28 const {filterNotifier} = require("./filterNotifier"); |
28 | 29 |
29 const resources = require("../data/resources.json"); | 30 const resources = require("../data/resources.json"); |
30 | 31 |
31 /** | 32 /** |
32 * Map of internal resources for URL rewriting. | 33 * Map of internal resources for URL rewriting. |
33 * @type {Map.<string,string>} | 34 * @type {Map.<string,string>} |
34 */ | 35 */ |
35 let resourceMap = new Map( | 36 let resourceMap = new Map( |
36 Object.keys(resources).map(key => [key, resources[key]]) | 37 Object.keys(resources).map(key => [key, resources[key]]) |
37 ); | 38 ); |
38 | 39 |
39 /** | 40 /** |
40 * Regular expression used to match the <code>||</code> prefix in an otherwise | 41 * Regular expression used to match the <code>||</code> prefix in an otherwise |
41 * literal pattern. | 42 * literal pattern. |
42 * @type {RegExp} | 43 * @type {RegExp} |
43 */ | 44 */ |
44 let doubleAnchorRegExp = new RegExp(filterToRegExp("||") + "$"); | 45 let doubleAnchorRegExp = new RegExp(filterToRegExp("||") + "$"); |
45 | 46 |
46 /** | 47 /** |
47 * Regular expression used to match the <code>^</code> suffix in an otherwise | 48 * Regular expression used to match the <code>^</code> suffix in an otherwise |
48 * literal pattern. | 49 * literal pattern. |
49 * @type {RegExp} | 50 * @type {RegExp} |
50 */ | 51 */ |
51 // Note: This should match the pattern in lib/common.js | 52 // Note: This should match the pattern in lib/common.js |
52 let separatorRegExp = /[\x00-\x24\x26-\x2C\x2F\x3A-\x40\x5B-\x5E\x60\x7B-\x7F]/; | 53 let separatorRegExp = /[\x00-\x24\x26-\x2C\x2F\x3A-\x40\x5B-\x5E\x60\x7B-\x7F]/; |
53 | 54 |
54 /** | 55 /** |
55 * All known unique domain sources mapped to their parsed values. | 56 * Cache of domain maps. The domains part of filter text |
56 * @type {Map.<string,Map.<string,boolean>>} | 57 * (e.g. <code>example.com,~mail.example.com</code>) is often repeated across |
58 * filters. This cache enables deduplication of the <code>Map</code> objects | |
59 * that specify on which domains the filter does and does not apply, which | |
60 * reduces memory usage and improves performance. | |
61 * @type {Map.<string, Map.<string, boolean>>} | |
57 */ | 62 */ |
58 let knownDomainMaps = new Map(); | 63 let domainMapCache = new Cache(1000); |
59 | 64 |
60 /** | 65 /** |
61 * Checks whether the given pattern is a string of literal characters with no | 66 * Checks whether the given pattern is a string of literal characters with no |
62 * wildcards or any other special characters. If the pattern is prefixed with a | 67 * wildcards or any other special characters. If the pattern is prefixed with a |
63 * <code>||</code> or suffixed with a <code>^</code> but otherwise contains no | 68 * <code>||</code> or suffixed with a <code>^</code> but otherwise contains no |
64 * special characters, it is still considered to be a literal pattern. | 69 * special characters, it is still considered to be a literal pattern. |
65 * @param {string} pattern | 70 * @param {string} pattern |
66 * @returns {boolean} | 71 * @returns {boolean} |
67 */ | 72 */ |
68 function isLiteralPattern(pattern) | 73 function isLiteralPattern(pattern) |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
400 * Domains that the filter is restricted to separated by domainSeparator | 405 * Domains that the filter is restricted to separated by domainSeparator |
401 * e.g. "foo.com|bar.com|~baz.com" | 406 * e.g. "foo.com|bar.com|~baz.com" |
402 * @constructor | 407 * @constructor |
403 * @augments Filter | 408 * @augments Filter |
404 */ | 409 */ |
405 function ActiveFilter(text, domains) | 410 function ActiveFilter(text, domains) |
406 { | 411 { |
407 Filter.call(this, text); | 412 Filter.call(this, text); |
408 | 413 |
409 if (domains) | 414 if (domains) |
410 this.domainSource = domains; | 415 this.domainSource = domains.toLowerCase(); |
Manish Jethani
2019/03/04 12:02:54
Lower-case in advance during initialization.
hub
2019/03/06 13:10:40
Do we know if there is a performance difference be
Manish Jethani
2019/03/06 18:11:10
You mean that we could require that the domains ar
hub
2019/03/06 18:14:25
I was just wondering if toLowerCase() is faster wh
Manish Jethani
2019/03/06 18:28:10
Ah, I see what you mean. I don't expect it to be f
| |
411 } | 416 } |
412 exports.ActiveFilter = ActiveFilter; | 417 exports.ActiveFilter = ActiveFilter; |
413 | 418 |
414 ActiveFilter.prototype = extend(Filter, { | 419 ActiveFilter.prototype = extend(Filter, { |
415 _disabled: false, | 420 _disabled: false, |
416 _hitCount: 0, | 421 _hitCount: 0, |
417 _lastHit: 0, | 422 _lastHit: 0, |
418 | 423 |
419 /** | 424 /** |
420 * Defines whether the filter is disabled | 425 * Defines whether the filter is disabled |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
487 */ | 492 */ |
488 domainSeparator: null, | 493 domainSeparator: null, |
489 | 494 |
490 /** | 495 /** |
491 * Map containing domains that this filter should match on/not match | 496 * Map containing domains that this filter should match on/not match |
492 * on or null if the filter should match on all domains | 497 * on or null if the filter should match on all domains |
493 * @type {?Map.<string,boolean>} | 498 * @type {?Map.<string,boolean>} |
494 */ | 499 */ |
495 get domains() | 500 get domains() |
496 { | 501 { |
497 let domains = null; | 502 let {domainSource} = this; |
Manish Jethani
2019/03/04 12:02:54
Tip: The diff of this function is smaller with the
| |
503 if (!domainSource) | |
504 return null; | |
498 | 505 |
499 if (this.domainSource) | 506 let domains = domainMapCache.get(domainSource); |
507 if (domains) | |
508 return domains; | |
509 | |
510 let list = domainSource.split(this.domainSeparator); | |
511 if (list.length == 1 && list[0][0] != "~") | |
500 { | 512 { |
501 // For most filter types this property is accessed only rarely, | 513 // Fast track for the common one-domain scenario |
502 // especially when the subscriptions are initially loaded. We defer any | 514 domains = new Map([[list[0], true], ["", false]]); |
503 // caching by default. | 515 } |
504 let cacheDomains = this._cacheDomains; | 516 else |
517 { | |
518 let hasIncludes = false; | |
519 for (let i = 0; i < list.length; i++) | |
520 { | |
521 let domain = list[i]; | |
522 if (domain == "") | |
523 continue; | |
505 | 524 |
506 let source = this.domainSource.toLowerCase(); | 525 let include; |
507 | 526 if (domain[0] == "~") |
508 let knownMap = knownDomainMaps.get(source); | |
509 if (knownMap) | |
510 { | |
511 domains = knownMap; | |
512 } | |
513 else | |
514 { | |
515 let list = source.split(this.domainSeparator); | |
516 if (list.length == 1 && list[0][0] != "~") | |
517 { | 527 { |
518 // Fast track for the common one-domain scenario | 528 include = false; |
519 domains = new Map([[list[0], true], ["", false]]); | 529 domain = domain.substring(1); |
520 } | 530 } |
521 else | 531 else |
522 { | 532 { |
523 let hasIncludes = false; | 533 include = true; |
524 for (let i = 0; i < list.length; i++) | 534 hasIncludes = true; |
525 { | |
526 let domain = list[i]; | |
527 if (domain == "") | |
528 continue; | |
529 | |
530 let include; | |
531 if (domain[0] == "~") | |
532 { | |
533 include = false; | |
534 domain = domain.substring(1); | |
535 } | |
536 else | |
537 { | |
538 include = true; | |
539 hasIncludes = true; | |
540 } | |
541 | |
542 if (!domains) | |
543 domains = new Map(); | |
544 | |
545 domains.set(domain, include); | |
546 } | |
547 | |
548 if (domains) | |
549 domains.set("", !hasIncludes); | |
550 } | 535 } |
551 | 536 |
552 if (!domains || cacheDomains) | 537 if (!domains) |
553 knownDomainMaps.set(source, domains); | 538 domains = new Map(); |
539 | |
540 domains.set(domain, include); | |
554 } | 541 } |
555 | 542 |
556 if (!domains || cacheDomains) | 543 if (domains) |
557 { | 544 domains.set("", !hasIncludes); |
558 this.domainSource = null; | |
559 Object.defineProperty(this, "domains", {value: domains}); | |
560 } | |
561 } | 545 } |
562 | 546 |
563 this._cacheDomains = true; | 547 domainMapCache.set(domainSource, domains); |
564 | 548 |
565 return domains; | 549 return domains; |
566 }, | 550 }, |
567 | 551 |
568 /** | 552 /** |
569 * Whether the value of {@link ActiveFilter#domains} should be cached. | |
570 * @type {boolean} | |
571 * @private | |
572 */ | |
573 _cacheDomains: false, | |
574 | |
575 /** | |
576 * Array containing public keys of websites that this filter should apply to | 553 * Array containing public keys of websites that this filter should apply to |
577 * @type {?string[]} | 554 * @type {?string[]} |
578 */ | 555 */ |
579 sitekeys: null, | 556 sitekeys: null, |
580 | 557 |
581 /** | 558 /** |
582 * Checks whether this filter is active on a domain. | 559 * Checks whether this filter is active on a domain. |
583 * @param {string} [docDomain] domain name of the document that loads the URL | 560 * @param {string} [docDomain] domain name of the document that loads the URL |
584 * @param {string} [sitekey] public key provided by the document | 561 * @param {string} [sitekey] public key provided by the document |
585 * @return {boolean} true in case of the filter being active | 562 * @return {boolean} true in case of the filter being active |
(...skipping 847 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1433 | 1410 |
1434 /** | 1411 /** |
1435 * Script that should be executed | 1412 * Script that should be executed |
1436 * @type {string} | 1413 * @type {string} |
1437 */ | 1414 */ |
1438 get script() | 1415 get script() |
1439 { | 1416 { |
1440 return this.body; | 1417 return this.body; |
1441 } | 1418 } |
1442 }); | 1419 }); |
OLD | NEW |