OLD | NEW |
1 /* | 1 /* |
2 * This file is part of Adblock Plus <http://adblockplus.org/>, | 2 * This file is part of Adblock Plus <http://adblockplus.org/>, |
3 * Copyright (C) 2006-2014 Eyeo GmbH | 3 * Copyright (C) 2006-2014 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 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 | 209 |
210 /** | 210 /** |
211 * Combines a matcher for blocking and exception rules, automatically sorts | 211 * Combines a matcher for blocking and exception rules, automatically sorts |
212 * rules into two Matcher instances. | 212 * rules into two Matcher instances. |
213 * @constructor | 213 * @constructor |
214 */ | 214 */ |
215 function CombinedMatcher() | 215 function CombinedMatcher() |
216 { | 216 { |
217 this.blacklist = new Matcher(); | 217 this.blacklist = new Matcher(); |
218 this.whitelist = new Matcher(); | 218 this.whitelist = new Matcher(); |
| 219 this.userBlacklist = new Matcher(); |
| 220 this.userWhitelist = new Matcher(); |
219 this.resultCache = Object.create(null); | 221 this.resultCache = Object.create(null); |
220 } | 222 } |
221 exports.CombinedMatcher = CombinedMatcher; | 223 exports.CombinedMatcher = CombinedMatcher; |
222 | 224 |
223 /** | 225 /** |
224 * Maximal number of matching cache entries to be kept | 226 * Maximal number of matching cache entries to be kept |
225 * @type Number | 227 * @type Number |
226 */ | 228 */ |
227 CombinedMatcher.maxCacheEntries = 1000; | 229 CombinedMatcher.maxCacheEntries = 1000; |
228 | 230 |
229 CombinedMatcher.prototype = | 231 CombinedMatcher.prototype = |
230 { | 232 { |
231 /** | 233 /** |
232 * Matcher for blocking rules. | 234 * Matcher for blocking rules. |
233 * @type Matcher | 235 * @type Matcher |
234 */ | 236 */ |
235 blacklist: null, | 237 blacklist: null, |
236 | 238 |
237 /** | 239 /** |
238 * Matcher for exception rules. | 240 * Matcher for exception rules. |
239 * @type Matcher | 241 * @type Matcher |
240 */ | 242 */ |
241 whitelist: null, | 243 whitelist: null, |
242 | 244 |
243 /** | 245 /** |
| 246 * Matcher for user-defined blocking rules. |
| 247 * @type Matcher |
| 248 */ |
| 249 userBlacklist: null, |
| 250 |
| 251 /** |
| 252 * Matcher for user-defined exception rules. |
| 253 * @type Matcher |
| 254 */ |
| 255 userWhitelist: null, |
| 256 |
| 257 /** |
244 * Lookup table of previous matchesAny results | 258 * Lookup table of previous matchesAny results |
245 * @type Object | 259 * @type Object |
246 */ | 260 */ |
247 resultCache: null, | 261 resultCache: null, |
248 | 262 |
249 /** | 263 /** |
250 * Number of entries in resultCache | 264 * Number of entries in resultCache |
251 * @type Number | 265 * @type Number |
252 */ | 266 */ |
253 cacheEntries: 0, | 267 cacheEntries: 0, |
254 | 268 |
| 269 _getMatcher: function(filter) |
| 270 { |
| 271 if (filter.isUserDefined) |
| 272 { |
| 273 if (filter instanceof WhitelistFilter) |
| 274 return this.userWhitelist; |
| 275 else |
| 276 return this.userBlacklist; |
| 277 } |
| 278 else |
| 279 { |
| 280 if (filter instanceof WhitelistFilter) |
| 281 return this.whitelist; |
| 282 else |
| 283 return this.blacklist; |
| 284 } |
| 285 }, |
| 286 |
255 /** | 287 /** |
256 * @see Matcher#clear | 288 * @see Matcher#clear |
257 */ | 289 */ |
258 clear: function() | 290 clear: function() |
259 { | 291 { |
260 this.blacklist.clear(); | 292 this.blacklist.clear(); |
261 this.whitelist.clear(); | 293 this.whitelist.clear(); |
| 294 this.userBlacklist.clear(); |
| 295 this.userWhitelist.clear(); |
262 this.resultCache = Object.create(null); | 296 this.resultCache = Object.create(null); |
263 this.cacheEntries = 0; | 297 this.cacheEntries = 0; |
264 }, | 298 }, |
265 | 299 |
266 /** | 300 /** |
267 * @see Matcher#add | 301 * @see Matcher#add |
268 */ | 302 */ |
269 add: function(filter) | 303 add: function(filter) |
270 { | 304 { |
271 if (filter instanceof WhitelistFilter) | 305 this._getMatcher(filter).add(filter); |
272 this.whitelist.add(filter); | |
273 else | |
274 this.blacklist.add(filter); | |
275 | 306 |
276 if (this.cacheEntries > 0) | 307 if (this.cacheEntries > 0) |
277 { | 308 { |
278 this.resultCache = Object.create(null); | 309 this.resultCache = Object.create(null); |
279 this.cacheEntries = 0; | 310 this.cacheEntries = 0; |
280 } | 311 } |
281 }, | 312 }, |
282 | 313 |
283 /** | 314 /** |
284 * @see Matcher#remove | 315 * @see Matcher#remove |
285 */ | 316 */ |
286 remove: function(filter) | 317 remove: function(filter) |
287 { | 318 { |
288 if (filter instanceof WhitelistFilter) | 319 this._getMatcher(filter).remove(filter); |
289 this.whitelist.remove(filter); | |
290 else | |
291 this.blacklist.remove(filter); | |
292 | 320 |
293 if (this.cacheEntries > 0) | 321 if (this.cacheEntries > 0) |
294 { | 322 { |
295 this.resultCache = Object.create(null); | 323 this.resultCache = Object.create(null); |
296 this.cacheEntries = 0; | 324 this.cacheEntries = 0; |
297 } | 325 } |
298 }, | 326 }, |
299 | 327 |
300 /** | 328 /** |
301 * @see Matcher#findKeyword | 329 * @see Matcher#findKeyword |
302 */ | 330 */ |
303 findKeyword: function(filter) | 331 findKeyword: function(filter) |
304 { | 332 { |
305 if (filter instanceof WhitelistFilter) | 333 return this._getMatcher(filter).findKeyword(filter); |
306 return this.whitelist.findKeyword(filter); | |
307 else | |
308 return this.blacklist.findKeyword(filter); | |
309 }, | 334 }, |
310 | 335 |
311 /** | 336 /** |
312 * @see Matcher#hasFilter | 337 * @see Matcher#hasFilter |
313 */ | 338 */ |
314 hasFilter: function(filter) | 339 hasFilter: function(filter) |
315 { | 340 { |
316 if (filter instanceof WhitelistFilter) | 341 return this._getMatcher(filter).hasFilter(filter); |
317 return this.whitelist.hasFilter(filter); | |
318 else | |
319 return this.blacklist.hasFilter(filter); | |
320 }, | 342 }, |
321 | 343 |
322 /** | 344 /** |
323 * @see Matcher#getKeywordForFilter | 345 * @see Matcher#getKeywordForFilter |
324 */ | 346 */ |
325 getKeywordForFilter: function(filter) | 347 getKeywordForFilter: function(filter) |
326 { | 348 { |
327 if (filter instanceof WhitelistFilter) | 349 return this._getMatcher(filter).getKeywordForFilter(filter); |
328 return this.whitelist.getKeywordForFilter(filter); | |
329 else | |
330 return this.blacklist.getKeywordForFilter(filter); | |
331 }, | 350 }, |
332 | 351 |
333 /** | 352 /** |
334 * Checks whether a particular filter is slow | 353 * Checks whether a particular filter is slow |
335 */ | 354 */ |
336 isSlowFilter: function(/**RegExpFilter*/ filter) /**Boolean*/ | 355 isSlowFilter: function(/**RegExpFilter*/ filter) /**Boolean*/ |
337 { | 356 { |
338 let matcher = (filter instanceof WhitelistFilter ? this.whitelist : this.bla
cklist); | 357 let matcher = this._getMatcher(filter); |
339 if (matcher.hasFilter(filter)) | 358 if (matcher.hasFilter(filter)) |
340 return !matcher.getKeywordForFilter(filter); | 359 return !matcher.getKeywordForFilter(filter); |
341 else | 360 else |
342 return !matcher.findKeyword(filter); | 361 return !matcher.findKeyword(filter); |
343 }, | 362 }, |
344 | 363 |
345 /** | 364 /** |
346 * Optimized filter matching testing both whitelist and blacklist matchers | 365 * Optimized filter matching testing both whitelist and blacklist matchers |
347 * simultaneously. For parameters see Matcher.matchesAny(). | 366 * simultaneously. |
348 * @see Matcher#matchesAny | 367 * @see Matcher#matchesAny |
349 */ | 368 */ |
350 matchesAnyInternal: function(location, contentType, docDomain, thirdParty, sit
ekey) | 369 matchesAnyInternal: function(blacklist, whitelist, candidates, location, conte
ntType, docDomain, thirdParty, sitekey) |
351 { | 370 { |
352 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); | |
353 if (candidates === null) | |
354 candidates = []; | |
355 candidates.push(""); | |
356 | |
357 let blacklistHit = null; | 371 let blacklistHit = null; |
358 for (let i = 0, l = candidates.length; i < l; i++) | 372 for (let i = 0, l = candidates.length; i < l; i++) |
359 { | 373 { |
360 let substr = candidates[i]; | 374 let substr = candidates[i]; |
361 if (substr in this.whitelist.filterByKeyword) | 375 if (substr in whitelist.filterByKeyword) |
362 { | 376 { |
363 let result = this.whitelist._checkEntryMatch(substr, location, contentTy
pe, docDomain, thirdParty, sitekey); | 377 let result = whitelist._checkEntryMatch(substr, location, contentType, d
ocDomain, thirdParty, sitekey); |
364 if (result) | 378 if (result) |
365 return result; | 379 return result; |
366 } | 380 } |
367 if (substr in this.blacklist.filterByKeyword && blacklistHit === null) | 381 if (substr in blacklist.filterByKeyword && blacklistHit === null) |
368 blacklistHit = this.blacklist._checkEntryMatch(substr, location, content
Type, docDomain, thirdParty, sitekey); | 382 blacklistHit = blacklist._checkEntryMatch(substr, location, contentType,
docDomain, thirdParty, sitekey); |
369 } | 383 } |
370 return blacklistHit; | 384 return blacklistHit; |
371 }, | 385 }, |
372 | 386 |
373 /** | 387 /** |
374 * @see Matcher#matchesAny | 388 * @see Matcher#matchesAny |
375 */ | 389 */ |
376 matchesAny: function(location, contentType, docDomain, thirdParty, sitekey) | 390 matchesAny: function(location, contentType, docDomain, thirdParty, sitekey) |
377 { | 391 { |
378 let key = location + " " + contentType + " " + docDomain + " " + thirdParty
+ " " + sitekey; | 392 let key = location + " " + contentType + " " + docDomain + " " + thirdParty
+ " " + sitekey; |
379 if (key in this.resultCache) | 393 if (key in this.resultCache) |
380 return this.resultCache[key]; | 394 return this.resultCache[key]; |
381 | 395 |
382 let result = this.matchesAnyInternal(location, contentType, docDomain, third
Party, sitekey); | 396 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); |
| 397 if (candidates === null) |
| 398 candidates = []; |
| 399 candidates.push(""); |
| 400 |
| 401 let result = (this.matchesAnyInternal(this.userBlacklist, this.userWhitelist
, candidates, location, contentType, docDomain, thirdParty, sitekey) || |
| 402 this.matchesAnyInternal(this.blacklist, this.whitelist,
candidates, location, contentType, docDomain, thirdParty, sitekey)); |
383 | 403 |
384 if (this.cacheEntries >= CombinedMatcher.maxCacheEntries) | 404 if (this.cacheEntries >= CombinedMatcher.maxCacheEntries) |
385 { | 405 { |
386 this.resultCache = Object.create(null); | 406 this.resultCache = Object.create(null); |
387 this.cacheEntries = 0; | 407 this.cacheEntries = 0; |
388 } | 408 } |
389 | 409 |
390 this.resultCache[key] = result; | 410 this.resultCache[key] = result; |
391 this.cacheEntries++; | 411 this.cacheEntries++; |
392 | 412 |
393 return result; | 413 return result; |
394 } | 414 } |
395 } | 415 } |
396 | 416 |
397 /** | 417 /** |
398 * Shared CombinedMatcher instance that should usually be used. | 418 * Shared CombinedMatcher instance that should usually be used. |
399 * @type CombinedMatcher | 419 * @type CombinedMatcher |
400 */ | 420 */ |
401 let defaultMatcher = exports.defaultMatcher = new CombinedMatcher(); | 421 let defaultMatcher = exports.defaultMatcher = new CombinedMatcher(); |
OLD | NEW |