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 { |
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 Loading... | |
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 }; |
OLD | NEW |