| 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 |