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-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 Loading... | |
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 Loading... | |
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 Loading... | |
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 { |
417 let unlessDomain = exceptionDomains.size > 0 ? [] : null; | |
kzar
2017/07/11 12:20:03
Nit: This seems like overkill since `[]` is falsey
Manish Jethani
2017/07/11 16:28:39
[] evaluates to true. If you mean checking the len
kzar
2017/07/11 16:30:36
Whoops, you're right.
| |
418 | |
419 exceptionDomains.forEach(name => unlessDomain.push("*" + name)); | |
420 | |
405 while (selectors.length) | 421 while (selectors.length) |
406 { | 422 { |
407 let selector = selectors.splice(0, selectorLimit).join(", "); | 423 let selector = selectors.splice(0, selectorLimit).join(", "); |
408 | 424 |
409 // As of Safari 9.0 element IDs are matched as lowercase. We work around | 425 // As of Safari 9.0 element IDs are matched as lowercase. We work around |
410 // this by converting to the attribute format [id="elementID"] | 426 // this by converting to the attribute format [id="elementID"] |
411 selector = convertIDSelectorsToAttributeSelectors(selector); | 427 selector = convertIDSelectorsToAttributeSelectors(selector); |
412 | 428 |
413 rules.push({ | 429 let rule = { |
414 trigger: {"url-filter": matchDomain, | 430 trigger: {"url-filter": matchDomain, |
415 "url-filter-is-case-sensitive": true}, | 431 "url-filter-is-case-sensitive": true}, |
416 action: {type: "css-display-none", | 432 action: {type: "css-display-none", |
417 selector: selector} | 433 selector: selector} |
418 }); | 434 }; |
435 | |
436 if (unlessDomain) | |
437 rule.trigger["unless-domain"] = unlessDomain; | |
438 | |
439 rules.push(rule); | |
419 } | 440 } |
420 } | 441 } |
421 | 442 |
422 let ContentBlockerList = | 443 let ContentBlockerList = |
423 /** | 444 /** |
424 * Create a new Adblock Plus filter to content blocker list converter | 445 * Create a new Adblock Plus filter to content blocker list converter |
425 * | 446 * |
426 * @constructor | 447 * @constructor |
427 */ | 448 */ |
428 exports.ContentBlockerList = function () | 449 exports.ContentBlockerList = function () |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
505 { | 526 { |
506 for (let matchDomain of result.matchDomains) | 527 for (let matchDomain of result.matchDomains) |
507 { | 528 { |
508 let group = groupedElemhideFilters.get(matchDomain) || []; | 529 let group = groupedElemhideFilters.get(matchDomain) || []; |
509 group.push(result.selector); | 530 group.push(result.selector); |
510 groupedElemhideFilters.set(matchDomain, group); | 531 groupedElemhideFilters.set(matchDomain, group); |
511 } | 532 } |
512 } | 533 } |
513 } | 534 } |
514 | 535 |
515 addCSSRules(rules, genericSelectors, "^https?://"); | 536 // Separate out the element hiding exceptions that have only a hostname part |
537 // from the rest. This allows us to implement a workaround for issue #5345 | |
538 // (WebKit bug #167423), but as a bonus it also reduces the number of | |
539 // generated rules. The downside is that the exception will only apply to the | |
540 // top-level document, not to iframes. We have to live with this until the | |
541 // WebKit bug is fixed in all supported versions of Safari. | |
542 // https://bugs.webkit.org/show_bug.cgi?id=167423 | |
543 // | |
544 // Note that as a result of this workaround we end up with a huge rule set in | |
545 // terms of the amount of memory used. This can cause Node.js to throw | |
546 // "JavaScript heap out of memory". To avoid this, call Node.js with | |
547 // --max_old_space_size=4096 | |
548 let elemhideExceptionDomains = extractFilterDomains(this.elemhideExceptions); | |
516 | 549 |
517 // Right after the generic element hiding filters, add the exceptions that | 550 let genericSelectorExceptionDomains = |
518 // should apply only to those filters. | 551 extractFilterDomains(this.generichideExceptions); |
519 for (let filter of this.generichideExceptions) | 552 elemhideExceptionDomains.forEach(name => |
520 convertFilterAddRules(rules, filter, "ignore-previous-rules", false); | 553 { |
554 genericSelectorExceptionDomains.add(name); | |
555 }); | |
556 | |
557 addCSSRules(rules, genericSelectors, "^https?://", | |
558 genericSelectorExceptionDomains); | |
521 | 559 |
522 groupedElemhideFilters.forEach((selectors, matchDomain) => | 560 groupedElemhideFilters.forEach((selectors, matchDomain) => |
523 { | 561 { |
524 addCSSRules(rules, selectors, matchDomain); | 562 addCSSRules(rules, selectors, matchDomain, elemhideExceptionDomains); |
525 }); | 563 }); |
526 | 564 |
527 for (let filter of this.elemhideExceptions) | |
528 convertFilterAddRules(rules, filter, "ignore-previous-rules", false); | |
529 | |
530 let requestFilterExceptionDomains = []; | 565 let requestFilterExceptionDomains = []; |
531 for (let filter of this.genericblockExceptions) | 566 for (let filter of this.genericblockExceptions) |
532 { | 567 { |
533 let parsed = parseFilterRegexpSource(filter.regexpSource); | 568 let parsed = parseFilterRegexpSource(filter.regexpSource); |
534 if (parsed.hostname) | 569 if (parsed.hostname) |
535 requestFilterExceptionDomains.push(parsed.hostname); | 570 requestFilterExceptionDomains.push(parsed.hostname); |
536 } | 571 } |
537 | 572 |
538 for (let filter of this.requestFilters) | 573 for (let filter of this.requestFilters) |
539 { | 574 { |
540 convertFilterAddRules(rules, filter, "block", true, | 575 convertFilterAddRules(rules, filter, "block", true, |
541 requestFilterExceptionDomains); | 576 requestFilterExceptionDomains); |
542 } | 577 } |
543 | 578 |
544 for (let filter of this.requestExceptions) | 579 for (let filter of this.requestExceptions) |
545 convertFilterAddRules(rules, filter, "ignore-previous-rules", true); | 580 convertFilterAddRules(rules, filter, "ignore-previous-rules", true); |
546 | 581 |
547 return rules.filter(rule => !hasNonASCI(rule)); | 582 return rules.filter(rule => !hasNonASCI(rule)); |
548 }; | 583 }; |
OLD | NEW |