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

Delta Between Two Patch Sets: lib/abp2blocklist.js

Issue 29443587: Noissue - Do not add subdomain wildcard if subdomain excluded (Closed) Base URL: https://hg.adblockplus.org/abp2blocklist
Left Patch Set: Created May 20, 2017, 11:50 p.m.
Right Patch Set: Rebase Created May 23, 2017, 5:03 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | test/abp2blocklist.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 } 55 }
56 56
57 function escapeRegExp(s) 57 function escapeRegExp(s)
58 { 58 {
59 return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); 59 return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
60 } 60 }
61 61
62 function matchDomain(domain) 62 function matchDomain(domain)
63 { 63 {
64 return "^https?://([^/:]*\\.)?" + escapeRegExp(domain).toLowerCase() + "[/:]"; 64 return "^https?://([^/:]*\\.)?" + escapeRegExp(domain).toLowerCase() + "[/:]";
65 }
66
67 function findSubdomainsInList(domain, list)
68 {
69 let subdomains = [];
70 let suffixLength = domain.length + 1;
71
72 for (let name of list)
73 {
74 if (name.length > suffixLength && name.slice(-suffixLength) == "." + domain)
75 subdomains.push(name.slice(0, -suffixLength));
76 }
77
78 return subdomains;
65 } 79 }
66 80
67 function convertElemHideFilter(filter, elemhideSelectorExceptions) 81 function convertElemHideFilter(filter, elemhideSelectorExceptions)
68 { 82 {
69 let included = []; 83 let included = [];
70 let excluded = []; 84 let excluded = [];
71 let rules = []; 85 let rules = [];
72 86
73 parseDomains(filter.domains, included, excluded); 87 parseDomains(filter.domains, included, excluded);
74 88
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 276
263 if (trigger["resource-type"].length == 0) 277 if (trigger["resource-type"].length == 0)
264 return; 278 return;
265 } 279 }
266 280
267 if (filter.thirdParty != null) 281 if (filter.thirdParty != null)
268 trigger["load-type"] = [filter.thirdParty ? "third-party" : "first-party"]; 282 trigger["load-type"] = [filter.thirdParty ? "third-party" : "first-party"];
269 283
270 if (included.length > 0) 284 if (included.length > 0)
271 { 285 {
272 trigger["if-domain"] = included.map(name => 286 trigger["if-domain"] = [];
273 { 287
274 if (filter instanceof filterClasses.WhitelistFilter) 288 for (let name of included)
275 return "*" + name; 289 {
276 290 // If this is a blocking filter or an element hiding filter, add the
277 // If this is not a whitelisting filter, add the subdomain wildcard only 291 // subdomain wildcard only if no subdomains have been excluded.
278 // if no subdomains have been excluded. 292 let notSubdomains = null;
279 let regExp = new RegExp("\." + escapeRegExp(name) + "$"); 293 if ((filter instanceof filterClasses.BlockingFilter ||
280 if (!excluded.some(name => regExp.test(name))) 294 filter instanceof filterClasses.ElemHideFilter) &&
281 return "*" + name; 295 (notSubdomains = findSubdomainsInList(name, excluded)).length > 0)
282 296 {
283 return name; 297 trigger["if-domain"].push(name);
284 }); 298
299 // Add the "www" prefix but only if it hasn't been excluded.
300 if (!notSubdomains.includes("www"))
301 trigger["if-domain"].push("www." + name);
302 }
303 else
304 {
305 trigger["if-domain"].push("*" + name);
306 }
307 }
285 } 308 }
286 else if (excluded.length > 0) 309 else if (excluded.length > 0)
287 { 310 {
288 trigger["unless-domain"] = excluded.map(name => "*" + name); 311 trigger["unless-domain"] = excluded.map(name => "*" + name);
289 } 312 }
290 313
291 rules.push({trigger: trigger, action: {type: action}}); 314 rules.push({trigger: trigger, action: {type: action}});
292 } 315 }
293 316
294 function hasNonASCI(obj) 317 function hasNonASCI(obj)
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 { 382 {
360 newSelector.push(selector.substring(i, pos.start)); 383 newSelector.push(selector.substring(i, pos.start));
361 newSelector.push('[id=', selector.substring(pos.start + 1, pos.end), ']'); 384 newSelector.push('[id=', selector.substring(pos.start + 1, pos.end), ']');
362 i = pos.end; 385 i = pos.end;
363 } 386 }
364 newSelector.push(selector.substring(i)); 387 newSelector.push(selector.substring(i));
365 388
366 return newSelector.join(""); 389 return newSelector.join("");
367 } 390 }
368 391
392 function addCSSRules(rules, selectors, matchDomain)
393 {
394 while (selectors.length)
395 {
396 let selector = selectors.splice(0, selectorLimit).join(", ");
397
398 // As of Safari 9.0 element IDs are matched as lowercase. We work around
399 // this by converting to the attribute format [id="elementID"]
400 selector = convertIDSelectorsToAttributeSelectors(selector);
401
402 rules.push({
403 trigger: {"url-filter": matchDomain,
404 "url-filter-is-case-sensitive": true},
405 action: {type: "css-display-none",
406 selector: selector}
407 });
408 }
409 }
410
369 let ContentBlockerList = 411 let ContentBlockerList =
370 /** 412 /**
371 * Create a new Adblock Plus filter to content blocker list converter 413 * Create a new Adblock Plus filter to content blocker list converter
372 * 414 *
373 * @constructor 415 * @constructor
374 */ 416 */
375 exports.ContentBlockerList = function () 417 exports.ContentBlockerList = function ()
376 { 418 {
377 this.requestFilters = []; 419 this.requestFilters = [];
378 this.requestExceptions = []; 420 this.requestExceptions = [];
379 this.elemhideFilters = []; 421 this.elemhideFilters = [];
380 this.elemhideExceptions = []; 422 this.elemhideExceptions = [];
423 this.generichideExceptions = [];
381 this.elemhideSelectorExceptions = new Map(); 424 this.elemhideSelectorExceptions = new Map();
382 }; 425 };
383 426
384 /** 427 /**
385 * Add Adblock Plus filter to be converted 428 * Add Adblock Plus filter to be converted
386 * 429 *
387 * @param {Filter} filter Filter to convert 430 * @param {Filter} filter Filter to convert
388 */ 431 */
389 ContentBlockerList.prototype.addFilter = function(filter) 432 ContentBlockerList.prototype.addFilter = function(filter)
390 { 433 {
391 if (filter.sitekeys) 434 if (filter.sitekeys)
392 return; 435 return;
393 if (filter instanceof filterClasses.RegExpFilter && 436 if (filter instanceof filterClasses.RegExpFilter &&
394 filter.regexpSource == null) 437 filter.regexpSource == null)
395 return; 438 return;
396 439
397 if (filter instanceof filterClasses.BlockingFilter) 440 if (filter instanceof filterClasses.BlockingFilter)
398 this.requestFilters.push(filter); 441 this.requestFilters.push(filter);
399 442
400 if (filter instanceof filterClasses.WhitelistFilter) 443 if (filter instanceof filterClasses.WhitelistFilter)
401 { 444 {
402 if (filter.contentType & (typeMap.DOCUMENT | whitelistableRequestTypes)) 445 if (filter.contentType & (typeMap.DOCUMENT | whitelistableRequestTypes))
403 this.requestExceptions.push(filter); 446 this.requestExceptions.push(filter);
404 447
405 if (filter.contentType & typeMap.ELEMHIDE) 448 if (filter.contentType & typeMap.ELEMHIDE)
406 this.elemhideExceptions.push(filter); 449 this.elemhideExceptions.push(filter);
450 else if (filter.contentType & typeMap.GENERICHIDE)
451 this.generichideExceptions.push(filter);
407 } 452 }
408 453
409 if (filter instanceof filterClasses.ElemHideFilter) 454 if (filter instanceof filterClasses.ElemHideFilter)
410 this.elemhideFilters.push(filter); 455 this.elemhideFilters.push(filter);
411 456
412 if (filter instanceof filterClasses.ElemHideException) 457 if (filter instanceof filterClasses.ElemHideException)
413 { 458 {
414 let domains = this.elemhideSelectorExceptions[filter.selector]; 459 let domains = this.elemhideSelectorExceptions[filter.selector];
415 if (!domains) 460 if (!domains)
416 domains = this.elemhideSelectorExceptions[filter.selector] = []; 461 domains = this.elemhideSelectorExceptions[filter.selector] = [];
417 462
418 parseDomains(filter.domains, domains, []); 463 parseDomains(filter.domains, domains, []);
419 } 464 }
420 }; 465 };
421 466
422 /** 467 /**
423 * Generate content blocker list for all filters that were added 468 * Generate content blocker list for all filters that were added
424 * 469 *
425 * @returns {Filter} filter Filter to convert 470 * @returns {Filter} filter Filter to convert
426 */ 471 */
427 ContentBlockerList.prototype.generateRules = function(filter) 472 ContentBlockerList.prototype.generateRules = function(filter)
428 { 473 {
429 let rules = []; 474 let rules = [];
430 475
476 let genericSelectors = [];
431 let groupedElemhideFilters = new Map(); 477 let groupedElemhideFilters = new Map();
478
432 for (let filter of this.elemhideFilters) 479 for (let filter of this.elemhideFilters)
433 { 480 {
434 let result = convertElemHideFilter(filter, this.elemhideSelectorExceptions); 481 let result = convertElemHideFilter(filter, this.elemhideSelectorExceptions);
435 if (!result) 482 if (!result)
436 continue; 483 continue;
437 484
438 if (result.matchDomains.length == 0) 485 if (result.matchDomains.length == 0)
439 result.matchDomains = ["^https?://"]; 486 {
440 487 genericSelectors.push(result.selector);
441 for (let matchDomain of result.matchDomains) 488 }
442 { 489 else
443 let group = groupedElemhideFilters.get(matchDomain) || []; 490 {
444 group.push(result.selector); 491 for (let matchDomain of result.matchDomains)
445 groupedElemhideFilters.set(matchDomain, group); 492 {
446 } 493 let group = groupedElemhideFilters.get(matchDomain) || [];
447 } 494 group.push(result.selector);
495 groupedElemhideFilters.set(matchDomain, group);
496 }
497 }
498 }
499
500 addCSSRules(rules, genericSelectors, "^https?://");
501
502 // Right after the generic element hiding filters, add the exceptions that
503 // should apply only to those filters.
504 for (let filter of this.generichideExceptions)
505 convertFilterAddRules(rules, filter, "ignore-previous-rules", false);
448 506
449 groupedElemhideFilters.forEach((selectors, matchDomain) => 507 groupedElemhideFilters.forEach((selectors, matchDomain) =>
450 { 508 {
451 while (selectors.length) 509 addCSSRules(rules, selectors, matchDomain);
452 {
453 let selector = selectors.splice(0, selectorLimit).join(", ");
454
455 // As of Safari 9.0 element IDs are matched as lowercase. We work around
456 // this by converting to the attribute format [id="elementID"]
457 selector = convertIDSelectorsToAttributeSelectors(selector);
458
459 rules.push({
460 trigger: {"url-filter": matchDomain,
461 "url-filter-is-case-sensitive": true},
462 action: {type: "css-display-none",
463 selector: selector}
464 });
465 }
466 }); 510 });
467 511
468 for (let filter of this.elemhideExceptions) 512 for (let filter of this.elemhideExceptions)
469 convertFilterAddRules(rules, filter, "ignore-previous-rules", false); 513 convertFilterAddRules(rules, filter, "ignore-previous-rules", false);
470 for (let filter of this.requestFilters) 514 for (let filter of this.requestFilters)
471 convertFilterAddRules(rules, filter, "block", true); 515 convertFilterAddRules(rules, filter, "block", true);
472 for (let filter of this.requestExceptions) 516 for (let filter of this.requestExceptions)
473 convertFilterAddRules(rules, filter, "ignore-previous-rules", true); 517 convertFilterAddRules(rules, filter, "ignore-previous-rules", true);
474 518
475 return rules.filter(rule => !hasNonASCI(rule)); 519 return rules.filter(rule => !hasNonASCI(rule));
476 }; 520 };
LEFTRIGHT

Powered by Google App Engine
This is Rietveld