Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/abp2blocklist.js

Issue 29473555: Issue 5345 - Whitelist $elemhide and $generichide domains where possible (Closed) Base URL: https://hg.adblockplus.org/abp2blocklist
Patch Set: Address comments to Patch Set 1 Created July 8, 2017, 5:32 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « abp2blocklist.js ('k') | test/abp2blocklist.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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-2017 eyeo GmbH 3 * Copyright (C) 2006-2017 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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 71
72 for (let name of list) 72 for (let name of list)
73 { 73 {
74 if (name.length > suffixLength && name.slice(-suffixLength) == "." + domain) 74 if (name.length > suffixLength && name.slice(-suffixLength) == "." + domain)
75 subdomains.push(name.slice(0, -suffixLength)); 75 subdomains.push(name.slice(0, -suffixLength));
76 } 76 }
77 77
78 return subdomains; 78 return subdomains;
79 } 79 }
80 80
81 function extractFilterDomains(filters)
82 {
83 let domains = new Set();
84 for (let filter of filters)
85 {
86 let parsed = parseFilterRegexpSource(filter.regexpSource);
87 if (parsed.justHostname)
88 domains.add(parsed.hostname);
89 }
90 return domains;
91 }
92
81 function convertElemHideFilter(filter, elemhideSelectorExceptions) 93 function convertElemHideFilter(filter, elemhideSelectorExceptions)
82 { 94 {
83 let included = []; 95 let included = [];
84 let excluded = []; 96 let excluded = [];
85 let rules = []; 97 let rules = [];
86 98
87 parseDomains(filter.domains, included, excluded); 99 parseDomains(filter.domains, included, excluded);
88 100
89 if (excluded.length == 0 && !(filter.selector in elemhideSelectorExceptions)) 101 if (excluded.length == 0 && !(filter.selector in elemhideSelectorExceptions))
90 return {matchDomains: included.map(matchDomain), selector: filter.selector}; 102 return {matchDomains: included.map(matchDomain), selector: filter.selector};
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 // If we're currently inside the hostname we have to be careful not to 138 // If we're currently inside the hostname we have to be careful not to
127 // escape any characters until after we have converted it to punycode. 139 // escape any characters until after we have converted it to punycode.
128 if (hostnameStart != null && !hostnameFinished) 140 if (hostnameStart != null && !hostnameFinished)
129 { 141 {
130 let endingChar = (c == "*" || c == "^" || 142 let endingChar = (c == "*" || c == "^" ||
131 c == "?" || c == "/" || c == "|"); 143 c == "?" || c == "/" || c == "|");
132 if (!endingChar && i != lastIndex) 144 if (!endingChar && i != lastIndex)
133 continue; 145 continue;
134 146
135 hostname = punycode.toASCII( 147 hostname = punycode.toASCII(
136 text.substring(hostnameStart, endingChar ? i : i + 1) 148 text.substring(hostnameStart, endingChar ? i : i + 1).toLowerCase()
137 ); 149 );
138 hostnameFinished = justHostname = true; 150 hostnameFinished = justHostname = true;
139 regexp.push(escapeRegExp(hostname)); 151 regexp.push(escapeRegExp(hostname));
140 if (!endingChar) 152 if (!endingChar)
141 break; 153 break;
142 } 154 }
143 155
144 switch (c) 156 switch (c)
145 { 157 {
146 case "*": 158 case "*":
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
393 { 405 {
394 newSelector.push(selector.substring(i, pos.start)); 406 newSelector.push(selector.substring(i, pos.start));
395 newSelector.push('[id=', selector.substring(pos.start + 1, pos.end), ']'); 407 newSelector.push('[id=', selector.substring(pos.start + 1, pos.end), ']');
396 i = pos.end; 408 i = pos.end;
397 } 409 }
398 newSelector.push(selector.substring(i)); 410 newSelector.push(selector.substring(i));
399 411
400 return newSelector.join(""); 412 return newSelector.join("");
401 } 413 }
402 414
403 function addCSSRules(rules, selectors, matchDomain) 415 function addCSSRules(rules, selectors, matchDomain, exceptionDomains)
404 { 416 {
405 while (selectors.length) 417 while (selectors.length)
406 { 418 {
407 let selector = selectors.splice(0, selectorLimit).join(", "); 419 let selector = selectors.splice(0, selectorLimit).join(", ");
408 420
409 // As of Safari 9.0 element IDs are matched as lowercase. We work around 421 // As of Safari 9.0 element IDs are matched as lowercase. We work around
410 // this by converting to the attribute format [id="elementID"] 422 // this by converting to the attribute format [id="elementID"]
411 selector = convertIDSelectorsToAttributeSelectors(selector); 423 selector = convertIDSelectorsToAttributeSelectors(selector);
412 424
413 rules.push({ 425 let rule = {
414 trigger: {"url-filter": matchDomain, 426 trigger: {"url-filter": matchDomain,
415 "url-filter-is-case-sensitive": true}, 427 "url-filter-is-case-sensitive": true},
416 action: {type: "css-display-none", 428 action: {type: "css-display-none",
417 selector: selector} 429 selector: selector}
418 }); 430 };
431
432 if (exceptionDomains.size > 0)
433 {
434 rule.trigger["unless-domain"] = [];
435 exceptionDomains.forEach(name =>
436 {
437 rule.trigger["unless-domain"].push("*" + name);
438 });
439 }
440
441 rules.push(rule);
419 } 442 }
420 } 443 }
421 444
422 let ContentBlockerList = 445 let ContentBlockerList =
423 /** 446 /**
424 * Create a new Adblock Plus filter to content blocker list converter 447 * Create a new Adblock Plus filter to content blocker list converter
425 * 448 *
426 * @constructor 449 * @constructor
427 */ 450 */
428 exports.ContentBlockerList = function () 451 exports.ContentBlockerList = function ()
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 { 528 {
506 for (let matchDomain of result.matchDomains) 529 for (let matchDomain of result.matchDomains)
507 { 530 {
508 let group = groupedElemhideFilters.get(matchDomain) || []; 531 let group = groupedElemhideFilters.get(matchDomain) || [];
509 group.push(result.selector); 532 group.push(result.selector);
510 groupedElemhideFilters.set(matchDomain, group); 533 groupedElemhideFilters.set(matchDomain, group);
511 } 534 }
512 } 535 }
513 } 536 }
514 537
515 addCSSRules(rules, genericSelectors, "^https?://"); 538 // Separate out the element hiding exceptions that have only a hostname part
539 // from the rest. This allows us to implement a workaround for issue #5345
540 // (WebKit bug #167423), but as a bonus it also reduces the number of
541 // generated rules. The downside is that the exception will only apply to the
542 // top-level document, not to iframes. We have to live with this until the
543 // WebKit bug is fixed in all supported versions of Safari.
544 // https://bugs.webkit.org/show_bug.cgi?id=167423
545 //
546 // Note that as a result of this workaround we end up with a huge rule set in
547 // terms of the amount of memory used. This can cause Node.js to throw
548 // "JavaScript heap out of memory". To avoid this, call Node.js with
549 // --max_old_space_size=4096
550 let elemhideExceptionDomains = extractFilterDomains(this.elemhideExceptions);
516 551
517 // Right after the generic element hiding filters, add the exceptions that 552 let genericSelectorExceptionDomains =
518 // should apply only to those filters. 553 extractFilterDomains(this.generichideExceptions);
519 for (let filter of this.generichideExceptions) 554 elemhideExceptionDomains.forEach(name =>
520 convertFilterAddRules(rules, filter, "ignore-previous-rules", false); 555 {
556 genericSelectorExceptionDomains.add(name);
kzar 2017/07/10 12:33:08 I wonder if it would be better to pass two Sets of
Manish Jethani 2017/07/11 11:19:18 We'd still have to combine them into one set if we
kzar 2017/07/11 12:20:03 Fair enough.
557 });
558
559 addCSSRules(rules, genericSelectors, "^https?://",
560 genericSelectorExceptionDomains);
521 561
522 groupedElemhideFilters.forEach((selectors, matchDomain) => 562 groupedElemhideFilters.forEach((selectors, matchDomain) =>
523 { 563 {
524 addCSSRules(rules, selectors, matchDomain); 564 addCSSRules(rules, selectors, matchDomain, elemhideExceptionDomains);
525 }); 565 });
526 566
527 for (let filter of this.elemhideExceptions)
528 convertFilterAddRules(rules, filter, "ignore-previous-rules", false);
529
530 let requestFilterExceptionDomains = []; 567 let requestFilterExceptionDomains = [];
531 for (let filter of this.genericblockExceptions) 568 for (let filter of this.genericblockExceptions)
532 { 569 {
533 let parsed = parseFilterRegexpSource(filter.regexpSource); 570 let parsed = parseFilterRegexpSource(filter.regexpSource);
534 if (parsed.hostname) 571 if (parsed.hostname)
535 requestFilterExceptionDomains.push(parsed.hostname); 572 requestFilterExceptionDomains.push(parsed.hostname);
536 } 573 }
537 574
538 for (let filter of this.requestFilters) 575 for (let filter of this.requestFilters)
539 { 576 {
540 convertFilterAddRules(rules, filter, "block", true, 577 convertFilterAddRules(rules, filter, "block", true,
541 requestFilterExceptionDomains); 578 requestFilterExceptionDomains);
542 } 579 }
543 580
544 for (let filter of this.requestExceptions) 581 for (let filter of this.requestExceptions)
545 convertFilterAddRules(rules, filter, "ignore-previous-rules", true); 582 convertFilterAddRules(rules, filter, "ignore-previous-rules", true);
546 583
547 return rules.filter(rule => !hasNonASCI(rule)); 584 return rules.filter(rule => !hasNonASCI(rule));
548 }; 585 };
OLDNEW
« no previous file with comments | « abp2blocklist.js ('k') | test/abp2blocklist.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld