|
|
|
@ -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 µm = µMatrix;
|
|
|
|
|
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 ) {
|
|
|
|
|
reqKeys = reqKeys.sort(function(a,b){
|
|
|
|
|
return pageStats.requests[b] - pageStats.requests[a];
|
|
|
|
|
}).slice(µm.behindTheSceneMaxReq);
|
|
|
|
|
var iReqKey = reqKeys.length;
|
|
|
|
|
while ( iReqKey-- ) {
|
|
|
|
|
pageStats.requests.disposeOne(reqKeys[iReqKey]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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 pageStore.requests[b] - pageStore.requests[a];
|
|
|
|
|
}).slice(µm.behindTheSceneMaxReq);
|
|
|
|
|
var iReqKey = reqKeys.length;
|
|
|
|
|
while ( iReqKey-- ) {
|
|
|
|
|
pageStore.requests.disposeOne(reqKeys[iReqKey]);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -417,7 +422,7 @@
|
|
|
|
|
'gcPageStats',
|
|
|
|
|
null,
|
|
|
|
|
gcPageStats,
|
|
|
|
|
8 * 60 * 1000,
|
|
|
|
|
5 * 60 * 1000,
|
|
|
|
|
true
|
|
|
|
|
);
|
|
|
|
|
})();
|
|
|
|
|