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