| OLD | NEW | 
|---|
| 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-2017 eyeo GmbH | 3  * Copyright (C) 2006-2017 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 (function() | 20 (function() | 
| 21 { | 21 { | 
| 22   let nonEmptyPageMaps = Object.create(null); | 22   let allPageMaps = new Set(); | 
| 23   let pageMapCounter = 0; |  | 
| 24 | 23 | 
| 25   let PageMap = ext.PageMap = function() | 24   let PageMap = ext.PageMap = function() | 
| 26   { | 25   { | 
| 27     this._map = Object.create(null); | 26     this._map = new Map(); | 
| 28     this._id = ++pageMapCounter; | 27 | 
|  | 28     allPageMaps.add(this); | 
| 29   }; | 29   }; | 
| 30   PageMap.prototype = { | 30   PageMap.prototype = { | 
| 31     _delete(id) | 31     _delete(id) | 
| 32     { | 32     { | 
| 33       delete this._map[id]; | 33       this._map.delete(id); | 
| 34 |  | 
| 35       if (Object.keys(this._map).length == 0) |  | 
| 36         delete nonEmptyPageMaps[this._id]; |  | 
| 37     }, | 34     }, | 
| 38     keys() | 35     keys() | 
| 39     { | 36     { | 
| 40       return Object.keys(this._map).map(ext.getPage); | 37       return this._map.keys(); | 
| 41     }, | 38     }, | 
| 42     get(page) | 39     get(page) | 
| 43     { | 40     { | 
| 44       return this._map[page.id]; | 41       return this._map.get(page.id); | 
| 45     }, | 42     }, | 
| 46     set(page, value) | 43     set(page, value) | 
| 47     { | 44     { | 
| 48       this._map[page.id] = value; | 45       this._map.set(page.id, value); | 
| 49       nonEmptyPageMaps[this._id] = this; |  | 
| 50     }, | 46     }, | 
| 51     has(page) | 47     has(page) | 
| 52     { | 48     { | 
| 53       return page.id in this._map; | 49       return this._map.has(page.id); | 
| 54     }, | 50     }, | 
| 55     clear() | 51     clear() | 
| 56     { | 52     { | 
| 57       for (let id in this._map) | 53       this._map.clear(); | 
| 58         this._delete(id); |  | 
| 59     }, | 54     }, | 
| 60     delete(page) | 55     delete(page) | 
| 61     { | 56     { | 
| 62       this._delete(page.id); | 57       this._delete(page.id); | 
| 63     } | 58     } | 
| 64   }; | 59   }; | 
| 65 | 60 | 
| 66   ext._removeFromAllPageMaps = pageId => | 61   ext._removeFromAllPageMaps = pageId => | 
| 67   { | 62   { | 
| 68     for (let pageMapId in nonEmptyPageMaps) | 63     for (let pageMap of allPageMaps) | 
| 69       nonEmptyPageMaps[pageMapId]._delete(pageId); | 64       pageMap._delete(pageId); | 
| 70   }; | 65   }; | 
| 71 | 66 | 
| 72   /* Pages */ | 67   /* Pages */ | 
| 73 | 68 | 
| 74   let Page = ext.Page = function(tab) | 69   let Page = ext.Page = function(tab) | 
| 75   { | 70   { | 
| 76     this.id = tab.id; | 71     this.id = tab.id; | 
| 77     this._url = tab.url && new URL(tab.url); | 72     this._url = tab.url && new URL(tab.url); | 
| 78 | 73 | 
| 79     this.browserAction = new BrowserAction(tab.id); | 74     this.browserAction = new BrowserAction(tab.id); | 
| 80     this.contextMenus = new ContextMenus(this); | 75     this.contextMenus = new ContextMenus(this); | 
| 81   }; | 76   }; | 
| 82   Page.prototype = { | 77   Page.prototype = { | 
| 83     get url() | 78     get url() | 
| 84     { | 79     { | 
| 85       // usually our Page objects are created from Chrome's Tab objects, which | 80       // usually our Page objects are created from Chrome's Tab objects, which | 
| 86       // provide the url. So we can return the url given in the constructor. | 81       // provide the url. So we can return the url given in the constructor. | 
| 87       if (this._url) | 82       if (this._url) | 
| 88         return this._url; | 83         return this._url; | 
| 89 | 84 | 
| 90       // but sometimes we only have the tab id when we create a Page object. | 85       // but sometimes we only have the tab id when we create a Page object. | 
| 91       // In that case we get the url from top frame of the tab, recorded by | 86       // In that case we get the url from top frame of the tab, recorded by | 
| 92       // the onBeforeRequest handler. | 87       // the onBeforeRequest handler. | 
| 93       let frames = framesOfTabs[this.id]; | 88       let frames = framesOfTabs.get(this.id); | 
| 94       if (frames) | 89       if (frames) | 
| 95       { | 90       { | 
| 96         let frame = frames[0]; | 91         let frame = frames.get(0); | 
| 97         if (frame) | 92         if (frame) | 
| 98           return frame.url; | 93           return frame.url; | 
| 99       } | 94       } | 
| 100     }, | 95     }, | 
| 101     sendMessage(message, responseCallback) | 96     sendMessage(message, responseCallback) | 
| 102     { | 97     { | 
| 103       chrome.tabs.sendMessage(this.id, message, responseCallback); | 98       chrome.tabs.sendMessage(this.id, message, responseCallback); | 
| 104     } | 99     } | 
| 105   }; | 100   }; | 
| 106 | 101 | 
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 151   }; | 146   }; | 
| 152 | 147 | 
| 153   chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => | 148   chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => | 
| 154   { | 149   { | 
| 155     if (changeInfo.status == "loading") | 150     if (changeInfo.status == "loading") | 
| 156       ext.pages.onLoading._dispatch(new Page(tab)); | 151       ext.pages.onLoading._dispatch(new Page(tab)); | 
| 157   }); | 152   }); | 
| 158 | 153 | 
| 159   function createFrame(tabId, frameId) | 154   function createFrame(tabId, frameId) | 
| 160   { | 155   { | 
| 161     let frames = framesOfTabs[tabId]; | 156     let frames = framesOfTabs.get(tabId); | 
| 162     if (!frames) | 157     if (!frames) | 
| 163       frames = framesOfTabs[tabId] = Object.create(null); | 158     { | 
|  | 159       frames = new Map(); | 
|  | 160       framesOfTabs.set(tabId, frames); | 
|  | 161     } | 
| 164 | 162 | 
| 165     let frame = frames[frameId]; | 163     let frame = frames.get(frameId); | 
| 166     if (!frame) | 164     if (!frame) | 
| 167       frame = frames[frameId] = {}; | 165     { | 
|  | 166       frame = {}; | 
|  | 167       frames.set(frameId, frame); | 
|  | 168     } | 
| 168 | 169 | 
| 169     return frame; | 170     return frame; | 
| 170   } | 171   } | 
| 171 | 172 | 
| 172   function updatePageFrameStructure(frameId, tabId, url, parentFrameId) | 173   function updatePageFrameStructure(frameId, tabId, url, parentFrameId) | 
| 173   { | 174   { | 
| 174     if (frameId == 0) | 175     if (frameId == 0) | 
| 175     { | 176     { | 
| 176       let page = new Page({id: tabId, url}); | 177       let page = new Page({id: tabId, url}); | 
| 177 | 178 | 
| 178       ext._removeFromAllPageMaps(tabId); | 179       ext._removeFromAllPageMaps(tabId); | 
| 179 | 180 | 
| 180       chrome.tabs.get(tabId, () => | 181       chrome.tabs.get(tabId, () => | 
| 181       { | 182       { | 
| 182         // If the tab is prerendered, chrome.tabs.get() sets | 183         // If the tab is prerendered, chrome.tabs.get() sets | 
| 183         // chrome.runtime.lastError and we have to dispatch the onLoading event, | 184         // chrome.runtime.lastError and we have to dispatch the onLoading event, | 
| 184         // since the onUpdated event isn't dispatched for prerendered tabs. | 185         // since the onUpdated event isn't dispatched for prerendered tabs. | 
| 185         // However, we have to keep relying on the unUpdated event for tabs that | 186         // However, we have to keep relying on the unUpdated event for tabs that | 
| 186         // are already visible. Otherwise browser action changes get overridden | 187         // are already visible. Otherwise browser action changes get overridden | 
| 187         // when Chrome automatically resets them on navigation. | 188         // when Chrome automatically resets them on navigation. | 
| 188         if (chrome.runtime.lastError) | 189         if (chrome.runtime.lastError) | 
| 189           ext.pages.onLoading._dispatch(page); | 190           ext.pages.onLoading._dispatch(page); | 
| 190       }); | 191       }); | 
| 191     } | 192     } | 
| 192 | 193 | 
| 193     // Update frame parent and URL in frame structure | 194     // Update frame URL and parent in frame structure | 
| 194     let frame = createFrame(tabId, frameId); | 195     let frame = createFrame(tabId, frameId); | 
| 195     frame.url = new URL(url); | 196     frame.url = new URL(url); | 
| 196     frame.parent = framesOfTabs[tabId][parentFrameId] || null; | 197 | 
|  | 198     let parentFrame = framesOfTabs.get(tabId).get(parentFrameId); | 
|  | 199     if (parentFrame) | 
|  | 200       frame.parent = parentFrame; | 
| 197   } | 201   } | 
| 198 | 202 | 
| 199   chrome.webRequest.onHeadersReceived.addListener(details => | 203   chrome.webRequest.onHeadersReceived.addListener(details => | 
| 200   { | 204   { | 
| 201     // We have to update the frame structure when switching to a new | 205     // We have to update the frame structure when switching to a new | 
| 202     // document, so that we process any further requests made by that | 206     // document, so that we process any further requests made by that | 
| 203     // document in the right context. Unfortunately, we cannot rely | 207     // document in the right context. Unfortunately, we cannot rely | 
| 204     // on webNavigation.onCommitted since it isn't guaranteed to fire | 208     // on webNavigation.onCommitted since it isn't guaranteed to fire | 
| 205     // before any subresources start downloading[1]. As an | 209     // before any subresources start downloading[1]. As an | 
| 206     // alternative we use webRequest.onHeadersReceived for HTTP(S) | 210     // alternative we use webRequest.onHeadersReceived for HTTP(S) | 
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 285       updatePageFrameStructure(details.frameId, details.tabId, details.url, | 289       updatePageFrameStructure(details.frameId, details.tabId, details.url, | 
| 286                                details.parentFrameId); | 290                                details.parentFrameId); | 
| 287     } | 291     } | 
| 288   }); | 292   }); | 
| 289 | 293 | 
| 290   function forgetTab(tabId) | 294   function forgetTab(tabId) | 
| 291   { | 295   { | 
| 292     ext.pages.onRemoved._dispatch(tabId); | 296     ext.pages.onRemoved._dispatch(tabId); | 
| 293 | 297 | 
| 294     ext._removeFromAllPageMaps(tabId); | 298     ext._removeFromAllPageMaps(tabId); | 
| 295     delete framesOfTabs[tabId]; | 299     framesOfTabs.delete(tabId); | 
| 296   } | 300   } | 
| 297 | 301 | 
| 298   chrome.tabs.onReplaced.addListener((addedTabId, removedTabId) => | 302   chrome.tabs.onReplaced.addListener((addedTabId, removedTabId) => | 
| 299   { | 303   { | 
| 300     forgetTab(removedTabId); | 304     forgetTab(removedTabId); | 
| 301   }); | 305   }); | 
| 302 | 306 | 
| 303   chrome.tabs.onRemoved.addListener(forgetTab); | 307   chrome.tabs.onRemoved.addListener(forgetTab); | 
| 304 | 308 | 
| 305   chrome.tabs.onActivated.addListener(details => | 309   chrome.tabs.onActivated.addListener(details => | 
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 483 | 487 | 
| 484   chrome.windows.onFocusChanged.addListener(windowId => | 488   chrome.windows.onFocusChanged.addListener(windowId => | 
| 485   { | 489   { | 
| 486     if (windowId != chrome.windows.WINDOW_ID_NONE) | 490     if (windowId != chrome.windows.WINDOW_ID_NONE) | 
| 487       updateContextMenu(); | 491       updateContextMenu(); | 
| 488   }); | 492   }); | 
| 489 | 493 | 
| 490 | 494 | 
| 491   /* Web requests */ | 495   /* Web requests */ | 
| 492 | 496 | 
| 493   let framesOfTabs = Object.create(null); | 497   let framesOfTabs = new Map(); | 
| 494 | 498 | 
| 495   ext.getFrame = (tabId, frameId) => | 499   ext.getFrame = (tabId, frameId) => | 
| 496   { | 500   { | 
| 497     return (framesOfTabs[tabId] || {})[frameId]; | 501     let frames = framesOfTabs.get(tabId); | 
|  | 502     return frames && frames.get(frameId); | 
| 498   }; | 503   }; | 
| 499 | 504 | 
| 500   let handlerBehaviorChangedQuota = | 505   let handlerBehaviorChangedQuota = | 
| 501     chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES; | 506     chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES; | 
| 502 | 507 | 
| 503   function propagateHandlerBehaviorChange() | 508   function propagateHandlerBehaviorChange() | 
| 504   { | 509   { | 
| 505     // Make sure to not call handlerBehaviorChanged() more often than allowed | 510     // Make sure to not call handlerBehaviorChanged() more often than allowed | 
| 506     // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES. | 511     // by chrome.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES. | 
| 507     // Otherwise Chrome notifies the user that this extension is causing issues. | 512     // Otherwise Chrome notifies the user that this extension is causing issues. | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
| 532   }; | 537   }; | 
| 533 | 538 | 
| 534   chrome.tabs.query({}, tabs => | 539   chrome.tabs.query({}, tabs => | 
| 535   { | 540   { | 
| 536     tabs.forEach(tab => | 541     tabs.forEach(tab => | 
| 537     { | 542     { | 
| 538       chrome.webNavigation.getAllFrames({tabId: tab.id}, details => | 543       chrome.webNavigation.getAllFrames({tabId: tab.id}, details => | 
| 539       { | 544       { | 
| 540         if (details && details.length > 0) | 545         if (details && details.length > 0) | 
| 541         { | 546         { | 
| 542           let frames = framesOfTabs[tab.id] = Object.create(null); | 547           let frames = new Map(); | 
|  | 548           framesOfTabs.set(tab.id, frames); | 
| 543 | 549 | 
| 544           for (let i = 0; i < details.length; i++) | 550           for (let detail of details) | 
|  | 551             frames.set(detail.frameId, {url: new URL(detail.url)}); | 
|  | 552 | 
|  | 553           for (let detail of details) | 
| 545           { | 554           { | 
| 546             frames[details[i].frameId] = { | 555             let {parentFrameId} = detail; | 
| 547               url: new URL(details[i].url), |  | 
| 548               parent: null |  | 
| 549             }; |  | 
| 550           } |  | 
| 551 |  | 
| 552           for (let i = 0; i < details.length; i++) |  | 
| 553           { |  | 
| 554             let {parentFrameId} = details[i]; |  | 
| 555 | 556 | 
| 556             if (parentFrameId != -1) | 557             if (parentFrameId != -1) | 
| 557               frames[details[i].frameId].parent = frames[parentFrameId]; | 558               frames.get(detail.frameId).parent = frames.get(parentFrameId); | 
| 558           } | 559           } | 
| 559         } | 560         } | 
| 560       }); | 561       }); | 
| 561     }); | 562     }); | 
| 562   }); | 563   }); | 
| 563 | 564 | 
| 564   chrome.webRequest.onBeforeRequest.addListener(details => | 565   chrome.webRequest.onBeforeRequest.addListener(details => | 
| 565   { | 566   { | 
| 566     // The high-level code isn't interested in requests that aren't | 567     // The high-level code isn't interested in requests that aren't | 
| 567     // related to a tab or requests loading a top-level document, | 568     // related to a tab or requests loading a top-level document, | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 604 | 605 | 
| 605     // Add "page" and "frame" if the message was sent by a content script. | 606     // Add "page" and "frame" if the message was sent by a content script. | 
| 606     // If sent by popup or the background page itself, there is no "tab". | 607     // If sent by popup or the background page itself, there is no "tab". | 
| 607     if ("tab" in rawSender) | 608     if ("tab" in rawSender) | 
| 608     { | 609     { | 
| 609       sender.page = new Page(rawSender.tab); | 610       sender.page = new Page(rawSender.tab); | 
| 610       sender.frame = { | 611       sender.frame = { | 
| 611         url: new URL(rawSender.url), | 612         url: new URL(rawSender.url), | 
| 612         get parent() | 613         get parent() | 
| 613         { | 614         { | 
| 614           let frames = framesOfTabs[rawSender.tab.id]; | 615           let frames = framesOfTabs.get(rawSender.tab.id); | 
| 615 | 616 | 
| 616           if (!frames) | 617           if (!frames) | 
| 617             return null; | 618             return null; | 
| 618 | 619 | 
| 619           let frame = frames[rawSender.frameId]; | 620           let frame = frames.get(rawSender.frameId); | 
| 620           if (frame) | 621           if (frame) | 
| 621             return frame.parent; | 622             return frame.parent || null; | 
| 622 | 623 | 
| 623           return frames[0]; | 624           return frames.get(0) || null; | 
| 624         } | 625         } | 
| 625       }; | 626       }; | 
| 626     } | 627     } | 
| 627 | 628 | 
| 628     return ext.onMessage._dispatch( | 629     return ext.onMessage._dispatch( | 
| 629       message, sender, sendResponse | 630       message, sender, sendResponse | 
| 630     ).indexOf(true) != -1; | 631     ).indexOf(true) != -1; | 
| 631   }); | 632   }); | 
| 632 | 633 | 
| 633 | 634 | 
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 724   ext.windows = { | 725   ext.windows = { | 
| 725     create(createData, callback) | 726     create(createData, callback) | 
| 726     { | 727     { | 
| 727       chrome.windows.create(createData, createdWindow => | 728       chrome.windows.create(createData, createdWindow => | 
| 728       { | 729       { | 
| 729         afterTabLoaded(callback)(createdWindow.tabs[0]); | 730         afterTabLoaded(callback)(createdWindow.tabs[0]); | 
| 730       }); | 731       }); | 
| 731     } | 732     } | 
| 732   }; | 733   }; | 
| 733 }()); | 734 }()); | 
| OLD | NEW | 
|---|