started work on #105, #475, and possibly #510

This commit is contained in:
gorhill 2015-01-19 18:42:58 -05:00
parent ee1f861deb
commit 759a156e24
11 changed files with 139 additions and 31 deletions

View File

@ -61,6 +61,14 @@ vAPI.tabs = {};
/******************************************************************************/
vAPI.isNoTabId = function(tabId) {
return tabId.toString() === '-1';
};
vAPI.noTabId = '-1';
/******************************************************************************/
vAPI.tabs.registerListeners = function() {
if ( typeof this.onNavigation === 'function' ) {
chrome.webNavigation.onCommitted.addListener(this.onNavigation);

View File

@ -329,6 +329,14 @@ vAPI.tabs = {};
/******************************************************************************/
vAPI.isNoTabId = function(tabId) {
return tabId.toString() === '_';
};
vAPI.noTabId = '_';
/******************************************************************************/
vAPI.tabs.registerListeners = function() {
// onNavigation and onUpdated handled with tabsProgressListener
// onClosed - handled in windowWatcher.onTabClose

View File

@ -187,6 +187,14 @@ vAPI.tabs = {
/******************************************************************************/
vAPI.isNoTabId = function(tabId) {
return tabId.toString() === '-1';
};
vAPI.noTabId = '-1';
/******************************************************************************/
vAPI.tabs.registerListeners = function() {
var onNavigation = this.onNavigation;

View File

@ -2,7 +2,7 @@
<html>
<head>
<meta charset="utf-8">
<title>µBlock — Statistics</title>
<title data-i18n="statsPageName"></title>
<link rel="stylesheet" type="text/css" href="css/common.css">
<link rel="stylesheet" type="text/css" href="css/devtools.css">
</head>

View File

@ -187,7 +187,7 @@ return asyncJobManager;
};
var updateBadgeAsync = function(tabId) {
if ( tabId < 0 ) {
if ( vAPI.isNoTabId(tabId) ) {
return;
}
µb.asyncJobs.add('updateBadge-' + tabId, tabId, updateBadge, 250);

View File

@ -30,7 +30,7 @@
/******************************************************************************/
var messager = vAPI.messaging.channel('stats.js');
var messager = vAPI.messaging.channel('devtools.js');
/******************************************************************************/
@ -74,9 +74,21 @@ var selectPage = function() {
var inspector = uDom('#content');
var currentSrc = inspector.attr('src');
var targetSrc = 'devtool-log.html?tabId=' + tabId;
if ( targetSrc !== currentSrc ) {
inspector.attr('src', targetSrc);
if ( targetSrc === currentSrc ) {
return;
}
inspector.attr('src', targetSrc);
// This is useful for when the user force-refresh the page: this will
// prevent a reset to the original request log.
// This is also useful for an outside observer to find out which tab is
// being logged, i.e. the popup menu can initialize itself according to
// what tab is currently being logged.
window.history.pushState(
{},
'',
window.location.href.replace(/^(.+[\?&])tabId=([^&]+)(.*)$/, '$1tabId=' + tabId + '$3')
);
};
/******************************************************************************/

View File

@ -72,7 +72,9 @@ var onMessage = function(request, sender, callback) {
break;
case 'reloadTab':
vAPI.tabs.reload(request.tabId);
if ( vAPI.isNoTabId(request.tabId) === false ) {
vAPI.tabs.reload(request.tabId);
}
break;
case 'userSettings':
@ -204,12 +206,35 @@ var getStats = function(tabId) {
/******************************************************************************/
var getTargetTabId = function(tab) {
if ( !tab ) {
return '';
}
// If the URL is that of the network request logger, fill the popup with
// the data from the tab being observed by the logger.
// This allows a user to actually modify filtering profile for
// behind-the-scene requests.
if ( tab.url.indexOf(vAPI.getURL('devtools.html')) !== 0 ) {
return tab.id;
}
// Extract the target tab id from the URL
var matches = tab.url.match(/[\?&]tabId=([^&]+)/);
if ( matches && matches.length === 2 ) {
return matches[1];
}
return tab.id;
};
/******************************************************************************/
var onMessage = function(request, sender, callback) {
// Async
switch ( request.what ) {
case 'getPopupData':
vAPI.tabs.get(null, function(tab) {
var tabId = tab && tab.id;
var tabId = getTargetTabId(tab);
callback(getStats(tabId));
});
return;
@ -751,7 +776,7 @@ vAPI.messaging.listen('whitelist.js', onMessage);
/******************************************************************************/
/******************************************************************************/
// stats.js
// devtools.js
(function() {
@ -767,25 +792,41 @@ var getPageDetails = function(callback) {
var out = {};
var tabIds = Object.keys(µb.pageStores);
var countdown = tabIds.length;
if ( countdown === 0 ) {
// Just in case... I expect there will always be a behind-the-scene page
// store, but just to be safe.
if ( tabIds.length === 0 ) {
callback(out);
return;
}
var onTabDetails = function(tab) {
if ( tab ) {
out[tab.id] = tab.title;
}
var countdown = tabIds.length;
var doCountdown = function() {
countdown -= 1;
if ( countdown === 0 ) {
callback(out);
}
};
// Let's not populate the page selector with reference itself
var devtoolsURL = vAPI.getURL('devtools.html');
var devtoolsURLLen = devtoolsURL.length;
var onTabDetails = function(tab) {
if ( tab && tab.url.slice(0, devtoolsURLLen) !== devtoolsURL ) {
out[tab.id] = tab.title;
}
doCountdown();
};
var i = countdown;
while ( i-- ) {
vAPI.tabs.get(tabIds[i], onTabDetails);
// Special case: behind-the-scene virtual tab (does not really exist)
if ( vAPI.isNoTabId(tabIds[i]) ) {
out[vAPI.noTabId] = vAPI.i18n('logBehindTheScene');
doCountdown();
} else {
vAPI.tabs.get(tabIds[i], onTabDetails);
}
}
};
@ -813,7 +854,7 @@ var onMessage = function(request, sender, callback) {
callback(response);
};
vAPI.messaging.listen('stats.js', onMessage);
vAPI.messaging.listen('devtools.js', onMessage);
/******************************************************************************/

View File

@ -65,6 +65,7 @@ var metadata = {
};
var hashToContentMap = {};
var urlKeyPendingMap = {};
var loaded = false;
@ -377,8 +378,14 @@ var cacheAsset = function(url) {
if ( metadataExists(urlKey) ) {
return;
}
// Avoid re-entrancy
if ( urlKeyPendingMap.hasOwnProperty(urlKey) ) {
return;
}
urlKeyPendingMap[urlKey] = true;
var onRemoteAssetLoaded = function() {
delete urlKeyPendingMap[urlKey];
this.onload = this.onerror = null;
if ( this.status !== 200 ) {
return;
@ -410,6 +417,7 @@ var cacheAsset = function(url) {
};
var onRemoteAssetError = function() {
delete urlKeyPendingMap[urlKey];
this.onload = this.onerror = null;
};
@ -422,7 +430,11 @@ var cacheAsset = function(url) {
/******************************************************************************/
var toURL = function(url, cache) {
var toURL = function(url, type, cache) {
// Unsupported types
if ( type === 'font' ) {
return '';
}
exports.tryCount += 1;
var urlKey = toUrlKey(url);
if ( urlKey === '' ) {

View File

@ -121,12 +121,21 @@ vAPI.tabs.registerListeners();
// hostname. This way, for a specific scheme you can create scope with
// rules which will apply only to that scheme.
µb.normalizePageURL = function(pageURL) {
µb.normalizePageURL = function(tabId, pageURL) {
if ( vAPI.isNoTabId(tabId) ) {
return 'http://behind-the-scene/';
}
var uri = this.URI.set(pageURL);
if ( uri.scheme === 'https' || uri.scheme === 'http' ) {
var scheme = uri.scheme;
if ( scheme === 'https' || scheme === 'http' ) {
return uri.normalizedURI();
}
return '';
if ( uri.hostname !== '' ) {
return 'http://' + scheme + '-' + uri.hostname + uri.path;
}
return 'http://' + scheme + '-scheme/';
};
/******************************************************************************/
@ -138,7 +147,7 @@ vAPI.tabs.registerListeners();
// https://github.com/gorhill/httpswitchboard/issues/303
// Normalize page URL
pageURL = this.normalizePageURL(pageURL);
pageURL = this.normalizePageURL(tabId, pageURL);
// Do not create a page store for URLs which are of no interests
if ( pageURL === '' ) {
@ -194,6 +203,15 @@ vAPI.tabs.registerListeners();
return this.pageStores[tabId];
};
/******************************************************************************/
// Permanent page store for behind-the-scene requests. Must never be removed.
µb.pageStores[vAPI.noTabId] = µb.PageStore.factory(
vAPI.noTabId,
µb.normalizePageURL(vAPI.noTabId)
);
/******************************************************************************/
/******************************************************************************/
@ -218,9 +236,15 @@ var pageStoreJanitor = function() {
if ( pageStoreJanitorSampleAt >= tabIds.length ) {
pageStoreJanitorSampleAt = 0;
}
var tabId;
var n = Math.min(pageStoreJanitorSampleAt + pageStoreJanitorSampleSize, tabIds.length);
for ( var i = pageStoreJanitorSampleAt; i < n; i++ ) {
checkTab(tabIds[i]);
tabId = tabIds[i];
// Do not remove behind-the-scene page store
if ( vAPI.isNoTabId(tabId) ) {
continue;
}
checkTab(tabId);
}
pageStoreJanitorSampleAt = n;

View File

@ -38,11 +38,6 @@ var onBeforeRequest = function(details) {
// Do not block behind the scene requests.
var tabId = details.tabId;
if ( tabId < 0 ) {
// TODO: logging behind-the-scene requests could be nice..
return;
}
var µb = µBlock;
var requestURL = details.url;
var requestType = details.type;
@ -120,7 +115,7 @@ var onBeforeRequest = function(details) {
// https://code.google.com/p/chromium/issues/detail?id=387198
// Not all redirects will succeed, until bug above is fixed.
var redirectURL = pageStore.toMirrorURL(requestURL);
var redirectURL = pageStore.toMirrorURL(requestURL, requestType);
if ( redirectURL !== '' ) {
pageStore.logBuffer.writeOne(requestContext, 'ma:');

View File

@ -288,10 +288,10 @@ var matchWhitelistDirective = function(url, hostname, directive) {
return type;
}
var ext = path.slice(pos) + '.';
if ( '.css.eot.ttf.otf.svg.woff.woff2.'.indexOf(ext) !== -1 ) {
return 'stylesheet';
if ( '.eot.ttf.otf.svg.woff.woff2.'.indexOf(ext) !== -1 ) {
return 'font';
}
if ( '.ico.png.gif.jpg.jpeg.'.indexOf(ext) !== -1 ) {
if ( '.ico.'.indexOf(ext) !== -1 ) {
return 'image';
}
return type;