| 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 |