Skip to content

Loading…

Fix 475 #576

Closed
wants to merge 14 commits into from
This page is out of date. Refresh to see the latest.
View
2 platform/chromium/manifest.json
@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "µBlock",
- "version": "0.8.5.7",
+ "version": "0.8.6.0",
"default_locale": "en",
"description": "__MSG_extShortDesc__",
View
117 platform/chromium/vapi-background.js
@@ -38,6 +38,8 @@ var manifest = chrome.runtime.getManifest();
vAPI.chrome = true;
+var noopFunc = function(){};
+
/******************************************************************************/
vAPI.app = {
@@ -61,6 +63,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);
@@ -85,7 +95,7 @@ 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 ) {
- ;
+ /* noop */
}
// Caller must be prepared to deal with nil tab value
callback(tab);
@@ -100,7 +110,7 @@ vAPI.tabs.get = function(tabId, callback) {
var onTabReceived = function(tabs) {
// https://code.google.com/p/chromium/issues/detail?id=410868#c8
if ( chrome.runtime.lastError ) {
- ;
+ /* noop */
}
callback(tabs[0]);
};
@@ -139,10 +149,8 @@ vAPI.tabs.open = function(details) {
};
if ( details.tabId ) {
- details.tabId = parseInt(tabId, 10);
-
// update doesn't accept index, must use move
- chrome.tabs.update(details.tabId, _details, function(tab) {
+ chrome.tabs.update(parseInt(details.tabId, 10), _details, function(tab) {
// if the tab doesn't exist
if ( vAPI.lastError() ) {
chrome.tabs.create(_details);
@@ -209,7 +217,7 @@ vAPI.tabs.remove = function(tabId) {
/******************************************************************************/
-vAPI.tabs.reload = function(tabId, flags) {
+vAPI.tabs.reload = function(tabId /*, flags*/) {
if ( typeof tabId === 'string' ) {
tabId = parseInt(tabId, 10);
}
@@ -272,7 +280,7 @@ vAPI.messaging = {
ports: {},
listeners: {},
defaultHandler: null,
- NOOPFUNC: function(){},
+ NOOPFUNC: noopFunc,
UNHANDLED: 'vAPI.messaging.notHandled'
};
@@ -374,25 +382,84 @@ vAPI.messaging.broadcast = function(message) {
/******************************************************************************/
-vAPI.net = {
- registerListeners: function() {
- var listeners = [
- 'onBeforeRequest',
- 'onBeforeSendHeaders',
- 'onHeadersReceived'
- ];
-
- for ( var i = 0; i < listeners.length; i++ ) {
- chrome.webRequest[listeners[i]].addListener(
- this[listeners[i]].callback,
- {
- 'urls': this[listeners[i]].urls || ['<all_urls>'],
- 'types': this[listeners[i]].types || []
- },
- this[listeners[i]].extra
- );
+vAPI.net = {};
+
+/******************************************************************************/
+
+vAPI.net.registerListeners = function() {
+ var µb = µBlock;
+ var µburi = µb.URI;
+
+ var normalizeRequestDetails = function(details) {
+ µburi.set(details.url);
+
+ details.tabId = details.tabId.toString();
+ details.hostname = µburi.hostnameFromURI(details.url);
+
+ // The rest of the function code is to normalize type
+ var type = details.type;
+ if ( type !== 'other' ) {
+ return;
}
- }
+ var path = µburi.path;
+ var pos = path.lastIndexOf('.');
+ if ( pos === -1 ) {
+ return;
+ }
+ var ext = path.slice(pos) + '.';
+ if ( '.eot.ttf.otf.svg.woff.woff2.'.indexOf(ext) !== -1 ) {
+ details.type = 'font';
+ return;
+ }
+ // Still need this because often behind-the-scene requests are wrongly
+ // categorized as 'other'
+ if ( '.ico.png.gif.jpg.jpeg.webp.'.indexOf(ext) !== -1 ) {
+ details.type = 'image';
+ return;
+ }
+ // https://code.google.com/p/chromium/issues/detail?id=410382
+ if ( type === 'other' ) {
+ details.type = 'object';
+ return;
+ }
+ };
+
+ var onBeforeRequestClient = this.onBeforeRequest.callback;
+ var onBeforeRequest = function(details) {
+ normalizeRequestDetails(details);
+ return onBeforeRequestClient(details);
+ };
+ chrome.webRequest.onBeforeRequest.addListener(
+ onBeforeRequest,
+ {
+ 'urls': this.onBeforeRequest.urls || ['<all_urls>'],
+ 'types': this.onBeforeRequest.types || []
+ },
+ this.onBeforeRequest.extra
+ );
+
+ chrome.webRequest.onBeforeSendHeaders.addListener(
+ this.onBeforeSendHeaders.callback,
+ {
+ 'urls': this.onBeforeSendHeaders.urls || ['<all_urls>'],
+ 'types': this.onBeforeSendHeaders.types || []
+ },
+ this.onBeforeSendHeaders.extra
+ );
+
+ var onHeadersReceivedClient = this.onHeadersReceived.callback;
+ var onHeadersReceived = function(details) {
+ normalizeRequestDetails(details);
+ return onHeadersReceivedClient(details);
+ };
+ chrome.webRequest.onHeadersReceived.addListener(
+ onHeadersReceived,
+ {
+ 'urls': this.onHeadersReceived.urls || ['<all_urls>'],
+ 'types': this.onHeadersReceived.types || []
+ },
+ this.onHeadersReceived.extra
+ );
};
/******************************************************************************/
View
68 platform/firefox/vapi-background.js
@@ -19,7 +19,8 @@
Home: https://github.com/gorhill/uBlock
*/
-/* global punycode */
+/* jshint esnext: true, bitwise: false */
+/* global self, Components, punycode */
// For background page
@@ -45,7 +46,7 @@ vAPI.firefox = true;
// TODO: read these data from somewhere...
vAPI.app = {
name: 'µBlock',
- version: '0.8.5.7'
+ version: '0.8.6.0'
};
/******************************************************************************/
@@ -143,7 +144,7 @@ vAPI.storage = {
sqlWhere: function(col, params) {
if ( params > 0 ) {
- params = Array(params + 1).join('?, ').slice(0, -2);
+ params = new Array(params + 1).join('?, ').slice(0, -2);
return ' WHERE ' + col + ' IN (' + params + ')';
}
@@ -307,19 +308,23 @@ var tabsProgressListener = {
var tabId = vAPI.tabs.getTabId(browser);
+ // LOCATION_CHANGE_SAME_DOCUMENT = "did not load a new document"
if ( flags & 1 ) {
vAPI.tabs.onUpdated(tabId, {url: location.asciiSpec}, {
frameId: 0,
tabId: tabId,
url: browser.currentURI.asciiSpec
});
- } else if ( location.schemeIs('http') || location.schemeIs('https') ) {
- vAPI.tabs.onNavigation({
- frameId: 0,
- tabId: tabId,
- url: location.asciiSpec
- });
+ return;
}
+
+ // https://github.com/gorhill/uBlock/issues/105
+ // Allow any kind of pages
+ vAPI.tabs.onNavigation({
+ frameId: 0,
+ tabId: tabId,
+ url: location.asciiSpec
+ });
}
};
@@ -329,6 +334,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
@@ -777,6 +790,7 @@ var httpObserver = {
contractID: '@' + location.host + '/net-channel-event-sinks;1',
ABORT: Components.results.NS_BINDING_ABORTED,
ACCEPT: Components.results.NS_SUCCEEDED,
+ // Request types: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIContentPolicy#Constants
MAIN_FRAME: Ci.nsIContentPolicy.TYPE_DOCUMENT,
VALID_CSP_TARGETS: 1 << Ci.nsIContentPolicy.TYPE_DOCUMENT |
1 << Ci.nsIContentPolicy.TYPE_SUBDOCUMENT,
@@ -787,7 +801,9 @@ var httpObserver = {
5: 'object',
6: 'main_frame',
7: 'sub_frame',
- 11: 'xmlhttprequest'
+ 11: 'xmlhttprequest',
+ 12: 'object',
+ 14: 'font'
},
lastRequest: {
url: null,
@@ -884,11 +900,12 @@ var httpObserver = {
}
var result = onBeforeRequest.callback({
- url: channel.URI.asciiSpec,
- type: type,
- tabId: details.tabId,
frameId: details.frameId,
- parentFrameId: details.parentFrameId
+ hostname: channel.URI.asciiHost,
+ parentFrameId: details.parentFrameId,
+ tabId: details.tabId,
+ type: type,
+ url: channel.URI.asciiSpec
});
if ( !result || typeof result !== 'object' ) {
@@ -898,7 +915,9 @@ var httpObserver = {
if ( result.cancel === true ) {
channel.cancel(this.ABORT);
return true;
- } else if ( result.redirectUrl ) {
+ }
+
+ if ( result.redirectUrl ) {
channel.redirectionLimit = 1;
channel.redirectTo(
Services.io.newURI(result.redirectUrl, null, null)
@@ -946,10 +965,11 @@ var httpObserver = {
}
result = vAPI.net.onHeadersReceived.callback({
- url: URI.asciiSpec,
- tabId: channelData[1],
+ hostname: URI.asciiHost,
parentFrameId: channelData[0] === this.MAIN_FRAME ? -1 : 0,
- responseHeaders: result ? [{name: topic, value: result}] : []
+ responseHeaders: result ? [{name: topic, value: result}] : [],
+ tabId: channelData[1],
+ url: URI.asciiSpec
});
if ( result ) {
@@ -985,7 +1005,7 @@ var httpObserver = {
// Probably isn't the best method to identify the source tab
if ( tabURI.spec !== lastRequest.openerURL ) {
- continue
+ continue;
}
sourceTabId = vAPI.tabs.getTabId(tab);
@@ -1090,11 +1110,11 @@ vAPI.net.registerListeners = function() {
// data: and about:blank
if ( details.url.charAt(0) !== 'h' ) {
vAPI.net.onBeforeRequest.callback({
- url: 'http://' + details.url.slice(0, details.url.indexOf(':')),
- type: 'main_frame',
- tabId: vAPI.tabs.getTabId(e.target),
frameId: details.frameId,
- parentFrameId: details.parentFrameId
+ parentFrameId: details.parentFrameId,
+ tabId: vAPI.tabs.getTabId(e.target),
+ type: 'main_frame',
+ url: 'http://' + details.url.slice(0, details.url.indexOf(':'))
});
return;
}
@@ -1343,6 +1363,8 @@ vAPI.contextMenu.displayMenuItem = function(e) {
var menuitem = doc.getElementById(vAPI.contextMenu.menuItemId);
var currentURI = gContextMenu.browser.currentURI;
+ // https://github.com/gorhill/uBlock/issues/105
+ // TODO: Should the element picker works on any kind of pages?
if ( !currentURI.schemeIs('http') && !currentURI.schemeIs('https') ) {
menuitem.hidden = true;
return;
View
23 platform/safari/vapi-background.js
@@ -19,7 +19,7 @@
Home: https://github.com/gorhill/uBlock
*/
-/* global µBlock, SafariBrowserTab */
+/* global self, safari, SafariBrowserTab, µBlock */
// For background page
@@ -187,6 +187,14 @@ vAPI.tabs = {
/******************************************************************************/
+vAPI.isNoTabId = function(tabId) {
+ return tabId.toString() === '-1';
+};
+
+vAPI.noTabId = '-1';
+
+/******************************************************************************/
+
vAPI.tabs.registerListeners = function() {
safari.application.addEventListener('beforeNavigate', function(e) {
if ( !vAPI.tabs.popupCandidate || !e.target || e.url === 'about:blank' ) {
@@ -352,7 +360,7 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
}
if ( details.file ) {
- var xhr = new XMLHttpRequest;
+ var xhr = new XMLHttpRequest();
xhr.overrideMimeType('application/x-javascript;charset=utf-8');
xhr.open('GET', details.file, false);
xhr.send();
@@ -583,6 +591,8 @@ vAPI.net = {};
/******************************************************************************/
vAPI.net.registerListeners = function() {
+ var µb = µBlock;
+
// Since it's not used
this.onBeforeSendHeaders = null;
this.onHeadersReceived = null;
@@ -607,9 +617,11 @@ vAPI.net.registerListeners = function() {
}
if ( e.message.isURLWhiteListed ) {
- block = µBlock.URI.hostnameFromURI(e.message.isURLWhiteListed);
- block = µBlock.URI.domainFromHostname(block) || block;
- e.message = !!µBlock.netWhitelist[block];
+ block = µb.URI.hostnameFromURI(e.message.isURLWhiteListed);
+ block = µb.URI.domainFromHostname(block) || block;
+
+ // TODO: revise, this can't work properly
+ e.message = !!µb.netWhitelist[block];
return e.message;
}
@@ -651,6 +663,7 @@ vAPI.net.registerListeners = function() {
return true;
}
+ e.message.hostname = µb.URI.hostnameFromURI(e.message.url);
e.message.tabId = vAPI.tabs.getTabId(e.target);
block = onBeforeRequest(e.message);
View
2 src/devtools.html
@@ -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
2 src/js/async.js
@@ -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
3 src/js/background.js
@@ -21,12 +21,13 @@
/* global vAPI */
/* exported µBlock */
-'use strict';
/******************************************************************************/
var µBlock = (function() {
+'use strict';
+
/******************************************************************************/
var oneSecond = 1000;
View
18 src/js/devtools.js
@@ -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
85 src/js/messaging.js
@@ -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':
@@ -195,6 +197,8 @@ var getStats = function(tabId) {
r.hostnameDict = getHostnameDict(pageStore.hostnameToCountMap);
r.contentLastModified = pageStore.contentLastModified;
r.dynamicFilterRules = getDynamicFilterRules(pageStore.pageHostname, r.hostnameDict);
+ r.canElementPicker = r.pageHostname.indexOf('.') !== -1;
+ r.canRequestLog = canRequestLog;
} else {
r.hostnameDict = {};
r.dynamicFilterRules = getDynamicFilterRules();
@@ -202,6 +206,39 @@ var getStats = function(tabId) {
return r;
};
+// Not the most elegant approach, but it does keep everything simple:
+// This will be set by getTargetTabId() and used by getStats().
+var canRequestLog = true;
+
+/******************************************************************************/
+
+var getTargetTabId = function(tab) {
+ canRequestLog = true;
+
+ if ( !tab ) {
+ return '';
+ }
+
+ if ( tab.url.lastIndexOf(vAPI.getURL('devtools.html'), 0) !== 0 ) {
+ return tab.id;
+ }
+
+ // 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.
+
+ canRequestLog = false;
+
+ // 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) {
@@ -209,8 +246,7 @@ var onMessage = function(request, sender, callback) {
switch ( request.what ) {
case 'getPopupData':
vAPI.tabs.get(null, function(tab) {
- var tabId = tab && tab.id;
- callback(getStats(tabId));
+ callback(getStats(getTargetTabId(tab)));
});
return;
@@ -241,12 +277,11 @@ var onMessage = function(request, sender, callback) {
break;
case 'toggleNetFiltering':
- µb.toggleNetFilteringSwitch(
- request.url,
- request.scope,
- request.state
- );
- µb.updateBadgeAsync(request.tabId);
+ var pageStore = µb.pageStoreFromTabId(request.tabId);
+ if ( pageStore ) {
+ pageStore.toggleNetFilteringSwitch(request.url, request.scope, request.state);
+ µb.updateBadgeAsync(request.tabId);
+ }
break;
default:
@@ -751,7 +786,7 @@ vAPI.messaging.listen('whitelist.js', onMessage);
/******************************************************************************/
/******************************************************************************/
-// stats.js
+// devtools.js
(function() {
@@ -767,22 +802,37 @@ var getPageDetails = function(callback) {
var out = {};
var tabIds = Object.keysb.pageStores);
- var countdown = tabIds.length;
- if ( countdown === 0 ) {
+ // Special case: behind-the-scene virtual tab (does not really exist)
+ var pos = tabIds.indexOf(vAPI.noTabId);
+ if ( pos !== -1 ) {
+ tabIds.splice(pos, 1);
+ out[vAPI.noTabId] = vAPI.i18n('logBehindTheScene');
+ }
+
+ // This can happen
+ 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 to self
+ var devtoolsURL = vAPI.getURL('devtools.html');
+
+ var onTabDetails = function(tab) {
+ if ( tab && tab.url.lastIndexOf(devtoolsURL, 0) !== 0 ) {
+ out[tab.id] = tab.title;
+ }
+ doCountdown();
+ };
+
var i = countdown;
while ( i-- ) {
vAPI.tabs.get(tabIds[i], onTabDetails);
@@ -813,7 +863,7 @@ var onMessage = function(request, sender, callback) {
callback(response);
};
-vAPI.messaging.listen('stats.js', onMessage);
+vAPI.messaging.listen('devtools.js', onMessage);
/******************************************************************************/
@@ -861,6 +911,7 @@ var restoreUserData = function(userData) {
var onAllRemoved = function() {
// Be sure to adjust `countdown` if adding/removing anything below
+ µb.XAL.keyvalSetOne('version', userData.version);
µBlock.saveLocalSettings(onCountdown);
µb.XAL.keyvalSetMany(userData.userSettings, onCountdown);
µb.XAL.keyvalSetOne('remoteBlacklists', userData.filterLists, onCountdown);
View
14 src/js/mirrors.js
@@ -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
39 src/js/pagestore.js
@@ -67,7 +67,6 @@ var logEntryJunkyardMax = 100;
LogEntry.prototype.init = function(details, result) {
this.tstamp = Date.now();
this.url = details.requestURL;
- this.domain = details.requestDomain;
this.hostname = details.requestHostname;
this.type = details.requestType;
this.result = result;
@@ -77,7 +76,7 @@ LogEntry.prototype.init = function(details, result) {
/******************************************************************************/
LogEntry.prototype.dispose = function() {
- this.url = this.domain = this.hostname = this.type = this.result = '';
+ this.url = this.hostname = this.type = this.result = '';
if ( logEntryJunkyard.length < logEntryJunkyardMax ) {
logEntryJunkyard.push(this);
}
@@ -262,7 +261,6 @@ NetFilteringResultCacheEntry.factory = function(result, type) {
/******************************************************************************/
// To mitigate memory churning
-var uidGenerator = 1;
var netFilteringCacheJunkyard = [];
var netFilteringCacheJunkyardMax = 10;
@@ -297,18 +295,7 @@ NetFilteringResultCache.prototype.init = function() {
/******************************************************************************/
NetFilteringResultCache.prototype.dispose = function() {
- for ( var key in this.urls ) {
- if ( this.urls.hasOwnProperty(key) === false ) {
- continue;
- }
- this.urls[key].dispose();
- }
- this.urls = {};
- this.count = 0;
- if ( this.timer !== null ) {
- clearTimeout(this.timer);
- this.timer = null;
- }
+ this.empty();
this.boundPruneAsyncCallback = null;
if ( netFilteringCacheJunkyard.length < netFilteringCacheJunkyardMax ) {
netFilteringCacheJunkyard.push(this);
@@ -337,8 +324,19 @@ NetFilteringResultCache.prototype.add = function(context, result) {
/******************************************************************************/
-NetFilteringResultCache.prototype.fetchAll = function() {
- return this.urls;
+NetFilteringResultCache.prototype.empty = function() {
+ for ( var key in this.urls ) {
+ if ( this.urls.hasOwnProperty(key) === false ) {
+ continue;
+ }
+ this.urls[key].dispose();
+ }
+ this.urls = {};
+ this.count = 0;
+ if ( this.timer !== null ) {
+ clearTimeout(this.timer);
+ this.timer = null;
+ }
};
/******************************************************************************/
@@ -610,6 +608,13 @@ PageStore.prototype.getCosmeticFilteringSwitch = function() {
/******************************************************************************/
+PageStore.prototype.toggleNetFilteringSwitch = function(url, scope, state) {
+ µb.toggleNetFilteringSwitch(url, scope, state);
+ this.netFilteringCache.empty();
+};
+
+/******************************************************************************/
+
PageStore.prototype.filterRequest = function(context) {
if ( this.getNetFilteringSwitch() === false ) {
this.cacheResult(context, '');
View
18 src/js/popup.js
@@ -298,23 +298,13 @@ var buildAllDynamicFilters = function() {
var renderPopup = function() {
uDom('#appname').text(popupData.appName);
uDom('#version').text(popupData.appVersion);
-
- var isHTTP = /^https?:\/\/[0-9a-z]/.test(popupData.pageURL);
-
- // Condition for dynamic filtering toggler:
- // - Advanced user
uDom('body').toggleClass('advancedUser', popupData.advancedUserEnabled);
-
uDom('#switch').toggleClass('off', popupData.pageURL === '' || !popupData.netFilteringSwitch);
- // Conditions for request log:
- // - `http` or `https` scheme
- uDom('#gotoLog').toggleClass('enabled', isHTTP);
- uDom('#gotoLog').attr('href', 'devtools.html?tabId=' + popupData.tabId);
-
- // Conditions for element picker:
- // - `http` or `https` scheme
- uDom('#gotoPick').toggleClass('enabled', isHTTP);
+ // If you think the `=== true` is pointless, you are mistaken
+ uDom('#gotoLog').toggleClass('enabled', popupData.canRequestLog === true)
+ .attr('href', 'devtools.html?tabId=' + popupData.tabId);
+ uDom('#gotoPick').toggleClass('enabled', popupData.canElementPicker === true);
var or = vAPI.i18n('popupOr');
var blocked = popupData.pageBlockedRequestCount;
View
14 src/js/static-net-filtering.js
@@ -68,6 +68,7 @@ var typeNameToTypeValue = {
'inline-script': 14 << 4,
'popup': 15 << 4
};
+var typeOtherToTypeValue = typeNameToTypeValue.other;
const BlockAnyTypeAnyParty = BlockAction | AnyType | AnyParty;
const BlockAnyType = BlockAction | AnyType;
@@ -1754,9 +1755,11 @@ FilterContainer.prototype.matchStringExactType = function(context, requestURL, r
// This will be used by hostname-based filters
pageHostname = context.pageHostname || '';
- var type = typeNameToTypeValue[requestType];
- var categories = this.categories;
+ // Be prepared to support unknown types
+ var bf = false;
var bucket;
+ var categories = this.categories;
+ var type = typeNameToTypeValue[requestType] || typeOtherToTypeValue;
// Tokenize only once
this.tokenize(url);
@@ -1777,7 +1780,6 @@ FilterContainer.prototype.matchStringExactType = function(context, requestURL, r
}
// Test against block filters
- bf = false;
if ( bucket = categories[this.makeCategoryKey(BlockAnyParty | type)] ) {
bf = this.matchTokens(bucket, url);
}
@@ -1814,7 +1816,8 @@ FilterContainer.prototype.matchStringExactType = function(context, requestURL, r
FilterContainer.prototype.matchString = function(context) {
// https://github.com/gorhill/uBlock/issues/519
// Use exact type match for anything beyond `other`
- var type = typeNameToTypeValue[context.requestType];
+ // Also, be prepared to support unknown types
+ var type = typeNameToTypeValue[context.requestType] || typeOtherToTypeValue;
if ( type > 8 << 4 ) {
return this.matchStringExactType(context, context.requestURL, context.requestType);
}
@@ -1852,12 +1855,13 @@ FilterContainer.prototype.matchString = function(context) {
// This will be used by hostname-based filters
pageHostname = context.pageHostname || '';
+ var bf, bucket;
var categories = this.categories;
- var bucket;
// Tokenize only once
this.tokenize(url);
+
// https://github.com/gorhill/uBlock/issues/139
// Test against important block filters.
// The purpose of the `important` option is to reverse the order of
View
44 src/js/storage.js
@@ -66,9 +66,7 @@
/******************************************************************************/
µBlock.saveUserSettings = function() {
- vAPI.storage.set(this.userSettings, function() {
- µBlock.getBytesInUse();
- });
+ vAPI.storage.set(this.userSettings);
};
/******************************************************************************/
@@ -97,9 +95,7 @@
var bin = {
'netWhitelist': this.stringFromWhitelist(this.netWhitelist)
};
- vAPI.storage.set(bin, function() {
- µBlock.getBytesInUse();
- });
+ vAPI.storage.set(bin);
this.netWhitelistModifyTime = Date.now();
};
@@ -128,7 +124,7 @@
};
var bin = {
- 'netWhitelist': '',
+ 'netWhitelist': 'behind-the-scene',
'netExceptionList': ''
};
vAPI.storage.get(bin, onWhitelistLoaded);
@@ -595,18 +591,10 @@
var µb = this;
var fromSelfie = false;
- // Filter lists
- // Whitelist
- var countdown = 2;
-
// Final initialization steps after all needed assets are in memory.
// - Initialize internal state with maybe already existing tabs.
// - Schedule next update operation.
- var doCountdown = function() {
- countdown -= 1;
- if ( countdown !== 0 ) {
- return;
- }
+ var onAllReady = function() {
// https://github.com/gorhill/uBlock/issues/426
// Important: remove barrier to remote fetching, this was useful only
// for launch time.
@@ -619,6 +607,29 @@
µb.updater.restartb.firstUpdateAfter);
};
+ // To bring older versions up to date
+ var onVersionReady = function(bin) {
+ var lastVersion = bin.version || '0.0.0.0';
+ // Whitelist behind-the-scene scope by default
+ if ( lastVersion.localeCompare('0.8.6.0') < 0 ) {
+ µb.toggleNetFilteringSwitch('http://behind-the-scene/', 'site', false);
+ }
+ vAPI.storage.set({ version: vAPI.app.version });
+ onAllReady();
+ };
+
+ // Filter lists
+ // Whitelist
+ var countdown = 2;
+ var doCountdown = function() {
+ countdown -= 1;
+ if ( countdown !== 0 ) {
+ return;
+ }
+ // Last step: do whatever is necessary when version changes
+ vAPI.storage.get('version', onVersionReady);
+ };
+
// Filters are in memory.
// Filter engines need PSL to be ready.
var onFiltersReady = function() {
@@ -689,5 +700,4 @@
this.loadUserSettings(onUserSettingsReady);
this.loadWhitelist(onWhitelistReady);
this.loadLocalSettings();
- this.getBytesInUse();
};
View
34 src/js/tab.js
@@ -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 === '' ) {
@@ -195,6 +204,15 @@ vAPI.tabs.registerListeners();
};
/******************************************************************************/
+
+// 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)
+);
+
+/******************************************************************************/
/******************************************************************************/
// Stale page store entries janitor
@@ -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
41 src/js/traffic.js
@@ -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;
@@ -61,26 +56,6 @@ var onBeforeRequest = function(details) {
return;
}
- // Commented out until (and if ever) there is a fix for:
- // https://code.google.com/p/chromium/issues/detail?id=410382
- //
- // Try to transpose generic `other` category into something more meaningful.
- if ( requestType === 'other' ) {
- requestType = µb.transposeType('other', µb.URI.set(requestURL).path);
- // https://github.com/gorhill/uBlock/issues/206
- // https://code.google.com/p/chromium/issues/detail?id=410382
- // Work around the issue of Chromium not properly setting the type for
- // `object` requests. Unclear whether this issue will be fixed, hence
- // this workaround to prevent torch-and-pitchfork mobs because ads are
- // no longer blocked in videos.
- // https://github.com/gorhill/uBlock/issues/281
- // Looks like Chrome 38 (but not 39) doesn't provide the expected request
- // header `X-Requested-With`. Sigh.
- if ( requestType === 'other' ) {
- requestType = 'object';
- }
- }
-
// Lookup the page store associated with this tab id.
pageStore = µb.pageStoreFromTabId(tabId);
if ( !pageStore ) {
@@ -99,7 +74,7 @@ var onBeforeRequest = function(details) {
// Setup context and evaluate
requestContext.requestURL = requestURL;
- requestContext.requestHostname = µb.URI.hostnameFromURI(requestURL);
+ requestContext.requestHostname = details.hostname;
requestContext.requestType = requestType;
var result = pageStore.filterRequest(requestContext);
@@ -222,7 +197,7 @@ var onBeforeSendHeaders = function(details) {
var result = µb.staticNetFilteringEngine.matchStringExactType(pageDetails, requestURL, 'popup');
// Not blocked?
- if ( result === '' || result.slice(0, 2) === '@@' ) {
+ if ( µb.isAllowResult(result) ) {
return;
}
@@ -259,8 +234,7 @@ var onHeadersReceived = function(details) {
//}
var requestURL = details.url;
- var requestHostname = µb.URI.hostnameFromURI(requestURL);
- var requestDomain = µb.URI.domainFromHostname(requestHostname);
+ var requestHostname = details.hostname;
// https://github.com/gorhill/uBlock/issues/525
// When we are dealing with the root frame, due to fix to issue #516, it
@@ -271,11 +245,12 @@ var onHeadersReceived = function(details) {
// inline scripts.
var context;
if ( details.parentFrameId === -1 ) {
+ var contextDomain = µb.URI.domainFromHostname(requestHostname);
context = {
rootHostname: requestHostname,
- rootDomain: requestDomain,
+ rootDomain: contextDomain,
pageHostname: requestHostname,
- pageDomain: requestDomain
+ pageDomain: contextDomain
};
} else {
context = pageStore;
@@ -287,7 +262,6 @@ var onHeadersReceived = function(details) {
// URLs-different type
context.requestURL = requestURL + '{inline-script}';
context.requestHostname = requestHostname;
- context.requestDomain = requestDomain;
context.requestType = 'inline-script';
var result = pageStore.filterRequest(context);
@@ -325,10 +299,9 @@ var headerValue = function(headers, name) {
/******************************************************************************/
var headerStartsWith = function(headers, prefix) {
- var prefixLen = prefix.length;
var i = headers.length;
while ( i-- ) {
- if ( headers[i].name.slice(0, prefixLen).toLowerCase() === prefix ) {
+ if ( headers[i].name.toLowerCase().lastIndexOf(prefix, 0) === 0 ) {
return headers[i].value;
}
}
View
20 src/js/ublock.js
@@ -281,26 +281,6 @@ var matchWhitelistDirective = function(url, hostname, directive) {
/******************************************************************************/
Block.transposeType = function(type, path) {
- if ( type !== 'other' ) {
- return type;
- }
- var pos = path.lastIndexOf('.');
- if ( pos === -1 ) {
- return type;
- }
- var ext = path.slice(pos) + '.';
- if ( '.css.eot.ttf.otf.svg.woff.woff2.'.indexOf(ext) !== -1 ) {
- return 'stylesheet';
- }
- if ( '.ico.png.gif.jpg.jpeg.'.indexOf(ext) !== -1 ) {
- return 'image';
- }
- return type;
-};
-
-/******************************************************************************/
-
µBlock.elementPickerExec = function(tabId, targetElement) {
this.elementPickerTarget = targetElement || '';
vAPI.tabs.injectScript(tabId, { file: 'js/element-picker.js' });
Something went wrong with that request. Please try again.