lots of informal fixes

- us integer tab id -- do not stringify anymore
- improved the parsing of hosts files
- better handling of behind-the-scene network requests when a
  context is provided by the webRequest API
- imported webextFlavor code from uBO
- converted instances of object-as-dict to Map()
pull/2/head
Raymond Hill 7 years ago
parent dd5a3a807c
commit 31cc15ca6c
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2

@ -3,14 +3,15 @@
"devel": true,
"eqeqeq": true,
"esnext": true,
"strict": "global",
"undef": true,
"unused": true,
"globals": {
"browser": false, // global variable in Firefox, Edge
"self": false,
"chrome": false,
"vAPI": false,
"µMatrix": false,
"Components": false // global variable in Firefox
}
"µMatrix": false
},
"strict": "global",
"undef": true,
"unused": true,
"validthis": true
}

@ -20,8 +20,6 @@
Home: https://github.com/gorhill/uMatrix
*/
/* global self, µMatrix */
// For background page
'use strict';
@ -37,22 +35,13 @@ var vAPI = self.vAPI = self.vAPI || {};
var chrome = self.chrome;
var manifest = chrome.runtime.getManifest();
vAPI.chrome = true;
vAPI.webextFlavor = undefined;
if (
self.browser instanceof Object &&
typeof self.browser.runtime.getBrowserInfo === 'function'
) {
self.browser.runtime.getBrowserInfo().then(function(info) {
vAPI.webextFlavor = info.vendor + '-' + info.name + '-' + info.version;
});
} else {
vAPI.webextFlavor = '';
}
var noopFunc = function(){};
// https://code.google.com/p/chromium/issues/detail?id=410868#c8
var resetLastError = function() {
void chrome.runtime.lastError;
};
/******************************************************************************/
// https://github.com/gorhill/uMatrix/issues/234
@ -96,10 +85,13 @@ vAPI.tabs = {};
/******************************************************************************/
vAPI.isBehindTheSceneTabId = function(tabId) {
return tabId.toString() === '-1';
if ( typeof tabId === 'string' ) { debugger; }
return tabId < 0;
};
vAPI.noTabId = '-1';
vAPI.unsetTabId = 0;
vAPI.noTabId = -1; // definitely not any existing tab
vAPI.anyTabId = -2; // one of the existing tab
/******************************************************************************/
@ -126,12 +118,10 @@ vAPI.tabs.registerListeners = function() {
var onCreatedNavigationTarget = function(details) {
//console.debug('onCreatedNavigationTarget: tab id %d = "%s"', details.tabId, details.url);
if ( reGoodForWebRequestAPI.test(details.url) ) { return; }
details.tabId = details.tabId.toString();
onNavigationClient(details);
};
var onUpdated = function(tabId, changeInfo, tab) {
tabId = tabId.toString();
onUpdatedClient(tabId, changeInfo, tab);
};
@ -140,13 +130,12 @@ vAPI.tabs.registerListeners = function() {
if ( details.frameId !== 0 ) {
return;
}
details.tabId = details.tabId.toString();
onNavigationClient(details);
//console.debug('onCommitted: tab id %d = "%s"', details.tabId, details.url);
};
var onClosed = function(tabId) {
onClosedClient(tabId.toString());
onClosedClient(tabId);
};
chrome.webNavigation.onCreatedNavigationTarget.addListener(onCreatedNavigationTarget);
@ -161,29 +150,18 @@ vAPI.tabs.registerListeners = function() {
vAPI.tabs.get = function(tabId, callback) {
var onTabReady = function(tab) {
// https://code.google.com/p/chromium/issues/detail?id=410868#c8
if ( chrome.runtime.lastError ) {
}
if ( tab instanceof Object ) {
tab.id = tab.id.toString();
}
resetLastError();
callback(tab);
};
if ( tabId !== null ) {
if ( typeof tabId === 'string' ) {
tabId = parseInt(tabId, 10);
}
chrome.tabs.get(tabId, onTabReady);
return;
}
var onTabReceived = function(tabs) {
// https://code.google.com/p/chromium/issues/detail?id=410868#c8
if ( chrome.runtime.lastError ) {
}
resetLastError();
var tab = null;
if ( Array.isArray(tabs) && tabs.length !== 0 ) {
tab = tabs[0];
tab.id = tab.id.toString();
}
callback(tab);
};
@ -193,16 +171,7 @@ vAPI.tabs.get = function(tabId, callback) {
/******************************************************************************/
vAPI.tabs.getAll = function(callback) {
var onTabsReady = function(tabs) {
if ( Array.isArray(tabs) ) {
var i = tabs.length;
while ( i-- ) {
tabs[i].id = tabs[i].id.toString();
}
}
callback(tabs);
};
chrome.tabs.query({ url: '<all_urls>' }, onTabsReady);
chrome.tabs.query({ url: '<all_urls>' }, callback);
};
/******************************************************************************/
@ -254,7 +223,7 @@ vAPI.tabs.open = function(details) {
}
// update doesn't accept index, must use move
chrome.tabs.update(parseInt(details.tabId, 10), _details, function(tab) {
chrome.tabs.update(details.tabId, _details, function(tab) {
// if the tab doesn't exist
if ( vAPI.lastError() ) {
chrome.tabs.create(_details, focusWindow);
@ -292,7 +261,7 @@ vAPI.tabs.open = function(details) {
}
chrome.tabs.query({ url: targetURL }, function(tabs) {
if ( chrome.runtime.lastError ) { /* noop */ }
resetLastError();
var tab = Array.isArray(tabs) && tabs[0];
if ( tab ) {
chrome.tabs.update(tab.id, { active: true }, function(tab) {
@ -316,40 +285,21 @@ vAPI.tabs.replace = function(tabId, url) {
targetURL = vAPI.getURL(targetURL);
}
if ( typeof tabId !== 'number' ) {
tabId = parseInt(tabId, 10);
if ( isNaN(tabId) ) {
return;
}
}
if ( typeof tabId !== 'number' || tabId < 0 ) { return; }
chrome.tabs.update(tabId, { url: targetURL }, function() {
// this prevent console error
if ( chrome.runtime.lastError ) {
return;
}
});
chrome.tabs.update(tabId, { url: targetURL }, resetLastError);
};
/******************************************************************************/
vAPI.tabs.remove = function(tabId) {
var onTabRemoved = function() {
if ( vAPI.lastError() ) {
}
};
chrome.tabs.remove(parseInt(tabId, 10), onTabRemoved);
chrome.tabs.remove(tabId, resetLastError);
};
/******************************************************************************/
vAPI.tabs.reload = function(tabId, bypassCache) {
if ( typeof tabId === 'string' ) {
tabId = parseInt(tabId, 10);
}
if ( isNaN(tabId) ) {
return;
}
if ( typeof tabId !== 'number' || tabId < 0 ) { return; }
chrome.tabs.reload(tabId, { bypassCache: bypassCache === true });
};
@ -357,15 +307,12 @@ vAPI.tabs.reload = function(tabId, bypassCache) {
vAPI.tabs.injectScript = function(tabId, details, callback) {
var onScriptExecuted = function() {
// https://code.google.com/p/chromium/issues/detail?id=410868#c8
if ( chrome.runtime.lastError ) {
}
resetLastError();
if ( typeof callback === 'function' ) {
callback();
}
};
if ( tabId ) {
tabId = parseInt(tabId, 10);
chrome.tabs.executeScript(tabId, details, onScriptExecuted);
} else {
chrome.tabs.executeScript(details, onScriptExecuted);
@ -399,8 +346,7 @@ vAPI.setIcon = (function() {
};
return function(tabId, iconDetails, badgeDetails) {
tabId = parseInt(tabId, 10);
if ( isNaN(tabId) || tabId === -1 ) { return; }
if ( typeof tabId !== 'number' || tabId < 0 ) { return; }
chrome.browserAction.setIcon(
{ tabId: tabId, path: iconDetails },
function() { onIconReady(tabId, badgeDetails); }
@ -572,7 +518,13 @@ vAPI.net.registerListeners = function() {
]);
var normalizeRequestDetails = function(details) {
details.tabId = details.tabId.toString();
if (
details.tabId === -1 &&
details.documentUrl === undefined &&
details.initiator !== undefined
) {
details.documentUrl = details.initiator;
}
// The rest of the function code is to normalize request type
if ( details.type !== 'other' ) { return; }
@ -762,31 +714,32 @@ vAPI.cloud = (function() {
var maxChunkCountPerItem = Math.floor(512 * 0.75) & ~(chunkCountPerFetch - 1);
// Mind chrome.storage.sync.QUOTA_BYTES_PER_ITEM (8192 at time of writing)
var maxChunkSize = chrome.storage.sync.QUOTA_BYTES_PER_ITEM || 8192;
// Mind chrome.storage.sync.QUOTA_BYTES (128 kB at time of writing)
// Firefox:
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/sync
// > You can store up to 100KB of data using this API/
var maxStorageSize = chrome.storage.sync.QUOTA_BYTES || 102400;
// Flavor-specific handling needs to be done here. Reason: to allow time
// for vAPI.webextFlavor to be properly set.
// https://github.com/gorhill/uBlock/issues/3006
// For Firefox, we will use a lower ratio to allow for more overhead for
// the infrastructure. Unfortunately this leads to less usable space for
// actual data, but all of this is provided for free by browser vendors,
// so we need to accept and deal with these limitations.
var initialize = function() {
var ratio =
vAPI.webextFlavor === undefined ||
vAPI.webextFlavor.startsWith('Mozilla-Firefox-') ?
0.6 :
0.75;
maxChunkSize = Math.floor(maxChunkSize * ratio);
initialize = function(){};
var evalMaxChunkSize = function() {
return Math.floor(
(chrome.storage.sync.QUOTA_BYTES_PER_ITEM || 8192) *
(vAPI.webextFlavor.soup.has('firefox') ? 0.6 : 0.75)
);
};
var maxChunkSize = evalMaxChunkSize();
// The real actual webextFlavor value may not be set in stone, so listen
// for possible future changes.
window.addEventListener('webextFlavor', function() {
maxChunkSize = evalMaxChunkSize();
}, { once: true });
// Mind chrome.storage.sync.QUOTA_BYTES (128 kB at time of writing)
// Firefox:
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/sync
// > You can store up to 100KB of data using this API/
var maxStorageSize = chrome.storage.sync.QUOTA_BYTES || 102400;
var options = {
defaultDeviceName: window.navigator.platform,
deviceName: vAPI.localStorage.getItem('deviceName') || ''
@ -843,7 +796,6 @@ vAPI.cloud = (function() {
};
var push = function(dataKey, data, callback) {
initialize();
var bin = {
'source': options.deviceName || options.defaultDeviceName,
@ -882,7 +834,6 @@ vAPI.cloud = (function() {
};
var pull = function(dataKey, callback) {
initialize();
var assembleChunks = function(bin) {
if ( chrome.runtime.lastError ) {

@ -1,7 +1,7 @@
/*******************************************************************************
uMatrix - a browser extension to block requests.
Copyright (C) 2014-2017 The uMatrix/uBlock Origin authors
Copyright (C) 2014-2018 The uMatrix/uBlock Origin authors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -47,7 +47,6 @@ vAPI.vapiClientInjected = true;
vAPI.sessionId = String.fromCharCode(Date.now() % 26 + 97) +
Math.random().toString(36).slice(2);
vAPI.chrome = true;
/******************************************************************************/

@ -1,7 +1,7 @@
/*******************************************************************************
uMatrix - a browser extension to block requests.
Copyright (C) 2014-2017 The uMatrix/uBlock Origin authors
Copyright (C) 2014-2018 The uMatrix/uBlock Origin authors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -40,6 +40,86 @@ var chrome = self.chrome;
/******************************************************************************/
vAPI.setTimeout = vAPI.setTimeout || window.setTimeout.bind(window);
/******************************************************************************/
vAPI.webextFlavor = {
major: 0,
soup: new Set()
};
(function() {
var ua = navigator.userAgent,
flavor = vAPI.webextFlavor,
soup = flavor.soup;
var dispatch = function() {
window.dispatchEvent(new CustomEvent('webextFlavor'));
};
// This is always true.
soup.add('ublock');
if ( /\bMobile\b/.test(ua) ) {
soup.add('mobile');
}
// Asynchronous
var async = self.browser instanceof Object &&
typeof self.browser.runtime.getBrowserInfo === 'function';
if ( async ) {
self.browser.runtime.getBrowserInfo().then(function(info) {
flavor.major = parseInt(info.version, 10) || 0;
soup.add(info.vendor.toLowerCase())
.add(info.name.toLowerCase());
if ( flavor.major >= 53 ) { soup.add('user_stylesheet'); }
if ( flavor.major >= 57 ) { soup.add('html_filtering'); }
dispatch();
});
}
// Synchronous
var match = /Firefox\/([\d.]+)/.exec(ua);
if ( match !== null ) {
flavor.major = parseInt(match[1], 10) || 0;
soup.add('mozilla')
.add('firefox');
if ( flavor.major >= 53 ) { soup.add('user_stylesheet'); }
if ( flavor.major >= 57 ) { soup.add('html_filtering'); }
} else {
match = /OPR\/([\d.]+)/.exec(ua);
if ( match !== null ) {
var reEx = /Chrom(?:e|ium)\/([\d.]+)/;
if ( reEx.test(ua) ) { match = reEx.exec(ua); }
flavor.major = parseInt(match[1], 10) || 0;
soup.add('opera').add('chromium');
} else {
match = /Chromium\/([\d.]+)/.exec(ua);
if ( match !== null ) {
flavor.major = parseInt(match[1], 10) || 0;
soup.add('chromium');
} else {
match = /Chrome\/([\d.]+)/.exec(ua);
if ( match !== null ) {
flavor.major = parseInt(match[1], 10) || 0;
soup.add('google').add('chromium');
}
}
}
// https://github.com/gorhill/uBlock/issues/3588
if ( soup.has('chromium') && flavor.major >= 67 ) {
soup.add('user_stylesheet');
}
}
// Don't starve potential listeners
if ( !async ) {
vAPI.setTimeout(dispatch, 97);
}
})();
/******************************************************************************/
// http://www.w3.org/International/questions/qa-scripts#directions
var setScriptDirection = function(language) {
@ -121,10 +201,6 @@ vAPI.localStorage = {
/******************************************************************************/
vAPI.setTimeout = vAPI.setTimeout || window.setTimeout.bind(window);
/******************************************************************************/
})(this);
/******************************************************************************/

@ -208,7 +208,8 @@ return {
clearBrowserCacheCycle: 0,
cspNoInlineScript: "script-src 'unsafe-eval' blob: *",
cspNoInlineStyle: "style-src blob: *",
cspNoWorker: undefined,
cspNoWorker: "worker-src 'none'; report-uri about:blank",
cantMergeCSPHeaders: false,
updateAssetsEvery: 11 * oneDay + 1 * oneHour + 1 * oneMinute + 1 * oneSecond,
firstUpdateAfter: 11 * oneMinute,
nextUpdateAfter: 11 * oneHour,
@ -220,9 +221,9 @@ return {
// urls stats are kept on the back burner while waiting to be reactivated
// in a tab or another.
pageStores: {},
pageStores: new Map(),
pageStoresToken: 0,
pageStoreCemetery: {},
pageStoreCemetery: new Map(),
// page url => permission scope
tMatrix: null,

@ -1,6 +1,6 @@
/*******************************************************************************
uMatrix - a Chromium browser extension to black/white list requests.
uMatrix - a browser extension to black/white list requests.
Copyright (C) 2017-2018 Raymond Hill
This program is free software: you can redistribute it and/or modify

@ -1,6 +1,6 @@
/*******************************************************************************
uMatrix - a Chromium browser extension to black/white list requests.
uMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2018 Raymond Hill
This program is free software: you can redistribute it and/or modify

@ -509,10 +509,7 @@ vAPI.cookies.onChanged = (function() {
queue.delete(qentry[0]);
}
if ( cookieKeys.length !== 0 ) {
let pageStores = µm.pageStores;
for ( let tabId in pageStores ) {
if ( pageStores.hasOwnProperty(tabId) === false ) { continue; }
let pageStore = pageStores[tabId];
for ( let pageStore of µm.pageStores.values() ) {
let allHostnamesString = pageStore.allHostnamesString;
for ( let cookieKey of cookieKeys ) {
if ( cookieMatchDomains(cookieKey, allHostnamesString) ) {

@ -1,7 +1,7 @@
/*******************************************************************************
uMatrix - a browser extension to benchmark browser session.
Copyright (C) 2015 Raymond Hill
Copyright (C) 2015-2018 Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -36,8 +36,8 @@ var firstVarDataCol = 2; // currently, column 2 (0-based index)
var lastVarDataIndex = 3; // currently, d0-d3
var maxEntries = 0;
var noTabId = '';
var allTabIds = {};
var allTabIdsToken;
var pageStores = new Map();
var pageStoresToken;
var ownerId = Date.now();
var emphasizeTemplate = document.querySelector('#emphasizeTemplate > span');
@ -71,7 +71,7 @@ var classNameFromTabId = function(tabId) {
if ( tabId === noTabId ) {
return 'tab_bts';
}
if ( tabId !== '' ) {
if ( tabId > 0 ) {
return 'tab_' + tabId;
}
return '';
@ -298,22 +298,17 @@ var logDate = new Date(),
var renderLogEntries = function(response) {
var entries = response.entries;
if ( entries.length === 0 ) {
return;
}
if ( entries.length === 0 ) { return; }
// Preserve scroll position
var height = tbody.offsetHeight;
var tabIds = response.tabIds;
var n = entries.length;
var entry;
for ( var i = 0; i < n; i++ ) {
entry = entries[i];
// Unlikely, but it may happen
if ( entry.tab && tabIds.hasOwnProperty(entry.tab) === false ) {
continue;
}
if ( entry.tab && pageStores.has(entry.tab) === false ) { continue; }
renderLogEntry(entries[i]);
}
@ -346,18 +341,14 @@ var renderLogEntries = function(response) {
/******************************************************************************/
var synchronizeTabIds = function(newTabIds) {
var oldTabIds = allTabIds;
var synchronizeTabIds = function(newPageStores) {
var oldPageStores = pageStores;
var autoDeleteVoidRows = !!vAPI.localStorage.getItem('loggerAutoDeleteVoidRows');
var rowVoided = false;
var trs;
for ( var tabId in oldTabIds ) {
if ( oldTabIds.hasOwnProperty(tabId) === false ) {
continue;
}
if ( newTabIds.hasOwnProperty(tabId) ) {
continue;
}
for ( let entry of oldPageStores ) {
let tabId = entry[0];
if ( newPageStores.has(tabId) ) { continue; }
// Mark or remove voided rows
trs = uDom('.tab_' + tabId);
if ( autoDeleteVoidRows ) {
@ -374,22 +365,20 @@ var synchronizeTabIds = function(newTabIds) {
var select = document.getElementById('pageSelector');
var selectValue = select.value;
var tabIds = Object.keys(newTabIds).sort(function(a, b) {
return newTabIds[a].localeCompare(newTabIds[b]);
var tabIds = Array.from(newPageStores.keys()).sort(function(a, b) {
return newPageStores.get(a).localeCompare(newPageStores.get(b));
});
var option;
for ( var i = 0, j = 2; i < tabIds.length; i++ ) {
tabId = tabIds[i];
if ( tabId === noTabId ) {
continue;
}
let tabId = tabIds[i];
if ( tabId === noTabId ) { continue; }
option = select.options[j];
j += 1;
if ( !option ) {
option = document.createElement('option');
select.appendChild(option);
}
option.textContent = newTabIds[tabId];
option.textContent = newPageStores.get(tabId);
option.value = classNameFromTabId(tabId);
if ( option.value === selectValue ) {
option.setAttribute('selected', '');
@ -407,7 +396,7 @@ var synchronizeTabIds = function(newTabIds) {
pageSelectorChanged();
}
allTabIds = newTabIds;
pageStores = newPageStores;
return rowVoided;
};
@ -446,9 +435,11 @@ var onLogBufferRead = function(response) {
// Neuter rows for which a tab does not exist anymore
var rowVoided = false;
if ( response.tabIdsToken !== allTabIdsToken ) {
rowVoided = synchronizeTabIds(response.tabIds);
allTabIdsToken = response.tabIdsToken;
if ( response.pageStoresToken !== pageStoresToken ) {
if ( Array.isArray(response.pageStores) ) {
rowVoided = synchronizeTabIds(new Map(response.pageStores));
}
pageStoresToken = response.pageStoresToken;
}
renderLogEntries(response);
@ -479,7 +470,11 @@ var readLogBuffer = function() {
if ( ownerId === undefined ) { return; }
vAPI.messaging.send(
'logger-ui.js',
{ what: 'readMany', ownerId: ownerId },
{
what: 'readMany',
ownerId: ownerId,
pageStoresToken: pageStoresToken
},
onLogBufferRead
);
};
@ -515,15 +510,11 @@ var pageSelectorChanged = function() {
var refreshTab = function() {
var tabClass = document.getElementById('pageSelector').value;
var matches = tabClass.match(/^tab_(.+)$/);
if ( matches === null ) {
return;
}
if ( matches[1] === 'bts' ) {
return;
}
if ( matches === null ) { return; }
if ( matches[1] === 'bts' ) { return; }
vAPI.messaging.send(
'logger-ui.js',
{ what: 'forceReloadTab', tabId: matches[1] }
{ what: 'forceReloadTab', tabId: parseInt(matches[1], 10) }
);
};

@ -1,6 +1,6 @@
/*******************************************************************************
uMatrix - a Chromium browser extension to black/white list requests.
uMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2018 Raymond Hill
This program is free software: you can redistribute it and/or modify
@ -938,20 +938,23 @@ var onMessage = function(request, sender, callback) {
response = { unavailable: true };
break;
}
var tabIds = {};
for ( var tabId in µm.pageStores ) {
var pageStore = µm.pageStoreFromTabId(tabId);
if ( pageStore === null ) { continue; }
let pageStores;
if ( request.pageStoresToken !== µm.pageStoresToken ) {
pageStores = [];
for ( let entry of µm.pageStores ) {
let tabId = entry[0];
let pageStore = entry[1];
if ( pageStore.rawUrl.startsWith(loggerURL) ) { continue; }
tabIds[tabId] = pageStore.title || pageStore.rawUrl;
pageStores.push([ tabId, pageStore.title || pageStore.rawUrl ]);
}
}
response = {
colorBlind: false,
entries: µm.logger.readAll(request.ownerId),
maxLoggedRequests: µm.userSettings.maxLoggedRequests,
noTabId: vAPI.noTabId,
tabIds: tabIds,
tabIdsToken: µm.pageStoresToken
pageStores: pageStores,
pageStoresToken: µm.pageStoresToken
};
break;

@ -1,6 +1,6 @@
/*******************************************************************************
uMatrix - a Chromium browser extension to black/white list requests.
uMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2018 Raymond Hill
This program is free software: you can redistribute it and/or modify
@ -1584,13 +1584,13 @@ var matrixSnapshotPoller = (function() {
};
(function() {
var tabId = matrixSnapshot.tabId;
let tabId = matrixSnapshot.tabId;
// If no tab id yet, see if there is one specified in our URL
if ( tabId === undefined ) {
var matches = window.location.search.match(/(?:\?|&)tabId=([^&]+)/);
if ( matches !== null ) {
tabId = matches[1];
tabId = parseInt(matches[1], 10);
// No need for logger button when embedded in logger
uDom('[data-extension-url="logger-ui.html"]').remove();
}

@ -1,7 +1,7 @@
/*******************************************************************************
uMatrix - a Chromium browser extension to black/white list requests.
Copyright (C) 2014-2017 Raymond Hill
uMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2018 Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -89,8 +89,10 @@ var onPSLReady = function() {
// rhill 2013-11-24: bind behind-the-scene virtual tab/url manually, since the
// normal way forbid binding behind the scene tab.
// https://github.com/gorhill/httpswitchboard/issues/67
µm.pageStores[vAPI.noTabId] = µm.pageStoreFactory(µm.tabContextManager.mustLookup(vAPI.noTabId));
µm.pageStores[vAPI.noTabId].title = vAPI.i18n('statsPageDetailedBehindTheScenePage');
let pageStore =
µm.pageStoreFactory(µm.tabContextManager.mustLookup(vAPI.noTabId));
pageStore.title = vAPI.i18n('statsPageDetailedBehindTheScenePage');
µm.pageStores.set(vAPI.noTabId, pageStore);
vAPI.tabs.getAll(onTabsReady);
};

@ -519,11 +519,32 @@
µMatrix.mergeHostsFileContent = function(rawText) {
var rawEnd = rawText.length;
var ubiquitousBlacklist = this.ubiquitousBlacklist;
var reLocalhost = /(^|\s)(localhost\.localdomain|localhost|local|broadcasthost|0\.0\.0\.0|127\.0\.0\.1|::1|fe80::1%lo0)(?=\s|$)/g;
var reLocalhost = new RegExp(
[
'(?:^|\\s+)(?:',
[
'broadcasthost',
'ip6-allnodes',
'ip6-allrouters',
'ip6-localhost',
'ip6-loopback',
'localhost\\.localdomain',
'localhost',
'local',
'0\\.0\\.0\\.0',
'127\\.0\\.0\\.1',
'255\\.255\\.255\\.255',
'::1',
'ff02::1',
'ff02::2',
'fe80::1%lo0',
].join('|'),
')(?=\\s+|$)'
].join(''),
'g'
);
var reAsciiSegment = /^[\x21-\x7e]+$/;
var matches;
var lineBeg = 0, lineEnd;
var line;
while ( lineBeg < rawEnd ) {
lineEnd = rawText.indexOf('\n', lineBeg);
@ -537,7 +558,7 @@
// rhill 2014-04-18: The trim is important here, as without it there
// could be a lingering `\r` which would cause problems in the
// following parsing code.
line = rawText.slice(lineBeg, lineEnd).trim();
let line = rawText.slice(lineBeg, lineEnd).trim();
lineBeg = lineEnd + 1;
// https://github.com/gorhill/httpswitchboard/issues/15
@ -550,22 +571,15 @@
// The filter is whatever sequence of printable ascii character without
// whitespaces
matches = reAsciiSegment.exec(line);
if ( !matches || matches.length === 0 ) {
continue;
}
let matches = reAsciiSegment.exec(line);
if ( matches === null ) { continue; }
// Bypass anomalies
// For example, when a filter contains whitespace characters, or
// whatever else outside the range of printable ascii characters.
if ( matches[0] !== line ) {
continue;
}
if ( matches[0] !== line ) { continue; }
line = matches[0];
if ( line === '' ) {
continue;
}
if ( line === '' ) { continue; }
ubiquitousBlacklist.add(line);
}

@ -1,6 +1,6 @@
/*******************************************************************************
uMatrix - a Chromium browser extension to black/white list requests.
uMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2018 Raymond Hill
This program is free software: you can redistribute it and/or modify
@ -140,7 +140,7 @@ housekeep itself.
*/
µm.tabContextManager = (function() {
var tabContexts = Object.create(null);
var tabContexts = new Map();
// https://github.com/chrisaljoudi/uBlock/issues/1001
// This is to be used as last-resort fallback in case a tab is found to not
@ -170,18 +170,16 @@ housekeep itself.
this.commitTimer = null;
this.gcTimer = null;
tabContexts[tabId] = this;
tabContexts.set(tabId, this);
};
TabContext.prototype.destroy = function() {
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) {
return;
}
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; }
if ( this.gcTimer !== null ) {
clearTimeout(this.gcTimer);
this.gcTimer = null;
}
delete tabContexts[this.tabId];
tabContexts.delete(this.tabId);
};
TabContext.prototype.onTab = function(tab) {
@ -285,7 +283,7 @@ housekeep itself.
// These are to be used for the API of the tab context manager.
var push = function(tabId, url, context) {
var entry = tabContexts[tabId];
let entry = tabContexts.get(tabId);
if ( entry === undefined ) {
entry = new TabContext(tabId);
entry.autodestroy();
@ -303,7 +301,7 @@ housekeep itself.
if ( url !== undefined ) {
entry = push(tabId, url);
} else {
entry = tabContexts[tabId];
entry = tabContexts.get(tabId);
}
if ( entry !== undefined ) {
return entry;
@ -329,11 +327,11 @@ housekeep itself.
// about to fall through the cracks.
// Example: Chromium + case #12 at
// http://raymondhill.net/ublock/popup.html
return tabContexts[vAPI.noTabId];
return tabContexts.get(vAPI.noTabId);
};
var lookup = function(tabId) {
return tabContexts[tabId] || null;
return tabContexts.get(tabId) || null;
};
// Behind-the-scene tab context
@ -372,7 +370,7 @@ housekeep itself.
vAPI.tabs.onClosed = function(tabId) {
µm.unbindTabFromPageStats(tabId);
var entry = tabContexts[tabId];
let entry = tabContexts.get(tabId);
if ( entry instanceof TabContext ) {
entry.destroy();
}
@ -397,7 +395,7 @@ vAPI.tabs.registerListeners();
// Do not create a page store for URLs which are of no interests
// Example: dev console
var tabContext = this.tabContextManager.lookup(tabId);
let tabContext = this.tabContextManager.lookup(tabId);
if ( tabContext === null ) {
throw new Error('Unmanaged tab id: ' + tabId);
}
@ -406,14 +404,14 @@ vAPI.tabs.registerListeners();
// virtual tab.
// https://github.com/gorhill/httpswitchboard/issues/67
if ( vAPI.isBehindTheSceneTabId(tabId) ) {
return this.pageStores[tabId];
return this.pageStores.get(tabId);
}
var normalURL = tabContext.normalURL;
var pageStore = this.pageStores[tabId] || null;
let normalURL = tabContext.normalURL;
let pageStore = this.pageStores.get(tabId);
// The previous page URL, if any, associated with the tab
if ( pageStore !== null ) {
if ( pageStore !== undefined ) {
// No change, do not rebind
if ( pageStore.pageUrl === normalURL ) {
return pageStore;
@ -425,7 +423,10 @@ vAPI.tabs.registerListeners();
// Example: Google Maps, Github
// https://github.com/gorhill/uMatrix/issues/72
// Need to double-check that the new scope is same as old scope
if ( context === 'updateURL' && pageStore.pageHostname === tabContext.rootHostname ) {
if (
context === 'updateURL' &&
pageStore.pageHostname === tabContext.rootHostname
) {
pageStore.rawURL = tabContext.rawURL;
pageStore.normalURL = normalURL;
this.updateTitle(tabId);
@ -442,29 +443,22 @@ vAPI.tabs.registerListeners();
if ( pageStore === null ) {
pageStore = this.pageStoreFactory(tabContext);
}
this.pageStores[tabId] = pageStore;
this.pageStores.set(tabId, pageStore);
this.updateTitle(tabId);
this.pageStoresToken = Date.now();
// console.debug('tab.js > bindTabToPageStats(): dispatching traffic in tab id %d to page store "%s"', tabId, pageUrl);
return pageStore;
};
/******************************************************************************/
µm.unbindTabFromPageStats = function(tabId) {
// Never unbind behind-the-scene page store.
if ( vAPI.isBehindTheSceneTabId(tabId) ) {
return;
}
if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
var pageStore = this.pageStores[tabId] || null;
if ( pageStore === null ) {
return;
}
let pageStore = this.pageStores.get(tabId);
if ( pageStore === undefined ) { return; }
delete this.pageStores[tabId];
this.pageStores.delete(tabId);
this.pageStoresToken = Date.now();
if ( pageStore.incinerationTimer ) {
@ -472,13 +466,13 @@ vAPI.tabs.registerListeners();
pageStore.incinerationTimer = null;
}
if ( this.pageStoreCemetery.hasOwnProperty(tabId) === false ) {
this.pageStoreCemetery[tabId] = {};
let pageStoreCrypt = this.pageStoreCemetery.get(tabId);
if ( pageStoreCrypt === undefined ) {
this.pageStoreCemetery.set(tabId, (pageStoreCrypt = new Map()));
}
var pageStoreCrypt = this.pageStoreCemetery[tabId];
var pageURL = pageStore.pageUrl;
pageStoreCrypt[pageURL] = pageStore;
let pageURL = pageStore.pageUrl;
pageStoreCrypt.set(pageURL, pageStore);
pageStore.incinerationTimer = vAPI.setTimeout(
this.incineratePageStore.bind(this, tabId, pageURL),
@ -489,25 +483,21 @@ vAPI.tabs.registerListeners();
/******************************************************************************/
µm.resurrectPageStore = function(tabId, pageURL) {
if ( this.pageStoreCemetery.hasOwnProperty(tabId) === false ) {
return null;
}
var pageStoreCrypt = this.pageStoreCemetery[tabId];
let pageStoreCrypt = this.pageStoreCemetery.get(tabId);
if ( pageStoreCrypt === undefined ) { return null; }
if ( pageStoreCrypt.hasOwnProperty(pageURL) === false ) {
return null;
}
let pageStore = pageStoreCrypt.get(pageURL);
if ( pageStore === undefined ) { return null; }
var pageStore = pageStoreCrypt[pageURL];
if ( pageStore.incinerationTimer !== null ) {
clearTimeout(pageStore.incinerationTimer);
pageStore.incinerationTimer = null;
}
delete pageStoreCrypt[pageURL];
if ( Object.keys(pageStoreCrypt).length === 0 ) {
delete this.pageStoreCemetery[tabId];
pageStoreCrypt.delete(pageURL);
if ( pageStoreCrypt.size === 0 ) {
this.pageStoreCemetery.delete(tabId);
}
return pageStore;
@ -516,24 +506,20 @@ vAPI.tabs.registerListeners();
/******************************************************************************/
µm.incineratePageStore = function(tabId, pageURL) {
if ( this.pageStoreCemetery.hasOwnProperty(tabId) === false ) {
return;
}
var pageStoreCrypt = this.pageStoreCemetery[tabId];
let pageStoreCrypt = this.pageStoreCemetery.get(tabId);
if ( pageStoreCrypt === undefined ) { return; }
if ( pageStoreCrypt.hasOwnProperty(pageURL) === false ) {
return;
}
let pageStore = pageStoreCrypt.get(pageURL);
if ( pageStore === undefined ) { return; }
var pageStore = pageStoreCrypt[pageURL];
if ( pageStore.incinerationTimer !== null ) {
clearTimeout(pageStore.incinerationTimer);
pageStore.incinerationTimer = null;
}
delete pageStoreCrypt[pageURL];
if ( Object.keys(pageStoreCrypt).length === 0 ) {
delete this.pageStoreCemetery[tabId];
pageStoreCrypt.delete(pageURL);
if ( pageStoreCrypt.size === 0 ) {
this.pageStoreCemetery.delete(tabId);
}
pageStore.dispose();
@ -542,12 +528,12 @@ vAPI.tabs.registerListeners();
/******************************************************************************/
µm.pageStoreFromTabId = function(tabId) {
return this.pageStores[tabId] || null;
return this.pageStores.get(tabId) || null;
};
// Never return null
µm.mustPageStoreFromTabId = function(tabId) {
return this.pageStores[tabId] || this.pageStores[vAPI.noTabId];
return this.pageStores.get(tabId) || this.pageStores.get(vAPI.noTabId);
};
/******************************************************************************/
@ -608,25 +594,26 @@ vAPI.tabs.registerListeners();
/******************************************************************************/
µm.updateTitle = (function() {
var tabIdToTimer = Object.create(null);
var tabIdToTryCount = Object.create(null);
var delay = 499;
let tabIdToTimer = new Map();
let tabIdToTryCount = new Map();
let delay = 499;
var tryNoMore = function(tabId) {
delete tabIdToTryCount[tabId];
let tryNoMore = function(tabId) {
tabIdToTryCount.delete(tabId);
};
var tryAgain = function(tabId) {
var count = tabIdToTryCount[tabId];
if ( count === undefined ) {
return false;
}
let tryAgain = function(tabId) {
let count = tabIdToTryCount.get(tabId);
if ( count === undefined ) { return false; }
if ( count === 1 ) {
delete tabIdToTryCount[tabId];
tabIdToTryCount.delete(tabId);
return false;
}
tabIdToTryCount[tabId] = count - 1;
tabIdToTimer[tabId] = vAPI.setTimeout(updateTitle.bind(µm, tabId), delay);
tabIdToTryCount.set(tabId, count - 1);
tabIdToTimer.set(
tabId,
vAPI.setTimeout(updateTitle.bind(µm, tabId), delay)
);
return true;
};
@ -652,19 +639,21 @@ vAPI.tabs.registerListeners();
};
var updateTitle = function(tabId) {
delete tabIdToTimer[tabId];
tabIdToTimer.delete(tabId);
vAPI.tabs.get(tabId, onTabReady.bind(this, tabId));
};
return function(tabId) {
if ( vAPI.isBehindTheSceneTabId(tabId) ) {
return;
}
if ( tabIdToTimer[tabId] ) {
clearTimeout(tabIdToTimer[tabId]);
if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
let timer = tabIdToTimer.get(tabId);
if ( timer !== undefined ) {
clearTimeout(timer);
}
tabIdToTimer[tabId] = vAPI.setTimeout(updateTitle.bind(this, tabId), delay);
tabIdToTryCount[tabId] = 5;
tabIdToTimer.set(
tabId,
vAPI.setTimeout(updateTitle.bind(this, tabId), delay)
);
tabIdToTryCount.set(tabId, 5);
};
})();
@ -680,7 +669,7 @@ vAPI.tabs.registerListeners();
var cleanup = function() {
var vapiTabs = vAPI.tabs;
var tabIds = Object.keys(µm.pageStores).sort();
var tabIds = Array.from(µm.pageStores.keys()).sort();
var checkTab = function(tabId) {
vapiTabs.get(tabId, function(tab) {
if ( !tab ) {
@ -695,9 +684,7 @@ vAPI.tabs.registerListeners();
var n = Math.min(cleanupSampleAt + cleanupSampleSize, tabIds.length);
for ( var i = cleanupSampleAt; i < n; i++ ) {
tabId = tabIds[i];
if ( vAPI.isBehindTheSceneTabId(tabId) ) {
continue;
}
if ( vAPI.isBehindTheSceneTabId(tabId) ) { continue; }
checkTab(tabId);
}
cleanupSampleAt = n;

@ -127,6 +127,12 @@ var onBeforeRequestHandler = function(details) {
rootHostname = tabContext.rootHostname,
specificity = 0;
if ( tabId < 0 && details.documentUrl !== undefined ) {
rootHostname = µmuri.hostnameFromURI(
µm.normalizePageURL(0, details.documentUrl)
);
}
// Filter through matrix
var block = µm.tMatrix.mustBlock(
rootHostname,
@ -344,16 +350,10 @@ var onHeadersReceived = function(details) {
csp.push(µm.cspNoInlineStyle);
}
// https://bugzilla.mozilla.org/show_bug.cgi?id=1302667
var cspNoWorker = µm.cspNoWorker;
if ( cspNoWorker === undefined ) {
cspNoWorker = cspNoWorkerInit();
}
if ( µm.tMatrix.evaluateSwitchZ('no-workers', rootHostname) ) {
csp.push(cspNoWorker);
csp.push(µm.cspNoWorker);
} else if ( µm.rawSettings.disableCSPReportInjection === false ) {
cspReport.push(cspNoWorker);
cspReport.push(µm.cspNoWorker);
}
if ( csp.length === 0 && cspReport.length === 0 ) { return; }
@ -368,7 +368,7 @@ var onHeadersReceived = function(details) {
if ( csp.length !== 0 ) {
let cspRight = csp.join(', ');
let cspTotal = cspRight;
if ( cantMergeCSPHeaders ) {
if ( µm.cantMergeCSPHeaders ) {
let i = headerIndexFromName(
'content-security-policy',
headers
@ -390,7 +390,7 @@ var onHeadersReceived = function(details) {
if ( cspReport.length !== 0 ) {
let cspRight = cspReport.join(', ');
let cspTotal = cspRight;
if ( cantMergeCSPHeaders ) {
if ( µm.cantMergeCSPHeaders ) {
let i = headerIndexFromName(
'content-security-policy-report-only',
headers
@ -411,34 +411,19 @@ var onHeadersReceived = function(details) {
/******************************************************************************/
// https://bugzilla.mozilla.org/show_bug.cgi?id=1302667
// https://github.com/gorhill/uMatrix/issues/967#issuecomment-373002011
// This can be removed once Firefox 60 ESR is released.
var cantMergeCSPHeaders = (function() {
if (
self.browser instanceof Object &&
typeof self.browser.runtime.getBrowserInfo === 'function'
) {
self.browser.runtime.getBrowserInfo().then(function(info) {
cantMergeCSPHeaders =
info.vendor === 'Mozilla' &&
info.name === 'Firefox' &&
parseInt(info.version, 10) < 59;
});
}
return false;
})();
/******************************************************************************/
var cspNoWorkerInit = function() {
if ( vAPI.webextFlavor === undefined ) {
return "child-src 'none'; frame-src data: blob: *; report-uri about:blank";
window.addEventListener('webextFlavor', function() {
if ( vAPI.webextFlavor.soup.has('firefox') === false ) { return; }
if ( vAPI.webextFlavor.major <= 57 ) {
µMatrix.cspNoWorker =
"child-src 'none'; frame-src data: blob: *; report-uri about:blank";
}
µMatrix.cspNoWorker = /^Mozilla-Firefox-5[67]/.test(vAPI.webextFlavor) ?
"child-src 'none'; frame-src data: blob: *; report-uri about:blank" :
"worker-src 'none'; report-uri about:blank" ;
return µMatrix.cspNoWorker;
};
if ( vAPI.webextFlavor.major <= 58 ) {
µMatrix.cantMergeCSPHeaders = true;
}
}, { once: true });
/******************************************************************************/

Loading…
Cancel
Save