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

Delta Between Two Patch Sets: lib/matcher.js

Issue 29897555: Issue 6940 - Use underscore prefixes lib/matcher.js (Closed)
Left Patch Set: Address some PS2 comments Created Oct. 23, 2018, 1:26 a.m.
Right Patch Set: Address PS6 comment Created Oct. 24, 2018, 6:47 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/filterListener.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-present eyeo GmbH 3 * Copyright (C) 2006-present 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
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 "use strict"; 18 "use strict";
19 19
20 /** 20 /**
21 * @fileOverview Matcher class implementing matching addresses against 21 * @fileOverview Matcher class implementing matching addresses against
22 * a list of filters. 22 * a list of filters.
23 */ 23 */
24 24
25 const {WhitelistFilter} = require("./filterClasses"); 25 const {RegExpFilter, WhitelistFilter} = require("./filterClasses");
26 26
27 /** 27 /**
28 * Regular expression for matching a keyword in a filter. 28 * Regular expression for matching a keyword in a filter.
29 * @type {RegExp} 29 * @type {RegExp}
30 */ 30 */
31 const keywordRegExp = /[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/; 31 const keywordRegExp = /[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/;
32 32
33 /** 33 /**
34 * Regular expression for matching all keywords in a filter. 34 * Regular expression for matching all keywords in a filter.
35 * @type {RegExp} 35 * @type {RegExp}
36 */ 36 */
37 const allKeywordsRegExp = new RegExp(keywordRegExp, "g"); 37 const allKeywordsRegExp = new RegExp(keywordRegExp, "g");
38
39 /**
40 * Bitmask for "types" that are for exception rules only, like
41 * <code>$document</code>, <code>$elemhide</code>, and so on.
42 * @type {number}
43 */
44 const WHITELIST_ONLY_TYPES = RegExpFilter.typeMap.DOCUMENT |
45 RegExpFilter.typeMap.ELEMHIDE |
46 RegExpFilter.typeMap.GENERICHIDE |
47 RegExpFilter.typeMap.GENERICBLOCK;
38 48
39 /** 49 /**
40 * Checks whether a particular filter is slow. 50 * Checks whether a particular filter is slow.
41 * @param {RegExpFilter} filter 51 * @param {RegExpFilter} filter
42 * @returns {boolean} 52 * @returns {boolean}
43 */ 53 */
44 function isSlowFilter(filter) 54 function isSlowFilter(filter)
45 { 55 {
46 return !filter.pattern || !keywordRegExp.test(filter.pattern); 56 return !filter.pattern || !keywordRegExp.test(filter.pattern);
47 } 57 }
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 * @param {string} location 172 * @param {string} location
163 * @param {number} typeMask 173 * @param {number} typeMask
164 * @param {string} [docDomain] 174 * @param {string} [docDomain]
165 * @param {boolean} [thirdParty] 175 * @param {boolean} [thirdParty]
166 * @param {string} [sitekey] 176 * @param {string} [sitekey]
167 * @param {boolean} [specificOnly] 177 * @param {boolean} [specificOnly]
168 * @returns {?Filter} 178 * @returns {?Filter}
169 * @protected 179 * @protected
170 */ 180 */
171 checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey, 181 checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey,
172 specificOnly) 182 specificOnly)
173 { 183 {
174 let set = this._filterByKeyword.get(keyword); 184 let set = this._filterByKeyword.get(keyword);
175 if (typeof set == "undefined") 185 if (typeof set == "undefined")
176 return null; 186 return null;
177 187
178 for (let filter of set) 188 for (let filter of set)
179 { 189 {
180 if (specificOnly && filter.isGeneric() && 190 if (specificOnly && filter.isGeneric() &&
181 !(filter instanceof WhitelistFilter)) 191 !(filter instanceof WhitelistFilter))
182 continue; 192 continue;
(...skipping 23 matching lines...) Expand all
206 */ 216 */
207 matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly) 217 matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly)
208 { 218 {
209 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); 219 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
210 if (candidates === null) 220 if (candidates === null)
211 candidates = []; 221 candidates = [];
212 candidates.push(""); 222 candidates.push("");
213 for (let i = 0, l = candidates.length; i < l; i++) 223 for (let i = 0, l = candidates.length; i < l; i++)
214 { 224 {
215 let result = this.checkEntryMatch(candidates[i], location, typeMask, 225 let result = this.checkEntryMatch(candidates[i], location, typeMask,
216 docDomain, thirdParty, sitekey, 226 docDomain, thirdParty, sitekey,
217 specificOnly); 227 specificOnly);
218 if (result) 228 if (result)
219 return result; 229 return result;
220 } 230 }
221 231
222 return null; 232 return null;
223 } 233 }
224 } 234 }
225 235
226 exports.Matcher = Matcher; 236 exports.Matcher = Matcher;
227 237
228 /** 238 /**
229 * Combines a matcher for blocking and exception rules, automatically sorts 239 * Combines a matcher for blocking and exception rules, automatically sorts
230 * rules into two {@link Matcher} instances. 240 * rules into two {@link Matcher} instances.
231 */ 241 */
232 class CombinedMatcher 242 class CombinedMatcher
233 { 243 {
234 constructor() 244 constructor()
235 { 245 {
236 /** 246 /**
237 * Maximal number of matching cache entries to be kept 247 * Maximal number of matching cache entries to be kept
238 * @type {number} 248 * @type {number}
239 */ 249 */
240 this.maxCacheEntries = 1000; 250 this.maxCacheEntries = 1000;
241 251
242 /** 252 /**
243 * Matcher for blocking rules. 253 * Matcher for blocking rules.
244 * @type {Matcher} 254 * @type {Matcher}
245 * @protected 255 * @private
246 */ 256 */
247 this.blacklist = new Matcher(); 257 this._blacklist = new Matcher();
248 258
249 /** 259 /**
250 * Matcher for exception rules. 260 * Matcher for exception rules.
251 * @type {Matcher} 261 * @type {Matcher}
252 * @protected 262 * @private
253 */ 263 */
254 this.whitelist = new Matcher(); 264 this._whitelist = new Matcher();
255 265
256 /** 266 /**
257 * Lookup table of previous {@link Matcher#matchesAny} results 267 * Lookup table of previous {@link Matcher#matchesAny} results
258 * @type {Map.<string,Filter>} 268 * @type {Map.<string,Filter>}
259 * @private 269 * @private
260 */ 270 */
261 this._resultCache = new Map(); 271 this._resultCache = new Map();
262 } 272 }
263 273
264 /** 274 /**
265 * @see Matcher#clear 275 * @see Matcher#clear
266 */ 276 */
267 clear() 277 clear()
268 { 278 {
269 this.blacklist.clear(); 279 this._blacklist.clear();
270 this.whitelist.clear(); 280 this._whitelist.clear();
271 this._resultCache.clear(); 281 this._resultCache.clear();
272 } 282 }
273 283
274 /** 284 /**
275 * @see Matcher#add 285 * @see Matcher#add
276 * @param {Filter} filter 286 * @param {Filter} filter
277 */ 287 */
278 add(filter) 288 add(filter)
279 { 289 {
280 if (filter instanceof WhitelistFilter) 290 if (filter instanceof WhitelistFilter)
281 this.whitelist.add(filter); 291 this._whitelist.add(filter);
282 else 292 else
283 this.blacklist.add(filter); 293 this._blacklist.add(filter);
284 294
285 this._resultCache.clear(); 295 this._resultCache.clear();
286 } 296 }
287 297
288 /** 298 /**
289 * @see Matcher#remove 299 * @see Matcher#remove
290 * @param {Filter} filter 300 * @param {Filter} filter
291 */ 301 */
292 remove(filter) 302 remove(filter)
293 { 303 {
294 if (filter instanceof WhitelistFilter) 304 if (filter instanceof WhitelistFilter)
295 this.whitelist.remove(filter); 305 this._whitelist.remove(filter);
296 else 306 else
297 this.blacklist.remove(filter); 307 this._blacklist.remove(filter);
298 308
299 this._resultCache.clear(); 309 this._resultCache.clear();
300 } 310 }
301 311
302 /** 312 /**
303 * @see Matcher#findKeyword 313 * @see Matcher#findKeyword
304 * @param {Filter} filter 314 * @param {Filter} filter
305 * @returns {string} keyword 315 * @returns {string} keyword
306 * @protected 316 * @protected
307 */ 317 */
308 findKeyword(filter) 318 findKeyword(filter)
309 { 319 {
310 if (filter instanceof WhitelistFilter) 320 if (filter instanceof WhitelistFilter)
311 return this.whitelist.findKeyword(filter); 321 return this._whitelist.findKeyword(filter);
312 return this.blacklist.findKeyword(filter); 322 return this._blacklist.findKeyword(filter);
313 } 323 }
314 324
315 /** 325 /**
316 * Optimized filter matching testing both whitelist and blacklist matchers 326 * Optimized filter matching testing both whitelist and blacklist matchers
317 * simultaneously. For parameters see 327 * simultaneously. For parameters see
318 {@link Matcher#matchesAny Matcher.matchesAny()}. 328 {@link Matcher#matchesAny Matcher.matchesAny()}.
319 * @see Matcher#matchesAny 329 * @see Matcher#matchesAny
320 * @inheritdoc 330 * @inheritdoc
321 * @private 331 * @private
322 */ 332 */
323 _matchesAnyInternal(location, typeMask, docDomain, thirdParty, sitekey, 333 _matchesAnyInternal(location, typeMask, docDomain, thirdParty, sitekey,
324 specificOnly) 334 specificOnly)
325 { 335 {
326 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); 336 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
327 if (candidates === null) 337 if (candidates === null)
328 candidates = []; 338 candidates = [];
329 candidates.push(""); 339 candidates.push("");
330 340
341 let whitelistHit = null;
331 let blacklistHit = null; 342 let blacklistHit = null;
332 for (let i = 0, l = candidates.length; i < l; i++) 343
333 { 344 // If the type mask includes no types other than whitelist-only types, we
334 let substr = candidates[i]; 345 // can skip the blacklist.
335 let result = this.whitelist.checkEntryMatch( 346 if ((typeMask & ~WHITELIST_ONLY_TYPES) != 0)
336 substr, location, typeMask, docDomain, thirdParty, sitekey 347 {
337 ); 348 for (let i = 0, l = candidates.length; !blacklistHit && i < l; i++)
338 if (result)
339 return result;
340 if (blacklistHit === null)
341 { 349 {
342 blacklistHit = this.blacklist.checkEntryMatch( 350 blacklistHit = this._blacklist.checkEntryMatch(candidates[i], location,
343 substr, location, typeMask, docDomain, thirdParty, sitekey, 351 typeMask, docDomain,
344 specificOnly 352 thirdParty, sitekey,
345 ); 353 specificOnly);
346 } 354 }
347 } 355 }
348 return blacklistHit; 356
357 // If the type mask includes any whitelist-only types, we need to check the
358 // whitelist.
359 if (blacklistHit || (typeMask & WHITELIST_ONLY_TYPES) != 0)
360 {
361 for (let i = 0, l = candidates.length; !whitelistHit && i < l; i++)
362 {
363 whitelistHit = this._whitelist.checkEntryMatch(candidates[i], location,
364 typeMask, docDomain,
365 thirdParty, sitekey);
366 }
367 }
368
369 return whitelistHit || blacklistHit;
349 } 370 }
350 371
351 /** 372 /**
352 * @see Matcher#matchesAny 373 * @see Matcher#matchesAny
353 * @inheritdoc 374 * @inheritdoc
354 */ 375 */
355 matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly) 376 matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly)
356 { 377 {
357 let key = location + " " + typeMask + " " + docDomain + " " + thirdParty + 378 let key = location + " " + typeMask + " " + docDomain + " " + thirdParty +
358 " " + sitekey + " " + specificOnly; 379 " " + sitekey + " " + specificOnly;
359 380
360 let result = this._resultCache.get(key); 381 let result = this._resultCache.get(key);
361 if (typeof result != "undefined") 382 if (typeof result != "undefined")
362 return result; 383 return result;
363 384
364 result = this._matchesAnyInternal(location, typeMask, docDomain, 385 result = this._matchesAnyInternal(location, typeMask, docDomain,
365 thirdParty, sitekey, specificOnly); 386 thirdParty, sitekey, specificOnly);
366 387
367 if (this._resultCache.size >= this.maxCacheEntries) 388 if (this._resultCache.size >= this.maxCacheEntries)
368 this._resultCache.clear(); 389 this._resultCache.clear();
369 390
370 this._resultCache.set(key, result); 391 this._resultCache.set(key, result);
371 392
372 return result; 393 return result;
373 } 394 }
374 } 395 }
375 396
376 exports.CombinedMatcher = CombinedMatcher; 397 exports.CombinedMatcher = CombinedMatcher;
377 398
378 /** 399 /**
379 * Shared {@link CombinedMatcher} instance that should usually be used. 400 * Shared {@link CombinedMatcher} instance that should usually be used.
380 * @type {CombinedMatcher} 401 * @type {CombinedMatcher}
381 */ 402 */
382 let defaultMatcher = new CombinedMatcher(); 403 let defaultMatcher = new CombinedMatcher();
383 404
384 exports.defaultMatcher = defaultMatcher; 405 exports.defaultMatcher = defaultMatcher;
LEFTRIGHT

Powered by Google App Engine
This is Rietveld