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

Side by Side Diff: lib/abp2blocklist.js

Issue 29452289: Issue 5283 - Add support for $websocket and $webrtc (Closed) Base URL: https://hg.adblockplus.org/abp2blocklist
Patch Set: Rebase Created July 13, 2017, 11:41 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 | « no previous file | node_modules/filterClasses.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 15 matching lines...) Expand all
26 const typeMap = filterClasses.RegExpFilter.typeMap; 26 const typeMap = filterClasses.RegExpFilter.typeMap;
27 const whitelistableRequestTypes = (typeMap.IMAGE 27 const whitelistableRequestTypes = (typeMap.IMAGE
28 | typeMap.STYLESHEET 28 | typeMap.STYLESHEET
29 | typeMap.SCRIPT 29 | typeMap.SCRIPT
30 | typeMap.FONT 30 | typeMap.FONT
31 | typeMap.MEDIA 31 | typeMap.MEDIA
32 | typeMap.POPUP 32 | typeMap.POPUP
33 | typeMap.OBJECT 33 | typeMap.OBJECT
34 | typeMap.OBJECT_SUBREQUEST 34 | typeMap.OBJECT_SUBREQUEST
35 | typeMap.XMLHTTPREQUEST 35 | typeMap.XMLHTTPREQUEST
36 | typeMap.WEBSOCKET
37 | typeMap.WEBRTC
36 | typeMap.PING 38 | typeMap.PING
37 | typeMap.SUBDOCUMENT 39 | typeMap.SUBDOCUMENT
38 | typeMap.OTHER); 40 | typeMap.OTHER);
39 41
40 function parseDomains(domains, included, excluded) 42 function parseDomains(domains, included, excluded)
41 { 43 {
42 for (let domain in domains) 44 for (let domain in domains)
43 { 45 {
44 if (domain != "") 46 if (domain != "")
45 { 47 {
(...skipping 11 matching lines...) Expand all
57 function escapeRegExp(s) 59 function escapeRegExp(s)
58 { 60 {
59 return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); 61 return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
60 } 62 }
61 63
62 function matchDomain(domain) 64 function matchDomain(domain)
63 { 65 {
64 return "^https?://([^/:]*\\.)?" + escapeRegExp(domain).toLowerCase() + "[/:]"; 66 return "^https?://([^/:]*\\.)?" + escapeRegExp(domain).toLowerCase() + "[/:]";
65 } 67 }
66 68
69 function getURLSchemes(contentType)
70 {
71 // If the given content type includes all supported URL schemes, simply
72 // return a single generic URL scheme pattern. This minimizes the size of the
73 // generated rule set. The downside to this is that it will also match
74 // schemes that we do not want to match (e.g. "ftp://"), but this can be
75 // mitigated by adding exceptions for those schemes.
76 if (contentType & typeMap.WEBSOCKET && contentType & typeMap.WEBRTC &&
77 contentType & ~(typeMap.WEBSOCKET | typeMap.WEBRTC))
78 return ["[^:]+:(//)?"];
79
80 let urlSchemes = [];
81
82 if (contentType & typeMap.WEBSOCKET)
83 urlSchemes.push("wss?://");
84
85 if (contentType & typeMap.WEBRTC)
86 urlSchemes.push("stuns?:", "turns?:");
87
88 if (contentType & ~(typeMap.WEBSOCKET | typeMap.WEBRTC))
89 urlSchemes.push("https?://");
90
91 return urlSchemes;
92 }
93
67 function findSubdomainsInList(domain, list) 94 function findSubdomainsInList(domain, list)
68 { 95 {
69 let subdomains = []; 96 let subdomains = [];
70 let suffixLength = domain.length + 1; 97 let suffixLength = domain.length + 1;
71 98
72 for (let name of list) 99 for (let name of list)
73 { 100 {
74 if (name.length > suffixLength && name.slice(-suffixLength) == "." + domain) 101 if (name.length > suffixLength && name.slice(-suffixLength) == "." + domain)
75 subdomains.push(name.slice(0, -suffixLength)); 102 subdomains.push(name.slice(0, -suffixLength));
76 } 103 }
(...skipping 25 matching lines...) Expand all
102 return {matchDomains: included.map(matchDomain), selector: filter.selector}; 129 return {matchDomains: included.map(matchDomain), selector: filter.selector};
103 } 130 }
104 131
105 /** 132 /**
106 * Parse the given filter "regexpSource" string. Producing a regular expression, 133 * Parse the given filter "regexpSource" string. Producing a regular expression,
107 * extracting the hostname (if any), deciding if the regular expression is safe 134 * extracting the hostname (if any), deciding if the regular expression is safe
108 * to be converted + matched as lower case and noting if the source contains 135 * to be converted + matched as lower case and noting if the source contains
109 * anything after the hostname.) 136 * anything after the hostname.)
110 * 137 *
111 * @param {string} text regexpSource property of a filter 138 * @param {string} text regexpSource property of a filter
139 * @param {string} urlScheme The URL scheme to use in the regular expression
112 * @returns {object} An object containing a regular expression string, a bool 140 * @returns {object} An object containing a regular expression string, a bool
113 * indicating if the filter can be safely matched as lower 141 * indicating if the filter can be safely matched as lower
114 * case, a hostname string (or undefined) and a bool 142 * case, a hostname string (or undefined) and a bool
115 * indicating if the source only contains a hostname or not: 143 * indicating if the source only contains a hostname or not:
116 * {regexp: "...", 144 * {regexp: "...",
117 * canSafelyMatchAsLowercase: true/false, 145 * canSafelyMatchAsLowercase: true/false,
118 * hostname: "...", 146 * hostname: "...",
119 * justHostname: true/false} 147 * justHostname: true/false}
120 */ 148 */
121 function parseFilterRegexpSource(text) 149 function parseFilterRegexpSource(text, urlScheme)
122 { 150 {
123 let regexp = []; 151 let regexp = [];
124 152
125 // Convert the text into an array of Unicode characters. 153 // Convert the text into an array of Unicode characters.
126 // 154 //
127 // In the case of surrogate pairs (the smiley emoji, for example), one 155 // In the case of surrogate pairs (the smiley emoji, for example), one
128 // Unicode code point is represented by two JavaScript characters together. 156 // Unicode code point is represented by two JavaScript characters together.
129 // We want to iterate over Unicode code points rather than JavaScript 157 // We want to iterate over Unicode code points rather than JavaScript
130 // characters. 158 // characters.
131 let characters = Array.from(text); 159 let characters = Array.from(text);
132 160
133 let lastIndex = characters.length - 1; 161 let lastIndex = characters.length - 1;
134 let hostname; 162 let hostname;
135 let hostnameStart = null; 163 let hostnameStart = null;
136 let hostnameFinished = false; 164 let hostnameFinished = false;
137 let justHostname = false; 165 let justHostname = false;
138 let canSafelyMatchAsLowercase = false; 166 let canSafelyMatchAsLowercase = false;
139 167
168 if (!urlScheme)
169 urlScheme = getURLSchemes()[0];
170
140 for (let i = 0; i < characters.length; i++) 171 for (let i = 0; i < characters.length; i++)
141 { 172 {
142 let c = characters[i]; 173 let c = characters[i];
143 174
144 if (hostnameFinished) 175 if (hostnameFinished)
145 justHostname = false; 176 justHostname = false;
146 177
147 // If we're currently inside the hostname we have to be careful not to 178 // If we're currently inside the hostname we have to be careful not to
148 // escape any characters until after we have converted it to punycode. 179 // escape any characters until after we have converted it to punycode.
149 if (hostnameStart != null && !hostnameFinished) 180 if (hostnameStart != null && !hostnameFinished)
(...skipping 28 matching lines...) Expand all
178 // expression (if the URL contains only the hostname part), leaving us 209 // expression (if the URL contains only the hostname part), leaving us
179 // with "a-za-z", which would be redundant. 210 // with "a-za-z", which would be redundant.
180 if (!justHostname) 211 if (!justHostname)
181 alphabet = "A-Z" + alphabet; 212 alphabet = "A-Z" + alphabet;
182 let digits = "0-9"; 213 let digits = "0-9";
183 // Note that the "-" must appear first here in order to retain its 214 // Note that the "-" must appear first here in order to retain its
184 // literal meaning within the brackets. 215 // literal meaning within the brackets.
185 let specialCharacters = "-_.%"; 216 let specialCharacters = "-_.%";
186 let separator = "[^" + specialCharacters + alphabet + digits + "]"; 217 let separator = "[^" + specialCharacters + alphabet + digits + "]";
187 if (i == 0) 218 if (i == 0)
188 regexp.push("^https?://(.*" + separator + ")?"); 219 regexp.push("^" + urlScheme + "(.*" + separator + ")?");
189 else if (i == lastIndex) 220 else if (i == lastIndex)
190 regexp.push("(" + separator + ".*)?$"); 221 regexp.push("(" + separator + ".*)?$");
191 else 222 else
192 regexp.push(separator); 223 regexp.push(separator);
193 break; 224 break;
194 case "|": 225 case "|":
195 if (i == 0) 226 if (i == 0)
196 { 227 {
197 regexp.push("^"); 228 regexp.push("^");
198 break; 229 break;
199 } 230 }
200 if (i == lastIndex) 231 if (i == lastIndex)
201 { 232 {
202 regexp.push("$"); 233 regexp.push("$");
203 break; 234 break;
204 } 235 }
205 if (i == 1 && characters[0] == "|") 236 if (i == 1 && characters[0] == "|")
206 { 237 {
207 hostnameStart = i + 1; 238 hostnameStart = i + 1;
208 canSafelyMatchAsLowercase = true; 239 canSafelyMatchAsLowercase = true;
209 regexp.push("https?://([^/]+\\.)?"); 240 regexp.push(urlScheme + "([^/]+\\.)?");
210 break; 241 break;
211 } 242 }
212 regexp.push("\\|"); 243 regexp.push("\\|");
213 break; 244 break;
214 case "/": 245 case "/":
215 if (!hostnameFinished && 246 if (!hostnameFinished &&
216 characters[i - 2] == ":" && characters[i - 1] == "/") 247 characters[i - 2] == ":" && characters[i - 1] == "/")
217 { 248 {
218 hostnameStart = i + 1; 249 hostnameStart = i + 1;
219 canSafelyMatchAsLowercase = true; 250 canSafelyMatchAsLowercase = true;
(...skipping 14 matching lines...) Expand all
234 } 265 }
235 266
236 return { 267 return {
237 regexp: regexp.join(""), 268 regexp: regexp.join(""),
238 canSafelyMatchAsLowercase: canSafelyMatchAsLowercase, 269 canSafelyMatchAsLowercase: canSafelyMatchAsLowercase,
239 hostname: hostname, 270 hostname: hostname,
240 justHostname: justHostname 271 justHostname: justHostname
241 }; 272 };
242 } 273 }
243 274
244 function getResourceTypes(filter) 275 function getResourceTypes(contentType)
245 { 276 {
246 let types = []; 277 let types = [];
247 278
248 if (filter.contentType & typeMap.IMAGE) 279 if (contentType & typeMap.IMAGE)
249 types.push("image"); 280 types.push("image");
250 if (filter.contentType & typeMap.STYLESHEET) 281 if (contentType & typeMap.STYLESHEET)
251 types.push("style-sheet"); 282 types.push("style-sheet");
252 if (filter.contentType & typeMap.SCRIPT) 283 if (contentType & typeMap.SCRIPT)
253 types.push("script"); 284 types.push("script");
254 if (filter.contentType & typeMap.FONT) 285 if (contentType & typeMap.FONT)
255 types.push("font"); 286 types.push("font");
256 if (filter.contentType & (typeMap.MEDIA | typeMap.OBJECT)) 287 if (contentType & (typeMap.MEDIA | typeMap.OBJECT))
257 types.push("media"); 288 types.push("media");
258 if (filter.contentType & typeMap.POPUP) 289 if (contentType & typeMap.POPUP)
259 types.push("popup"); 290 types.push("popup");
260 if (filter.contentType & (typeMap.XMLHTTPREQUEST | 291 if (contentType & (typeMap.XMLHTTPREQUEST |
261 typeMap.OBJECT_SUBREQUEST | 292 typeMap.WEBSOCKET |
262 typeMap.PING | 293 typeMap.WEBRTC |
263 typeMap.OTHER)) 294 typeMap.OBJECT_SUBREQUEST |
295 typeMap.PING |
296 typeMap.OTHER))
297 {
264 types.push("raw"); 298 types.push("raw");
265 if (filter.contentType & typeMap.SUBDOCUMENT) 299 }
300 if (contentType & typeMap.SUBDOCUMENT)
266 types.push("document"); 301 types.push("document");
267 302
268 return types; 303 return types;
269 } 304 }
270 305
306 function makeRuleCopies(trigger, action, urlSchemes)
307 {
308 let copies = [];
309
310 // Always make a deep copy of the rule, since rules may have to be
311 // manipulated individually at a later stage.
312 let stringifiedTrigger = JSON.stringify(trigger);
313
314 let filterPattern = trigger["url-filter"].substring(1);
315 let startIndex = 0;
316
317 // If the URL filter already begins with the first URL scheme pattern, skip
318 // it.
319 if (trigger["url-filter"].startsWith("^" + urlSchemes[0]))
320 {
321 filterPattern = filterPattern.substring(urlSchemes[0].length);
322 startIndex = 1;
323 }
324 else
325 {
326 filterPattern = ".*" + filterPattern;
327 }
328
329 for (let i = startIndex; i < urlSchemes.length; i++)
330 {
331 let copyTrigger = Object.assign(JSON.parse(stringifiedTrigger), {
332 "url-filter": "^" + urlSchemes[i] + filterPattern
333 });
334 copies.push({trigger: copyTrigger, action});
335 }
336
337 return copies;
338 }
339
340 function excludeTopURLFromTrigger(trigger)
341 {
342 trigger["unless-top-url"] = [trigger["url-filter"]];
343 if (trigger["url-filter-is-case-sensitive"])
344 trigger["top-url-filter-is-case-sensitive"] = true;
345 }
346
271 function convertFilterAddRules(rules, filter, action, withResourceTypes, 347 function convertFilterAddRules(rules, filter, action, withResourceTypes,
272 exceptionDomains) 348 exceptionDomains, contentType)
273 { 349 {
274 let parsed = parseFilterRegexpSource(filter.regexpSource); 350 if (!contentType)
351 contentType = filter.contentType;
352
353 // If WebSocket or WebRTC are given along with other options but not
354 // including all three of WebSocket, WebRTC, and XMLHttpRequest, we must
355 // generate multiple rules. For example, for the filter
356 // "foo$websocket,image", we must generate one rule with "^wss?://" and "raw"
357 // and another rule with "^https?://" and "image". If we merge the two, we
358 // end up blocking requests of type XMLHttpRequest inadvertently.
359 if ((contentType & typeMap.WEBSOCKET && contentType != typeMap.WEBSOCKET &&
360 !(contentType & typeMap.WEBRTC &&
361 contentType & typeMap.XMLHTTPREQUEST)) ||
362 (contentType & typeMap.WEBRTC && contentType != typeMap.WEBRTC &&
363 !(contentType & typeMap.WEBSOCKET &&
364 contentType & typeMap.XMLHTTPREQUEST)))
365 {
366 if (contentType & typeMap.WEBSOCKET)
367 {
368 convertFilterAddRules(rules, filter, action, withResourceTypes,
369 exceptionDomains, typeMap.WEBSOCKET);
370 }
371
372 if (contentType & typeMap.WEBRTC)
373 {
374 convertFilterAddRules(rules, filter, action, withResourceTypes,
375 exceptionDomains, typeMap.WEBRTC);
376 }
377
378 contentType &= ~(typeMap.WEBSOCKET | typeMap.WEBRTC);
379
380 if (!contentType)
381 return;
382 }
383
384 let urlSchemes = getURLSchemes(contentType);
385 let parsed = parseFilterRegexpSource(filter.regexpSource, urlSchemes[0]);
275 386
276 // For the special case of $document whitelisting filters with just a domain 387 // For the special case of $document whitelisting filters with just a domain
277 // we can generate an equivalent blocking rule exception using if-domain. 388 // we can generate an equivalent blocking rule exception using if-domain.
278 if (filter instanceof filterClasses.WhitelistFilter && 389 if (filter instanceof filterClasses.WhitelistFilter &&
279 filter.contentType & typeMap.DOCUMENT && 390 contentType & typeMap.DOCUMENT &&
280 parsed.justHostname) 391 parsed.justHostname)
281 { 392 {
282 rules.push({ 393 rules.push({
283 trigger: { 394 trigger: {
284 "url-filter": ".*", 395 "url-filter": ".*",
285 "if-domain": ["*" + parsed.hostname] 396 "if-domain": ["*" + parsed.hostname]
286 }, 397 },
287 action: {type: "ignore-previous-rules"} 398 action: {type: "ignore-previous-rules"}
288 }); 399 });
289 // If the filter contains other supported options we'll need to generate 400 // If the filter contains other supported options we'll need to generate
290 // further rules for it, but if not we can simply return now. 401 // further rules for it, but if not we can simply return now.
291 if (!(filter.contentType & whitelistableRequestTypes)) 402 if (!(contentType & whitelistableRequestTypes))
292 return; 403 return;
293 } 404 }
294 405
295 let trigger = {"url-filter": parsed.regexp}; 406 let trigger = {"url-filter": parsed.regexp};
296 407
297 // Limit rules to HTTP(S) URLs 408 // If the URL filter begins with one of the URL schemes for this content
298 if (!/^(\^|http)/i.test(trigger["url-filter"])) 409 // type, we generate additional rules for all the URL scheme patterns;
299 trigger["url-filter"] = "^https?://.*" + trigger["url-filter"]; 410 // otherwise, if the start of the URL filter literally matches the first URL
411 // scheme pattern, we just generate additional rules for the remaining URL
412 // scheme patterns.
413 //
414 // For example, "stun:foo$webrtc" will give us "stun:foo", then we add a "^"
415 // in front of this and generate two additional rules for
416 // "^stuns?:.*stun:foo" and "^turns?:.*stun:foo". On the other hand,
417 // "||foo$webrtc" will give us "^stuns?:([^/]+\\.)?foo", so we just generate
418 // "^turns?:([^/]+\\.)?foo" in addition.
419 //
420 // Note that the filter can be already anchored to the beginning
421 // (e.g. "|stun:foo$webrtc"), in which case we do not generate any additional
422 // rules.
423 let needAltRules = trigger["url-filter"][0] != "^" ||
424 trigger["url-filter"].startsWith("^" + urlSchemes[0]);
425
426 if (trigger["url-filter"][0] != "^")
427 {
428 if (!urlSchemes.some(scheme => new RegExp("^" + scheme)
429 .test(trigger["url-filter"])))
430 {
431 trigger["url-filter"] = urlSchemes[0] + ".*" + trigger["url-filter"];
432 }
433
434 trigger["url-filter"] = "^" + trigger["url-filter"];
435 }
300 436
301 // For rules containing only a hostname we know that we're matching against 437 // For rules containing only a hostname we know that we're matching against
302 // a lowercase string unless the matchCase option was passed. 438 // a lowercase string unless the matchCase option was passed.
303 if (parsed.canSafelyMatchAsLowercase && !filter.matchCase) 439 if (parsed.canSafelyMatchAsLowercase && !filter.matchCase)
304 trigger["url-filter"] = trigger["url-filter"].toLowerCase(); 440 trigger["url-filter"] = trigger["url-filter"].toLowerCase();
305 441
306 if (parsed.canSafelyMatchAsLowercase || filter.matchCase) 442 if (parsed.canSafelyMatchAsLowercase || filter.matchCase)
307 trigger["url-filter-is-case-sensitive"] = true; 443 trigger["url-filter-is-case-sensitive"] = true;
308 444
309 let included = []; 445 let included = [];
310 let excluded = []; 446 let excluded = [];
311 447
312 parseDomains(filter.domains, included, excluded); 448 parseDomains(filter.domains, included, excluded);
313 449
314 if (exceptionDomains) 450 if (exceptionDomains)
315 excluded = excluded.concat(exceptionDomains); 451 excluded = excluded.concat(exceptionDomains);
316 452
317 if (withResourceTypes) 453 if (withResourceTypes)
318 { 454 {
319 let resourceTypes = getResourceTypes(filter); 455 let resourceTypes = getResourceTypes(contentType);
320 456
321 // Content blocker rules can't differentiate between sub-document requests 457 // Content blocker rules can't differentiate between sub-document requests
322 // (iframes) and top-level document requests. To avoid too many false 458 // (iframes) and top-level document requests. To avoid too many false
323 // positives, we prevent rules with no hostname part from blocking document 459 // positives, we prevent rules with no hostname part from blocking document
324 // requests. 460 // requests.
325 // 461 //
326 // Once Safari 11 becomes our minimum supported version, we could change 462 // Once Safari 11 becomes our minimum supported version, we could change
327 // our approach here to use the new "unless-top-url" property instead. 463 // our approach here to use the new "unless-top-url" property instead.
328 if (filter instanceof filterClasses.BlockingFilter && !parsed.hostname) 464 if (filter instanceof filterClasses.BlockingFilter && !parsed.hostname)
329 resourceTypes = resourceTypes.filter(type => type != "document"); 465 resourceTypes = resourceTypes.filter(type => type != "document");
330 466
331 if (resourceTypes.length == 0) 467 if (resourceTypes.length == 0)
332 return; 468 return;
333 469
334 trigger["resource-type"] = resourceTypes; 470 trigger["resource-type"] = resourceTypes;
335 } 471 }
336 472
337 if (filter.thirdParty != null) 473 if (filter.thirdParty != null)
338 trigger["load-type"] = [filter.thirdParty ? "third-party" : "first-party"]; 474 trigger["load-type"] = [filter.thirdParty ? "third-party" : "first-party"];
339 475
476 let addTopLevelException = false;
477
340 if (included.length > 0) 478 if (included.length > 0)
341 { 479 {
342 trigger["if-domain"] = []; 480 trigger["if-domain"] = [];
343 481
344 for (let name of included) 482 for (let name of included)
345 { 483 {
346 // If this is a blocking filter or an element hiding filter, add the 484 // If this is a blocking filter or an element hiding filter, add the
347 // subdomain wildcard only if no subdomains have been excluded. 485 // subdomain wildcard only if no subdomains have been excluded.
348 let notSubdomains = null; 486 let notSubdomains = null;
349 if ((filter instanceof filterClasses.BlockingFilter || 487 if ((filter instanceof filterClasses.BlockingFilter ||
(...skipping 19 matching lines...) Expand all
369 else if (filter instanceof filterClasses.BlockingFilter && 507 else if (filter instanceof filterClasses.BlockingFilter &&
370 filter.contentType & typeMap.SUBDOCUMENT && parsed.hostname) 508 filter.contentType & typeMap.SUBDOCUMENT && parsed.hostname)
371 { 509 {
372 // Rules with a hostname part are still allowed to block document requests, 510 // Rules with a hostname part are still allowed to block document requests,
373 // but we add an exception for top-level documents. 511 // but we add an exception for top-level documents.
374 // 512 //
375 // Note that we can only do this if there's no "unless-domain" property for 513 // Note that we can only do this if there's no "unless-domain" property for
376 // now. This also only works in Safari 11 onwards, while older versions 514 // now. This also only works in Safari 11 onwards, while older versions
377 // simply ignore this property. Once Safari 11 becomes our minimum 515 // simply ignore this property. Once Safari 11 becomes our minimum
378 // supported version, we can merge "unless-domain" into "unless-top-url". 516 // supported version, we can merge "unless-domain" into "unless-top-url".
379 trigger["unless-top-url"] = [trigger["url-filter"]]; 517 addTopLevelException = true;
380 if (trigger["url-filter-is-case-sensitive"]) 518 excludeTopURLFromTrigger(trigger);
381 trigger["top-url-filter-is-case-sensitive"] = true;
382 } 519 }
383 520
384 rules.push({trigger: trigger, action: {type: action}}); 521 rules.push({trigger: trigger, action: {type: action}});
522
523 if (needAltRules)
524 {
525 // Generate additional rules for any alternative URL schemes.
526 for (let altRule of makeRuleCopies(trigger, {type: action}, urlSchemes))
527 {
528 if (addTopLevelException)
529 excludeTopURLFromTrigger(altRule.trigger);
530
531 rules.push(altRule);
532 }
533 }
385 } 534 }
386 535
387 function convertIDSelectorsToAttributeSelectors(selector) 536 function convertIDSelectorsToAttributeSelectors(selector)
388 { 537 {
389 // First we figure out where all the IDs are 538 // First we figure out where all the IDs are
390 let sep = ""; 539 let sep = "";
391 let start = null; 540 let start = null;
392 let positions = []; 541 let positions = [];
393 for (let i = 0; i < selector.length; i++) 542 for (let i = 0; i < selector.length; i++)
394 { 543 {
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 { 746 {
598 convertFilterAddRules(rules, filter, "block", true, 747 convertFilterAddRules(rules, filter, "block", true,
599 requestFilterExceptionDomains); 748 requestFilterExceptionDomains);
600 } 749 }
601 750
602 for (let filter of this.requestExceptions) 751 for (let filter of this.requestExceptions)
603 convertFilterAddRules(rules, filter, "ignore-previous-rules", true); 752 convertFilterAddRules(rules, filter, "ignore-previous-rules", true);
604 753
605 return rules; 754 return rules;
606 }; 755 };
OLDNEW
« no previous file with comments | « no previous file | node_modules/filterClasses.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld