| Left: | ||
| Right: | 
| LEFT | RIGHT | 
|---|---|
| 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-2015 Eyeo GmbH | 3 * Copyright (C) 2006-2015 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 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 320 /* Web requests */ | 320 /* Web requests */ | 
| 321 | 321 | 
| 322 var framesOfTabs = Object.create(null); | 322 var framesOfTabs = Object.create(null); | 
| 323 | 323 | 
| 324 ext.getFrame = function(tabId, frameId) | 324 ext.getFrame = function(tabId, frameId) | 
| 325 { | 325 { | 
| 326 return (framesOfTabs[tabId] || {})[frameId]; | 326 return (framesOfTabs[tabId] || {})[frameId]; | 
| 327 }; | 327 }; | 
| 328 | 328 | 
| 329 var handlerBehaviorChangedQuota = chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANG ED_CALLS_PER_10_MINUTES; | 329 var handlerBehaviorChangedQuota = chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANG ED_CALLS_PER_10_MINUTES; | 
| 330 var handlerBehaviorChangedQuotaExceeded = false; | 330 | 
| 331 var handlerBehaviorChangedPending = false; | 331 function propagateHandlerBehaviorChange() | 
| 332 | 332 { | 
| 333 function handlerBehaviorChanged() | |
| 334 { | |
| 335 chrome.webRequest.handlerBehaviorChanged(); | |
| 336 handlerBehaviorChangedQuota--; | |
| 337 | |
| 338 // Make sure to not call handlerBehaviorChanged() more often than allowed | 333 // Make sure to not call handlerBehaviorChanged() more often than allowed | 
| 339 // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES. | 334 // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES. | 
| 340 // Otherwise Chrome notifies the user that this extension is causing issues. | 335 // Otherwise Chrome notifies the user that this extension is causing issues. | 
| 341 setTimeout(function() | 336 if (handlerBehaviorChangedQuota > 0) | 
| 342 { | 337 { | 
| 343 handlerBehaviorChangedQuota++; | 338 chrome.webNavigation.onBeforeNavigate.removeListener(propagateHandlerBehav iorChange); | 
| 344 | 339 chrome.webRequest.handlerBehaviorChanged(); | 
| 345 // If the quota were exceeded, call handlerBehaviorChanged() | 340 | 
| 346 // delayed, when 10 minutes since the first call within the | 341 handlerBehaviorChangedQuota--; | 
| 347 // past 10 minutes passed. | 342 setTimeout(function() { handlerBehaviorChangedQuota++; }, 600000); | 
| 348 if (handlerBehaviorChangedQuotaExceeded) | 343 } | 
| 349 { | |
| 350 handlerBehaviorChangedQuotaExceeded = false; | |
| 351 handlerBehaviorChanged(); | |
| 352 } | |
| 353 }, 600000); | |
| 354 } | 344 } | 
| 
 
Wladimir Palant
2015/02/23 18:25:26
Is this really a good approach? I think that we sh
 
Sebastian Noack
2015/02/23 19:12:08
We call handlerBehaviorChanged() only if it did. T
 
Wladimir Palant
2015/02/23 19:22:42
If users are changing filters frequently (more oft
 
Sebastian Noack
2015/04/09 07:04:55
How about this: The new patch defers handlerBehavi
 
 | |
| 355 | 345 | 
| 356 ext.webRequest = { | 346 ext.webRequest = { | 
| 357 onBeforeRequest: new ext._EventTarget(), | 347 onBeforeRequest: new ext._EventTarget(), | 
| 358 handlerBehaviorChanged: function() | 348 handlerBehaviorChanged: function() | 
| 359 { | 349 { | 
| 360 if (handlerBehaviorChangedQuota > 0) | 350 // Defer handlerBehaviorChanged() until navigation occurs. | 
| 361 { | 351 // There wouldn't be any visible effect when calling it earlier, | 
| 362 // Call handlerBehaviorChanged() asynchronously, and only if it | 352 // but it's an expensive operation and that way we avoid to call | 
| 363 // hasn't been scheduled yet. That way we avoid to call it multiple | 353 // it multiple times, if multiple filters are added/removed. | 
| 364 // times, if multiple filters were added/removed simultanously. | 354 var onBeforeNavigate = chrome.webNavigation.onBeforeNavigate; | 
| 365 if (!handlerBehaviorChangedPending) | 355 if (!onBeforeNavigate.hasListener(propagateHandlerBehaviorChange)) | 
| 366 { | 356 onBeforeNavigate.addListener(propagateHandlerBehaviorChange); | 
| 367 handlerBehaviorChangedPending = true; | 357 } | 
| 368 | 358 }; | 
| 369 setTimeout(function() | 359 | 
| 370 { | 360 // Since Chrome 38 requests of type 'object' (e.g. requests | 
| 371 handlerBehaviorChanged(); | 361 // initiated by Flash) are mistakenly reported with the type 'other'. | 
| 372 handlerBehaviorChangedPending = false; | 362 // https://code.google.com/p/chromium/issues/detail?id=410382 | 
| 373 }, 0); | 363 if (parseInt(navigator.userAgent.match(/\bChrome\/(\d+)/)[1], 10) >= 38) | 
| 374 } | 364 { | 
| 375 } | 365 ext.webRequest.indistinguishableTypes = [ | 
| 376 else | 366 ["OTHER", "OBJECT", "OBJECT_SUBREQUEST"] | 
| 377 { | 367 ]; | 
| 378 handlerBehaviorChangedQuotaExceeded = true; | 368 } | 
| 379 } | 369 else | 
| 380 } | 370 { | 
| 381 }; | 371 ext.webRequest.indistinguishableTypes = [ | 
| 372 ["OBJECT", "OBJECT_SUBREQUEST"], | |
| 373 ["OTHER", "MEDIA", "FONT"] | |
| 374 ]; | |
| 375 } | |
| 382 | 376 | 
| 383 chrome.tabs.query({}, function(tabs) | 377 chrome.tabs.query({}, function(tabs) | 
| 384 { | 378 { | 
| 385 tabs.forEach(function(tab) | 379 tabs.forEach(function(tab) | 
| 386 { | 380 { | 
| 387 chrome.webNavigation.getAllFrames({tabId: tab.id}, function(details) | 381 chrome.webNavigation.getAllFrames({tabId: tab.id}, function(details) | 
| 388 { | 382 { | 
| 389 if (details && details.length > 0) | 383 if (details && details.length > 0) | 
| 390 { | 384 { | 
| 391 var frames = framesOfTabs[tab.id] = Object.create(null); | 385 var frames = framesOfTabs[tab.id] = Object.create(null); | 
| (...skipping 16 matching lines...) Expand all Loading... | |
| 408 chrome.webRequest.onBeforeRequest.addListener(function(details) | 402 chrome.webRequest.onBeforeRequest.addListener(function(details) | 
| 409 { | 403 { | 
| 410 try | 404 try | 
| 411 { | 405 { | 
| 412 // the high-level code isn't interested in requests that aren't related | 406 // the high-level code isn't interested in requests that aren't related | 
| 413 // to a tab and since those can only be handled in Chrome, we ignore | 407 // to a tab and since those can only be handled in Chrome, we ignore | 
| 414 // them here instead of in the browser independent high-level code. | 408 // them here instead of in the browser independent high-level code. | 
| 415 if (details.tabId == -1) | 409 if (details.tabId == -1) | 
| 416 return; | 410 return; | 
| 417 | 411 | 
| 418 var requestType = details.type; | 412 var isMainFrame = details.type == "main_frame" || ( | 
| 419 var isMainFrame = requestType == "main_frame" || ( | |
| 420 | 413 | 
| 421 // assume that the first request belongs to the top frame. Chrome | 414 // assume that the first request belongs to the top frame. Chrome | 
| 422 // may give the top frame the type "object" instead of "main_frame". | 415 // may give the top frame the type "object" instead of "main_frame". | 
| 423 // https://code.google.com/p/chromium/issues/detail?id=281711 | 416 // https://code.google.com/p/chromium/issues/detail?id=281711 | 
| 424 details.frameId == 0 && !(details.tabId in framesOfTabs) | 417 details.frameId == 0 && !(details.tabId in framesOfTabs) | 
| 425 ); | 418 ); | 
| 426 | 419 | 
| 427 var frames = null; | 420 var frames = null; | 
| 428 if (!isMainFrame) | 421 if (!isMainFrame) | 
| 429 frames = framesOfTabs[details.tabId]; | 422 frames = framesOfTabs[details.tabId]; | 
| 430 if (!frames) | 423 if (!frames) | 
| 431 frames = framesOfTabs[details.tabId] = Object.create(null); | 424 frames = framesOfTabs[details.tabId] = Object.create(null); | 
| 432 | 425 | 
| 433 var frame = null; | 426 var frame = null; | 
| 434 var url = new URL(details.url); | 427 var url = new URL(details.url); | 
| 435 if (!isMainFrame) | 428 if (!isMainFrame) | 
| 436 { | 429 { | 
| 437 // we are looking for the frame that contains the element that | 430 // we are looking for the frame that contains the element that | 
| 438 // is about to load, however if a frame is loading the surrounding | 431 // is about to load, however if a frame is loading the surrounding | 
| 439 // frame is indicated by parentFrameId instead of frameId | 432 // frame is indicated by parentFrameId instead of frameId | 
| 440 var frameId; | 433 var frameId; | 
| 441 if (requestType == "sub_frame") | 434 var requestType; | 
| 435 if (details.type == "sub_frame") | |
| 436 { | |
| 442 frameId = details.parentFrameId; | 437 frameId = details.parentFrameId; | 
| 438 requestType = "SUBDOCUMENT"; | |
| 439 } | |
| 443 else | 440 else | 
| 441 { | |
| 444 frameId = details.frameId; | 442 frameId = details.frameId; | 
| 443 requestType = details.type.toUpperCase(); | |
| 444 } | |
| 445 | 445 | 
| 446 frame = frames[frameId] || frames[Object.keys(frames)[0]]; | 446 frame = frames[frameId] || frames[Object.keys(frames)[0]]; | 
| 447 | 447 | 
| 448 if (frame) | 448 if (frame) | 
| 449 { | 449 { | 
| 450 // Since Chrome 38 requests of type 'object' (e.g. requests | |
| 451 // initiated by Flash) are mistakenly reported with the type 'other'. | |
| 452 // https://code.google.com/p/chromium/issues/detail?id=410382 | |
| 453 if (requestType == "other" && parseInt(navigator.userAgent.match(/\bCh rome\/(\d+)/)[1], 10) >= 38) | |
| 454 requestType = "object"; | |
| 455 | |
| 456 var results = ext.webRequest.onBeforeRequest._dispatch( | 450 var results = ext.webRequest.onBeforeRequest._dispatch( | 
| 457 url, | 451 url, | 
| 458 requestType, | 452 requestType, | 
| 459 new Page({id: details.tabId}), | 453 new Page({id: details.tabId}), | 
| 460 frame | 454 frame | 
| 461 ); | 455 ); | 
| 462 | 456 | 
| 463 if (results.indexOf(false) != -1) | 457 if (results.indexOf(false) != -1) | 
| 464 return {cancel: true}; | 458 return {cancel: true}; | 
| 465 } | 459 } | 
| 466 } | 460 } | 
| 467 | 461 | 
| 468 if (isMainFrame || details.type == "sub_frame") | 462 if (isMainFrame || details.type == "sub_frame") | 
| 469 frames[details.frameId] = {url: url, parent: frame}; | 463 frames[details.frameId] = {url: url, parent: frame}; | 
| 470 } | 464 } | 
| 471 catch (e) | 465 catch (e) | 
| 472 { | 466 { | 
| 473 // recent versions of Chrome cancel the request when an error occurs in | 467 // recent versions of Chrome cancel the request when an error occurs in | 
| 474 // the onBeforeRequest listener. However in our case it is preferred, to | 468 // the onBeforeRequest listener. However in our case it is preferred, to | 
| 475 // let potentially some ads through, rather than blocking legit requests. | 469 // let potentially some ads through, rather than blocking legit requests. | 
| 476 console.error(e); | 470 console.error(e); | 
| 477 } | 471 } | 
| 478 }, {urls: ["http://*/*", "https://*/*"]}, ["blocking"]); | 472 }, {urls: ["http://*/*", "https://*/*"]}, ["blocking"]); | 
| 479 | 473 | 
| 480 | 474 | 
| 481 /* Message passing */ | 475 /* Message passing */ | 
| 482 | 476 | 
| 483 chrome.runtime.onMessage.addListener(function(message, rawSender, sendResponse ) | 477 chrome.runtime.onMessage.addListener(function(message, rawSender, sendResponse ) | 
| 484 { | 478 { | 
| 485 var sender = { | 479 var sender = {}; | 
| 486 page: new Page(rawSender.tab), | 480 | 
| 487 frame: { | 481 // Add "page" and "frame" if the message was sent by a content script. | 
| 482 // If sent by popup or the background page itself, there is no "tab". | |
| 483 if ("tab" in rawSender) | |
| 484 { | |
| 485 sender.page = new Page(rawSender.tab); | |
| 486 sender.frame = { | |
| 488 url: new URL(rawSender.url), | 487 url: new URL(rawSender.url), | 
| 489 get parent() | 488 get parent() | 
| 490 { | 489 { | 
| 491 var frames = framesOfTabs[rawSender.tab.id]; | 490 var frames = framesOfTabs[rawSender.tab.id]; | 
| 492 | 491 | 
| 493 if (!frames) | 492 if (!frames) | 
| 494 return null; | 493 return null; | 
| 495 | 494 | 
| 496 if ("frameId" in rawSender) | 495 if ("frameId" in rawSender) | 
| 497 { | 496 { | 
| 498 // Chrome 41+ | 497 // Chrome 41+ | 
| 499 var frame = frames[rawSender.frameId]; | 498 var frame = frames[rawSender.frameId]; | 
| 500 if (frame) | 499 if (frame) | 
| 501 return frame.parent; | 500 return frame.parent; | 
| 502 } | 501 } | 
| 503 else | 502 else | 
| 504 { | 503 { | 
| 505 // Chrome 28-40 | 504 // Chrome 28-40 | 
| 506 for (var frameId in frames) | 505 for (var frameId in frames) | 
| 507 { | 506 { | 
| 508 if (frames[frameId].url.href == this.url.href) | 507 if (frames[frameId].url.href == this.url.href) | 
| 509 return frames[frameId].parent; | 508 return frames[frameId].parent; | 
| 510 } | 509 } | 
| 511 } | 510 } | 
| 512 | 511 | 
| 513 return frames[0]; | 512 return frames[0]; | 
| 514 } | 513 } | 
| 515 } | 514 }; | 
| 516 }; | 515 } | 
| 517 | 516 | 
| 518 return ext.onMessage._dispatch(message, sender, sendResponse).indexOf(true) != -1; | 517 return ext.onMessage._dispatch(message, sender, sendResponse).indexOf(true) != -1; | 
| 519 }); | 518 }); | 
| 520 | 519 | 
| 521 // We have to ensure there is at least one listener for the onConnect event. | 520 // We have to ensure there is at least one listener for the onConnect event. | 
| 522 // Otherwise we can't connect a port later, which we need to do in order to | 521 // Otherwise we can't connect a port later, which we need to do in order to | 
| 523 // detect when the extension is reloaded, disabled or uninstalled. | 522 // detect when the extension is reloaded, disabled or uninstalled. | 
| 524 chrome.runtime.onConnect.addListener(function() {}); | 523 chrome.runtime.onConnect.addListener(function() {}); | 
| 525 | 524 | 
| 526 | 525 | 
| (...skipping 17 matching lines...) Expand all Loading... | |
| 544 if (!win.incognito) | 543 if (!win.incognito) | 
| 545 queryInfo.windowId = win.id; | 544 queryInfo.windowId = win.id; | 
| 546 | 545 | 
| 547 chrome.tabs.query(queryInfo, function(tabs) | 546 chrome.tabs.query(queryInfo, function(tabs) | 
| 548 { | 547 { | 
| 549 if (tabs.length > 0) | 548 if (tabs.length > 0) | 
| 550 { | 549 { | 
| 551 var tab = tabs[0]; | 550 var tab = tabs[0]; | 
| 552 | 551 | 
| 553 chrome.windows.update(tab.windowId, {focused: true}); | 552 chrome.windows.update(tab.windowId, {focused: true}); | 
| 554 chrome.tabs.highlight( | 553 chrome.tabs.update(tab.id, {active: true}); | 
| 555 { | |
| 556 windowId: tab.windowId, | |
| 557 tabs: [tab.index] | |
| 558 }, | |
| 559 function() {} | |
| 560 ); | |
| 561 | 554 | 
| 562 if (callback) | 555 if (callback) | 
| 563 callback(new Page(tab)); | 556 callback(new Page(tab)); | 
| 564 } | 557 } | 
| 565 else | 558 else | 
| 566 { | 559 { | 
| 567 ext.pages.open(optionsUrl, callback); | 560 ext.pages.open(optionsUrl, callback); | 
| 568 } | 561 } | 
| 569 }); | 562 }); | 
| 570 }); | 563 }); | 
| 571 }; | 564 }; | 
| 572 })(); | 565 })(); | 
| LEFT | RIGHT |