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 |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 | 293 |
294 /** | 294 /** |
295 * Checks whether the entries for a particular keyword match a URL | 295 * Checks whether the entries for a particular keyword match a URL |
296 * @param {string} keyword | 296 * @param {string} keyword |
297 * @param {string} location | 297 * @param {string} location |
298 * @param {number} typeMask | 298 * @param {number} typeMask |
299 * @param {string} [docDomain] | 299 * @param {string} [docDomain] |
300 * @param {boolean} [thirdParty] | 300 * @param {boolean} [thirdParty] |
301 * @param {string} [sitekey] | 301 * @param {string} [sitekey] |
302 * @param {boolean} [specificOnly] | 302 * @param {boolean} [specificOnly] |
| 303 * @param {?Array.<Filter>} [collection] An optional list of filters to which |
| 304 * to append any results. If specified, the function adds <em>all</em> |
| 305 * matching filters to the list; if omitted, the function directly returns |
| 306 * the first matching filter. |
303 * @returns {?Filter} | 307 * @returns {?Filter} |
304 * @protected | 308 * @protected |
305 */ | 309 */ |
306 checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey, | 310 checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey, |
307 specificOnly) | 311 specificOnly, collection) |
308 { | 312 { |
309 // We need to skip the simple (location-only) filters if the type mask does | 313 // We need to skip the simple (location-only) filters if the type mask does |
310 // not contain any default content types. | 314 // not contain any default content types. |
311 if ((typeMask & DEFAULT_TYPES) != 0) | 315 if ((typeMask & DEFAULT_TYPES) != 0) |
312 { | 316 { |
313 let simpleSet = this._simpleFiltersByKeyword.get(keyword); | 317 let simpleSet = this._simpleFiltersByKeyword.get(keyword); |
314 if (simpleSet) | 318 if (simpleSet) |
315 { | 319 { |
316 for (let filter of simpleSet) | 320 for (let filter of simpleSet) |
317 { | 321 { |
318 if (specificOnly && !(filter instanceof WhitelistFilter)) | 322 if (specificOnly && !(filter instanceof WhitelistFilter)) |
319 continue; | 323 continue; |
320 | 324 |
321 if (filter.matchesLocation(location)) | 325 if (filter.matchesLocation(location)) |
322 return filter; | 326 { |
| 327 if (!collection) |
| 328 return filter; |
| 329 |
| 330 collection.push(filter); |
| 331 } |
323 } | 332 } |
324 } | 333 } |
325 } | 334 } |
326 | 335 |
327 let complexSet = null; | 336 let complexSet = null; |
328 | 337 |
329 // If the type mask contains a non-default type (first condition) and it is | 338 // If the type mask contains a non-default type (first condition) and it is |
330 // the only type in the mask (second condition), we can use the | 339 // the only type in the mask (second condition), we can use the |
331 // type-specific map, which typically contains a lot fewer filters. This | 340 // type-specific map, which typically contains a lot fewer filters. This |
332 // enables faster lookups for whitelisting types like $document, $elemhide, | 341 // enables faster lookups for whitelisting types like $document, $elemhide, |
(...skipping 11 matching lines...) Expand all Loading... |
344 | 353 |
345 if (complexSet) | 354 if (complexSet) |
346 { | 355 { |
347 for (let filter of complexSet) | 356 for (let filter of complexSet) |
348 { | 357 { |
349 if (specificOnly && filter.isGeneric() && | 358 if (specificOnly && filter.isGeneric() && |
350 !(filter instanceof WhitelistFilter)) | 359 !(filter instanceof WhitelistFilter)) |
351 continue; | 360 continue; |
352 | 361 |
353 if (filter.matches(location, typeMask, docDomain, thirdParty, sitekey)) | 362 if (filter.matches(location, typeMask, docDomain, thirdParty, sitekey)) |
354 return filter; | 363 { |
| 364 if (!collection) |
| 365 return filter; |
| 366 |
| 367 collection.push(filter); |
| 368 } |
355 } | 369 } |
356 } | 370 } |
357 | 371 |
358 return null; | 372 return null; |
359 } | 373 } |
360 | 374 |
361 /** | 375 /** |
362 * Tests whether the URL matches any of the known filters | 376 * Tests whether the URL matches any of the known filters |
363 * @param {string} location | 377 * @param {string} location |
364 * URL to be tested | 378 * URL to be tested |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
523 { | 537 { |
524 whitelistHit = this._whitelist.checkEntryMatch(candidates[i], location, | 538 whitelistHit = this._whitelist.checkEntryMatch(candidates[i], location, |
525 typeMask, docDomain, | 539 typeMask, docDomain, |
526 thirdParty, sitekey); | 540 thirdParty, sitekey); |
527 } | 541 } |
528 } | 542 } |
529 | 543 |
530 return whitelistHit || blacklistHit; | 544 return whitelistHit || blacklistHit; |
531 } | 545 } |
532 | 546 |
| 547 _searchInternal(location, typeMask, docDomain, thirdParty, sitekey, |
| 548 specificOnly, filterType) |
| 549 { |
| 550 let hits = {}; |
| 551 |
| 552 let searchBlocking = filterType == "blocking" || filterType == "all"; |
| 553 let searchWhitelist = filterType == "whitelist" || filterType == "all"; |
| 554 |
| 555 if (searchBlocking) |
| 556 hits.blocking = []; |
| 557 |
| 558 if (searchWhitelist) |
| 559 hits.whitelist = []; |
| 560 |
| 561 // If the type mask includes no types other than whitelist-only types, we |
| 562 // can skip the blacklist. |
| 563 if ((typeMask & ~WHITELIST_ONLY_TYPES) == 0) |
| 564 searchBlocking = false; |
| 565 |
| 566 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); |
| 567 if (candidates === null) |
| 568 candidates = []; |
| 569 candidates.push(""); |
| 570 |
| 571 for (let i = 0, l = candidates.length; i < l; i++) |
| 572 { |
| 573 if (searchBlocking) |
| 574 { |
| 575 this._blacklist.checkEntryMatch(candidates[i], location, typeMask, |
| 576 docDomain, thirdParty, sitekey, |
| 577 specificOnly, hits.blocking); |
| 578 } |
| 579 |
| 580 if (searchWhitelist) |
| 581 { |
| 582 this._whitelist.checkEntryMatch(candidates[i], location, typeMask, |
| 583 docDomain, thirdParty, sitekey, |
| 584 false, hits.whitelist); |
| 585 } |
| 586 } |
| 587 |
| 588 return hits; |
| 589 } |
| 590 |
533 /** | 591 /** |
534 * @see Matcher#matchesAny | 592 * @see Matcher#matchesAny |
535 * @inheritdoc | 593 * @inheritdoc |
536 */ | 594 */ |
537 matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly) | 595 matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly) |
538 { | 596 { |
539 let key = location + " " + typeMask + " " + docDomain + " " + thirdParty + | 597 let key = location + " " + typeMask + " " + docDomain + " " + thirdParty + |
540 " " + sitekey + " " + specificOnly; | 598 " " + sitekey + " " + specificOnly; |
541 | 599 |
542 let result = this._resultCache.get(key); | 600 let result = this._resultCache.get(key); |
543 if (typeof result != "undefined") | 601 if (typeof result != "undefined") |
544 return result; | 602 return result; |
545 | 603 |
546 result = this._matchesAnyInternal(location, typeMask, docDomain, | 604 result = this._matchesAnyInternal(location, typeMask, docDomain, |
547 thirdParty, sitekey, specificOnly); | 605 thirdParty, sitekey, specificOnly); |
548 | 606 |
549 if (this._resultCache.size >= this.maxCacheEntries) | 607 if (this._resultCache.size >= this.maxCacheEntries) |
550 this._resultCache.clear(); | 608 this._resultCache.clear(); |
551 | 609 |
552 this._resultCache.set(key, result); | 610 this._resultCache.set(key, result); |
553 | 611 |
554 return result; | 612 return result; |
555 } | 613 } |
556 | 614 |
557 /** | 615 /** |
| 616 * @typedef {object} MatcherSearchResults |
| 617 * @property {Array.<BlockingFilter>} [blocking] List of blocking filters |
| 618 * found. |
| 619 * @property {Array.<WhitelistFilter>} [whitelist] List of whitelist filters |
| 620 * found. |
| 621 */ |
| 622 |
| 623 /** |
| 624 * Searches all blocking and whitelist filters and returns results matching |
| 625 * the given parameters. |
| 626 * |
| 627 * @param {string} location |
| 628 * @param {number} typeMask |
| 629 * @param {string} [docDomain] |
| 630 * @param {boolean} [thirdParty] |
| 631 * @param {string} [sitekey] |
| 632 * @param {boolean} [specificOnly] |
| 633 * @param {string} [filterType] The types of filters to look for. This can be |
| 634 * <code>"blocking"</code>, <code>"whitelist"</code>, or |
| 635 * <code>"all"</code> (default). |
| 636 * |
| 637 * @returns {MatcherSearchResults} |
| 638 */ |
| 639 search(location, typeMask, docDomain, thirdParty, sitekey, specificOnly, |
| 640 filterType = "all") |
| 641 { |
| 642 let key = "* " + location + " " + typeMask + " " + docDomain + " " + |
| 643 thirdParty + " " + sitekey + " " + specificOnly + " " + |
| 644 filterType; |
| 645 |
| 646 let result = this._resultCache.get(key); |
| 647 if (typeof result != "undefined") |
| 648 return result; |
| 649 |
| 650 result = this._searchInternal(location, typeMask, docDomain, thirdParty, |
| 651 sitekey, specificOnly, filterType); |
| 652 |
| 653 if (this._resultCache.size >= this.maxCacheEntries) |
| 654 this._resultCache.clear(); |
| 655 |
| 656 this._resultCache.set(key, result); |
| 657 |
| 658 return result; |
| 659 } |
| 660 |
| 661 /** |
558 * Tests whether the URL is whitelisted | 662 * Tests whether the URL is whitelisted |
559 * @see Matcher#matchesAny | 663 * @see Matcher#matchesAny |
560 * @inheritdoc | 664 * @inheritdoc |
561 * @returns {boolean} | 665 * @returns {boolean} |
562 */ | 666 */ |
563 isWhitelisted(location, typeMask, docDomain, thirdParty, sitekey, | 667 isWhitelisted(location, typeMask, docDomain, thirdParty, sitekey, |
564 specificOnly) | 668 specificOnly) |
565 { | 669 { |
566 return !!this._whitelist.matchesAny(location, typeMask, docDomain, | 670 return !!this._whitelist.matchesAny(location, typeMask, docDomain, |
567 thirdParty, sitekey, specificOnly); | 671 thirdParty, sitekey, specificOnly); |
568 } | 672 } |
569 } | 673 } |
570 | 674 |
571 exports.CombinedMatcher = CombinedMatcher; | 675 exports.CombinedMatcher = CombinedMatcher; |
572 | 676 |
573 /** | 677 /** |
574 * Shared {@link CombinedMatcher} instance that should usually be used. | 678 * Shared {@link CombinedMatcher} instance that should usually be used. |
575 * @type {CombinedMatcher} | 679 * @type {CombinedMatcher} |
576 */ | 680 */ |
577 let defaultMatcher = new CombinedMatcher(); | 681 let defaultMatcher = new CombinedMatcher(); |
578 | 682 |
579 exports.defaultMatcher = defaultMatcher; | 683 exports.defaultMatcher = defaultMatcher; |
OLD | NEW |