| 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 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 { | 158 { |
| 159 if (filter.text in this.keywordByFilter) | 159 if (filter.text in this.keywordByFilter) |
| 160 return this.keywordByFilter[filter.text]; | 160 return this.keywordByFilter[filter.text]; |
| 161 else | 161 else |
| 162 return null; | 162 return null; |
| 163 }, | 163 }, |
| 164 | 164 |
| 165 /** | 165 /** |
| 166 * Checks whether the entries for a particular keyword match a URL | 166 * Checks whether the entries for a particular keyword match a URL |
| 167 */ | 167 */ |
| 168 _checkEntryMatch: function(keyword, location, contentType, docDomain, thirdPar
ty) | 168 _checkEntryMatch: function(keyword, location, contentType, docDomain, thirdPar
ty, docLocation, siteKey) |
| 169 { | 169 { |
| 170 let list = this.filterByKeyword[keyword]; | 170 let list = this.filterByKeyword[keyword]; |
| 171 for (let i = 0; i < list.length; i++) | 171 for (let i = 0; i < list.length; i++) |
| 172 { | 172 { |
| 173 let filter = list[i]; | 173 let filter = list[i]; |
| 174 if (filter.matches(location, contentType, docDomain, thirdParty)) | 174 if (filter.matches(location, contentType, docDomain, thirdParty, docLocati
on, siteKey)) |
| 175 return filter; | 175 return filter; |
| 176 } | 176 } |
| 177 return null; | 177 return null; |
| 178 }, | 178 }, |
| 179 | 179 |
| 180 /** | 180 /** |
| 181 * Tests whether the URL matches any of the known filters | 181 * Tests whether the URL matches any of the known filters |
| 182 * @param {String} location URL to be tested | 182 * @param {String} location URL to be tested |
| 183 * @param {String} contentType content type identifier of the URL | 183 * @param {String} contentType content type identifier of the URL |
| 184 * @param {String} docDomain domain name of the document that loads the URL | 184 * @param {String} docDomain domain name of the document that loads the URL |
| 185 * @param {Boolean} thirdParty should be true if the URL is a third-party requ
est | 185 * @param {Boolean} thirdParty should be true if the URL is a third-party requ
est |
| 186 * @param {String} docLocation location the document that loads the URL |
| 187 * @param {String} siteKey public key provided by the document |
| 186 * @return {RegExpFilter} matching filter or null | 188 * @return {RegExpFilter} matching filter or null |
| 187 */ | 189 */ |
| 188 matchesAny: function(location, contentType, docDomain, thirdParty) | 190 matchesAny: function(location, contentType, docDomain, thirdParty, docLocation
, siteKey) |
| 189 { | 191 { |
| 190 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); | 192 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); |
| 191 if (candidates === null) | 193 if (candidates === null) |
| 192 candidates = []; | 194 candidates = []; |
| 193 candidates.push(""); | 195 candidates.push(""); |
| 194 for (let i = 0, l = candidates.length; i < l; i++) | 196 for (let i = 0, l = candidates.length; i < l; i++) |
| 195 { | 197 { |
| 196 let substr = candidates[i]; | 198 let substr = candidates[i]; |
| 197 if (substr in this.filterByKeyword) | 199 if (substr in this.filterByKeyword) |
| 198 { | 200 { |
| 199 let result = this._checkEntryMatch(substr, location, contentType, docDom
ain, thirdParty); | 201 let result = this._checkEntryMatch(substr, location, contentType, docDom
ain, thirdParty, docLocation, siteKey); |
| 200 if (result) | 202 if (result) |
| 201 return result; | 203 return result; |
| 202 } | 204 } |
| 203 } | 205 } |
| 204 | 206 |
| 205 return null; | 207 return null; |
| 206 } | 208 } |
| 207 }; | 209 }; |
| 208 | 210 |
| 209 /** | 211 /** |
| 210 * Combines a matcher for blocking and exception rules, automatically sorts | 212 * Combines a matcher for blocking and exception rules, automatically sorts |
| 211 * rules into two Matcher instances. | 213 * rules into two Matcher instances. |
| 212 * @constructor | 214 * @constructor |
| 213 */ | 215 */ |
| 214 function CombinedMatcher() | 216 function CombinedMatcher() |
| 215 { | 217 { |
| 216 this.blacklist = new Matcher(); | 218 this.blacklist = new Matcher(); |
| 217 this.whitelist = new Matcher(); | 219 this.whitelist = new Matcher(); |
| 218 this.keys = Object.create(null); | |
| 219 this.resultCache = Object.create(null); | 220 this.resultCache = Object.create(null); |
| 220 } | 221 } |
| 221 exports.CombinedMatcher = CombinedMatcher; | 222 exports.CombinedMatcher = CombinedMatcher; |
| 222 | 223 |
| 223 /** | 224 /** |
| 224 * Maximal number of matching cache entries to be kept | 225 * Maximal number of matching cache entries to be kept |
| 225 * @type Number | 226 * @type Number |
| 226 */ | 227 */ |
| 227 CombinedMatcher.maxCacheEntries = 1000; | 228 CombinedMatcher.maxCacheEntries = 1000; |
| 228 | 229 |
| 229 CombinedMatcher.prototype = | 230 CombinedMatcher.prototype = |
| 230 { | 231 { |
| 231 /** | 232 /** |
| 232 * Matcher for blocking rules. | 233 * Matcher for blocking rules. |
| 233 * @type Matcher | 234 * @type Matcher |
| 234 */ | 235 */ |
| 235 blacklist: null, | 236 blacklist: null, |
| 236 | 237 |
| 237 /** | 238 /** |
| 238 * Matcher for exception rules. | 239 * Matcher for exception rules. |
| 239 * @type Matcher | 240 * @type Matcher |
| 240 */ | 241 */ |
| 241 whitelist: null, | 242 whitelist: null, |
| 242 | 243 |
| 243 /** | 244 /** |
| 244 * Exception rules that are limited by public keys, mapped by the correspondin
g keys. | |
| 245 * @type Object | |
| 246 */ | |
| 247 keys: null, | |
| 248 | |
| 249 /** | |
| 250 * Lookup table of previous matchesAny results | 245 * Lookup table of previous matchesAny results |
| 251 * @type Object | 246 * @type Object |
| 252 */ | 247 */ |
| 253 resultCache: null, | 248 resultCache: null, |
| 254 | 249 |
| 255 /** | 250 /** |
| 256 * Number of entries in resultCache | 251 * Number of entries in resultCache |
| 257 * @type Number | 252 * @type Number |
| 258 */ | 253 */ |
| 259 cacheEntries: 0, | 254 cacheEntries: 0, |
| 260 | 255 |
| 261 /** | 256 /** |
| 262 * @see Matcher#clear | 257 * @see Matcher#clear |
| 263 */ | 258 */ |
| 264 clear: function() | 259 clear: function() |
| 265 { | 260 { |
| 266 this.blacklist.clear(); | 261 this.blacklist.clear(); |
| 267 this.whitelist.clear(); | 262 this.whitelist.clear(); |
| 268 this.keys = Object.create(null); | |
| 269 this.resultCache = Object.create(null); | 263 this.resultCache = Object.create(null); |
| 270 this.cacheEntries = 0; | 264 this.cacheEntries = 0; |
| 271 }, | 265 }, |
| 272 | 266 |
| 273 /** | 267 /** |
| 274 * @see Matcher#add | 268 * @see Matcher#add |
| 275 */ | 269 */ |
| 276 add: function(filter) | 270 add: function(filter) |
| 277 { | 271 { |
| 278 if (filter instanceof WhitelistFilter) | 272 if (filter instanceof WhitelistFilter) |
| 279 { | 273 this.whitelist.add(filter); |
| 280 if (filter.siteKeys) | |
| 281 { | |
| 282 for (let i = 0; i < filter.siteKeys.length; i++) | |
| 283 this.keys[filter.siteKeys[i]] = filter.text; | |
| 284 } | |
| 285 else | |
| 286 this.whitelist.add(filter); | |
| 287 } | |
| 288 else | 274 else |
| 289 this.blacklist.add(filter); | 275 this.blacklist.add(filter); |
| 290 | 276 |
| 291 if (this.cacheEntries > 0) | 277 if (this.cacheEntries > 0) |
| 292 { | 278 { |
| 293 this.resultCache = Object.create(null); | 279 this.resultCache = Object.create(null); |
| 294 this.cacheEntries = 0; | 280 this.cacheEntries = 0; |
| 295 } | 281 } |
| 296 }, | 282 }, |
| 297 | 283 |
| 298 /** | 284 /** |
| 299 * @see Matcher#remove | 285 * @see Matcher#remove |
| 300 */ | 286 */ |
| 301 remove: function(filter) | 287 remove: function(filter) |
| 302 { | 288 { |
| 303 if (filter instanceof WhitelistFilter) | 289 if (filter instanceof WhitelistFilter) |
| 304 { | 290 this.whitelist.remove(filter); |
| 305 if (filter.siteKeys) | |
| 306 { | |
| 307 for (let i = 0; i < filter.siteKeys.length; i++) | |
| 308 delete this.keys[filter.siteKeys[i]]; | |
| 309 } | |
| 310 else | |
| 311 this.whitelist.remove(filter); | |
| 312 } | |
| 313 else | 291 else |
| 314 this.blacklist.remove(filter); | 292 this.blacklist.remove(filter); |
| 315 | 293 |
| 316 if (this.cacheEntries > 0) | 294 if (this.cacheEntries > 0) |
| 317 { | 295 { |
| 318 this.resultCache = Object.create(null); | 296 this.resultCache = Object.create(null); |
| 319 this.cacheEntries = 0; | 297 this.cacheEntries = 0; |
| 320 } | 298 } |
| 321 }, | 299 }, |
| 322 | 300 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 return !matcher.getKeywordForFilter(filter); | 341 return !matcher.getKeywordForFilter(filter); |
| 364 else | 342 else |
| 365 return !matcher.findKeyword(filter); | 343 return !matcher.findKeyword(filter); |
| 366 }, | 344 }, |
| 367 | 345 |
| 368 /** | 346 /** |
| 369 * Optimized filter matching testing both whitelist and blacklist matchers | 347 * Optimized filter matching testing both whitelist and blacklist matchers |
| 370 * simultaneously. For parameters see Matcher.matchesAny(). | 348 * simultaneously. For parameters see Matcher.matchesAny(). |
| 371 * @see Matcher#matchesAny | 349 * @see Matcher#matchesAny |
| 372 */ | 350 */ |
| 373 matchesAnyInternal: function(location, contentType, docDomain, thirdParty) | 351 matchesAnyInternal: function(location, contentType, docDomain, thirdParty, doc
Location, siteKey) |
| 374 { | 352 { |
| 375 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); | 353 let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); |
| 376 if (candidates === null) | 354 if (candidates === null) |
| 377 candidates = []; | 355 candidates = []; |
| 378 candidates.push(""); | 356 candidates.push(""); |
| 379 | 357 |
| 380 let blacklistHit = null; | 358 let blacklistHit = null; |
| 381 for (let i = 0, l = candidates.length; i < l; i++) | 359 for (let i = 0, l = candidates.length; i < l; i++) |
| 382 { | 360 { |
| 383 let substr = candidates[i]; | 361 let substr = candidates[i]; |
| 384 if (substr in this.whitelist.filterByKeyword) | 362 if (substr in this.whitelist.filterByKeyword) |
| 385 { | 363 { |
| 386 let result = this.whitelist._checkEntryMatch(substr, location, contentTy
pe, docDomain, thirdParty); | 364 let result = this.whitelist._checkEntryMatch(substr, location, contentTy
pe, docDomain, thirdParty, docLocation, siteKey); |
| 387 if (result) | 365 if (result) |
| 388 return result; | 366 return result; |
| 389 } | 367 } |
| 390 if (substr in this.blacklist.filterByKeyword && blacklistHit === null) | 368 if (substr in this.blacklist.filterByKeyword && blacklistHit === null) |
| 391 blacklistHit = this.blacklist._checkEntryMatch(substr, location, content
Type, docDomain, thirdParty); | 369 blacklistHit = this.blacklist._checkEntryMatch(substr, location, content
Type, docDomain, thirdParty, docLocation, siteKey); |
| 392 } | 370 } |
| 393 return blacklistHit; | 371 return blacklistHit; |
| 394 }, | 372 }, |
| 395 | 373 |
| 396 /** | 374 /** |
| 397 * @see Matcher#matchesAny | 375 * @see Matcher#matchesAny |
| 398 */ | 376 */ |
| 399 matchesAny: function(location, contentType, docDomain, thirdParty) | 377 matchesAny: function(location, contentType, docDomain, thirdParty, docLocation
, siteKey) |
| 400 { | 378 { |
| 401 let key = location + " " + contentType + " " + docDomain + " " + thirdParty; | 379 let key = location + " " + contentType + " " + docDomain + " " + thirdParty
+ " " + docLocation + " " + siteKey; |
| 402 if (key in this.resultCache) | 380 if (key in this.resultCache) |
| 403 return this.resultCache[key]; | 381 return this.resultCache[key]; |
| 404 | 382 |
| 405 let result = this.matchesAnyInternal(location, contentType, docDomain, third
Party); | 383 let result = this.matchesAnyInternal(location, contentType, docDomain, third
Party, docLocation, siteKey); |
| 406 | 384 |
| 407 if (this.cacheEntries >= CombinedMatcher.maxCacheEntries) | 385 if (this.cacheEntries >= CombinedMatcher.maxCacheEntries) |
| 408 { | 386 { |
| 409 this.resultCache = Object.create(null); | 387 this.resultCache = Object.create(null); |
| 410 this.cacheEntries = 0; | 388 this.cacheEntries = 0; |
| 411 } | 389 } |
| 412 | 390 |
| 413 this.resultCache[key] = result; | 391 this.resultCache[key] = result; |
| 414 this.cacheEntries++; | 392 this.cacheEntries++; |
| 415 | 393 |
| 416 return result; | 394 return result; |
| 417 }, | |
| 418 | |
| 419 /** | |
| 420 * Looks up whether any filters match the given website key. | |
| 421 */ | |
| 422 matchesByKey: function(/**String*/ location, /**String*/ key, /**String*/ docD
omain) | |
| 423 { | |
| 424 key = key.toUpperCase(); | |
| 425 if (key in this.keys) | |
| 426 { | |
| 427 let filter = Filter.knownFilters[this.keys[key]]; | |
| 428 if (filter && filter.matches(location, "DOCUMENT", docDomain, false)) | |
| 429 return filter; | |
| 430 else | |
| 431 return null; | |
| 432 } | |
| 433 else | |
| 434 return null; | |
| 435 } | 395 } |
| 436 } | 396 } |
| 437 | 397 |
| 438 /** | 398 /** |
| 439 * Shared CombinedMatcher instance that should usually be used. | 399 * Shared CombinedMatcher instance that should usually be used. |
| 440 * @type CombinedMatcher | 400 * @type CombinedMatcher |
| 441 */ | 401 */ |
| 442 let defaultMatcher = exports.defaultMatcher = new CombinedMatcher(); | 402 let defaultMatcher = exports.defaultMatcher = new CombinedMatcher(); |
| OLD | NEW |