| 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-present eyeo GmbH | 3  * Copyright (C) 2006-present 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 const {RegExpFilter, | 20 const {RegExpFilter, | 
| 21        WhitelistFilter, | 21        WhitelistFilter} = require("filterClasses"); | 
| 22        ElemHideFilter} = require("filterClasses"); |  | 
| 23 const {SpecialSubscription} = require("subscriptionClasses"); | 22 const {SpecialSubscription} = require("subscriptionClasses"); | 
| 24 const {FilterStorage} = require("filterStorage"); |  | 
| 25 const {defaultMatcher} = require("matcher"); | 23 const {defaultMatcher} = require("matcher"); | 
| 26 const {FilterNotifier} = require("filterNotifier"); | 24 const {FilterNotifier} = require("filterNotifier"); | 
| 27 const {extractHostFromFrame} = require("url"); | 25 const {extractHostFromFrame} = require("url"); | 
| 28 const {port} = require("messaging"); | 26 const {port} = require("messaging"); | 
|  | 27 const {HitLogger} = require("hitLogger"); | 
| 29 | 28 | 
| 30 const nonRequestTypes = ["DOCUMENT", "ELEMHIDE", "GENERICBLOCK", "GENERICHIDE"]; | 29 const nonRequestTypes = ["DOCUMENT", "ELEMHIDE", "GENERICBLOCK", "GENERICHIDE"]; | 
| 31 | 30 | 
| 32 // Mapping of inspected tabs to their devpanel page | 31 // Mapping of inspected tabs to their devpanel page | 
| 33 // and recorded items. We can't use a PageMap here, | 32 // and recorded items. We can't use a PageMap here, | 
| 34 // because data must persist after navigation/reload. | 33 // because data must persist after navigation/reload. | 
| 35 let panels = new Map(); | 34 let panels = new Map(); | 
| 36 | 35 | 
| 37 function isActivePanel(panel) | 36 function isActivePanel(panel) | 
| 38 { | 37 { | 
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 87        record.request.type == request.type) && | 86        record.request.type == request.type) && | 
| 88 | 87 | 
| 89     // Matched element hiding filters don't relate to a particular request, | 88     // Matched element hiding filters don't relate to a particular request, | 
| 90     // so we have to compare the selector in order to avoid duplicates. | 89     // so we have to compare the selector in order to avoid duplicates. | 
| 91     (record.filter && record.filter.selector) == (filter && filter.selector) | 90     (record.filter && record.filter.selector) == (filter && filter.selector) | 
| 92   ); | 91   ); | 
| 93 } | 92 } | 
| 94 | 93 | 
| 95 function addRecord(panel, request, filter) | 94 function addRecord(panel, request, filter) | 
| 96 { | 95 { | 
| 97   if (!hasRecord(panel, request, filter)) | 96   if (isActivePanel(panel) && !hasRecord(panel, request, filter)) | 
| 98   { | 97   { | 
| 99     panel.port.postMessage({ | 98     panel.port.postMessage({ | 
| 100       type: "add-record", | 99       type: "add-record", | 
| 101       request, | 100       request, | 
| 102       filter: getFilterInfo(filter) | 101       filter: getFilterInfo(filter) | 
| 103     }); | 102     }); | 
| 104 | 103 | 
| 105     panel.records.push({request, filter}); | 104     panel.records.push({request, filter}); | 
| 106   } | 105   } | 
| 107 } | 106 } | 
| 108 | 107 | 
| 109 function matchRequest(request) | 108 function matchRequest(request) | 
| 110 { | 109 { | 
| 111   return defaultMatcher.matchesAny( | 110   return defaultMatcher.matchesAny( | 
| 112     request.url, | 111     request.url, | 
| 113     RegExpFilter.typeMap[request.type], | 112     RegExpFilter.typeMap[request.type], | 
| 114     request.docDomain, | 113     request.docDomain, | 
| 115     request.thirdParty, | 114     request.thirdParty, | 
| 116     request.sitekey, | 115     request.sitekey, | 
| 117     request.specificOnly | 116     request.specificOnly | 
| 118   ); | 117   ); | 
| 119 } | 118 } | 
| 120 | 119 | 
| 121 /** |  | 
| 122  * Logs a request to the devtools panel. |  | 
| 123  * |  | 
| 124  * @param {?Page}    page          The page the request occured on or null if |  | 
| 125  *                                 the request isn't associated with a page |  | 
| 126  * @param {string}   url           The URL of the request |  | 
| 127  * @param {string}   type          The request type |  | 
| 128  * @param {string}   docDomain     The IDN-decoded hostname of the document |  | 
| 129  * @param {boolean}  thirdParty    Whether the origin of the request and |  | 
| 130  *                                 document differs |  | 
| 131  * @param {?string}  sitekey       The active sitekey if there is any |  | 
| 132  * @param {?boolean} specificOnly  Whether generic filters should be ignored |  | 
| 133  * @param {?BlockingFilter} filter The matched filter or null if there is no |  | 
| 134  *                                 match |  | 
| 135  */ |  | 
| 136 exports.logRequest = function(page, url, type, docDomain, |  | 
| 137                               thirdParty, sitekey, |  | 
| 138                               specificOnly, filter) |  | 
| 139 { |  | 
| 140   if (panels.size == 0) |  | 
| 141     return; |  | 
| 142 |  | 
| 143   let request = {url, type, docDomain, thirdParty, sitekey, specificOnly}; |  | 
| 144   for (let [tabId, panel] of panels) |  | 
| 145     if ((!page || page.id == tabId) && isActivePanel(panel)) |  | 
| 146       addRecord(panel, request, filter); |  | 
| 147 }; |  | 
| 148 |  | 
| 149 /** |  | 
| 150  * Logs active element hiding filters to the devtools panel. |  | 
| 151  * |  | 
| 152  * @param {Page}     page       The page the elements were hidden on |  | 
| 153  * @param {string[]} selectors  The selectors of applied ElemHideFilters |  | 
| 154  * @param {string[]} filters    The text of applied ElemHideEmulationFilters |  | 
| 155  * @param {string}   docDomain  The IDN-decoded hostname of the document |  | 
| 156  */ |  | 
| 157 function logHiddenElements(page, selectors, filters, docDomain) |  | 
| 158 { |  | 
| 159   let panel = getActivePanel(page); |  | 
| 160   if (panel) |  | 
| 161   { |  | 
| 162     for (let subscription of FilterStorage.subscriptions) |  | 
| 163     { |  | 
| 164       if (subscription.disabled) |  | 
| 165         continue; |  | 
| 166 |  | 
| 167       for (let filter of subscription.filters) |  | 
| 168       { |  | 
| 169         // We only know the exact filter in case of element hiding emulation. |  | 
| 170         // For regular element hiding filters, the content script only knows |  | 
| 171         // the selector, so we have to find a filter that has an identical |  | 
| 172         // selector and is active on the domain the match was reported from. |  | 
| 173         let isActiveElemHideFilter = filter instanceof ElemHideFilter && |  | 
| 174                                      selectors.includes(filter.selector) && |  | 
| 175                                      filter.isActiveOnDomain(docDomain); |  | 
| 176 |  | 
| 177         if (isActiveElemHideFilter || filters.includes(filter.text)) |  | 
| 178           addRecord(panel, {type: "ELEMHIDE", docDomain}, filter); |  | 
| 179       } |  | 
| 180     } |  | 
| 181   } |  | 
| 182 } |  | 
| 183 |  | 
| 184 /** |  | 
| 185  * Logs a whitelisting filter, that disables (some kind of) |  | 
| 186  * blocking for a particular document, to the devtools panel. |  | 
| 187  * |  | 
| 188  * @param {Page}         page      The page the whitelisting is active on |  | 
| 189  * @param {string}       url       The url of the whitelisted document |  | 
| 190  * @param {number}       typeMask  The bit mask of whitelisting types checked |  | 
| 191  *                                 for |  | 
| 192  * @param {string}       docDomain The IDN-decoded hostname of the parent |  | 
| 193  *                                 document |  | 
| 194  * @param {WhitelistFilter} filter The matched whitelisting filter |  | 
| 195  */ |  | 
| 196 exports.logWhitelistedDocument = function(page, url, typeMask, docDomain, |  | 
| 197                                           filter) |  | 
| 198 { |  | 
| 199   let panel = getActivePanel(page); |  | 
| 200   if (panel) |  | 
| 201   { |  | 
| 202     for (let type of nonRequestTypes) |  | 
| 203     { |  | 
| 204       if (typeMask & filter.contentType & RegExpFilter.typeMap[type]) |  | 
| 205         addRecord(panel, {url, type, docDomain}, filter); |  | 
| 206     } |  | 
| 207   } |  | 
| 208 }; |  | 
| 209 |  | 
| 210 /** |  | 
| 211  * Checks whether a page is inspected by the devtools panel. |  | 
| 212  * |  | 
| 213  * @param {Page} page |  | 
| 214  * @return {boolean} |  | 
| 215  */ |  | 
| 216 exports.hasPanel = function(page) |  | 
| 217 { |  | 
| 218   return panels.has(page.id); |  | 
| 219 }; |  | 
| 220 |  | 
| 221 function onBeforeRequest(details) | 120 function onBeforeRequest(details) | 
| 222 { | 121 { | 
| 223   let panel = panels.get(details.tabId); | 122   let panel = panels.get(details.tabId); | 
| 224 | 123 | 
| 225   // Clear the devtools panel and reload the inspected tab without caching | 124   // Clear the devtools panel and reload the inspected tab without caching | 
| 226   // when a new request is issued. However, make sure that we don't end up | 125   // when a new request is issued. However, make sure that we don't end up | 
| 227   // in an infinite recursion if we already triggered a reload. | 126   // in an infinite recursion if we already triggered a reload. | 
| 228   if (panel.reloading) | 127   if (panel.reloading) | 
| 229   { | 128   { | 
| 230     panel.reloading = false; | 129     panel.reloading = false; | 
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 335 } | 234 } | 
| 336 | 235 | 
| 337 browser.runtime.onConnect.addListener(newPort => | 236 browser.runtime.onConnect.addListener(newPort => | 
| 338 { | 237 { | 
| 339   let match = newPort.name.match(/^devtools-(\d+)$/); | 238   let match = newPort.name.match(/^devtools-(\d+)$/); | 
| 340   if (!match) | 239   if (!match) | 
| 341     return; | 240     return; | 
| 342 | 241 | 
| 343   let inspectedTabId = parseInt(match[1], 10); | 242   let inspectedTabId = parseInt(match[1], 10); | 
| 344   let localOnBeforeRequest = onBeforeRequest.bind(); | 243   let localOnBeforeRequest = onBeforeRequest.bind(); | 
|  | 244   let panel = {port: newPort, records: []}; | 
| 345 | 245 | 
| 346   browser.webRequest.onBeforeRequest.addListener( | 246   browser.webRequest.onBeforeRequest.addListener( | 
| 347     localOnBeforeRequest, | 247     localOnBeforeRequest, | 
| 348     { | 248     { | 
| 349       urls: ["http://*/*", "https://*/*"], | 249       urls: ["http://*/*", "https://*/*"], | 
| 350       types: ["main_frame"], | 250       types: ["main_frame"], | 
| 351       tabId: inspectedTabId | 251       tabId: inspectedTabId | 
| 352     } | 252     } | 
| 353   ); | 253   ); | 
| 354 | 254 | 
| 355   if (panels.size == 0) | 255   if (panels.size == 0) | 
| 356   { | 256   { | 
| 357     ext.pages.onLoading.addListener(onLoading); | 257     ext.pages.onLoading.addListener(onLoading); | 
| 358     FilterNotifier.on("filter.added", onFilterAdded); | 258     FilterNotifier.on("filter.added", onFilterAdded); | 
| 359     FilterNotifier.on("filter.removed", onFilterRemoved); | 259     FilterNotifier.on("filter.removed", onFilterRemoved); | 
| 360     FilterNotifier.on("subscription.added", onSubscriptionAdded); | 260     FilterNotifier.on("subscription.added", onSubscriptionAdded); | 
| 361   } | 261   } | 
| 362 | 262 | 
|  | 263   let hitListener = addRecord.bind(null, panel); | 
|  | 264 | 
| 363   newPort.onDisconnect.addListener(() => | 265   newPort.onDisconnect.addListener(() => | 
| 364   { | 266   { | 
|  | 267     HitLogger.off(inspectedTabId, hitListener); | 
| 365     panels.delete(inspectedTabId); | 268     panels.delete(inspectedTabId); | 
| 366     browser.webRequest.onBeforeRequest.removeListener(localOnBeforeRequest); | 269     browser.webRequest.onBeforeRequest.removeListener(localOnBeforeRequest); | 
| 367 | 270 | 
| 368     if (panels.size == 0) | 271     if (panels.size == 0) | 
| 369     { | 272     { | 
| 370       ext.pages.onLoading.removeListener(onLoading); | 273       ext.pages.onLoading.removeListener(onLoading); | 
| 371       FilterNotifier.off("filter.added", onFilterAdded); | 274       FilterNotifier.off("filter.added", onFilterAdded); | 
| 372       FilterNotifier.off("filter.removed", onFilterRemoved); | 275       FilterNotifier.off("filter.removed", onFilterRemoved); | 
| 373       FilterNotifier.off("subscription.added", onSubscriptionAdded); | 276       FilterNotifier.off("subscription.added", onSubscriptionAdded); | 
| 374     } | 277     } | 
| 375   }); | 278   }); | 
| 376 | 279 | 
| 377   panels.set(inspectedTabId, {port: newPort, records: []}); | 280   HitLogger.on(inspectedTabId, hitListener); | 
|  | 281   panels.set(inspectedTabId, panel); | 
| 378 }); | 282 }); | 
| 379 |  | 
| 380 port.on("devtools.traceElemHide", (message, sender) => |  | 
| 381 { |  | 
| 382   logHiddenElements( |  | 
| 383     sender.page, message.selectors, message.filters, |  | 
| 384     extractHostFromFrame(sender.frame) |  | 
| 385   ); |  | 
| 386 }); |  | 
| OLD | NEW | 
|---|