| 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 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 // If we're currently inside the hostname we have to be careful not to | 147 // If we're currently inside the hostname we have to be careful not to |
| 136 // escape any characters until after we have converted it to punycode. | 148 // escape any characters until after we have converted it to punycode. |
| 137 if (hostnameStart != null && !hostnameFinished) | 149 if (hostnameStart != null && !hostnameFinished) |
| 138 { | 150 { |
| 139 let endingChar = (c == "*" || c == "^" || | 151 let endingChar = (c == "*" || c == "^" || |
| 140 c == "?" || c == "/" || c == "|"); | 152 c == "?" || c == "/" || c == "|"); |
| 141 if (!endingChar && i != lastIndex) | 153 if (!endingChar && i != lastIndex) |
| 142 continue; | 154 continue; |
| 143 | 155 |
| 144 hostname = punycode.toASCII( | 156 hostname = punycode.toASCII( |
| 145 characters.slice(hostnameStart, endingChar ? i : i + 1).join("") | 157 characters.slice(hostnameStart, endingChar ? i : i + 1).join("") |
| 158 .toLowerCase() |
| 146 ); | 159 ); |
| 147 hostnameFinished = justHostname = true; | 160 hostnameFinished = justHostname = true; |
| 148 regexp.push(escapeRegExp(hostname)); | 161 regexp.push(escapeRegExp(hostname)); |
| 149 if (!endingChar) | 162 if (!endingChar) |
| 150 break; | 163 break; |
| 151 } | 164 } |
| 152 | 165 |
| 153 switch (c) | 166 switch (c) |
| 154 { | 167 { |
| 155 case "*": | 168 case "*": |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 { | 410 { |
| 398 newSelector.push(selector.substring(i, pos.start)); | 411 newSelector.push(selector.substring(i, pos.start)); |
| 399 newSelector.push('[id=', selector.substring(pos.start + 1, pos.end), ']'); | 412 newSelector.push('[id=', selector.substring(pos.start + 1, pos.end), ']'); |
| 400 i = pos.end; | 413 i = pos.end; |
| 401 } | 414 } |
| 402 newSelector.push(selector.substring(i)); | 415 newSelector.push(selector.substring(i)); |
| 403 | 416 |
| 404 return newSelector.join(""); | 417 return newSelector.join(""); |
| 405 } | 418 } |
| 406 | 419 |
| 407 function addCSSRules(rules, selectors, matchDomain) | 420 function addCSSRules(rules, selectors, matchDomain, exceptionDomains) |
| 408 { | 421 { |
| 422 let unlessDomain = exceptionDomains.size > 0 ? [] : null; |
| 423 |
| 424 exceptionDomains.forEach(name => unlessDomain.push("*" + name)); |
| 425 |
| 409 while (selectors.length) | 426 while (selectors.length) |
| 410 { | 427 { |
| 411 let selector = selectors.splice(0, selectorLimit).join(", "); | 428 let selector = selectors.splice(0, selectorLimit).join(", "); |
| 412 | 429 |
| 413 // As of Safari 9.0 element IDs are matched as lowercase. We work around | 430 // As of Safari 9.0 element IDs are matched as lowercase. We work around |
| 414 // this by converting to the attribute format [id="elementID"] | 431 // this by converting to the attribute format [id="elementID"] |
| 415 selector = convertIDSelectorsToAttributeSelectors(selector); | 432 selector = convertIDSelectorsToAttributeSelectors(selector); |
| 416 | 433 |
| 417 rules.push({ | 434 let rule = { |
| 418 trigger: {"url-filter": matchDomain, | 435 trigger: {"url-filter": matchDomain, |
| 419 "url-filter-is-case-sensitive": true}, | 436 "url-filter-is-case-sensitive": true}, |
| 420 action: {type: "css-display-none", | 437 action: {type: "css-display-none", |
| 421 selector: selector} | 438 selector: selector} |
| 422 }); | 439 }; |
| 440 |
| 441 if (unlessDomain) |
| 442 rule.trigger["unless-domain"] = unlessDomain; |
| 443 |
| 444 rules.push(rule); |
| 423 } | 445 } |
| 424 } | 446 } |
| 425 | 447 |
| 426 let ContentBlockerList = | 448 let ContentBlockerList = |
| 427 /** | 449 /** |
| 428 * Create a new Adblock Plus filter to content blocker list converter | 450 * Create a new Adblock Plus filter to content blocker list converter |
| 429 * | 451 * |
| 430 * @constructor | 452 * @constructor |
| 431 */ | 453 */ |
| 432 exports.ContentBlockerList = function () | 454 exports.ContentBlockerList = function () |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 { | 531 { |
| 510 for (let matchDomain of result.matchDomains) | 532 for (let matchDomain of result.matchDomains) |
| 511 { | 533 { |
| 512 let group = groupedElemhideFilters.get(matchDomain) || []; | 534 let group = groupedElemhideFilters.get(matchDomain) || []; |
| 513 group.push(result.selector); | 535 group.push(result.selector); |
| 514 groupedElemhideFilters.set(matchDomain, group); | 536 groupedElemhideFilters.set(matchDomain, group); |
| 515 } | 537 } |
| 516 } | 538 } |
| 517 } | 539 } |
| 518 | 540 |
| 519 addCSSRules(rules, genericSelectors, "^https?://"); | 541 // Separate out the element hiding exceptions that have only a hostname part |
| 542 // from the rest. This allows us to implement a workaround for issue #5345 |
| 543 // (WebKit bug #167423), but as a bonus it also reduces the number of |
| 544 // generated rules. The downside is that the exception will only apply to the |
| 545 // top-level document, not to iframes. We have to live with this until the |
| 546 // WebKit bug is fixed in all supported versions of Safari. |
| 547 // https://bugs.webkit.org/show_bug.cgi?id=167423 |
| 548 // |
| 549 // Note that as a result of this workaround we end up with a huge rule set in |
| 550 // terms of the amount of memory used. This can cause Node.js to throw |
| 551 // "JavaScript heap out of memory". To avoid this, call Node.js with |
| 552 // --max_old_space_size=4096 |
| 553 let elemhideExceptionDomains = extractFilterDomains(this.elemhideExceptions); |
| 520 | 554 |
| 521 // Right after the generic element hiding filters, add the exceptions that | 555 let genericSelectorExceptionDomains = |
| 522 // should apply only to those filters. | 556 extractFilterDomains(this.generichideExceptions); |
| 523 for (let filter of this.generichideExceptions) | 557 elemhideExceptionDomains.forEach(name => |
| 524 convertFilterAddRules(rules, filter, "ignore-previous-rules", false); | 558 { |
| 559 genericSelectorExceptionDomains.add(name); |
| 560 }); |
| 561 |
| 562 addCSSRules(rules, genericSelectors, "^https?://", |
| 563 genericSelectorExceptionDomains); |
| 525 | 564 |
| 526 groupedElemhideFilters.forEach((selectors, matchDomain) => | 565 groupedElemhideFilters.forEach((selectors, matchDomain) => |
| 527 { | 566 { |
| 528 addCSSRules(rules, selectors, matchDomain); | 567 addCSSRules(rules, selectors, matchDomain, elemhideExceptionDomains); |
| 529 }); | 568 }); |
| 530 | 569 |
| 531 for (let filter of this.elemhideExceptions) | |
| 532 convertFilterAddRules(rules, filter, "ignore-previous-rules", false); | |
| 533 | |
| 534 let requestFilterExceptionDomains = []; | 570 let requestFilterExceptionDomains = []; |
| 535 for (let filter of this.genericblockExceptions) | 571 for (let filter of this.genericblockExceptions) |
| 536 { | 572 { |
| 537 let parsed = parseFilterRegexpSource(filter.regexpSource); | 573 let parsed = parseFilterRegexpSource(filter.regexpSource); |
| 538 if (parsed.hostname) | 574 if (parsed.hostname) |
| 539 requestFilterExceptionDomains.push(parsed.hostname); | 575 requestFilterExceptionDomains.push(parsed.hostname); |
| 540 } | 576 } |
| 541 | 577 |
| 542 for (let filter of this.requestFilters) | 578 for (let filter of this.requestFilters) |
| 543 { | 579 { |
| 544 convertFilterAddRules(rules, filter, "block", true, | 580 convertFilterAddRules(rules, filter, "block", true, |
| 545 requestFilterExceptionDomains); | 581 requestFilterExceptionDomains); |
| 546 } | 582 } |
| 547 | 583 |
| 548 for (let filter of this.requestExceptions) | 584 for (let filter of this.requestExceptions) |
| 549 convertFilterAddRules(rules, filter, "ignore-previous-rules", true); | 585 convertFilterAddRules(rules, filter, "ignore-previous-rules", true); |
| 550 | 586 |
| 551 return rules; | 587 return rules; |
| 552 }; | 588 }; |
| OLD | NEW |