Index: lib/devtools.js |
diff --git a/lib/devtools.js b/lib/devtools.js |
index 167a7650e990cb3819b50d719a3e25501caf9e5f..04e2d58346d889c70e2d2baf45010190a44dbb71 100644 |
--- a/lib/devtools.js |
+++ b/lib/devtools.js |
@@ -17,322 +17,8 @@ |
"use strict"; |
-const {RegExpFilter, |
- WhitelistFilter, |
- ElemHideFilter} = require("filterClasses"); |
-const {SpecialSubscription} = require("subscriptionClasses"); |
-const {FilterStorage} = require("filterStorage"); |
-const {defaultMatcher} = require("matcher"); |
-const {FilterNotifier} = require("filterNotifier"); |
-const {extractHostFromFrame} = require("url"); |
const {port} = require("messaging"); |
- |
-const nonRequestTypes = ["DOCUMENT", "ELEMHIDE", "GENERICBLOCK", "GENERICHIDE"]; |
- |
-// Mapping of inspected tabs to their devpanel page |
-// and recorded items. We can't use a PageMap here, |
-// because data must persist after navigation/reload. |
-let panels = new Map(); |
- |
-function isActivePanel(panel) |
-{ |
- return panel && !panel.reload && !panel.reloading; |
-} |
- |
-function getActivePanel(page) |
-{ |
- let panel = panels.get(page.id); |
- if (isActivePanel(panel)) |
- return panel; |
- return null; |
-} |
- |
-function getFilterInfo(filter) |
-{ |
- if (!filter) |
- return null; |
- |
- let userDefined = false; |
- let subscriptionTitle = null; |
- |
- for (let subscription of filter.subscriptions) |
- { |
- if (!subscription.disabled) |
- { |
- if (subscription instanceof SpecialSubscription) |
- userDefined = true; |
- else |
- subscriptionTitle = subscription.title; |
- } |
- } |
- |
- return { |
- text: filter.text, |
- whitelisted: filter instanceof WhitelistFilter, |
- userDefined, |
- subscription: subscriptionTitle |
- }; |
-} |
- |
-function hasRecord(panel, request, filter) |
-{ |
- return panel.records.some(record => |
- record.request.url == request.url && |
- record.request.docDomain == request.docDomain && |
- |
- // Ignore partial (e.g. ELEMHIDE) whitelisting if there is already |
- // a DOCUMENT exception which disables all means of blocking. |
- (record.request.type == "DOCUMENT" ? |
- nonRequestTypes.includes(request.type) : |
- record.request.type == request.type) && |
- |
- // Matched element hiding filters don't relate to a particular request, |
- // so we have to compare the selector in order to avoid duplicates. |
- (record.filter && record.filter.selector) == (filter && filter.selector) |
- ); |
-} |
- |
-function addRecord(panel, request, filter) |
-{ |
- if (!hasRecord(panel, request, filter)) |
- { |
- panel.port.postMessage({ |
- type: "add-record", |
- request, |
- filter: getFilterInfo(filter) |
- }); |
- |
- panel.records.push({request, filter}); |
- } |
-} |
- |
-function matchRequest(request) |
-{ |
- return defaultMatcher.matchesAny( |
- request.url, |
- RegExpFilter.typeMap[request.type], |
- request.docDomain, |
- request.thirdParty, |
- request.sitekey, |
- request.specificOnly |
- ); |
-} |
- |
-/** |
- * Logs a request to the devtools panel. |
- * |
- * @param {?Page} page The page the request occured on or null if |
- * the request isn't associated with a page |
- * @param {string} url The URL of the request |
- * @param {string} type The request type |
- * @param {string} docDomain The IDN-decoded hostname of the document |
- * @param {boolean} thirdParty Whether the origin of the request and |
- * document differs |
- * @param {?string} sitekey The active sitekey if there is any |
- * @param {?boolean} specificOnly Whether generic filters should be ignored |
- * @param {?BlockingFilter} filter The matched filter or null if there is no |
- * match |
- */ |
-exports.logRequest = function(page, url, type, docDomain, |
- thirdParty, sitekey, |
- specificOnly, filter) |
-{ |
- if (panels.size == 0) |
- return; |
- |
- let request = {url, type, docDomain, thirdParty, sitekey, specificOnly}; |
- for (let [tabId, panel] of panels) |
- if ((!page || page.id == tabId) && isActivePanel(panel)) |
- addRecord(panel, request, filter); |
-}; |
- |
-/** |
- * Logs active element hiding filters to the devtools panel. |
- * |
- * @param {Page} page The page the elements were hidden on |
- * @param {string[]} selectors The selectors of applied ElemHideFilters |
- * @param {string[]} filters The text of applied ElemHideEmulationFilters |
- * @param {string} docDomain The IDN-decoded hostname of the document |
- */ |
-function logHiddenElements(page, selectors, filters, docDomain) |
-{ |
- let panel = getActivePanel(page); |
- if (panel) |
- { |
- for (let subscription of FilterStorage.subscriptions) |
- { |
- if (subscription.disabled) |
- continue; |
- |
- for (let filter of subscription.filters) |
- { |
- // We only know the exact filter in case of element hiding emulation. |
- // For regular element hiding filters, the content script only knows |
- // the selector, so we have to find a filter that has an identical |
- // selector and is active on the domain the match was reported from. |
- let isActiveElemHideFilter = filter instanceof ElemHideFilter && |
- selectors.includes(filter.selector) && |
- filter.isActiveOnDomain(docDomain); |
- |
- if (isActiveElemHideFilter || filters.includes(filter.text)) |
- addRecord(panel, {type: "ELEMHIDE", docDomain}, filter); |
- } |
- } |
- } |
-} |
- |
-/** |
- * Logs a whitelisting filter, that disables (some kind of) |
- * blocking for a particular document, to the devtools panel. |
- * |
- * @param {Page} page The page the whitelisting is active on |
- * @param {string} url The url of the whitelisted document |
- * @param {number} typeMask The bit mask of whitelisting types checked |
- * for |
- * @param {string} docDomain The IDN-decoded hostname of the parent |
- * document |
- * @param {WhitelistFilter} filter The matched whitelisting filter |
- */ |
-exports.logWhitelistedDocument = function(page, url, typeMask, docDomain, |
- filter) |
-{ |
- let panel = getActivePanel(page); |
- if (panel) |
- { |
- for (let type of nonRequestTypes) |
- { |
- if (typeMask & filter.contentType & RegExpFilter.typeMap[type]) |
- addRecord(panel, {url, type, docDomain}, filter); |
- } |
- } |
-}; |
- |
-/** |
- * Checks whether a page is inspected by the devtools panel. |
- * |
- * @param {Page} page |
- * @return {boolean} |
- */ |
-exports.hasPanel = function(page) |
-{ |
- return panels.has(page.id); |
-}; |
- |
-function onBeforeRequest(details) |
-{ |
- let panel = panels.get(details.tabId); |
- |
- // Clear the devtools panel and reload the inspected tab without caching |
- // when a new request is issued. However, make sure that we don't end up |
- // in an infinite recursion if we already triggered a reload. |
- if (panel.reloading) |
- { |
- panel.reloading = false; |
- } |
- else |
- { |
- panel.records = []; |
- panel.port.postMessage({type: "reset"}); |
- |
- // We can't repeat the request if it isn't a GET request. Chrome would |
- // prompt the user to confirm reloading the page, and POST requests are |
- // known to cause issues on many websites if repeated. |
- if (details.method == "GET") |
- panel.reload = true; |
- } |
-} |
- |
-function onLoading(page) |
-{ |
- let tabId = page.id; |
- let panel = panels.get(tabId); |
- |
- // Reloading the tab is the only way that allows bypassing all caches, in |
- // order to see all requests in the devtools panel. Reloading must not be |
- // performed before the tab changes to "loading", otherwise it will load the |
- // previous URL. |
- if (panel && panel.reload) |
- { |
- browser.tabs.reload(tabId, {bypassCache: true}); |
- |
- panel.reload = false; |
- panel.reloading = true; |
- } |
-} |
- |
-function updateFilters(filters, added) |
-{ |
- for (let panel of panels.values()) |
- { |
- for (let i = 0; i < panel.records.length; i++) |
- { |
- let record = panel.records[i]; |
- |
- // If an added filter matches a request shown in the devtools panel, |
- // update that record to show the new filter. Ignore filters that aren't |
- // associated with any sub-resource request. There is no record for these |
- // if they don't already match. In particular, in case of element hiding |
- // filters, we also wouldn't know if any new element matches. |
- if (added) |
- { |
- if (nonRequestTypes.includes(record.request.type)) |
- continue; |
- |
- let filter = matchRequest(record.request); |
- if (!filters.includes(filter)) |
- continue; |
- |
- record.filter = filter; |
- } |
- |
- // If a filter shown in the devtools panel got removed, update that |
- // record to show the filter that matches now, or none, instead. |
- // For filters that aren't associated with any sub-resource request, |
- // just remove the record. We wouldn't know whether another filter |
- // matches instead until the page is reloaded. |
- else |
- { |
- if (!filters.includes(record.filter)) |
- continue; |
- |
- if (nonRequestTypes.includes(record.request.type)) |
- { |
- panel.port.postMessage({ |
- type: "remove-record", |
- index: i |
- }); |
- panel.records.splice(i--, 1); |
- continue; |
- } |
- |
- record.filter = matchRequest(record.request); |
- } |
- |
- panel.port.postMessage({ |
- type: "update-record", |
- index: i, |
- request: record.request, |
- filter: getFilterInfo(record.filter) |
- }); |
- } |
- } |
-} |
- |
-function onFilterAdded(filter) |
-{ |
- updateFilters([filter], true); |
-} |
- |
-function onFilterRemoved(filter) |
-{ |
- updateFilters([filter], false); |
-} |
- |
-function onSubscriptionAdded(subscription) |
-{ |
- if (subscription instanceof SpecialSubscription) |
- updateFilters(subscription.filters, true); |
-} |
+const {DevLogger} = require("devLogger"); |
browser.runtime.onConnect.addListener(newPort => |
{ |
@@ -341,46 +27,11 @@ browser.runtime.onConnect.addListener(newPort => |
return; |
let inspectedTabId = parseInt(match[1], 10); |
- let localOnBeforeRequest = onBeforeRequest.bind(); |
- |
- browser.webRequest.onBeforeRequest.addListener( |
- localOnBeforeRequest, |
- { |
- urls: ["http://*/*", "https://*/*"], |
- types: ["main_frame"], |
- tabId: inspectedTabId |
- } |
- ); |
- |
- if (panels.size == 0) |
- { |
- ext.pages.onLoading.addListener(onLoading); |
- FilterNotifier.on("filter.added", onFilterAdded); |
- FilterNotifier.on("filter.removed", onFilterRemoved); |
- FilterNotifier.on("subscription.added", onSubscriptionAdded); |
- } |
+ let onDevLogger = newPort.postMessage.bind(newPort); |
+ DevLogger.on(inspectedTabId, onDevLogger); |
newPort.onDisconnect.addListener(() => |
{ |
- panels.delete(inspectedTabId); |
- browser.webRequest.onBeforeRequest.removeListener(localOnBeforeRequest); |
- |
- if (panels.size == 0) |
- { |
- ext.pages.onLoading.removeListener(onLoading); |
- FilterNotifier.off("filter.added", onFilterAdded); |
- FilterNotifier.off("filter.removed", onFilterRemoved); |
- FilterNotifier.off("subscription.added", onSubscriptionAdded); |
- } |
+ DevLogger.off(inspectedTabId, onDevLogger); |
}); |
- |
- panels.set(inspectedTabId, {port: newPort, records: []}); |
-}); |
- |
-port.on("devtools.traceElemHide", (message, sender) => |
-{ |
- logHiddenElements( |
- sender.page, message.selectors, message.filters, |
- extractHostFromFrame(sender.frame) |
- ); |
}); |