|
|
@ -25,27 +25,34 @@ |
|
|
|
|
|
|
|
// Create a new page url stats store (if not already present)
|
|
|
|
|
|
|
|
µMatrix.createPageStats = function(pageUrl) { |
|
|
|
µMatrix.createPageStore = function(pageURL) { |
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/303
|
|
|
|
// At this point, the URL has been page-URL-normalized
|
|
|
|
|
|
|
|
// do not create stats store for urls which are of no interest
|
|
|
|
if ( pageUrl.search(/^https?:\/\//) !== 0 ) { |
|
|
|
return undefined; |
|
|
|
if ( pageURL.search(/^https?/) !== 0 ) { |
|
|
|
return; |
|
|
|
} |
|
|
|
var pageStats = this.pageStats[pageUrl]; |
|
|
|
if ( !pageStats ) { |
|
|
|
pageStats = this.PageStore.factory(pageUrl); |
|
|
|
var pageStore = null; |
|
|
|
if ( this.pageStats.hasOwnProperty(pageURL) ) { |
|
|
|
pageStore = this.pageStats[pageURL]; |
|
|
|
} |
|
|
|
if ( pageStore === null ) { |
|
|
|
pageStore = this.PageStore.factory(pageURL); |
|
|
|
// These counters are used so that icon presents an overview of how
|
|
|
|
// much allowed/blocked.
|
|
|
|
pageStats.perLoadAllowedRequestCount = |
|
|
|
pageStats.perLoadBlockedRequestCount = 0; |
|
|
|
this.pageStats[pageUrl] = pageStats; |
|
|
|
} else if ( pageStats.pageUrl !== pageUrl ) { |
|
|
|
pageStats.init(pageUrl); |
|
|
|
pageStore.perLoadAllowedRequestCount = |
|
|
|
pageStore.perLoadBlockedRequestCount = 0; |
|
|
|
this.pageStats[pageURL] = pageStore; |
|
|
|
} |
|
|
|
|
|
|
|
return pageStats; |
|
|
|
// TODO: revisit code, need to account for those web pages for which the
|
|
|
|
// URL changes with the content only updated
|
|
|
|
if ( pageStore.pageUrl !== pageURL ) { |
|
|
|
pageStore.init(pageURL); |
|
|
|
} |
|
|
|
|
|
|
|
return pageStore; |
|
|
|
}; |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
@ -54,7 +61,7 @@ |
|
|
|
// Some kind of trick going on here:
|
|
|
|
// Any scheme other than 'http' and 'https' is remapped into a fake
|
|
|
|
// URL which trick the rest of µMatrix into being able to process an
|
|
|
|
// otherwise unmanageable scheme. µMatrix needs web page to have a proper
|
|
|
|
// otherwise unmanageable scheme. µMatrix needs web pages to have a proper
|
|
|
|
// hostname to work properly, so just like the 'chromium-behind-the-scene'
|
|
|
|
// fake domain name, we map unknown schemes into a fake '{scheme}-scheme'
|
|
|
|
// hostname. This way, for a specific scheme you can create scope with
|
|
|
@ -89,15 +96,19 @@ |
|
|
|
// Normalize to a page-URL.
|
|
|
|
pageURL = this.normalizePageURL(pageURL); |
|
|
|
|
|
|
|
var pageStats = this.createPageStats(pageURL); |
|
|
|
if ( this.tabIdToPageUrl[tabId] === pageURL ) { |
|
|
|
return this.pageStats[pageURL]; |
|
|
|
} |
|
|
|
|
|
|
|
var pageStore = this.createPageStore(pageURL); |
|
|
|
|
|
|
|
// console.debug('tab.js > µMatrix.bindTabToPageStats(): dispatching traffic in tab id %d to url stats store "%s"', tabId, pageUrl);
|
|
|
|
// console.debug('tab.js > bindTabToPageStats(): dispatching traffic in tab id %d to page store "%s"', tabId, pageUrl);
|
|
|
|
|
|
|
|
// rhill 2013-11-24: Never ever rebind chromium-behind-the-scene
|
|
|
|
// virtual tab.
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/67
|
|
|
|
if ( tabId === this.behindTheSceneTabId ) { |
|
|
|
return pageStats; |
|
|
|
return pageStore; |
|
|
|
} |
|
|
|
|
|
|
|
this.unbindTabFromPageStats(tabId); |
|
|
@ -105,23 +116,33 @@ |
|
|
|
// rhill 2014-02-08: Do not create an entry if no page store
|
|
|
|
// exists (like when visiting about:blank)
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/186
|
|
|
|
if ( !pageStats ) { |
|
|
|
if ( !pageStore ) { |
|
|
|
return null; |
|
|
|
} |
|
|
|
pageStats.visible = true; |
|
|
|
|
|
|
|
this.pageUrlToTabId[pageURL] = tabId; |
|
|
|
this.tabIdToPageUrl[tabId] = pageURL; |
|
|
|
pageStore.boundCount += 1; |
|
|
|
|
|
|
|
return pageStats; |
|
|
|
return pageStore; |
|
|
|
}; |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
|
|
|
|
|
µMatrix.unbindTabFromPageStats = function(tabId) { |
|
|
|
var pageUrl = this.tabIdToPageUrl[tabId]; |
|
|
|
if ( pageUrl ) { |
|
|
|
delete this.pageUrlToTabId[pageUrl]; |
|
|
|
if ( this.tabIdToPageUrl.hasOwnProperty(tabId) === false ) { |
|
|
|
return; |
|
|
|
} |
|
|
|
var pageURL = this.tabIdToPageUrl[tabId]; |
|
|
|
if ( this.pageStats.hasOwnProperty(pageURL) ) { |
|
|
|
var pageStore = this.pageStats[pageURL]; |
|
|
|
pageStore.boundCount -= 1; |
|
|
|
if ( pageStore.boundCount === 0 ) { |
|
|
|
pageStore.obsoleteAfter = Date.now() + (5 * 60 * 60 * 1000); |
|
|
|
} |
|
|
|
} |
|
|
|
delete this.tabIdToPageUrl[tabId]; |
|
|
|
delete this.pageUrlToTabId[pageURL]; |
|
|
|
}; |
|
|
|
|
|
|
|
/******************************************************************************/ |
|
|
@ -355,59 +376,43 @@ |
|
|
|
|
|
|
|
// Garbage collect stale url stats entries
|
|
|
|
(function() { |
|
|
|
var gcOrphanPageStats = function(tabs) { |
|
|
|
var µm = µMatrix; |
|
|
|
var visibleTabs = {}; |
|
|
|
tabs.map(function(tab) { |
|
|
|
visibleTabs[tab.id] = true; |
|
|
|
}); |
|
|
|
var pageUrls = Object.keys(µm.pageStats); |
|
|
|
var i = pageUrls.length; |
|
|
|
var pageUrl, tabId, pageStats; |
|
|
|
while ( i-- ) { |
|
|
|
pageUrl = pageUrls[i]; |
|
|
|
// Do not dispose of chromium-behind-the-scene virtual tab,
|
|
|
|
// GC is done differently on this one (i.e. just pruning).
|
|
|
|
if ( pageUrl === µm.behindTheSceneURL ) { |
|
|
|
var gcPageStats = function() { |
|
|
|
var pageStore; |
|
|
|
var now = Date.now(); |
|
|
|
for ( var pageURL in µm.pageStats ) { |
|
|
|
if ( µm.pageStats.hasOwnProperty(pageURL) === false ) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
tabId = µm.tabIdFromPageUrl(pageUrl); |
|
|
|
pageStats = µm.pageStats[pageUrl]; |
|
|
|
if ( !visibleTabs[tabId] && !pageStats.visible ) { |
|
|
|
// console.debug('HTTP Switchboard> tab.js: page stats garbage collector letting go of "%s"', pageUrl);
|
|
|
|
µm.cookieHunter.removePageCookies(pageStats); |
|
|
|
µm.pageStats[pageUrl].dispose(); |
|
|
|
delete µm.pageStats[pageUrl]; |
|
|
|
pageStore = µm.pageStats[pageURL]; |
|
|
|
if ( pageStore.boundCount !== 0 ) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
pageStats.visible = !!visibleTabs[tabId]; |
|
|
|
if ( !pageStats.visible ) { |
|
|
|
µm.unbindTabFromPageStats(tabId); |
|
|
|
if ( pageStore.obsoleteAfter > now ) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
µm.cookieHunter.removePageCookies(pageStore); |
|
|
|
µm.pageStats[pageURL].dispose(); |
|
|
|
delete µm.pageStats[pageURL]; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
var gcPageStats = function() { |
|
|
|
var µm = µMatrix; |
|
|
|
|
|
|
|
// Get rid of stale pageStats, those not bound to a tab for more than
|
|
|
|
// {duration placeholder}.
|
|
|
|
chrome.tabs.query({ 'url': '<all_urls>' }, gcOrphanPageStats); |
|
|
|
|
|
|
|
// Prune content of chromium-behind-the-scene virtual tab
|
|
|
|
// When `suggest-as-you-type` is on in Chromium, this can lead to a
|
|
|
|
// LOT of uninteresting behind the scene requests.
|
|
|
|
var pageStats = µm.pageStats[µm.behindTheSceneURL]; |
|
|
|
if ( pageStats ) { |
|
|
|
var reqKeys = pageStats.requests.getRequestKeys(); |
|
|
|
if ( reqKeys.length > µm.behindTheSceneMaxReq ) { |
|
|
|
pageStore = µm.pageStats[µm.behindTheSceneURL]; |
|
|
|
if ( !pageStore ) { |
|
|
|
return; |
|
|
|
} |
|
|
|
var reqKeys = pageStore.requests.getRequestKeys(); |
|
|
|
if ( reqKeys.length <= µm.behindTheSceneMaxReq ) { |
|
|
|
return; |
|
|
|
} |
|
|
|
reqKeys = reqKeys.sort(function(a,b){ |
|
|
|
return pageStats.requests[b] - pageStats.requests[a]; |
|
|
|
return pageStore.requests[b] - pageStore.requests[a]; |
|
|
|
}).slice(µm.behindTheSceneMaxReq); |
|
|
|
var iReqKey = reqKeys.length; |
|
|
|
while ( iReqKey-- ) { |
|
|
|
pageStats.requests.disposeOne(reqKeys[iReqKey]); |
|
|
|
} |
|
|
|
} |
|
|
|
pageStore.requests.disposeOne(reqKeys[iReqKey]); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
@ -417,7 +422,7 @@ |
|
|
|
'gcPageStats', |
|
|
|
null, |
|
|
|
gcPageStats, |
|
|
|
8 * 60 * 1000, |
|
|
|
5 * 60 * 1000, |
|
|
|
true |
|
|
|
); |
|
|
|
})(); |