diff --git a/platform/chromium/vapi-background.js b/platform/chromium/vapi-background.js
index c556ee59d..a4e341bd7 100644
--- a/platform/chromium/vapi-background.js
+++ b/platform/chromium/vapi-background.js
@@ -282,21 +282,12 @@ vAPI.tabs = {};
/******************************************************************************/
-// https://github.com/gorhill/uBlock/issues/3546
-// Added a new flavor of behind-the-scene tab id: vAPI.anyTabId.
-// vAPI.anyTabId will be used for network requests which can be filtered,
-// because they comes with enough contextual information. It's just not
-// possible to pinpoint exactly from which tab it comes from. For example,
-// with Firefox/webext, the `documentUrl` property is available for every
-// network requests.
-
vAPI.isBehindTheSceneTabId = function(tabId) {
return tabId < 0;
};
vAPI.unsetTabId = 0;
vAPI.noTabId = -1; // definitely not any existing tab
-vAPI.anyTabId = -2; // one of the existing tab
/******************************************************************************/
diff --git a/platform/chromium/vapi-webrequest.js b/platform/chromium/vapi-webrequest.js
index f9a8d97f5..e949b01dd 100644
--- a/platform/chromium/vapi-webrequest.js
+++ b/platform/chromium/vapi-webrequest.js
@@ -74,11 +74,9 @@
// Chromium 63+ supports the `initiator` property, which contains
// the URL of the origin from which the network request was made.
if (
- details.tabId === vAPI.noTabId &&
typeof details.initiator === 'string' &&
details.initiator !== 'null'
) {
- details.tabId = vAPI.anyTabId;
details.documentUrl = details.initiator;
}
diff --git a/platform/firefox/vapi-webrequest.js b/platform/firefox/vapi-webrequest.js
index 398d853bb..c2c1c9043 100644
--- a/platform/firefox/vapi-webrequest.js
+++ b/platform/firefox/vapi-webrequest.js
@@ -1,7 +1,7 @@
/*******************************************************************************
uBlock Origin - a browser extension to block requests.
- Copyright (C) 2017-2018 Raymond Hill
+ Copyright (C) 2017-present 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
@@ -66,13 +66,6 @@
let parsedURL = new URL('about:blank');
vAPI.net.normalizeDetails = function(details) {
- if (
- details.tabId === vAPI.noTabId &&
- typeof details.documentUrl === 'string'
- ) {
- details.tabId = vAPI.anyTabId;
- }
-
if ( mustPunycode && !reAsciiHostname.test(details.url) ) {
parsedURL.href = details.url;
details.url = details.url.replace(
diff --git a/platform/webext/vapi-webrequest.js b/platform/webext/vapi-webrequest.js
index a388adcc0..92f902d02 100644
--- a/platform/webext/vapi-webrequest.js
+++ b/platform/webext/vapi-webrequest.js
@@ -85,13 +85,11 @@ vAPI.net.registerListeners = function() {
// Chromium uses `initiator` property.
if (
details.documentUrl === undefined &&
- typeof details.initiator === 'string'
+ typeof details.initiator === 'string' &&
+ details.initiator !== 'null'
) {
details.documentUrl = details.initiator;
}
- if ( typeof details.documentUrl === 'string' ) {
- details.tabId = vAPI.anyTabId;
- }
}
// https://github.com/gorhill/uBlock/issues/1493
diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json
index 0ce842287..07c262708 100644
--- a/src/_locales/en/messages.json
+++ b/src/_locales/en/messages.json
@@ -536,7 +536,7 @@
"description":"Appears in the logger's tab selector"
},
"logBehindTheScene":{
- "message":"Behind the scene",
+ "message":"Tabless",
"description":"Pretty name for behind-the-scene network requests"
},
"loggerCurrentTab":{
diff --git a/src/background.html b/src/background.html
index fa1327b31..29b9a2970 100644
--- a/src/background.html
+++ b/src/background.html
@@ -20,6 +20,7 @@
+
diff --git a/src/css/logger-ui.css b/src/css/logger-ui.css
index 925f52f98..a2170377b 100644
--- a/src/css/logger-ui.css
+++ b/src/css/logger-ui.css
@@ -16,9 +16,11 @@ textarea {
width: 100%;
}
.permatoolbar {
+ align-items: center;
background-color: white;
border: 0;
box-sizing: border-box;
+ display: flex;
font-size: 120%;
left: 0;
margin: 0;
@@ -28,14 +30,15 @@ textarea {
z-index: 10;
}
.permatoolbar .button {
+ align-items: center;
background-color: white;
border: none;
box-sizing: border-box;
cursor: pointer;
- display: inline-block;
+ display: inline-flex;
font-size: 150%;
margin: 0;
- padding: 8px;
+ padding: 0.25em;
}
.permatoolbar .button.disabled {
opacity: 0.2;
@@ -54,8 +57,14 @@ textarea {
vertical-align: middle;
}
#pageSelector {
+ margin-right: 1em;
+ padding: 0.25em 0;
width: 28em;
- padding: 0.2em 0;
+ }
+#showpopup img {
+ filter: grayscale(100%);
+ height: auto;
+ width: 1em;
}
/*
@@ -128,19 +137,22 @@ textarea {
width: 4.6em;
}
#netInspector table > colgroup > col:nth-of-type(2) {
- width: 2.1em;
+ width: 16%;
}
#netInspector table > colgroup > col:nth-of-type(3) {
- width: 20%;
- }
-#netInspector table > colgroup > col:nth-of-type(4) {
width: 2.1em;
}
+#netInspector table > colgroup > col:nth-of-type(4) {
+ width: 20%;
+ }
#netInspector table > colgroup > col:nth-of-type(5) {
- width: 5.8em;
+ width: 2.4em;
}
#netInspector table > colgroup > col:nth-of-type(6) {
- width: calc(100% - 14.6em - 20%);
+ width: 6em;
+ }
+#netInspector table > colgroup > col:nth-of-type(7) {
+ width: calc(100% - 4.6em - 16% - 2.1em - 20% - 2.4em - 6em);
}
#netInspector.f table tr.f {
display: none;
@@ -205,6 +217,12 @@ body #netInspector td {
text-overflow: ellipsis;
white-space: nowrap;
}
+#netInspector tr[data-tabid].void {
+ opacity: 0.3;
+ }
+#netInspector tr[data-tabid].void:hover {
+ opacity: 0.7;
+ }
#netInspector tr td:nth-of-type(1) {
cursor: default;
@@ -212,68 +230,71 @@ body #netInspector td {
white-space: nowrap;
}
#netInspector tr td:nth-of-type(2) {
- text-align: center;
- white-space: nowrap;
}
-#netInspector tr.tab_bts > td:nth-of-type(2):before {
- content: '\f070';
- font: 1em FontAwesome;
- }
-#netInspector tr.tab:not(.canMtx) {
- opacity: 0.3;
- }
-#netInspector tr.tab:not(.canMtx):hover {
- opacity: 0.7;
- }
-#netInspector tr.tab:not(.canMtx) > td:nth-of-type(2):before {
- content: '\f00d';
- font: 1em FontAwesome;
- }
-body:not(.popupOn) #netInspector tr.canMtx td:nth-of-type(2) {
+#netInspector tr.canLookup td:nth-of-type(2) {
cursor: zoom-in;
}
-body:not(.popupOn) #netInspector tr.canMtx td:nth-of-type(2):hover {
- background: #ccc;
- }
-#netInspector tr.canLookup td:nth-of-type(3) {
- cursor: zoom-in;
- }
-#netInspector tr.cat_net td:nth-of-type(4),
-#netInspector tr.cat_cosmetic td:nth-of-type(4),
-#netInspector tr.cat_redirect td:nth-of-type(4) {
+#netInspector tr.cat_net td:nth-of-type(3),
+#netInspector tr.cat_cosmetic td:nth-of-type(3),
+#netInspector tr.cat_redirect td:nth-of-type(3) {
font: 12px monospace;
text-align: center;
white-space: nowrap;
}
-#netInspector tr.cat_net td:nth-of-type(4) {
+#netInspector tr.cat_net td:nth-of-type(3) {
cursor: pointer;
- position: relative;
}
-#netInspector tr.cat_net td:nth-of-type(4):hover {
+#netInspector tr.cat_net td:nth-of-type(3):hover {
background: #ccc;
}
-#netInspector tr.cat_net td:nth-of-type(6) > span > b {
+#netInspector tr td:nth-of-type(4) {
+ }
+#netInspector tr[data-dochn] td:nth-of-type(4) {
+ direction: rtl;
+ }
+#netInspector tr td:nth-of-type(5) {
+ cursor: default;
+ position: relative;
+ text-align: center;
+ }
+#netInspector tr.tab_bts td:nth-of-type(5)::after {
+ border: 5px solid #bbb;
+ border-bottom: 0;
+ border-top: 0;
+ bottom: 0;
+ content: '\00a0';
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: calc(100% - 10px);
+ z-index: -1;
+ }
+#netInspector tr td:nth-of-type(6) {
+ text-align: right;
+ }
+#netInspector tr.cat_net td:nth-of-type(7) > span > b {
font-weight: bold;
}
-#netInspector tr td:nth-of-type(6) b {
+#netInspector tr td:nth-of-type(7) b {
font-weight: normal;
}
-#netInspector tr.blocked td:nth-of-type(6) b {
+#netInspector tr.blocked td:nth-of-type(7) b {
background-color: rgba(192, 0, 0, 0.2);
}
-body.colorBlind #netInspector tr.blocked td:nth-of-type(6) b {
+body.colorBlind #netInspector tr.blocked td:nth-of-type(7) b {
background-color: rgba(0, 19, 110, 0.2);
}
-#netInspector tr.nooped td:nth-of-type(6) b {
+#netInspector tr.nooped td:nth-of-type(7) b {
background-color: rgba(108, 108, 108, 0.2);
}
-body.colorBlind #netInspector tr.nooped td:nth-of-type(6) b {
+body.colorBlind #netInspector tr.nooped td:nth-of-type(7) b {
background-color: rgba(96, 96, 96, 0.2);
}
-#netInspector tr.allowed td:nth-of-type(6) b {
+#netInspector tr.allowed td:nth-of-type(7) b {
background-color: rgba(0, 160, 0, 0.2);
}
-body.colorBlind #netInspector tr.allowed td:nth-of-type(6) b {
+body.colorBlind #netInspector tr.allowed td:nth-of-type(7) b {
background-color: rgba(255, 194, 57, 0.2);
}
@@ -281,49 +302,17 @@ body.colorBlind #netInspector tr.allowed td:nth-of-type(6) b {
background: white;
border: 1px solid gray;
border-radius: 3px;
+ bottom: 0;
box-sizing: border-box;
display: none;
overflow: hidden;
position: fixed;
right: 0;
- top: 0;
z-index: 200;
}
-#netInspector.popupOn #popupContainer {
+#inspectors.popupOn #popupContainer {
display: block;
}
-#popupContainer > div {
- background: #aaa;
- border: 0;
- }
-body[dir="ltr"] #popupContainer > div {
- text-align: right;
- }
-body[dir="rtl"] #popupContainer > div {
- text-align: left;
- }
-#popupContainer > div > span {
- color: #eee;
- cursor: pointer;
- display: inline-block;
- font: 14px FontAwesome;
- padding: 0 3px;
- }
-#popupContainer > div > span:hover {
- color: white;
- }
-#popupContainer > iframe {
- border: 0;
- padding: 0;
- margin: 0;
- width: 100%;
- }
-#popupContainer.hide {
- width: 6em !important;
- }
-#popupContainer.hide > iframe {
- display: none;
- }
.modalDialog {
align-items: center;
diff --git a/src/js/assets.js b/src/js/assets.js
index cd1869249..b80c6ba21 100644
--- a/src/js/assets.js
+++ b/src/js/assets.js
@@ -27,13 +27,12 @@
/******************************************************************************/
-var reIsExternalPath = /^(?:[a-z-]+):\/\//,
+const reIsExternalPath = /^(?:[a-z-]+):\/\//,
reIsUserAsset = /^user-/,
errorCantConnectTo = vAPI.i18n('errorCantConnectTo'),
noopfunc = function(){};
-var api = {
-};
+const api = {};
/******************************************************************************/
@@ -64,14 +63,14 @@ var fireNotification = function(topic, details) {
/******************************************************************************/
api.fetchText = function(url, onLoad, onError) {
- var isExternal = reIsExternalPath.test(url),
- actualUrl = isExternal ? url : vAPI.getURL(url);
+ const isExternal = reIsExternalPath.test(url);
+ let actualUrl = isExternal ? url : vAPI.getURL(url);
// https://github.com/gorhill/uBlock/issues/2592
// Force browser cache to be bypassed, but only for resources which have
// been fetched more than one hour ago.
if ( isExternal ) {
- var queryValue = '_=' + Math.floor(Date.now() / 7200000);
+ const queryValue = '_=' + Math.floor(Date.now() / 7200000);
if ( actualUrl.indexOf('?') === -1 ) {
actualUrl += '?';
} else {
@@ -84,12 +83,12 @@ api.fetchText = function(url, onLoad, onError) {
onError = onLoad;
}
- var contentLoaded = 0,
- timeoutAfter = µBlock.hiddenSettings.assetFetchTimeout * 1000 || 30000,
- timeoutTimer,
- xhr = new XMLHttpRequest();
+ const timeoutAfter = µBlock.hiddenSettings.assetFetchTimeout * 1000 || 30000;
+ const xhr = new XMLHttpRequest();
+ let contentLoaded = 0;
+ let timeoutTimer;
- var cleanup = function() {
+ const cleanup = function() {
xhr.removeEventListener('load', onLoadEvent);
xhr.removeEventListener('error', onErrorEvent);
xhr.removeEventListener('abort', onErrorEvent);
@@ -101,11 +100,11 @@ api.fetchText = function(url, onLoad, onError) {
};
// https://github.com/gorhill/uMatrix/issues/15
- var onLoadEvent = function() {
+ const onLoadEvent = function() {
cleanup();
// xhr for local files gives status 0, but actually succeeds
- var details = {
- url: url,
+ const details = {
+ url,
content: '',
statusCode: this.status || 200,
statusText: this.statusText || ''
@@ -120,7 +119,7 @@ api.fetchText = function(url, onLoad, onError) {
// we never download anything else than plain text: discard if response
// appears to be a HTML document: could happen when server serves
// some kind of error page I suppose
- var text = this.responseText.trim();
+ const text = this.responseText.trim();
if ( text.startsWith('<') && text.endsWith('>') ) {
return onError.call(null, details);
}
@@ -128,19 +127,21 @@ api.fetchText = function(url, onLoad, onError) {
onLoad(details);
};
- var onErrorEvent = function() {
+ const onErrorEvent = function() {
cleanup();
- µBlock.logger.writeOne('', 'error', errorCantConnectTo.replace('{{msg}}', actualUrl));
- onError({ url: url, content: '' });
+ µBlock.logger.writeOne({
+ error: errorCantConnectTo.replace('{{msg}}', actualUrl)
+ });
+ onError({ url, content: '' });
};
- var onTimeout = function() {
+ const onTimeout = function() {
xhr.abort();
};
// https://github.com/gorhill/uBlock/issues/2526
// - Timeout only when there is no progress.
- var onProgressEvent = function(ev) {
+ const onProgressEvent = function(ev) {
if ( ev.loaded === contentLoaded ) { return; }
contentLoaded = ev.loaded;
if ( timeoutTimer !== undefined ) {
diff --git a/src/js/cosmetic-filtering.js b/src/js/cosmetic-filtering.js
index eb59ecea3..3b9d0f184 100644
--- a/src/js/cosmetic-filtering.js
+++ b/src/js/cosmetic-filtering.js
@@ -1,7 +1,7 @@
/*******************************************************************************
uBlock Origin - a browser extension to block requests.
- Copyright (C) 2014-2018 Raymond Hill
+ Copyright (C) 2014-present 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
@@ -579,8 +579,11 @@ FilterContainer.prototype.compileGenericSelector = function(parsed, writer) {
/******************************************************************************/
-FilterContainer.prototype.compileGenericHideSelector = function(parsed, writer) {
- let selector = parsed.suffix;
+FilterContainer.prototype.compileGenericHideSelector = function(
+ parsed,
+ writer
+) {
+ const selector = parsed.suffix;
// For some selectors, it is mandatory to have a hostname or entity:
// ##.foo:-abp-contains(...)
@@ -596,18 +599,16 @@ FilterContainer.prototype.compileGenericHideSelector = function(parsed, writer)
// ##:xpath(...)
// ##.foo:style(...)
if ( this.reNeedHostname.test(selector) ) {
- µb.logger.writeOne(
- '',
- 'error',
- 'Cosmetic filtering – invalid generic filter: ##' + selector
- );
+ µb.logger.writeOne({
+ error: 'Cosmetic filtering – invalid generic filter: ##' + selector
+ });
return;
}
let type = selector.charCodeAt(0);
if ( type === 0x23 /* '#' */ ) {
- let key = this.keyFromSelector(selector);
+ const key = this.keyFromSelector(selector);
if ( key === undefined ) { return; }
// Simple selector-based CSS rule: no need to test for whether the
// selector is valid, the regex took care of this. Most generic
@@ -624,7 +625,7 @@ FilterContainer.prototype.compileGenericHideSelector = function(parsed, writer)
}
if ( type === 0x2E /* '.' */ ) {
- let key = this.keyFromSelector(selector);
+ const key = this.keyFromSelector(selector);
if ( key === undefined ) { return; }
// Simple selector-based CSS rule: no need to test for whether the
// selector is valid, the regex took care of this. Most generic
@@ -640,16 +641,16 @@ FilterContainer.prototype.compileGenericHideSelector = function(parsed, writer)
return;
}
- let compiled = µb.staticExtFilteringEngine.compileSelector(selector);
+ const compiled = µb.staticExtFilteringEngine.compileSelector(selector);
if ( compiled === undefined ) { return; }
// TODO: Detect and error on procedural cosmetic filters.
// https://github.com/gorhill/uBlock/issues/909
// Anything which contains a plain id/class selector can be classified
// as a low generic cosmetic filter.
- let matches = this.rePlainSelectorEx.exec(selector);
+ const matches = this.rePlainSelectorEx.exec(selector);
if ( matches !== null ) {
- let key = matches[1] || matches[2];
+ const key = matches[1] || matches[2];
type = key.charCodeAt(0);
writer.push([
type === 0x23 ? 1 : 3 /* lg+ */,
diff --git a/src/js/filtering-context.js b/src/js/filtering-context.js
new file mode 100644
index 000000000..8c0855c82
--- /dev/null
+++ b/src/js/filtering-context.js
@@ -0,0 +1,282 @@
+/*******************************************************************************
+
+ uBlock Origin - a browser extension to block requests.
+ Copyright (C) 2018-present 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see {http://www.gnu.org/licenses/}.
+
+ Home: https://github.com/gorhill/uBlock
+*/
+
+'use strict';
+
+/******************************************************************************/
+
+µBlock.FilteringContext = function(other) {
+ if ( other instanceof µBlock.FilteringContext ) {
+ return this.fromFilteringContext(other);
+ }
+ this.tstamp = 0;
+ this.realm = '';
+ this.type = undefined;
+ this.url = undefined;
+ this.hostname = undefined;
+ this.domain = undefined;
+ this.docId = undefined;
+ this.docOrigin = undefined;
+ this.docHostname = undefined;
+ this.docDomain = undefined;
+ this.tabId = undefined;
+ this.tabOrigin = undefined;
+ this.tabHostname = undefined;
+ this.tabDomain = undefined;
+ this.filter = undefined;
+};
+
+µBlock.FilteringContext.prototype = {
+ fromTabId: function(tabId) {
+ if ( tabId !== -1 || tabId !== this.tabId ) {
+ const tabContext = µBlock.tabContextManager.mustLookup(tabId);
+ this.tabOrigin = tabContext.origin;
+ this.tabHostname = tabContext.rootHostname;
+ this.tabDomain = tabContext.rootDomain;
+ this.tabId = tabId;
+ }
+ return this;
+ },
+ fromWebrequestDetails: function(details) {
+ const tabId = details.tabId;
+ if ( tabId > 0 && details.type === 'main_frame' ) {
+ µBlock.tabContextManager.push(tabId, details.url);
+ }
+ this.fromTabId(tabId);
+ this.realm = '';
+ this.type = details.type;
+ this.setURL(details.url);
+ this.docId = details.type !== 'sub_frame'
+ ? details.frameId
+ : details.parentFrameId;
+ if ( this.tabId > 0 ) {
+ if ( this.docId === 0 ) {
+ this.docOrigin = this.tabOrigin;
+ this.docHostname = this.tabHostname;
+ this.docDomain = this.tabDomain;
+ } else if ( details.documentUrl !== undefined ) {
+ this.setDocOriginFromURL(details.documentUrl);
+ } else {
+ const pageStore = µBlock.pageStoreFromTabId(this.docId);
+ const docStore = pageStore && pageStore.frames.get(this.docId);
+ if ( docStore ) {
+ this.docOrigin = undefined;
+ this.docHostname = docStore.pageHostname;
+ this.docDomain = docStore.pageDomain;
+ }
+ }
+ } else if ( details.documentUrl !== undefined ) {
+ this.setTabOriginFromURL(details.documentUrl);
+ this.setDocOriginFromURL(details.documentUrl);
+ } else {
+ this.setDocOrigin(this.tabOrigin);
+ }
+ this.filter = undefined;
+ return this;
+ },
+ fromFilteringContext: function(other) {
+ this.realm = other.realm;
+ this.type = other.type;
+ this.url = other.url;
+ this.hostname = other.hostname;
+ this.domain = other.domain;
+ this.docId = other.docId;
+ this.docOrigin = other.docOrigin;
+ this.docHostname = other.docHostname;
+ this.docDomain = other.docDomain;
+ this.tabId = other.tabId;
+ this.tabOrigin = other.tabOrigin;
+ this.tabHostname = other.tabHostname;
+ this.tabDomain = other.tabDomain;
+ this.filter = undefined;
+ return this;
+ },
+ duplicate: function() {
+ return (new µBlock.FilteringContext(this));
+ },
+ setRealm: function(a) {
+ this.realm = a;
+ return this;
+ },
+ setType: function(a) {
+ this.type = a;
+ return this;
+ },
+ setURL: function(a) {
+ if ( a !== this.url ) {
+ this.hostname = this.domain = undefined;
+ this.url = a;
+ }
+ return this;
+ },
+ getHostname: function() {
+ if ( this.hostname === undefined ) {
+ this.hostname = this.hostnameFromURI(this.url);
+ }
+ return this.hostname;
+ },
+ setHostname: function(a) {
+ if ( a !== this.hostname ) {
+ this.domain = undefined;
+ this.hostname = a;
+ }
+ return this;
+ },
+ getDomain: function() {
+ if ( this.domain === undefined ) {
+ this.domain = this.domainFromHostname(this.getHostname());
+ }
+ return this.domain;
+ },
+ setDomain: function(a) {
+ this.domain = a;
+ return this;
+ },
+ getDocOrigin: function() {
+ if ( this.docOrigin === undefined ) {
+ this.docOrigin = this.tabOrigin;
+ }
+ return this.docOrigin;
+ },
+ setDocOrigin: function(a) {
+ if ( a !== this.docOrigin ) {
+ this.docHostname = this.docDomain = undefined;
+ this.docOrigin = a;
+ }
+ return this;
+ },
+ setDocOriginFromURL: function(a) {
+ return this.setDocOrigin(this.originFromURI(a));
+ },
+ getDocHostname: function() {
+ if ( this.docHostname === undefined ) {
+ this.docHostname = this.hostnameFromURI(this.getDocOrigin());
+ }
+ return this.docHostname;
+ },
+ setDocHostname: function(a) {
+ if ( a !== this.docHostname ) {
+ this.docDomain = undefined;
+ this.docHostname = a;
+ }
+ return this;
+ },
+ getDocDomain: function() {
+ if ( this.docDomain === undefined ) {
+ this.docDomain = this.domainFromHostname(this.getDocHostname());
+ }
+ return this.docDomain;
+ },
+ setDocDomain: function(a) {
+ this.docDomain = a;
+ return this;
+ },
+ // The idea is to minimize the amout of work done to figure out whether
+ // the resource is 3rd-party to the document.
+ is3rdPartyToDoc: function() {
+ const docDomain = this.getDocDomain();
+ if ( this.domain !== undefined ) { return this.domain !== docDomain; }
+ const hostname = this.getHostname();
+ if ( hostname.endsWith(docDomain) === false ) { return true; }
+ const i = hostname.length - docDomain.length;
+ if ( i === 0 ) { return false; }
+ return hostname.charCodeAt(i - 1) !== 0x2E /* '.' */;
+ },
+ setTabId: function(a) {
+ this.tabId = a;
+ return this;
+ },
+ getTabOrigin: function() {
+ if ( this.tabOrigin === undefined ) {
+ const tabContext = µBlock.tabContextManager.mustLookup(this.tabId);
+ this.tabOrigin = tabContext.origin;
+ this.tabHostname = tabContext.rootHostname;
+ this.tabDomain = tabContext.rootDomain;
+ }
+ return this.tabOrigin;
+ },
+ setTabOrigin: function(a) {
+ if ( a !== this.tabOrigin ) {
+ this.tabHostname = this.tabDomain = undefined;
+ this.tabOrigin = a;
+ }
+ return this;
+ },
+ setTabOriginFromURL: function(a) {
+ return this.setTabOrigin(this.originFromURI(a));
+ },
+ getTabHostname: function() {
+ if ( this.tabHostname === undefined ) {
+ this.tabHostname = this.hostnameFromURI(this.getTabOrigin());
+ }
+ return this.tabHostname;
+ },
+ setTabHostname: function(a) {
+ if ( a !== this.tabHostname ) {
+ this.tabDomain = undefined;
+ this.tabHostname = a;
+ }
+ return this;
+ },
+ getTabDomain: function() {
+ if ( this.tabDomain === undefined ) {
+ this.tabDomain = this.domainFromHostname(this.getTabHostname());
+ }
+ return this.tabDomain;
+ },
+ setTabDomain: function(a) {
+ this.docDomain = a;
+ return this;
+ },
+ // The idea is to minimize the amout of work done to figure out whether
+ // the resource is 3rd-party to the top document.
+ is3rdPartyToTab: function() {
+ const tabDomain = this.getTabDomain();
+ if ( this.domain !== undefined ) { return this.domain !== tabDomain; }
+ const hostname = this.getHostname();
+ if ( hostname.endsWith(tabDomain) === false ) { return true; }
+ const i = hostname.length - tabDomain.length;
+ if ( i === 0 ) { return false; }
+ return hostname.charCodeAt(i - 1) !== 0x2E /* '.' */;
+ },
+ setFilter: function(a) {
+ this.filter = a;
+ return this;
+ },
+ toLogger: function() {
+ this.tstamp = Date.now();
+ if ( this.domain === undefined ) {
+ void this.getDomain();
+ }
+ if ( this.docDomain === undefined ) {
+ void this.getDocDomain();
+ }
+ if ( this.tabDomain === undefined ) {
+ void this.getTabDomain();
+ }
+ µBlock.logger.writeOne(this);
+ },
+ originFromURI: µBlock.URI.originFromURI,
+ hostnameFromURI: µBlock.URI.hostnameFromURI,
+ domainFromHostname: µBlock.URI.domainFromHostname,
+};
+
+µBlock.filteringContext = new µBlock.FilteringContext();
diff --git a/src/js/html-filtering.js b/src/js/html-filtering.js
index cac9e0752..b27e09cd2 100644
--- a/src/js/html-filtering.js
+++ b/src/js/html-filtering.js
@@ -162,18 +162,18 @@
};
const logOne = function(details, exception, selector) {
- µb.logger.writeOne(
- details.tabId,
- 'cosmetic',
- {
+ µBlock.filteringContext
+ .duplicate()
+ .fromTabId(details.tabId)
+ .setRealm('cosmetic')
+ .setType('dom')
+ .setURL(details.url)
+ .setDocOriginFromURL(details.url)
+ .setFilter({
source: 'cosmetic',
raw: (exception === 0 ? '##' : '#@#') + '^' + selector
- },
- 'dom',
- details.url,
- null,
- details.hostname
- );
+ })
+ .toLogger();
};
const applyProceduralSelector = function(details, selector) {
@@ -192,7 +192,7 @@
modified = true;
}
}
- if ( modified && µb.logger.isEnabled() ) {
+ if ( modified && µb.logger.enabled ) {
logOne(details, 0, pselector.raw);
}
return modified;
@@ -209,7 +209,7 @@
modified = true;
}
}
- if ( modified && µb.logger.isEnabled() ) {
+ if ( modified && µb.logger.enabled ) {
logOne(details, 0, selector);
}
return modified;
@@ -277,7 +277,7 @@
};
api.retrieve = function(details) {
- let hostname = details.hostname;
+ const hostname = details.hostname;
// https://github.com/gorhill/uBlock/issues/2835
// Do not filter if the site is under an `allow` rule.
@@ -288,13 +288,13 @@
return;
}
- let toRemoveArray = [];
- let domainHash = µb.staticExtFilteringEngine.makeHash(details.domain);
+ const toRemoveArray = [];
+ const domainHash = µb.staticExtFilteringEngine.makeHash(details.domain);
if ( domainHash !== 0 ) {
filterDB.retrieve(domainHash, hostname, toRemoveArray);
}
- let entity = details.entity;
- let entityHash = µb.staticExtFilteringEngine.makeHash(entity);
+ const entity = details.entity;
+ const entityHash = µb.staticExtFilteringEngine.makeHash(entity);
if ( entityHash !== 0 ) {
filterDB.retrieve(entityHash, entity, toRemoveArray);
}
@@ -313,14 +313,14 @@
return toRemoveArray;
}
- let toRemoveMap = new Map();
- for ( let entry of toRemoveArray ) {
+ const toRemoveMap = new Map();
+ for ( const entry of toRemoveArray ) {
toRemoveMap.set(entry.selector, entry);
}
- for ( let entry of notToRemoveArray ) {
+ for ( const entry of notToRemoveArray ) {
if ( toRemoveMap.has(entry.selector) === false ) { continue; }
toRemoveMap.delete(entry.selector);
- if ( µb.logger.isEnabled() === false ) { continue; }
+ if ( µb.logger.enabled === false ) { continue; }
let selector = entry.selector;
if ( entry.type === 65 ) {
selector = JSON.parse(selector).raw;
diff --git a/src/js/logger-ui-inspector.js b/src/js/logger-ui-inspector.js
index c911a748e..4103ba2cb 100644
--- a/src/js/logger-ui-inspector.js
+++ b/src/js/logger-ui-inspector.js
@@ -559,16 +559,16 @@ var onMouseOver = (function() {
/******************************************************************************/
-var currentTabId = function() {
+const currentTabId = function() {
if ( showdomButton.classList.contains('active') === false ) { return 0; }
return logger.tabIdFromPageSelector();
};
/******************************************************************************/
-var injectInspector = function() {
- var tabId = currentTabId();
- if ( tabId === 0 ) { return; }
+const injectInspector = function() {
+ const tabId = currentTabId();
+ if ( tabId <= 0 ) { return; }
inspectedTabId = tabId;
messaging.send('loggerUI', {
what: 'scriptlet',
@@ -592,7 +592,11 @@ var shutdownInspector = function() {
/******************************************************************************/
var onTabIdChanged = function() {
- if ( inspectedTabId !== currentTabId() ) {
+ const tabId = currentTabId();
+ if ( tabId <= 0 ) {
+ return toggleOff();
+ }
+ if ( inspectedTabId !== tabId ) {
shutdownInspector();
injectInspector();
}
@@ -632,7 +636,8 @@ var revert = function() {
/******************************************************************************/
-var toggleOn = function() {
+const toggleOn = function() {
+ uDom.nodeFromId('inspectors').classList.add('dom');
window.addEventListener('beforeunload', toggleOff);
document.addEventListener('tabIdChanged', onTabIdChanged);
domTree.addEventListener('click', onClicked, true);
@@ -647,7 +652,9 @@ var toggleOn = function() {
/******************************************************************************/
-var toggleOff = function() {
+const toggleOff = function() {
+ showdomButton.classList.remove('active');
+ uDom.nodeFromId('inspectors').classList.remove('dom');
shutdownInspector();
window.removeEventListener('beforeunload', toggleOff);
document.removeEventListener('tabIdChanged', onTabIdChanged);
@@ -663,7 +670,7 @@ var toggleOff = function() {
/******************************************************************************/
-var toggle = function() {
+const toggle = function() {
if ( showdomButton.classList.toggle('active') ) {
toggleOn();
} else {
diff --git a/src/js/logger-ui.js b/src/js/logger-ui.js
index 3dbb17abc..0c1e2bb07 100644
--- a/src/js/logger-ui.js
+++ b/src/js/logger-ui.js
@@ -29,16 +29,17 @@
/******************************************************************************/
-var logger = self.logger = {
+const messaging = vAPI.messaging;
+
+const logger = self.logger = {
ownerId: Date.now()
};
-var messaging = vAPI.messaging;
-var activeTabId;
+let activeTabId;
/******************************************************************************/
-var removeAllChildren = logger.removeAllChildren = function(node) {
+const removeAllChildren = logger.removeAllChildren = function(node) {
while ( node.firstChild ) {
node.removeChild(node.firstChild);
}
@@ -46,18 +47,19 @@ var removeAllChildren = logger.removeAllChildren = function(node) {
/******************************************************************************/
-var tabIdFromClassName = function(className) {
- var matches = className.match(/\btab_([^ ]+)\b/);
+const tabIdFromClassName = function(className) {
+ const matches = className.match(/\btab_([^ ]+)\b/);
if ( matches === null ) { return 0; }
if ( matches[1] === 'bts' ) { return -1; }
return parseInt(matches[1], 10);
};
-var tabIdFromPageSelector = logger.tabIdFromPageSelector = function() {
- var tabClass = uDom.nodeFromId('pageSelector').value;
+const tabIdFromPageSelector = logger.tabIdFromPageSelector = function() {
+ const tabClass = uDom.nodeFromId('pageSelector').value;
if ( tabClass === 'tab_active' && activeTabId !== undefined ) {
return activeTabId;
}
+ if ( tabClass === 'tab_bts' ) { return -1; }
return /^tab_\d+$/.test(tabClass) ? parseInt(tabClass.slice(4), 10) : 0;
};
@@ -78,12 +80,11 @@ var tabIdFromPageSelector = logger.tabIdFromPageSelector = function() {
var tbody = document.querySelector('#netInspector tbody');
var trJunkyard = [];
var tdJunkyard = [];
-var firstVarDataCol = 2; // currently, column 2 (0-based index)
-var lastVarDataIndex = 4; // currently, d0-d3
+var firstVarDataCol = 1;
+var lastVarDataIndex = 6;
var maxEntries = 5000;
var allTabIds = new Map();
var allTabIdsToken;
-var hiddenTemplate = document.querySelector('#hiddenTemplate > span');
var reRFC3986 = /^([^:\/?#]+:)?(\/\/[^\/?#]*)?([^?#]*)(\?[^#]*)?(#.*)?/;
var netFilteringDialog = uDom.nodeFromId('netFilteringDialog');
@@ -159,14 +160,15 @@ var renderedURLTemplate = document.querySelector('#renderedURLTemplate > span');
/******************************************************************************/
-var createCellAt = function(tr, index) {
- var td = tr.cells[index];
- var mustAppend = !td;
+const createCellAt = function(tr, index) {
+ let td = tr.cells[index];
+ const mustAppend = !td;
if ( mustAppend ) {
td = tdJunkyard.pop();
}
if ( td ) {
td.removeAttribute('colspan');
+ td.removeAttribute('title');
td.textContent = '';
} else {
td = document.createElement('td');
@@ -180,24 +182,25 @@ var createCellAt = function(tr, index) {
/******************************************************************************/
var createRow = function(layout) {
- var tr = trJunkyard.pop();
+ let tr = trJunkyard.pop();
if ( tr ) {
tr.className = '';
- tr.removeAttribute('data-hn-page');
- tr.removeAttribute('data-hn-frame');
+ tr.removeAttribute('data-tabhn');
+ tr.removeAttribute('data-dochn');
tr.removeAttribute('data-filter');
+ tr.removeAttribute('data-tabid');
+ tr.removeAttribute('title');
} else {
tr = document.createElement('tr');
}
- for ( var index = 0; index < firstVarDataCol; index++ ) {
+ let index = 0;
+ for ( ; index < firstVarDataCol; index++ ) {
createCellAt(tr, index);
}
- var i = 1, span = 1, td;
+ let i = 1, span = 1, td;
for (;;) {
td = createCellAt(tr, index);
- if ( i === lastVarDataIndex ) {
- break;
- }
+ if ( i === lastVarDataIndex ) { break; }
if ( layout.charAt(i) !== '1' ) {
span += 1;
} else {
@@ -221,24 +224,15 @@ var createRow = function(layout) {
/******************************************************************************/
-var createHiddenTextNode = function(text) {
- var node = hiddenTemplate.cloneNode(true);
- node.textContent = text;
- return node;
-};
-
-/******************************************************************************/
-
var padTo2 = function(v) {
return v < 10 ? '0' + v : v;
};
/******************************************************************************/
-var createGap = function(tabId, url) {
- var tr = createRow('1');
- tr.classList.add('tab');
- tr.classList.add('canMtx');
+const createGap = function(tabId, url) {
+ const tr = createRow('1');
+ tr.setAttribute('data-tabid', tabId);
tr.classList.add('tab_' + tabId);
tr.classList.add('maindoc');
tr.cells[firstVarDataCol].textContent = url;
@@ -247,36 +241,30 @@ var createGap = function(tabId, url) {
/******************************************************************************/
-var renderNetLogEntry = function(tr, entry) {
- var trcl = tr.classList;
- var filter = entry.d0 || undefined;
- var type = entry.d1;
- var url = entry.d2;
- var td;
-
- trcl.add('canMtx');
+var renderNetLogEntry = function(tr, details) {
+ const trcl = tr.classList;
+ const type = details.type;
+ const url = details.url;
+ let td;
// If the request is that of a root frame, insert a gap in the table
// in order to visually separate entries for different documents.
if ( type === 'main_frame' ) {
- createGap(entry.tab, url);
+ createGap(details.tabId, url);
}
- // Contexts
- if ( entry.d3 ) {
- tr.setAttribute('data-hn-page', entry.d3);
- }
- if ( entry.d4 ) {
- tr.setAttribute('data-hn-frame', entry.d4);
+ tr.classList.add('cat_' + details.realm);
+
+ let filter = details.filter || undefined;
+ let filteringType;
+ if ( filter !== undefined ) {
+ if ( typeof filter.source === 'string' ) {
+ filteringType = filter.source;
+ trcl.add(filteringType);
+ }
}
- var filteringType;
- if ( filter !== undefined && typeof filter.source === 'string' ) {
- filteringType = filter.source;
- trcl.add(filteringType);
- }
-
- td = tr.cells[2];
+ td = tr.cells[1];
if ( filter !== undefined ) {
if ( filteringType === 'static' ) {
td.textContent = filter.raw;
@@ -290,7 +278,7 @@ var renderNetLogEntry = function(tr, entry) {
}
}
- td = tr.cells[3];
+ td = tr.cells[2];
if ( filter !== undefined ) {
if ( filter.result === 1 ) {
trcl.add('blocked');
@@ -301,65 +289,86 @@ var renderNetLogEntry = function(tr, entry) {
} else if ( filter.result === 3 ) {
trcl.add('nooped');
td.textContent = '**';
- } else if ( filter.source === 'redirect' ) {
+ } else if ( filteringType === 'redirect' ) {
trcl.add('redirect');
td.textContent = '<<';
}
}
- tr.cells[4].textContent = (prettyRequestTypes[type] || type);
+ if ( details.tabHostname ) {
+ tr.setAttribute('data-tabhn', details.tabHostname);
+ }
+ if ( details.docHostname ) {
+ tr.setAttribute('data-dochn', details.docHostname);
+ tr.cells[3].textContent = details.docHostname;
+ }
- var re = null;
+ // Partyness
+ if ( details.realm === 'net' && details.domain !== undefined ) {
+ td = tr.cells[4];
+ let text = '';
+ if ( details.tabDomain !== undefined ) {
+ text += details.domain === details.tabDomain ? '1' : '3';
+ } else {
+ text += '?';
+ }
+ if ( details.docDomain !== details.tabDomain ) {
+ text += ',';
+ if ( details.docDomain !== undefined ) {
+ text += details.domain === details.docDomain ? '1' : '3';
+ } else {
+ text += '?';
+ }
+ }
+ td.textContent = text;
+ text = details.domain;
+ if ( details.docDomain ) {
+ text = details.docDomain + ' \u21d2 ' + text;
+ }
+ if ( details.tabDomain && details.tabDomain !== details.docDomain ) {
+ text = details.tabDomain + ' \u21d2 ' + text;
+ }
+ td.setAttribute('title', text);
+ }
+
+ tr.cells[5].textContent = (prettyRequestTypes[type] || type);
+
+ let re = null;
if ( filteringType === 'static' ) {
re = new RegExp(filter.regex, 'gi');
} else if ( filteringType === 'dynamicUrl' ) {
re = regexFromURLFilteringResult(filter.rule.join(' '));
}
- tr.cells[5].appendChild(nodeFromURL(url, re));
+ tr.cells[6].appendChild(nodeFromURL(url, re));
};
/******************************************************************************/
-var renderLogEntry = function(entry) {
- var tr;
- var fvdc = firstVarDataCol;
+var renderLogEntry = function(details) {
+ const fvdc = firstVarDataCol;
+ let tr;
- switch ( entry.cat ) {
- case 'error':
- case 'info':
+ if ( details.error !== undefined ) {
tr = createRow('1');
- tr.cells[fvdc].textContent = entry.d0;
- break;
-
- case 'cosmetic':
- case 'net':
- case 'redirect':
- tr = createRow('1111');
- renderNetLogEntry(tr, entry);
- break;
-
- default:
+ tr.cells[fvdc].textContent = details.error;
+ } else if ( details.url !== undefined ) {
+ tr = createRow('111111');
+ renderNetLogEntry(tr, details);
+ } else {
tr = createRow('1');
- tr.cells[fvdc].textContent = entry.d0;
- break;
+ tr.cells[fvdc].textContent = '???';
}
// Fields common to all rows.
- var time = logDate;
- time.setTime(entry.tstamp - logDateTimezoneOffset);
+ const time = logDate;
+ time.setTime(details.tstamp - logDateTimezoneOffset);
tr.cells[0].textContent = padTo2(time.getUTCHours()) + ':' +
padTo2(time.getUTCMinutes()) + ':' +
padTo2(time.getSeconds());
- if ( entry.tab ) {
- tr.classList.add('tab');
- tr.classList.add(classNameFromTabId(entry.tab));
- if ( entry.tab < 0 ) {
- tr.cells[1].appendChild(createHiddenTextNode('bts'));
- }
- }
- if ( entry.cat !== '' ) {
- tr.classList.add('cat_' + entry.cat);
+ if ( details.tabId ) {
+ tr.setAttribute('data-tabid', details.tabId);
+ tr.classList.add(classNameFromTabId(details.tabId));
}
rowFilterer.filterOne(tr, true);
@@ -368,29 +377,29 @@ var renderLogEntry = function(entry) {
};
// Reuse date objects.
-var logDate = new Date(),
- logDateTimezoneOffset = logDate.getTimezoneOffset() * 60000;
+const logDate = new Date();
+const logDateTimezoneOffset = logDate.getTimezoneOffset() * 60000;
/******************************************************************************/
-var renderLogEntries = function(response) {
+const renderLogEntries = function(response) {
document.body.classList.toggle('colorBlind', response.colorBlind);
- let entries = response.entries;
+ const entries = response.entries;
if ( entries.length === 0 ) { return; }
// Preserve scroll position
- let height = tbody.offsetHeight;
+ const height = tbody.offsetHeight;
- let tabIds = allTabIds;
- for ( let i = 0, n = entries.length; i < n; i++ ) {
- let entry = entries[i];
- let tr = renderLogEntry(entries[i]);
+ const tabIds = allTabIds;
+ for ( const entry of entries ) {
+ const details = JSON.parse(entry.details);
+ const tr = renderLogEntry(details);
// https://github.com/gorhill/uBlock/issues/1613#issuecomment-217637122
// Unlikely, but it may happen: mark as void if associated tab no
// longer exist.
- if ( entry.tab && tabIds.has(entry.tab) === false ) {
- tr.classList.remove('canMtx');
+ if ( details.tabId && tabIds.has(details.tabId) === false ) {
+ tr.classList.add('void');
}
}
@@ -400,9 +409,9 @@ var renderLogEntries = function(response) {
truncateLog(maxEntries);
// Follow waterfall if not observing top of waterfall.
- let yDelta = tbody.offsetHeight - height;
+ const yDelta = tbody.offsetHeight - height;
if ( yDelta === 0 ) { return; }
- let container = uDom.nodeFromSelector('#netInspector .vscrollable');
+ const container = uDom.nodeFromSelector('#netInspector .vscrollable');
if ( container.scrollTop !== 0 ) {
container.scrollTop += yDelta;
}
@@ -428,21 +437,20 @@ let updateCurrentTabTitle = (function() {
/******************************************************************************/
-var synchronizeTabIds = function(newTabIds) {
- var select = uDom.nodeFromId('pageSelector');
- var selectValue = select.value;
-
- var oldTabIds = allTabIds;
- var autoDeleteVoidRows = selectValue === 'tab_active';
- var rowVoided = false;
- for ( var tabId of oldTabIds.keys() ) {
+const synchronizeTabIds = function(newTabIds) {
+ const select = uDom.nodeFromId('pageSelector');
+ const selectValue = select.value;
+ const oldTabIds = allTabIds;
+ const autoDeleteVoidRows = selectValue === 'tab_active';
+ let rowVoided = false;
+ for ( const tabId of oldTabIds.keys() ) {
if ( newTabIds.has(tabId) ) { continue; }
// Mark or remove voided rows
- var trs = uDom('.tab_' + tabId);
+ const trs = uDom('.tab_' + tabId);
if ( autoDeleteVoidRows ) {
toJunkyard(trs);
} else {
- trs.removeClass('canMtx');
+ trs.addClass('void');
rowVoided = true;
}
// Remove popup if it is currently bound to a removed tab.
@@ -451,14 +459,14 @@ var synchronizeTabIds = function(newTabIds) {
}
}
- var tabIds = Array.from(newTabIds.keys()).sort(function(a, b) {
+ const tabIds = Array.from(newTabIds.keys()).sort(function(a, b) {
return newTabIds.get(a).localeCompare(newTabIds.get(b));
});
- var option;
- for ( var i = 0, j = 3; i < tabIds.length; i++ ) {
- tabId = tabIds[i];
+ let j = 3;
+ for ( let i = 0; i < tabIds.length; i++ ) {
+ const tabId = tabIds[i];
if ( tabId < 0 ) { continue; }
- option = select.options[j];
+ let option = select.options[j];
if ( !option ) {
option = document.createElement('option');
select.appendChild(option);
@@ -508,7 +516,7 @@ var truncateLog = function(size) {
/******************************************************************************/
-var onLogBufferRead = function(response) {
+const onLogBufferRead = function(response) {
if ( !response || response.unavailable ) {
readLogBufferAsync();
return;
@@ -547,7 +555,7 @@ var onLogBufferRead = function(response) {
if ( rowVoided ) {
uDom('#clean').toggleClass(
'disabled',
- tbody.querySelector('#netInspector tr.tab:not(.canMtx)') === null
+ tbody.querySelector('#netInspector tr[data-tabid].void') === null
);
}
@@ -566,20 +574,20 @@ var onLogBufferRead = function(response) {
// automatically. If called after init time, this will be messy, and this would
// require a bit more code to ensure no multi time out events.
-var readLogBuffer = function() {
+const readLogBuffer = function() {
if ( logger.ownerId === undefined ) { return; }
vAPI.messaging.send(
'loggerUI',
{
what: 'readAll',
ownerId: logger.ownerId,
- tabIdsToken: allTabIdsToken
+ tabIdsToken: allTabIdsToken,
},
onLogBufferRead
);
};
-var readLogBufferAsync = function() {
+const readLogBufferAsync = function() {
if ( logger.ownerId === undefined ) { return; }
vAPI.setTimeout(readLogBuffer, 1200);
};
@@ -646,10 +654,14 @@ let pageSelectorFromURLHash = (function() {
select.selectedIndex = option.index;
select.value = option.value;
- uDom('.needtab').toggleClass(
+ uDom('.needdom').toggleClass(
'disabled',
tabClass === '' || tabClass === 'tab_bts'
);
+ uDom('.needscope').toggleClass(
+ 'disabled',
+ tabClass === ''
+ );
};
})();
@@ -657,7 +669,7 @@ let pageSelectorFromURLHash = (function() {
var reloadTab = function(ev) {
var tabId = tabIdFromPageSelector();
- if ( tabId === 0 ) { return; }
+ if ( tabId <= 0 ) { return; }
messaging.send('loggerUI', {
what: 'reloadTab',
tabId: tabId,
@@ -1227,10 +1239,10 @@ var netFilteringManager = (function() {
dialog = netFilteringDialog.querySelector('.dialog');
targetRow = ev.target.parentElement;
targetTabId = tabIdFromClassName(targetRow.className);
- targetType = targetRow.cells[4].textContent.trim() || '';
- targetURLs = createTargetURLs(targetRow.cells[5].textContent);
- targetPageHostname = targetRow.getAttribute('data-hn-page') || '';
- targetFrameHostname = targetRow.getAttribute('data-hn-frame') || '';
+ targetType = targetRow.cells[5].textContent.trim() || '';
+ targetURLs = createTargetURLs(targetRow.cells[6].textContent);
+ targetPageHostname = targetRow.getAttribute('data-tabhn') || '';
+ targetFrameHostname = targetRow.getAttribute('data-dochn') || '';
// We need the root domain names for best user experience.
messaging.send(
@@ -1345,7 +1357,7 @@ var reverseLookupManager = (function() {
let toggleOn = function(ev) {
let row = ev.target.parentElement;
- rawFilter = row.cells[2].textContent;
+ rawFilter = row.cells[1].textContent;
if ( rawFilter === '' ) { return; }
if ( row.classList.contains('cat_net') ) {
@@ -1363,7 +1375,7 @@ var reverseLookupManager = (function() {
'loggerUI',
{
what: 'listsFromCosmeticFilter',
- url: row.cells[5].textContent,
+ url: row.cells[6].textContent,
rawFilter: rawFilter,
},
reverseLookupDone
@@ -1385,10 +1397,10 @@ var reverseLookupManager = (function() {
/******************************************************************************/
/******************************************************************************/
-var rowFilterer = (function() {
- var filters = [];
+const rowFilterer = (function() {
+ let filters = [];
- var parseInput = function() {
+ const parseInput = function() {
filters = [];
var rawPart, hardBeg, hardEnd;
@@ -1438,33 +1450,30 @@ var rowFilterer = (function() {
}
};
- var filterOne = function(tr, clean) {
- var ff = filters;
- var fcount = ff.length;
+ const filterOne = function(tr, clean) {
+ const ff = filters;
+ const fcount = ff.length;
if ( fcount === 0 && clean === true ) {
return;
}
// do not filter out doc boundaries, they help separate important
// section of log.
- var cl = tr.classList;
- if ( cl.contains('maindoc') ) {
- return;
- }
+ const cl = tr.classList;
+ if ( cl.contains('maindoc') ) { return; }
if ( fcount === 0 ) {
cl.remove('f');
return;
}
- var cc = tr.cells;
- var ccount = cc.length;
- var hit, j, f;
+ const cc = tr.cells;
+ const ccount = cc.length;
// each filter expression must hit (implicit and-op)
// if...
// positive filter expression = there must one hit on any field
// negative filter expression = there must be no hit on all fields
- for ( var i = 0; i < fcount; i++ ) {
- f = ff[i];
- hit = !f.r;
- for ( j = 0; j < ccount; j++ ) {
+ for ( let i = 0; i < fcount; i++ ) {
+ let f = ff[i];
+ let hit = !f.r;
+ for ( let j = 1; j < ccount; j++ ) {
if ( f.re.test(cc[j].textContent) ) {
hit = f.r;
break;
@@ -1478,7 +1487,7 @@ var rowFilterer = (function() {
cl.remove('f');
};
- var filterAll = function() {
+ const filterAll = function() {
// Special case: no filter
if ( filters.length === 0 ) {
uDom('#netInspector tr').removeClass('f');
@@ -1492,7 +1501,7 @@ var rowFilterer = (function() {
}
};
- var onFilterChangedAsync = (function() {
+ const onFilterChangedAsync = (function() {
var timer = null;
var commit = function() {
timer = null;
@@ -1507,7 +1516,7 @@ var rowFilterer = (function() {
};
})();
- var onFilterButton = function() {
+ const onFilterButton = function() {
uDom.nodeFromId('netInspector').classList.toggle('f');
};
@@ -1559,14 +1568,14 @@ var clearBuffer = function() {
);
uDom.nodeFromId('clean').classList.toggle(
'disabled',
- tbody.querySelector('#netInspector tr.tab:not(.canMtx)') === null
+ tbody.querySelector('#netInspector tr[data-tabid].void') === null
);
};
/******************************************************************************/
var cleanBuffer = function() {
- var rows = uDom('#netInspector tr.tab:not(.canMtx)').remove();
+ var rows = uDom('#netInspector tr[data-tabid].void').remove();
var i = rows.length;
while ( i-- ) {
trJunkyard.push(rows.nodeAt(i));
@@ -1587,44 +1596,23 @@ var toggleVCompactRow = function(ev) {
/******************************************************************************/
-var toggleInspectors = function() {
- uDom.nodeFromId('inspectors').classList.toggle('dom');
-};
-
-/******************************************************************************/
-
var popupManager = (function() {
- var realTabId = null;
- var localTabId = null;
- var container = null;
- var popup = null;
- var popupObserver = null;
- var style = null;
- var styleTemplate = [
- '#netInspector tr:not(.tab_{{tabId}}) {',
- 'cursor: not-allowed;',
- 'opacity: 0.2;',
- '}'
- ].join('\n');
+ let realTabId = 0;
+ let popup = null;
+ let popupObserver = null;
- var resizePopup = function() {
- if ( popup === null ) {
- return;
- }
- var popupBody = popup.contentWindow.document.body;
- if ( popupBody.clientWidth !== 0 && container.clientWidth !== popupBody.clientWidth ) {
- container.style.setProperty('width', popupBody.clientWidth + 'px');
+ const resizePopup = function() {
+ if ( popup === null ) { return; }
+ const popupBody = popup.contentWindow.document.body;
+ if ( popupBody.clientWidth !== 0 && popup.clientWidth !== popupBody.clientWidth ) {
+ popup.style.setProperty('width', popupBody.clientWidth + 'px');
}
if ( popupBody.clientHeight !== 0 && popup.clientHeight !== popupBody.clientHeight ) {
popup.style.setProperty('height', popupBody.clientHeight + 'px');
}
};
- var toggleSize = function() {
- container.classList.toggle('hide');
- };
-
- var onLoad = function() {
+ const onLoad = function() {
resizePopup();
popupObserver.observe(popup.contentDocument.body, {
subtree: true,
@@ -1632,61 +1620,55 @@ var popupManager = (function() {
});
};
- var toggleOn = function(td) {
- var tr = td.parentNode;
- realTabId = localTabId = tabIdFromClassName(tr.className);
- if ( realTabId === 0 ) { return; }
-
- container = uDom.nodeFromId('popupContainer');
-
- container.querySelector('div > span:nth-of-type(1)').addEventListener('click', toggleSize);
- container.querySelector('div > span:nth-of-type(2)').addEventListener('click', toggleOff);
-
- popup = document.createElement('iframe');
- popup.addEventListener('load', onLoad);
- popup.setAttribute('src', 'popup.html?tabId=' + realTabId);
- popupObserver = new MutationObserver(resizePopup);
- container.appendChild(popup);
-
- style = uDom.nodeFromId('popupFilterer');
- style.textContent = styleTemplate.replace('{{tabId}}', localTabId);
-
- var parent = uDom.nodeFromId('netInspector');
- var rect = parent.getBoundingClientRect();
- container.style.setProperty('top', rect.top + 'px');
- container.style.setProperty('right', (rect.right - parent.clientWidth) + 'px');
- parent.classList.add('popupOn');
+ const setTabId = function(tabId) {
+ if ( popup === null ) { return; }
+ popup.setAttribute('src', 'popup.html?tabId=' + tabId);
};
- var toggleOff = function() {
- uDom.nodeFromId('netInspector').classList.remove('popupOn');
+ const onTabIdChanged = function() {
+ const tabId = tabIdFromPageSelector();
+ if ( tabId === 0 ) { return toggleOff(); }
+ realTabId = tabId;
+ setTabId(realTabId);
+ };
- container.querySelector('div > span:nth-of-type(1)').removeEventListener('click', toggleSize);
- container.querySelector('div > span:nth-of-type(2)').removeEventListener('click', toggleOff);
- container.classList.remove('hide');
+ const toggleOn = function() {
+ const tabId = tabIdFromPageSelector();
+ if ( tabId === 0 ) { return; }
+ realTabId = tabId;
+ popup = uDom.nodeFromId('popupContainer');
+
+ popup.addEventListener('load', onLoad);
+ popupObserver = new MutationObserver(resizePopup);
+
+ const parent = uDom.nodeFromId('inspectors');
+ const rect = parent.getBoundingClientRect();
+ popup.style.setProperty('right', (rect.right - parent.clientWidth) + 'px');
+ parent.classList.add('popupOn');
+
+ document.addEventListener('tabIdChanged', onTabIdChanged);
+
+ setTabId(realTabId);
+ };
+
+ const toggleOff = function() {
+ document.removeEventListener('tabIdChanged', onTabIdChanged);
+ uDom.nodeFromId('inspectors').classList.remove('popupOn');
popup.removeEventListener('load', onLoad);
popupObserver.disconnect();
popupObserver = null;
popup.setAttribute('src', '');
- container.removeChild(popup);
- popup = null;
-
- style.textContent = '';
- style = null;
-
- container = null;
- realTabId = null;
+
+ realTabId = 0;
};
- var exports = {
- toggleOn: function(ev) {
- if ( realTabId === null ) {
- toggleOn(ev.target);
- }
+ const exports = {
+ toggleOn: function() {
+ void (realTabId === 0 ? toggleOn() : toggleOff());
},
toggleOff: function() {
- if ( realTabId !== null ) {
+ if ( realTabId !== 0 ) {
toggleOff();
}
}
@@ -1701,14 +1683,14 @@ var popupManager = (function() {
/******************************************************************************/
-var grabView = function() {
+const grabView = function() {
if ( logger.ownerId === undefined ) {
logger.ownerId = Date.now();
}
readLogBufferAsync();
};
-var releaseView = function() {
+const releaseView = function() {
if ( logger.ownerId === undefined ) { return; }
vAPI.messaging.send(
'loggerUI',
@@ -1728,16 +1710,15 @@ readLogBuffer();
uDom('#pageSelector').on('change', pageSelectorChanged);
uDom('#refresh').on('click', reloadTab);
-uDom('#showdom').on('click', toggleInspectors);
+uDom('#showpopup').on('click', popupManager.toggleOn);
uDom('#netInspector .vCompactToggler').on('click', toggleVCompactView);
uDom('#clean').on('click', cleanBuffer);
uDom('#clear').on('click', clearBuffer);
uDom('#maxEntries').on('change', onMaxEntriesChanged);
uDom('#netInspector table').on('click', 'tr > td:nth-of-type(1)', toggleVCompactRow);
-uDom('#netInspector table').on('click', 'tr.canMtx > td:nth-of-type(2)', popupManager.toggleOn);
-uDom('#netInspector').on('click', 'tr.canLookup > td:nth-of-type(3)', reverseLookupManager.toggleOn);
-uDom('#netInspector').on('click', 'tr.cat_net > td:nth-of-type(4)', netFilteringManager.toggleOn);
+uDom('#netInspector').on('click', 'tr.canLookup > td:nth-of-type(2)', reverseLookupManager.toggleOn);
+uDom('#netInspector').on('click', 'tr.cat_net > td:nth-of-type(3)', netFilteringManager.toggleOn);
// https://github.com/gorhill/uBlock/issues/507
// Ensure tab selector is in sync with URL hash
diff --git a/src/js/logger.js b/src/js/logger.js
index f4e33f5c8..96df0c844 100644
--- a/src/js/logger.js
+++ b/src/js/logger.js
@@ -1,7 +1,7 @@
/*******************************************************************************
- uBlock - a browser extension to block requests.
- Copyright (C) 2015-2017 Raymond Hill
+ uBlock Origin - a browser extension to block requests.
+ Copyright (C) 2015-present 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
@@ -26,34 +26,28 @@
µBlock.logger = (function() {
- var LogEntry = function(args) {
- this.init(args);
+ const LogEntry = function(details) {
+ this.init(details);
};
- LogEntry.prototype.init = function(args) {
- this.tstamp = Date.now();
- this.tab = args[0] || '';
- this.cat = args[1] || '';
- this.d0 = args[2];
- this.d1 = args[3];
- this.d2 = args[4];
- this.d3 = args[5];
- this.d4 = args[6];
+ LogEntry.prototype.init = function(details) {
+ this.details = JSON.stringify(details);
};
- var buffer = null;
- var lastReadTime = 0;
- var writePtr = 0;
+ let buffer = null;
+ let lastReadTime = 0;
+ let writePtr = 0;
// After 60 seconds without being read, a buffer will be considered
// unused, and thus removed from memory.
- var logBufferObsoleteAfter = 30 * 1000;
+ const logBufferObsoleteAfter = 30 * 1000;
- var janitor = function() {
+ const janitor = ( ) => {
if (
buffer !== null &&
lastReadTime < (Date.now() - logBufferObsoleteAfter)
) {
+ api.enabled = false;
buffer = null;
writePtr = 0;
api.ownerId = undefined;
@@ -64,31 +58,30 @@
}
};
- var api = {
+ const api = {
+ enabled: false,
ownerId: undefined,
- writeOne: function() {
+ writeOne: function(details) {
if ( buffer === null ) { return; }
if ( writePtr === buffer.length ) {
- buffer.push(new LogEntry(arguments));
+ buffer.push(new LogEntry(details));
} else {
- buffer[writePtr].init(arguments);
+ buffer[writePtr].init(details);
}
writePtr += 1;
},
readAll: function(ownerId) {
this.ownerId = ownerId;
if ( buffer === null ) {
+ this.enabled = true;
buffer = [];
vAPI.setTimeout(janitor, logBufferObsoleteAfter);
}
- var out = buffer.slice(0, writePtr);
+ const out = buffer.slice(0, writePtr);
writePtr = 0;
lastReadTime = Date.now();
return out;
},
- isEnabled: function() {
- return buffer !== null;
- }
};
return api;
diff --git a/src/js/messaging.js b/src/js/messaging.js
index 4d64f42f3..f242809e4 100644
--- a/src/js/messaging.js
+++ b/src/js/messaging.js
@@ -527,9 +527,8 @@ var onMessage = function(request, sender, callback) {
case 'shouldRenderNoscriptTags':
if ( pageStore === null ) { break; }
- let tabContext = µb.tabContextManager.lookup(tabId);
- if ( tabContext === null ) { break; }
- if ( pageStore.filterScripting(tabContext.rootHostname, undefined) ) {
+ const fctxt = µBlock.filteringContext.fromTabId(tabId);
+ if ( pageStore.filterScripting(fctxt, undefined) ) {
vAPI.tabs.injectScript(
tabId,
{
@@ -561,7 +560,10 @@ var onMessage = function(request, sender, callback) {
request.domain = µb.URI.domainFromHostname(request.hostname);
request.entity = µb.URI.entityFromDomain(request.domain);
response.specificCosmeticFilters =
- µb.cosmeticFilteringEngine.retrieveSpecificSelectors(request, response);
+ µb.cosmeticFilteringEngine.retrieveSpecificSelectors(
+ request,
+ response
+ );
if ( µb.canInjectScriptletsNow === false ) {
response.scriptlets = µb.scriptletFilteringEngine.retrieve(request);
}
@@ -1319,25 +1321,20 @@ var domSurveyFinalReport = function(tabId) {
/******************************************************************************/
-var logCosmeticFilters = function(tabId, details) {
- if ( µb.logger.isEnabled() === false ) {
- return;
- }
+const logCosmeticFilters = function(tabId, details) {
+ if ( µb.logger.enabled === false ) { return; }
- var selectors = details.matchedSelectors;
-
- selectors.sort();
-
- for ( var i = 0; i < selectors.length; i++ ) {
- µb.logger.writeOne(
- tabId,
- 'cosmetic',
- { source: 'cosmetic', raw: '##' + selectors[i] },
- 'dom',
- details.frameURL,
- null,
- details.frameHostname
- );
+ const filter = { source: 'cosmetic', raw: '' };
+ const fctxt = µb.filteringContext.duplicate();
+ fctxt.fromTabId(tabId)
+ .setRealm('cosmetic')
+ .setType('dom')
+ .setURL(details.frameURL)
+ .setDocOriginFromURL(details.frameURL)
+ .setFilter(filter);
+ for ( const selector of details.matchedSelectors.sort() ) {
+ filter.raw = '##' + selector;
+ fctxt.toLogger();
}
};
diff --git a/src/js/pagestore.js b/src/js/pagestore.js
index 67572ea55..a9dff032b 100644
--- a/src/js/pagestore.js
+++ b/src/js/pagestore.js
@@ -37,18 +37,18 @@ To create a log of net requests
/******************************************************************************/
-var µb = µBlock;
+const µb = µBlock;
/******************************************************************************/
/******************************************************************************/
// To mitigate memory churning
-var netFilteringCacheJunkyard = [],
- netFilteringCacheJunkyardMax = 10;
+const netFilteringCacheJunkyard = [];
+const netFilteringCacheJunkyardMax = 10;
/******************************************************************************/
-var NetFilteringResultCache = function() {
+const NetFilteringResultCache = function() {
this.boundPruneAsyncCallback = this.pruneAsyncCallback.bind(this);
this.init();
};
@@ -60,7 +60,7 @@ NetFilteringResultCache.prototype.shelfLife = 15 * 1000;
/******************************************************************************/
NetFilteringResultCache.factory = function() {
- var entry = netFilteringCacheJunkyard.pop();
+ let entry = netFilteringCacheJunkyard.pop();
if ( entry === undefined ) {
entry = new NetFilteringResultCache();
} else {
@@ -90,31 +90,35 @@ NetFilteringResultCache.prototype.dispose = function() {
/******************************************************************************/
-NetFilteringResultCache.prototype.rememberResult = function(context, result, logData) {
+NetFilteringResultCache.prototype.rememberResult = function(
+ fctxt,
+ result,
+ logData
+) {
if ( this.results.size === 0 ) {
this.pruneAsync();
}
- var key = context.pageHostname + ' ' + context.requestType + ' ' + context.requestURL;
+ const key = fctxt.getDocHostname() + ' ' + fctxt.type + ' ' + fctxt.url;
this.results.set(key, {
result: result,
logData: logData,
tstamp: Date.now()
});
if ( result !== 1 ) { return; }
- var now = Date.now();
+ const now = Date.now();
this.blocked.set(key, now);
this.hash = now;
};
/******************************************************************************/
-NetFilteringResultCache.prototype.rememberBlock = function(details) {
+NetFilteringResultCache.prototype.rememberBlock = function(fctxt) {
if ( this.blocked.size === 0 ) {
this.pruneAsync();
}
- var now = Date.now();
+ const now = Date.now();
this.blocked.set(
- details.pageHostname + ' ' + details.requestType + ' ' + details.requestURL,
+ fctxt.getDocHostname() + ' ' + fctxt.type + ' ' + fctxt.url,
now
);
this.hash = now;
@@ -162,21 +166,20 @@ NetFilteringResultCache.prototype.pruneAsyncCallback = function() {
/******************************************************************************/
-NetFilteringResultCache.prototype.lookupResult = function(context) {
+NetFilteringResultCache.prototype.lookupResult = function(fctxt) {
return this.results.get(
- context.pageHostname + ' ' +
- context.requestType + ' ' +
- context.requestURL
+ fctxt.getDocHostname() + ' ' +
+ fctxt.type + ' ' +
+ fctxt.url
);
};
/******************************************************************************/
NetFilteringResultCache.prototype.lookupAllBlocked = function(hostname) {
- var result = [],
- pos;
- for ( var entry of this.blocked ) {
- pos = entry[0].indexOf(' ');
+ const result = [];
+ for ( const entry of this.blocked ) {
+ const pos = entry[0].indexOf(' ');
if ( entry[0].slice(0, pos) === hostname ) {
result[result.length] = entry[0].slice(pos + 1);
}
@@ -193,19 +196,19 @@ NetFilteringResultCache.prototype.lookupAllBlocked = function(hostname) {
// refactoring.
// To mitigate memory churning
-var frameStoreJunkyard = [];
-var frameStoreJunkyardMax = 50;
+const frameStoreJunkyard = [];
+const frameStoreJunkyardMax = 50;
/******************************************************************************/
-var FrameStore = function(frameURL) {
+const FrameStore = function(frameURL) {
this.init(frameURL);
};
/******************************************************************************/
FrameStore.factory = function(frameURL) {
- var entry = frameStoreJunkyard.pop();
+ const entry = frameStoreJunkyard.pop();
if ( entry === undefined ) {
return new FrameStore(frameURL);
}
@@ -215,7 +218,7 @@ FrameStore.factory = function(frameURL) {
/******************************************************************************/
FrameStore.prototype.init = function(frameURL) {
- var µburi = µb.URI;
+ const µburi = µb.URI;
this.pageHostname = µburi.hostnameFromURI(frameURL);
this.pageDomain = µburi.domainFromHostname(this.pageHostname) || this.pageHostname;
return this;
@@ -235,12 +238,12 @@ FrameStore.prototype.dispose = function() {
/******************************************************************************/
// To mitigate memory churning
-var pageStoreJunkyard = [];
-var pageStoreJunkyardMax = 10;
+const pageStoreJunkyard = [];
+const pageStoreJunkyardMax = 10;
/******************************************************************************/
-var PageStore = function(tabId, context) {
+const PageStore = function(tabId, context) {
this.init(tabId, context);
this.journal = [];
this.journalTimer = null;
@@ -251,7 +254,7 @@ var PageStore = function(tabId, context) {
/******************************************************************************/
PageStore.factory = function(tabId, context) {
- var entry = pageStoreJunkyard.pop();
+ let entry = pageStoreJunkyard.pop();
if ( entry === undefined ) {
entry = new PageStore(tabId, context);
} else {
@@ -297,6 +300,18 @@ PageStore.prototype.init = function(tabId, context) {
this.netFilteringCache = NetFilteringResultCache.factory();
this.internalRedirectionCount = 0;
+ // The current filtering context is cloned because:
+ // - We may be called with or without the current context having been
+ // initialized.
+ // - If it has been initialized, we do not want to change the state
+ // of the current context.
+ const fctxt = µb.logger.enabled
+ ? µBlock.filteringContext
+ .duplicate()
+ .fromTabId(tabId)
+ .setURL(tabContext.rawURL)
+ : undefined;
+
// https://github.com/uBlockOrigin/uBlock-issues/issues/314
const masterSwitch = tabContext.getNetFilteringSwitch();
@@ -307,18 +322,13 @@ PageStore.prototype.init = function(tabId, context) {
if (
masterSwitch &&
this.noCosmeticFiltering &&
- µb.logger.isEnabled() &&
+ µb.logger.enabled &&
context === 'tabCommitted'
) {
- µb.logger.writeOne(
- tabId,
- 'cosmetic',
- µb.sessionSwitches.toLogData(),
- 'dom',
- tabContext.rawURL,
- this.tabHostname,
- this.tabHostname
- );
+ fctxt.setRealm('cosmetic')
+ .setType('dom')
+ .setFilter(µb.sessionSwitches.toLogData())
+ .toLogger();
}
// Support `generichide` filter option.
@@ -332,18 +342,13 @@ PageStore.prototype.init = function(tabId, context) {
this.noGenericCosmeticFiltering = result === 2;
if (
result !== 0 &&
- µb.logger.isEnabled() &&
+ µb.logger.enabled &&
context === 'tabCommitted'
) {
- µb.logger.writeOne(
- tabId,
- 'net',
- µb.staticNetFilteringEngine.toLogData(),
- 'generichide',
- tabContext.rawURL,
- this.tabHostname,
- this.tabHostname
- );
+ fctxt.setRealm('net')
+ .setType('generichide')
+ .setFilter(µb.staticNetFilteringEngine.toLogData())
+ .toLogger();
}
}
}
@@ -357,7 +362,7 @@ PageStore.prototype.reuse = function(context) {
// When force refreshing a page, the page store data needs to be reset.
// If the hostname changes, we can't merely just update the context.
- var tabContext = µb.tabContextManager.mustLookup(this.tabId);
+ const tabContext = µb.tabContextManager.mustLookup(this.tabId);
if ( tabContext.rootHostname !== this.tabHostname ) {
context = '';
}
@@ -416,22 +421,18 @@ PageStore.prototype.dispose = function() {
/******************************************************************************/
PageStore.prototype.disposeFrameStores = function() {
- for ( var frameStore of this.frames.values() ) {
+ for ( const frameStore of this.frames.values() ) {
frameStore.dispose();
}
this.frames.clear();
};
-/******************************************************************************/
-
PageStore.prototype.getFrame = function(frameId) {
return this.frames.get(frameId) || null;
};
-/******************************************************************************/
-
PageStore.prototype.setFrame = function(frameId, frameURL) {
- var frameStore = this.frames.get(frameId);
+ const frameStore = this.frames.get(frameId);
if ( frameStore !== undefined ) {
frameStore.init(frameURL);
} else {
@@ -441,54 +442,19 @@ PageStore.prototype.setFrame = function(frameId, frameURL) {
/******************************************************************************/
-PageStore.prototype.createContextFromPage = function() {
- var context = µb.tabContextManager.createContext(this.tabId);
- context.pageHostname = context.rootHostname;
- context.pageDomain = context.rootDomain;
- return context;
-};
-
-PageStore.prototype.createContextFromFrameId = function(frameId) {
- var context = µb.tabContextManager.createContext(this.tabId);
- var frameStore = this.frames.get(frameId);
- if ( frameStore !== undefined ) {
- context.pageHostname = frameStore.pageHostname;
- context.pageDomain = frameStore.pageDomain;
- } else {
- context.pageHostname = context.rootHostname;
- context.pageDomain = context.rootDomain;
- }
- return context;
-};
-
-PageStore.prototype.createContextFromFrameHostname = function(frameHostname) {
- var context = µb.tabContextManager.createContext(this.tabId);
- context.pageHostname = frameHostname;
- context.pageDomain = µb.URI.domainFromHostname(frameHostname) || frameHostname;
- return context;
-};
-
-/******************************************************************************/
-
PageStore.prototype.getNetFilteringSwitch = function() {
return µb.tabContextManager.mustLookup(this.tabId).getNetFilteringSwitch();
};
-/******************************************************************************/
-
PageStore.prototype.getSpecificCosmeticFilteringSwitch = function() {
return this.noCosmeticFiltering !== true;
};
-/******************************************************************************/
-
PageStore.prototype.getGenericCosmeticFilteringSwitch = function() {
return this.noGenericCosmeticFiltering !== true &&
this.noCosmeticFiltering !== true;
};
-/******************************************************************************/
-
PageStore.prototype.toggleNetFilteringSwitch = function(url, scope, state) {
µb.toggleNetFilteringSwitch(url, scope, state);
this.netFilteringCache.empty();
@@ -562,15 +528,14 @@ PageStore.prototype.journalProcess = function(fromTimer) {
}
this.journalTimer = null;
- var journal = this.journal,
- n = journal.length,
- aggregateCounts = 0,
- now = Date.now(),
- pivot = this.journalLastCommitted || 0;
+ const journal = this.journal;
+ const now = Date.now();
+ let aggregateCounts = 0;
+ let pivot = this.journalLastCommitted || 0;
// Everything after pivot originates from current page.
- for ( let i = pivot; i < n; i += 2 ) {
- let hostname = journal[i];
+ for ( let i = pivot; i < journal.length; i += 2 ) {
+ const hostname = journal[i];
let hostnameCounts = this.hostnameToCountMap.get(hostname);
if ( hostnameCounts === undefined ) {
hostnameCounts = 0;
@@ -605,88 +570,101 @@ PageStore.prototype.journalProcess = function(fromTimer) {
/******************************************************************************/
-PageStore.prototype.filterRequest = function(context) {
- this.logData = undefined;
+PageStore.prototype.filterRequest = function(fctxt) {
+ fctxt.filter = undefined;
if ( this.getNetFilteringSwitch() === false ) {
return 0;
}
- var requestType = context.requestType;
+ const requestType = fctxt.type;
- if ( requestType === 'csp_report' && this.filterCSPReport(context) === 1 ) {
+ if ( requestType === 'csp_report' && this.filterCSPReport(fctxt) === 1 ) {
return 1;
}
- if ( requestType.endsWith('font') && this.filterFont(context) === 1 ) {
+ if ( requestType.endsWith('font') && this.filterFont(fctxt) === 1 ) {
return 1;
}
if (
requestType === 'script' &&
- this.filterScripting(context.rootHostname, true) === 1
+ this.filterScripting(fctxt, true) === 1
) {
return 1;
}
- var cacheableResult = this.cacheableResults[requestType] === true;
+ const cacheableResult = this.cacheableResults.has(requestType);
if ( cacheableResult ) {
- var entry = this.netFilteringCache.lookupResult(context);
+ const entry = this.netFilteringCache.lookupResult(fctxt);
if ( entry !== undefined ) {
- this.logData = entry.logData;
+ fctxt.filter = entry.logData;
return entry.result;
}
}
// Dynamic URL filtering.
- var result = µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, requestType);
- if ( result !== 0 && µb.logger.isEnabled() ) {
- this.logData = µb.sessionURLFiltering.toLogData();
+ let result = µb.sessionURLFiltering.evaluateZ(
+ fctxt.getTabHostname(),
+ fctxt.url,
+ requestType
+ );
+ if ( result !== 0 && µb.logger.enabled ) {
+ fctxt.filter = µb.sessionURLFiltering.toLogData();
}
// Dynamic hostname/type filtering.
if ( result === 0 && µb.userSettings.advancedUserEnabled ) {
- result = µb.sessionFirewall.evaluateCellZY(context.rootHostname, context.requestHostname, requestType);
- if ( result !== 0 && result !== 3 && µb.logger.isEnabled() ) {
- this.logData = µb.sessionFirewall.toLogData();
+ result = µb.sessionFirewall.evaluateCellZY(
+ fctxt.getTabHostname(),
+ fctxt.getHostname(),
+ requestType
+ );
+ if ( result !== 0 && result !== 3 && µb.logger.enabled ) {
+ fctxt.filter = µb.sessionFirewall.toLogData();
}
}
// Static filtering has lowest precedence.
if ( result === 0 || result === 3 ) {
- result = µb.staticNetFilteringEngine.matchString(context);
- if ( result !== 0 && µb.logger.isEnabled() ) {
- this.logData = µb.staticNetFilteringEngine.toLogData();
+ result = µb.staticNetFilteringEngine.matchString(fctxt);
+ if ( result !== 0 && µb.logger.enabled ) {
+ fctxt.filter = µb.staticNetFilteringEngine.toLogData();
}
}
if ( cacheableResult ) {
- this.netFilteringCache.rememberResult(context, result, this.logData);
- } else if ( result === 1 && this.collapsibleResources[requestType] === true ) {
- this.netFilteringCache.rememberBlock(context, true);
+ this.netFilteringCache.rememberResult(fctxt, result, this.logData);
+ } else if ( result === 1 && this.collapsibleResources.has(requestType) ) {
+ this.netFilteringCache.rememberBlock(fctxt, true);
}
return result;
};
-PageStore.prototype.cacheableResults = {
- sub_frame: true
-};
+PageStore.prototype.cacheableResults = new Set([
+ 'sub_frame',
+]);
-PageStore.prototype.collapsibleResources = {
- image: true,
- media: true,
- object: true,
- sub_frame: true
-};
+PageStore.prototype.collapsibleResources = new Set([
+ 'image',
+ 'media',
+ 'object',
+ 'sub_frame',
+]);
/******************************************************************************/
-PageStore.prototype.filterCSPReport = function(context) {
- if ( µb.sessionSwitches.evaluateZ('no-csp-reports', context.requestHostname) ) {
- if ( µb.logger.isEnabled() ) {
- this.logData = µb.sessionSwitches.toLogData();
+PageStore.prototype.filterCSPReport = function(fctxt) {
+ if (
+ µb.sessionSwitches.evaluateZ(
+ 'no-csp-reports',
+ fctxt.getHostname()
+ )
+ ) {
+ if ( µb.logger.enabled ) {
+ fctxt.filter = µb.sessionSwitches.toLogData();
}
return 1;
}
@@ -695,13 +673,18 @@ PageStore.prototype.filterCSPReport = function(context) {
/******************************************************************************/
-PageStore.prototype.filterFont = function(context) {
- if ( context.requestType === 'font' ) {
+PageStore.prototype.filterFont = function(fctxt) {
+ if ( fctxt.type === 'font' ) {
this.remoteFontCount += 1;
}
- if ( µb.sessionSwitches.evaluateZ('no-remote-fonts', context.rootHostname) !== false ) {
- if ( µb.logger.isEnabled() ) {
- this.logData = µb.sessionSwitches.toLogData();
+ if (
+ µb.sessionSwitches.evaluateZ(
+ 'no-remote-fonts',
+ fctxt.getTabHostname()
+ ) !== false
+ ) {
+ if ( µb.logger.enabled ) {
+ fctxt.filter = µb.sessionSwitches.toLogData();
}
return 1;
}
@@ -710,18 +693,22 @@ PageStore.prototype.filterFont = function(context) {
/******************************************************************************/
-PageStore.prototype.filterScripting = function(rootHostname, netFiltering) {
+PageStore.prototype.filterScripting = function(fctxt, netFiltering) {
+ fctxt.filter = undefined;
if ( netFiltering === undefined ) {
netFiltering = this.getNetFilteringSwitch();
}
if (
netFiltering === false ||
- µb.sessionSwitches.evaluateZ('no-scripting', rootHostname) === false
+ µb.sessionSwitches.evaluateZ(
+ 'no-scripting',
+ fctxt.getTabHostname()
+ ) === false
) {
return 0;
}
- if ( µb.logger.isEnabled() ) {
- this.logData = µb.sessionSwitches.toLogData();
+ if ( µb.logger.enabled ) {
+ fctxt.filter = µb.sessionSwitches.toLogData();
}
return 1;
};
@@ -730,13 +717,18 @@ PageStore.prototype.filterScripting = function(rootHostname, netFiltering) {
// The caller is responsible to check whether filtering is enabled or not.
-PageStore.prototype.filterLargeMediaElement = function(size) {
- this.logData = undefined;
+PageStore.prototype.filterLargeMediaElement = function(fctxt, size) {
+ fctxt.filter = undefined;
if ( Date.now() < this.allowLargeMediaElementsUntil ) {
return 0;
}
- if ( µb.sessionSwitches.evaluateZ('no-large-media', this.tabHostname) !== true ) {
+ if (
+ µb.sessionSwitches.evaluateZ(
+ 'no-large-media',
+ fctxt.getTabHostname()
+ ) !== true
+ ) {
return 0;
}
if ( (size >>> 10) < µb.userSettings.largeMediaSize ) {
@@ -751,8 +743,8 @@ PageStore.prototype.filterLargeMediaElement = function(size) {
);
}
- if ( µb.logger.isEnabled() ) {
- this.logData = µb.sessionSwitches.toLogData();
+ if ( µb.logger.enabled ) {
+ fctxt.filter = µb.sessionSwitches.toLogData();
}
return 1;
@@ -763,26 +755,27 @@ PageStore.prototype.filterLargeMediaElement = function(size) {
/******************************************************************************/
PageStore.prototype.getBlockedResources = function(request, response) {
- var µburi = µb.URI,
- normalURL = µb.normalizePageURL(this.tabId, request.frameURL),
- frameHostname = µburi.hostnameFromURI(normalURL),
- resources = request.resources;
+ const normalURL = µb.normalizePageURL(this.tabId, request.frameURL);
+ const resources = request.resources;
+ const fctxt = µBlock.filteringContext;
+ fctxt.fromTabId(this.tabId)
+ .setDocOriginFromURL(normalURL);
// Force some resources to go through the filtering engine in order to
// populate the blocked-resources cache. This is required because for
// some resources it's not possible to detect whether they were blocked
// content script-side (i.e. `iframes` -- unlike `img`).
if ( Array.isArray(resources) && resources.length !== 0 ) {
- var context = this.createContextFromFrameHostname(frameHostname);
- for ( var resource of resources ) {
- context.requestType = resource.type;
- context.requestHostname = µburi.hostnameFromURI(resource.url);
- context.requestURL = resource.url;
- this.filterRequest(context);
+ for ( const resource of resources ) {
+ this.filterRequest(
+ fctxt.setType(resource.type)
+ .setURL(resource.url)
+ );
}
}
if ( this.netFilteringCache.hash === response.hash ) { return; }
response.hash = this.netFilteringCache.hash;
- response.blockedResources = this.netFilteringCache.lookupAllBlocked(frameHostname);
+ response.blockedResources =
+ this.netFilteringCache.lookupAllBlocked(fctxt.getDocHostname());
};
/******************************************************************************/
diff --git a/src/js/redirect-engine.js b/src/js/redirect-engine.js
index 8b106449f..bfcdfb5c0 100644
--- a/src/js/redirect-engine.js
+++ b/src/js/redirect-engine.js
@@ -95,14 +95,14 @@ const RedirectEntry = function() {
// - https://stackoverflow.com/a/8056313
// - https://bugzilla.mozilla.org/show_bug.cgi?id=998076
-RedirectEntry.prototype.toURL = function(details) {
+RedirectEntry.prototype.toURL = function(fctxt) {
if (
this.warURL !== undefined &&
- details instanceof Object &&
- details.requestType !== 'xmlhttprequest' &&
+ fctxt instanceof Object &&
+ fctxt.type !== 'xmlhttprequest' &&
(
suffersSpuriousRedirectConflicts === false ||
- details.requestURL.startsWith('https:')
+ fctxt.url.startsWith('https:')
)
) {
return this.warURL + '?secret=' + vAPI.warSecret;
@@ -187,14 +187,14 @@ RedirectEngine.prototype.toBroaderHostname = function(hostname) {
/******************************************************************************/
-RedirectEngine.prototype.lookup = function(context) {
- var type = context.requestType;
+RedirectEngine.prototype.lookup = function(fctxt) {
+ const type = fctxt.type;
if ( this.ruleTypes.has(type) === false ) { return; }
- var src = context.pageHostname,
- des = context.requestHostname,
- desAll = this._desAll,
- reqURL = context.requestURL;
- var n = 0;
+ const desAll = this._desAll;
+ const reqURL = fctxt.url;
+ let src = fctxt.getDocHostname();
+ let des = fctxt.getHostname();
+ let n = 0;
for (;;) {
if ( this.ruleDestinations.has(des) ) {
desAll[n] = des; n += 1;
@@ -203,11 +203,10 @@ RedirectEngine.prototype.lookup = function(context) {
if ( des === '' ) { break; }
}
if ( n === 0 ) { return; }
- var entries;
for (;;) {
if ( this.ruleSources.has(src) ) {
- for ( var i = 0; i < n; i++ ) {
- entries = this.rules.get(src + ' ' + desAll[i] + ' ' + type);
+ for ( let i = 0; i < n; i++ ) {
+ const entries = this.rules.get(src + ' ' + desAll[i] + ' ' + type);
if ( entries && this.lookupToken(entries, reqURL) ) {
return this.resourceNameRegister;
}
@@ -234,12 +233,12 @@ RedirectEngine.prototype.lookupToken = function(entries, reqURL) {
/******************************************************************************/
-RedirectEngine.prototype.toURL = function(context) {
- let token = this.lookup(context);
+RedirectEngine.prototype.toURL = function(fctxt) {
+ let token = this.lookup(fctxt);
if ( token === undefined ) { return; }
let entry = this.resources.get(token);
if ( entry !== undefined ) {
- return entry.toURL(context);
+ return entry.toURL(fctxt);
}
};
diff --git a/src/js/scriptlet-filtering.js b/src/js/scriptlet-filtering.js
index 258d580ee..57441bf8e 100644
--- a/src/js/scriptlet-filtering.js
+++ b/src/js/scriptlet-filtering.js
@@ -24,18 +24,26 @@
/******************************************************************************/
µBlock.scriptletFilteringEngine = (function() {
- let api = {};
-
- let µb = µBlock,
- scriptletDB = new µb.staticExtFilteringEngine.HostnameBasedDB(),
+ const µb = µBlock,
duplicates = new Set(),
- acceptedCount = 0,
- discardedCount = 0,
scriptletCache = new µb.MRUCache(32),
- exceptionsRegister = new Set(),
scriptletsRegister = new Map(),
+ exceptionsRegister = new Set(),
reEscapeScriptArg = /[\\'"]/g;
+ let acceptedCount = 0,
+ discardedCount = 0,
+ scriptletDB = new µb.staticExtFilteringEngine.HostnameBasedDB();
+
+ const api = {
+ get acceptedCount() {
+ return acceptedCount;
+ },
+ get discardedCount() {
+ return discardedCount;
+ }
+ };
+
// Purpose of `contentscriptCode` below is too programmatically inject
// content script code which only purpose is to inject scriptlets. This
// essentially does the same as what uBO's declarative content script does,
@@ -58,8 +66,8 @@
// Consequently, the programmatic-injection code path is taken only with
// Chromium-based browsers.
- let contentscriptCode = (function() {
- let parts = [
+ const contentscriptCode = (function() {
+ const parts = [
'(',
function(hostname, scriptlets) {
if (
@@ -163,15 +171,15 @@
};
})();
- let lookupScriptlet = function(raw, reng, toInject) {
+ const lookupScriptlet = function(raw, reng, toInject) {
if ( toInject.has(raw) ) { return; }
if ( scriptletCache.resetTime < reng.modifyTime ) {
scriptletCache.reset();
}
- var content = scriptletCache.lookup(raw);
+ let content = scriptletCache.lookup(raw);
if ( content === undefined ) {
- var token, args,
- pos = raw.indexOf(',');
+ const pos = raw.indexOf(',');
+ let token, args;
if ( pos === -1 ) {
token = raw;
} else {
@@ -196,13 +204,12 @@
// Fill template placeholders. Return falsy if:
// - At least one argument contains anything else than /\w/ and `.`
- let patchScriptlet = function(content, args) {
- var i = 1,
- pos, arg;
+ const patchScriptlet = function(content, args) {
+ let i = 1;
while ( args !== '' ) {
- pos = args.indexOf(',');
+ let pos = args.indexOf(',');
if ( pos === -1 ) { pos = args.length; }
- arg = args.slice(0, pos).trim().replace(reEscapeScriptArg, '\\$&');
+ const arg = args.slice(0, pos).trim().replace(reEscapeScriptArg, '\\$&');
content = content.replace('{{' + i + '}}', arg);
args = args.slice(pos + 1).trim();
i++;
@@ -210,19 +217,19 @@
return content;
};
- let logOne = function(isException, token, details) {
- µb.logger.writeOne(
- details.tabId,
- 'cosmetic',
- {
+ const logOne = function(isException, token, details) {
+ µBlock.filteringContext
+ .duplicate()
+ .fromTabId(details.tabId)
+ .setRealm('cosmetic')
+ .setType('dom')
+ .setURL(details.url)
+ .setDocOriginFromURL(details.url)
+ .setFilter({
source: 'cosmetic',
raw: (isException ? '#@#' : '##') + '+js(' + token + ')'
- },
- 'dom',
- details.url,
- null,
- details.hostname
- );
+ })
+ .toLogger();
};
api.reset = function() {
@@ -254,7 +261,7 @@
// because there is no way to create an exception to an exception.
for ( let hn of parsed.hostnames ) {
- let negated = hn.charCodeAt(0) === 0x7E /* '~' */;
+ const negated = hn.charCodeAt(0) === 0x7E /* '~' */;
if ( negated ) {
hn = hn.slice(1);
}
@@ -280,13 +287,13 @@
while ( reader.next() ) {
acceptedCount += 1;
- let fingerprint = reader.fingerprint();
+ const fingerprint = reader.fingerprint();
if ( duplicates.has(fingerprint) ) {
discardedCount += 1;
continue;
}
duplicates.add(fingerprint);
- let args = reader.args();
+ const args = reader.args();
if ( args.length < 4 ) { continue; }
scriptletDB.add(
args[1],
@@ -299,10 +306,10 @@
if ( scriptletDB.size === 0 ) { return; }
if ( µb.hiddenSettings.ignoreScriptInjectFilters ) { return; }
- let reng = µb.redirectEngine;
+ const reng = µb.redirectEngine;
if ( !reng ) { return; }
- let hostname = request.hostname;
+ const hostname = request.hostname;
// https://github.com/gorhill/uBlock/issues/2835
// Do not inject scriptlets if the site is under an `allow` rule.
@@ -313,8 +320,8 @@
return;
}
- let domain = request.domain,
- entity = request.entity;
+ const domain = request.domain;
+ const entity = request.entity;
// https://github.com/gorhill/uBlock/issues/1954
// Implicit
@@ -322,7 +329,7 @@
for (;;) {
lookupScriptlet(hn + '.js', reng, scriptletsRegister);
if ( hn === domain ) { break; }
- var pos = hn.indexOf('.');
+ const pos = hn.indexOf('.');
if ( pos === -1 ) { break; }
hn = hn.slice(pos + 1);
}
@@ -332,16 +339,16 @@
// Explicit
let entries = [];
- let domainHash = µb.staticExtFilteringEngine.makeHash(domain);
+ const domainHash = µb.staticExtFilteringEngine.makeHash(domain);
if ( domainHash !== 0 ) {
scriptletDB.retrieve(domainHash, hostname, entries);
}
- let entityHash = µb.staticExtFilteringEngine.makeHash(entity);
+ const entityHash = µb.staticExtFilteringEngine.makeHash(entity);
if ( entityHash !== 0 ) {
scriptletDB.retrieve(entityHash, entity, entries);
}
scriptletDB.retrieve(0, hostname, entries);
- for ( let entry of entries ) {
+ for ( const entry of entries ) {
lookupScriptlet(entry.token, reng, scriptletsRegister);
}
@@ -356,19 +363,19 @@
scriptletDB.retrieve(entityHash | 0b0001, entity, entries);
}
scriptletDB.retrieve(0 | 0b0001, hostname, entries);
- for ( let entry of entries ) {
+ for ( const entry of entries ) {
exceptionsRegister.add(entry.token);
}
// Return an array of scriptlets, and log results if needed.
- let out = [],
- logger = µb.logger.isEnabled() ? µb.logger : null,
- isException;
- for ( let entry of scriptletsRegister ) {
- if ( (isException = exceptionsRegister.has(entry[0])) === false ) {
+ const out = [];
+ const loggerEnabled = µb.logger.enabled;
+ for ( const entry of scriptletsRegister ) {
+ const isException = exceptionsRegister.has(entry[0]);
+ if ( isException === false ) {
out.push(entry[1]);
}
- if ( logger !== null ) {
+ if ( loggerEnabled ) {
logOne(isException, entry[0], request);
}
}
@@ -384,7 +391,7 @@
api.injectNow = function(details) {
if ( typeof details.frameId !== 'number' ) { return; }
if ( µb.URI.isNetworkURI(details.url) === false ) { return; }
- let request = {
+ const request = {
tabId: details.tabId,
frameId: details.frameId,
url: details.url,
@@ -394,7 +401,7 @@
};
request.domain = µb.URI.domainFromHostname(request.hostname);
request.entity = µb.URI.entityFromDomain(request.domain);
- let scriptlets = µb.scriptletFilteringEngine.retrieve(request);
+ const scriptlets = µb.scriptletFilteringEngine.retrieve(request);
if ( scriptlets === undefined ) { return; }
let code = contentscriptCode.assemble(request.hostname, scriptlets);
if ( µb.hiddenSettings.debugScriptlets ) {
@@ -419,19 +426,6 @@
scriptletDB = new µb.staticExtFilteringEngine.HostnameBasedDB(selfie);
};
- Object.defineProperties(api, {
- acceptedCount: {
- get: function() {
- return acceptedCount;
- }
- },
- discardedCount: {
- get: function() {
- return discardedCount;
- }
- }
- });
-
return api;
})();
diff --git a/src/js/static-ext-filtering.js b/src/js/static-ext-filtering.js
index e53e7739a..b54058547 100644
--- a/src/js/static-ext-filtering.js
+++ b/src/js/static-ext-filtering.js
@@ -663,11 +663,9 @@
return compiled;
}
- µb.logger.writeOne(
- '',
- 'error',
- 'Cosmetic filtering – invalid filter: ' + raw
- );
+ µb.logger.writeOne({
+ error: 'Cosmetic filtering – invalid filter: ' + raw
+ });
};
return entryPoint;
diff --git a/src/js/static-net-filtering.js b/src/js/static-net-filtering.js
index f02b3fe50..30b788639 100644
--- a/src/js/static-net-filtering.js
+++ b/src/js/static-net-filtering.js
@@ -126,13 +126,6 @@ let pageHostnameRegister = '',
// Local helpers
-// Be sure to not confuse 'example.com' with 'anotherexample.com'
-const isFirstParty = function(domain, hostname) {
- return hostname.endsWith(domain) &&
- (hostname.length === domain.length ||
- hostname.charCodeAt(hostname.length - domain.length - 1) === 0x2E /* '.' */);
-};
-
const normalizeRegexSource = function(s) {
try {
const re = new RegExp(s);
@@ -2184,12 +2177,10 @@ FilterContainer.prototype.compile = function(raw, writer) {
// ORDER OF TESTS IS IMPORTANT!
// Ignore empty lines
- var s = raw.trim();
- if ( s.length === 0 ) {
- return false;
- }
+ const s = raw.trim();
+ if ( s.length === 0 ) { return false; }
- var parsed = this.filterParser.parse(s);
+ const parsed = this.filterParser.parse(s);
// Ignore element-hiding filters
if ( parsed.elemHiding ) {
@@ -2198,7 +2189,9 @@ FilterContainer.prototype.compile = function(raw, writer) {
// Ignore filters with unsupported options
if ( parsed.unsupported ) {
- µb.logger.writeOne('', 'error', 'Network filtering – invalid filter: ' + raw);
+ µb.logger.writeOne({
+ error: 'Network filtering – invalid filter: ' + raw
+ });
return false;
}
@@ -2217,7 +2210,7 @@ FilterContainer.prototype.compile = function(raw, writer) {
parsed.makeToken();
- var fdata;
+ let fdata;
if ( parsed.isRegex ) {
fdata = FilterRegex.compile(parsed);
} else if ( parsed.hostnamePure ) {
@@ -2256,7 +2249,7 @@ FilterContainer.prototype.compile = function(raw, writer) {
fdata = FilterPlain.compile(parsed);
}
- var fwrapped;
+ let fwrapped;
if ( parsed.domainOpt !== '' ) {
fwrapped = fdata;
fdata = FilterOrigin.compile(parsed);
@@ -2520,24 +2513,22 @@ FilterContainer.prototype.matchStringGenericHide = function(requestURL) {
// Some type of requests are exceptional, they need custom handling,
// not the generic handling.
-FilterContainer.prototype.matchStringExactType = function(context, requestURL, requestType) {
+FilterContainer.prototype.matchStringExactType = function(fctxt, requestType) {
// Special cases.
if ( requestType === 'generichide' ) {
- return this.matchStringGenericHide(requestURL);
+ return this.matchStringGenericHide(fctxt.url);
}
let type = typeNameToTypeValue[requestType];
if ( type === undefined ) { return 0; }
// Prime tokenizer: we get a normalized URL in return.
- let url = this.urlTokenizer.setURL(requestURL);
+ let url = this.urlTokenizer.setURL(fctxt.url);
// These registers will be used by various filters
- pageHostnameRegister = context.pageHostname || '';
- requestHostnameRegister = µb.URI.hostnameFromURI(url);
+ pageHostnameRegister = fctxt.getDocHostname();
+ requestHostnameRegister = fctxt.getHostname();
- let party = isFirstParty(context.pageDomain, requestHostnameRegister)
- ? FirstParty
- : ThirdParty;
+ let party = fctxt.is3rdPartyToDoc() ? ThirdParty : FirstParty;
let categories = this.categories,
catBits, bucket;
@@ -2602,15 +2593,15 @@ FilterContainer.prototype.matchStringExactType = function(context, requestURL, r
/******************************************************************************/
-FilterContainer.prototype.matchString = function(context) {
+FilterContainer.prototype.matchString = function(fctxt) {
// https://github.com/chrisaljoudi/uBlock/issues/519
// Use exact type match for anything beyond `other`
// Also, be prepared to support unknown types
- let type = typeNameToTypeValue[context.requestType];
+ let type = typeNameToTypeValue[fctxt.type];
if ( type === undefined ) {
type = otherTypeBitValue;
} else if ( type === 0 || type > otherTypeBitValue ) {
- return this.matchStringExactType(context, context.requestURL, context.requestType);
+ return this.matchStringExactType(fctxt, fctxt.type);
}
// The logic here is simple:
@@ -2635,17 +2626,17 @@ FilterContainer.prototype.matchString = function(context) {
// filter.
// Prime tokenizer: we get a normalized URL in return.
- let url = this.urlTokenizer.setURL(context.requestURL);
+ let url = this.urlTokenizer.setURL(fctxt.url);
// These registers will be used by various filters
- pageHostnameRegister = context.pageHostname || '';
- requestHostnameRegister = context.requestHostname;
+ pageHostnameRegister = fctxt.getDocHostname();
+ requestHostnameRegister = fctxt.getHostname();
this.fRegister = null;
- let party = isFirstParty(context.pageDomain, context.requestHostname)
- ? FirstParty
- : ThirdParty;
+ let party = fctxt.is3rdPartyToDoc()
+ ? ThirdParty
+ : FirstParty;
let categories = this.categories,
catBits, bucket;
diff --git a/src/js/tab.js b/src/js/tab.js
index 35f90d9f5..8146f84b2 100644
--- a/src/js/tab.js
+++ b/src/js/tab.js
@@ -215,6 +215,7 @@ housekeep itself.
this.stack = [];
this.rawURL =
this.normalURL =
+ this.origin =
this.rootHostname =
this.rootDomain = '';
this.commitTimer = null;
@@ -305,14 +306,21 @@ housekeep itself.
TabContext.prototype.update = function() {
this.netFilteringReadTime = 0;
if ( this.stack.length === 0 ) {
- this.rawURL = this.normalURL = this.rootHostname = this.rootDomain = '';
+ this.rawURL =
+ this.normalURL =
+ this.origin =
+ this.rootHostname =
+ this.rootDomain = '';
return;
}
var stackEntry = this.stack[this.stack.length - 1];
this.rawURL = stackEntry.url;
this.normalURL = µb.normalizePageURL(this.tabId, this.rawURL);
- this.rootHostname = µb.URI.hostnameFromURI(this.normalURL);
- this.rootDomain = µb.URI.domainFromHostname(this.rootHostname) || this.rootHostname;
+ this.origin = µb.URI.originFromURI(this.normalURL);
+ this.rootHostname = µb.URI.hostnameFromURI(this.origin);
+ this.rootDomain =
+ µb.URI.domainFromHostname(this.rootHostname) ||
+ this.rootHostname;
};
// Called whenever a candidate root URL is spotted for the tab.
@@ -431,15 +439,13 @@ housekeep itself.
// Behind-the-scene tab context
(function() {
- var entry = new TabContext(vAPI.noTabId);
+ const entry = new TabContext(vAPI.noTabId);
entry.stack.push(new StackEntry('', true));
entry.rawURL = '';
entry.normalURL = µb.normalizePageURL(entry.tabId);
- entry.rootHostname = µb.URI.hostnameFromURI(entry.normalURL);
+ entry.origin = µb.URI.originFromURI(entry.normalURL);
+ entry.rootHostname = µb.URI.hostnameFromURI(entry.origin);
entry.rootDomain = µb.URI.domainFromHostname(entry.rootHostname);
-
- entry = new TabContext(vAPI.anyTabId);
- entry.stack.push(new StackEntry('', true));
})();
// Context object, typically to be used to feed filtering engines.
@@ -454,6 +460,7 @@ housekeep itself.
this.pageHostname =
this.pageDomain =
this.requestURL =
+ this.origin =
this.requestHostname =
this.requestDomain = '';
return this;
@@ -550,8 +557,7 @@ vAPI.tabs.onClosed = function(tabId) {
vAPI.tabs.onPopupUpdated = (function() {
// The same context object will be reused everytime. This also allows to
// remember whether a popup or popunder was matched.
- var context = {},
- logData;
+ const fctxt = µBlock.filteringContext.setFilter(undefined);
// https://github.com/gorhill/uBlock/commit/1d448b85b2931412508aa01bf899e0b6f0033626#commitcomment-14944764
// See if two URLs are different, disregarding scheme -- because the
@@ -560,10 +566,10 @@ vAPI.tabs.onPopupUpdated = (function() {
// Maybe no link element was clicked.
// https://github.com/gorhill/uBlock/issues/3287
// Do not bail out if the target URL has no hostname.
- var areDifferentURLs = function(a, b) {
+ const areDifferentURLs = function(a, b) {
if ( b === '' ) { return true; }
if ( b.startsWith('about:') ) { return false; }
- var pos = a.indexOf('://');
+ let pos = a.indexOf('://');
if ( pos === -1 ) { return false; }
a = a.slice(pos);
pos = b.indexOf('://');
@@ -573,19 +579,12 @@ vAPI.tabs.onPopupUpdated = (function() {
return b !== a;
};
- var popupMatch = function(openerURL, targetURL, popupType) {
- var openerHostname = µb.URI.hostnameFromURI(openerURL),
- openerDomain = µb.URI.domainFromHostname(openerHostname),
- result;
-
- context.pageHostname = openerHostname;
- context.pageDomain = openerDomain;
- context.rootURL = openerURL;
- context.rootHostname = openerHostname;
- context.rootDomain = openerDomain;
- context.requestURL = targetURL;
- context.requestHostname = µb.URI.hostnameFromURI(targetURL);
- context.requestType = 'popup';
+ const popupMatch = function(openerURL, targetURL, popupType) {
+ fctxt.setTabOriginFromURL(openerURL)
+ .setDocOriginFromURL(openerURL)
+ .setURL(targetURL)
+ .setType('popup');
+ let result;
// https://github.com/gorhill/uBlock/issues/1735
// Do not bail out on `data:` URI, they are commonly used for popups.
@@ -603,16 +602,19 @@ vAPI.tabs.onPopupUpdated = (function() {
// Ignore bad target URL. On Firefox, an `about:blank` tab may be
// opened for a new tab before it is filled in with the real target
// URL.
- if ( openerHostname !== '' && targetURL !== 'about:blank' ) {
+ if ( fctxt.getTabHostname() !== '' && targetURL !== 'about:blank' ) {
// Check per-site switch first
// https://github.com/gorhill/uBlock/issues/3060
// - The no-popups switch must apply only to popups, not to
// popunders.
if (
popupType === 'popup' &&
- µb.sessionSwitches.evaluateZ('no-popups', openerHostname)
+ µb.sessionSwitches.evaluateZ(
+ 'no-popups',
+ fctxt.getTabHostname()
+ )
) {
- logData = {
+ fctxt.filter = {
raw: 'no-popups: ' + µb.sessionSwitches.z + ' true',
result: 1,
source: 'switch'
@@ -624,7 +626,7 @@ vAPI.tabs.onPopupUpdated = (function() {
// Take into account popup-specific rules in dynamic URL
// filtering, OR generic allow rules.
result = µb.sessionURLFiltering.evaluateZ(
- openerHostname,
+ fctxt.getTabHostname(),
targetURL,
popupType
);
@@ -632,7 +634,7 @@ vAPI.tabs.onPopupUpdated = (function() {
result === 1 && µb.sessionURLFiltering.type === popupType ||
result === 2
) {
- logData = µb.sessionURLFiltering.toLogData();
+ fctxt.filter = µb.sessionURLFiltering.toLogData();
return result;
}
@@ -641,12 +643,12 @@ vAPI.tabs.onPopupUpdated = (function() {
// rules are ignored, as block rules are not meant to block
// specific types like `popup` (just like with static filters).
result = µb.sessionFirewall.evaluateCellZY(
- openerHostname,
- context.requestHostname,
+ fctxt.getTabHostname(),
+ fctxt.getHostname(),
popupType
);
if ( result === 2 ) {
- logData = µb.sessionFirewall.toLogData();
+ fctxt.filter = µb.sessionFirewall.toLogData();
return 2;
}
}
@@ -656,12 +658,11 @@ vAPI.tabs.onPopupUpdated = (function() {
// Don't block if uBlock is turned off in popup's context
if ( µb.getNetFilteringSwitch(targetURL) ) {
result = µb.staticNetFilteringEngine.matchStringExactType(
- context,
- targetURL,
+ fctxt,
popupType
);
if ( result !== 0 ) {
- logData = µb.staticNetFilteringEngine.toLogData();
+ fctxt.filter = µb.staticNetFilteringEngine.toLogData();
return result;
}
}
@@ -669,23 +670,23 @@ vAPI.tabs.onPopupUpdated = (function() {
return 0;
};
- var mapPopunderResult = function(popunderURL, popunderHostname, result) {
+ const mapPopunderResult = function(popunderURL, popunderHostname, result) {
if (
- logData === undefined ||
- logData.source !== 'static' ||
- logData.token === µb.staticNetFilteringEngine.noTokenHash
+ fctxt.filter === undefined ||
+ fctxt.filter !== 'static' ||
+ fctxt.filter.token === µb.staticNetFilteringEngine.noTokenHash
) {
return 0;
}
- if ( logData.token === µb.staticNetFilteringEngine.dotTokenHash ) {
+ if ( fctxt.filter.token === µb.staticNetFilteringEngine.dotTokenHash ) {
return result;
}
- var re = new RegExp(logData.regex, 'i'),
- matches = re.exec(popunderURL);
+ const re = new RegExp(fctxt.filter.regex, 'i');
+ const matches = re.exec(popunderURL);
if ( matches === null ) { return 0; }
- var beg = matches.index,
- end = beg + matches[0].length,
- pos = popunderURL.indexOf(popunderHostname);
+ const beg = matches.index;
+ const end = beg + matches[0].length;
+ const pos = popunderURL.indexOf(popunderHostname);
if ( pos === -1 ) { return 0; }
// https://github.com/gorhill/uBlock/issues/1471
// We test whether the opener hostname as at least one character
@@ -698,36 +699,32 @@ vAPI.tabs.onPopupUpdated = (function() {
: 0;
};
- var popunderMatch = function(openerURL, targetURL) {
- var result = popupMatch(targetURL, openerURL, 'popunder');
- if ( result === 1 ) {
- return result;
- }
+ const popunderMatch = function(openerURL, targetURL) {
+ let result = popupMatch(targetURL, openerURL, 'popunder');
+ if ( result === 1 ) { return result; }
+
// https://github.com/gorhill/uBlock/issues/1010#issuecomment-186824878
// Check the opener tab as if it were the newly opened tab: if there
// is a hit against a popup filter, and if the matching filter is not
// a broad one, we will consider the opener tab to be a popunder tab.
// For now, a "broad" filter is one which does not touch any part of
// the hostname part of the opener URL.
- var popunderURL = openerURL,
+ let popunderURL = openerURL,
popunderHostname = µb.URI.hostnameFromURI(popunderURL);
- if ( popunderHostname === '' ) {
- return 0;
- }
+ if ( popunderHostname === '' ) { return 0; }
+
result = mapPopunderResult(
popunderURL,
popunderHostname,
popupMatch(targetURL, popunderURL, 'popup')
);
- if ( result !== 0 ) {
- return result;
- }
+ if ( result !== 0 ) { return result; }
+
// https://github.com/gorhill/uBlock/issues/1598
- // Try to find a match against origin part of the opener URL.
+ // Try to find a match against origin part of the opener URL.
popunderURL = µb.URI.originFromURI(popunderURL);
- if ( popunderURL === '' ) {
- return 0;
- }
+ if ( popunderURL === '' ) { return 0; }
+
return mapPopunderResult(
popunderURL,
popunderHostname,
@@ -737,40 +734,43 @@ vAPI.tabs.onPopupUpdated = (function() {
return function(targetTabId, openerDetails) {
// Opener details.
- var openerTabId = openerDetails.tabId;
- var tabContext = µb.tabContextManager.lookup(openerTabId);
+ const openerTabId = openerDetails.tabId;
+ let tabContext = µb.tabContextManager.lookup(openerTabId);
if ( tabContext === null ) { return; }
- var openerURL = tabContext.rawURL;
+ const openerURL = tabContext.rawURL;
if ( openerURL === '' ) { return; }
// Popup details.
tabContext = µb.tabContextManager.lookup(targetTabId);
if ( tabContext === null ) { return; }
- var targetURL = tabContext.rawURL;
+ let targetURL = tabContext.rawURL;
if ( targetURL === '' ) { return; }
// https://github.com/gorhill/uBlock/issues/341
// Allow popups if uBlock is turned off in opener's context.
- if ( µb.getNetFilteringSwitch(openerURL) === false ) {
- return;
- }
+ if ( µb.getNetFilteringSwitch(openerURL) === false ) { return; }
// https://github.com/gorhill/uBlock/issues/1538
- if ( µb.getNetFilteringSwitch(µb.normalizePageURL(openerTabId, openerURL)) === false ) {
+ if (
+ µb.getNetFilteringSwitch(µb.normalizePageURL(
+ openerTabId,
+ openerURL)
+ ) === false
+ ) {
return;
}
// If the page URL is that of our "blocked page" URL, extract the URL of
// the page which was blocked.
if ( targetURL.startsWith(vAPI.getURL('document-blocked.html')) ) {
- var matches = /details=([^&]+)/.exec(targetURL);
+ const matches = /details=([^&]+)/.exec(targetURL);
if ( matches !== null ) {
targetURL = JSON.parse(atob(matches[1])).url;
}
}
// Popup test.
- var popupType = 'popup',
+ let popupType = 'popup',
result = 0;
// https://github.com/gorhill/uBlock/issues/2919
// - If the target tab matches a clicked link, assume it's legit.
@@ -788,18 +788,21 @@ vAPI.tabs.onPopupUpdated = (function() {
// Log only for when there was a hit against an actual filter (allow or block).
// https://github.com/gorhill/uBlock/issues/2776
- if ( µb.logger.isEnabled() ) {
- µb.logger.writeOne(
- popupType === 'popup' ? openerTabId : targetTabId,
- 'net',
- result !== 0 ? logData : undefined,
- popupType,
- popupType === 'popup' ? targetURL : openerURL,
- µb.URI.hostnameFromURI(context.rootURL),
- µb.URI.hostnameFromURI(context.rootURL)
- );
+ if ( µb.logger.enabled ) {
+ fctxt.setRealm('net').setType(popupType);
+ if ( popupType === 'popup' ) {
+ fctxt.setURL(targetURL)
+ .setTabId(openerTabId)
+ .setTabOriginFromURL(openerURL)
+ .setDocOriginFromURL(openerURL);
+ } else {
+ fctxt.setURL(openerURL)
+ .setTabId(targetTabId)
+ .setTabOriginFromURL(targetURL)
+ .setDocOriginFromURL(targetURL);
+ }
+ fctxt.toLogger();
}
- logData = undefined;
// Not blocked
if ( result !== 1 ) {
@@ -808,9 +811,9 @@ vAPI.tabs.onPopupUpdated = (function() {
// Only if a popup was blocked do we report it in the dynamic
// filtering pane.
- var pageStore = µb.pageStoreFromTabId(openerTabId);
+ const pageStore = µb.pageStoreFromTabId(openerTabId);
if ( pageStore ) {
- pageStore.journalAddRequest(context.requestHostname, result);
+ pageStore.journalAddRequest(fctxt.getHostname(), result);
pageStore.popupBlockedCount += 1;
}
@@ -910,13 +913,9 @@ vAPI.tabs.registerListeners();
// Permanent page store for behind-the-scene requests. Must never be removed.
(function() {
- var pageStore = µb.PageStore.factory(vAPI.noTabId);
+ const pageStore = µb.PageStore.factory(vAPI.noTabId);
µb.pageStores.set(pageStore.tabId, pageStore);
pageStore.title = vAPI.i18n('logBehindTheScene');
-
- pageStore = µb.PageStore.factory(vAPI.anyTabId);
- µb.pageStores.set(pageStore.tabId, pageStore);
- pageStore.title = '[Any one of the known tabs]';
})();
/******************************************************************************/
diff --git a/src/js/traffic.js b/src/js/traffic.js
index a46aa5112..1d5d0ba57 100644
--- a/src/js/traffic.js
+++ b/src/js/traffic.js
@@ -49,148 +49,98 @@ window.addEventListener('webextFlavor', function() {
dontCacheResponseHeaders =
vAPI.webextFlavor.soup.has('firefox');
cantMergeCSPHeaders =
- vAPI.webextFlavor.soup.has('firefox') && vAPI.webextFlavor.major < 59;
+ vAPI.webextFlavor.soup.has('firefox') &&
+ vAPI.webextFlavor.major < 59;
}, { once: true });
/******************************************************************************/
// Intercept and filter web requests.
-var onBeforeRequest = function(details) {
+const onBeforeRequest = function(details) {
+ const fctxt = µBlock.filteringContext.fromWebrequestDetails(details);
+
// Special handling for root document.
// https://github.com/chrisaljoudi/uBlock/issues/1001
// This must be executed regardless of whether the request is
// behind-the-scene
- var requestType = details.type;
- if ( requestType === 'main_frame' ) {
- return onBeforeRootFrameRequest(details);
+ if ( details.type === 'main_frame' ) {
+ return onBeforeRootFrameRequest(fctxt);
}
// Special treatment: behind-the-scene requests
- var tabId = details.tabId;
- if ( vAPI.isBehindTheSceneTabId(tabId) ) {
- return onBeforeBehindTheSceneRequest(details);
+ const tabId = details.tabId;
+ if ( tabId < 0 ) {
+ return onBeforeBehindTheSceneRequest(fctxt);
}
// Lookup the page store associated with this tab id.
- var µb = µBlock,
- pageStore = µb.pageStoreFromTabId(tabId);
- if ( !pageStore ) {
- var tabContext = µb.tabContextManager.mustLookup(tabId);
- if ( vAPI.isBehindTheSceneTabId(tabContext.tabId) ) {
- return onBeforeBehindTheSceneRequest(details);
+ const µb = µBlock;
+ let pageStore = µb.pageStoreFromTabId(tabId);
+ if ( pageStore === null ) {
+ const tabContext = µb.tabContextManager.mustLookup(tabId);
+ if ( tabContext.tabId < 0 ) {
+ return onBeforeBehindTheSceneRequest(fctxt);
}
- vAPI.tabs.onNavigation({ tabId: tabId, frameId: 0, url: tabContext.rawURL });
+ vAPI.tabs.onNavigation({ tabId, frameId: 0, url: tabContext.rawURL });
pageStore = µb.pageStoreFromTabId(tabId);
}
- // https://github.com/chrisaljoudi/uBlock/issues/886
- // For requests of type `sub_frame`, the parent frame id must be used
- // to lookup the proper context:
- // > If the document of a (sub-)frame is loaded (type is main_frame or
- // > sub_frame), frameId indicates the ID of this frame, not the ID of
- // > the outer frame.
- // > (ref: https://developer.chrome.com/extensions/webRequest)
- var isFrame = requestType === 'sub_frame';
+ const result = pageStore.filterRequest(fctxt);
- // https://github.com/chrisaljoudi/uBlock/issues/114
- var requestContext = pageStore.createContextFromFrameId(
- isFrame ? details.parentFrameId : details.frameId
- );
+ pageStore.journalAddRequest(fctxt.getHostname(), result);
- // Setup context and evaluate
- var requestURL = details.url;
- requestContext.requestURL = requestURL;
- requestContext.requestHostname = µb.URI.hostnameFromURI(requestURL);
- requestContext.requestType = requestType;
-
- var result = pageStore.filterRequest(requestContext);
-
- pageStore.journalAddRequest(requestContext.requestHostname, result);
-
- if ( µb.logger.isEnabled() ) {
- µb.logger.writeOne(
- tabId,
- 'net',
- pageStore.logData,
- requestType,
- requestURL,
- requestContext.rootHostname,
- requestContext.pageHostname
- );
+ if ( µb.logger.enabled ) {
+ fctxt.setRealm('net').toLogger();
}
// Not blocked
if ( result !== 1 ) {
- // https://github.com/chrisaljoudi/uBlock/issues/114
- if ( details.parentFrameId !== -1 && isFrame ) {
- pageStore.setFrame(details.frameId, requestURL);
+ if ( details.parentFrameId !== -1 && details.type === 'sub_frame' ) {
+ pageStore.setFrame(details.frameId, details.url);
}
- requestContext.dispose();
return;
}
// Blocked
// https://github.com/gorhill/uBlock/issues/949
- // Redirect blocked request?
+ // Redirect blocked request?
if ( µb.hiddenSettings.ignoreRedirectFilters !== true ) {
- var url = µb.redirectEngine.toURL(requestContext);
+ const url = µb.redirectEngine.toURL(fctxt);
if ( url !== undefined ) {
pageStore.internalRedirectionCount += 1;
- if ( µb.logger.isEnabled() ) {
- µb.logger.writeOne(
- tabId,
- 'redirect',
- { source: 'redirect', raw: µb.redirectEngine.resourceNameRegister },
- requestType,
- requestURL,
- requestContext.rootHostname,
- requestContext.pageHostname
- );
+ if ( µb.logger.enabled ) {
+ fctxt.setRealm('redirect')
+ .setFilter({ source: 'redirect', raw: µb.redirectEngine.resourceNameRegister })
+ .toLogger();
}
- requestContext.dispose();
return { redirectUrl: url };
}
}
- requestContext.dispose();
return { cancel: true };
};
/******************************************************************************/
-var onBeforeRootFrameRequest = function(details) {
- var tabId = details.tabId,
- requestURL = details.url,
- µb = µBlock;
-
- µb.tabContextManager.push(tabId, requestURL);
+const onBeforeRootFrameRequest = function(fctxt) {
+ const µb = µBlock;
+ const requestURL = fctxt.url;
// Special handling for root document.
// https://github.com/chrisaljoudi/uBlock/issues/1001
- // This must be executed regardless of whether the request is
- // behind-the-scene
- var µburi = µb.URI,
- requestHostname = µburi.hostnameFromURI(requestURL),
- requestDomain = µburi.domainFromHostname(requestHostname) || requestHostname;
- var context = {
- rootHostname: requestHostname,
- rootDomain: requestDomain,
- pageHostname: requestHostname,
- pageDomain: requestDomain,
- requestURL: requestURL,
- requestHostname: requestHostname,
- requestType: 'main_frame'
- };
- var result = 0,
- logData,
- logEnabled = µb.logger.isEnabled();
+ // This must be executed regardless of whether the request is
+ // behind-the-scene
+ const requestHostname = fctxt.getHostname();
+ const logEnabled = µb.logger.enabled;
+ let result = 0,
+ logData;
// If the site is whitelisted, disregard strict blocking
if ( µb.getNetFilteringSwitch(requestURL) === false ) {
result = 2;
- if ( logEnabled === true ) {
+ if ( logEnabled ) {
logData = { engine: 'u', result: 2, raw: 'whitelisted' };
}
}
@@ -207,10 +157,7 @@ var onBeforeRootFrameRequest = function(details) {
}
// Temporarily whitelisted?
- if (
- result === 0 &&
- strictBlockBypasser.isBypassed(requestHostname)
- ) {
+ if ( result === 0 && strictBlockBypasser.isBypassed(requestHostname) ) {
result = 2;
if ( logEnabled ) {
logData = { engine: 'u', result: 2, raw: 'no-strict-blocking: true (temporary)' };
@@ -218,20 +165,20 @@ var onBeforeRootFrameRequest = function(details) {
}
// Static filtering: We always need the long-form result here.
- var snfe = µb.staticNetFilteringEngine;
+ const snfe = µb.staticNetFilteringEngine;
// Check for specific block
if ( result === 0 ) {
- result = snfe.matchStringExactType(context, requestURL, 'main_frame');
- if ( result !== 0 || logEnabled === true ) {
+ result = snfe.matchStringExactType(fctxt, 'main_frame');
+ if ( result !== 0 || logEnabled ) {
logData = snfe.toLogData();
}
}
// Check for generic block
if ( result === 0 ) {
- result = snfe.matchStringExactType(context, requestURL, 'no_type');
- if ( result !== 0 || logEnabled === true ) {
+ result = snfe.matchStringExactType(fctxt, 'no_type');
+ if ( result !== 0 || logEnabled ) {
logData = snfe.toLogData();
}
// https://github.com/chrisaljoudi/uBlock/issues/1128
@@ -249,22 +196,14 @@ var onBeforeRootFrameRequest = function(details) {
}
// Log
- var pageStore = µb.bindTabToPageStats(tabId, 'beforeRequest');
+ const pageStore = µb.bindTabToPageStats(fctxt.tabId, 'beforeRequest');
if ( pageStore ) {
pageStore.journalAddRootFrame('uncommitted', requestURL);
pageStore.journalAddRequest(requestHostname, result);
}
if ( logEnabled ) {
- µb.logger.writeOne(
- tabId,
- 'net',
- logData,
- 'main_frame',
- requestURL,
- requestHostname,
- requestHostname
- );
+ fctxt.setRealm('net').setFilter(logData).toLogger();
}
// Not blocked
@@ -275,15 +214,18 @@ var onBeforeRootFrameRequest = function(details) {
if ( logData === undefined ) { return; }
// Blocked
- var query = btoa(JSON.stringify({
+ const query = btoa(JSON.stringify({
url: requestURL,
hn: requestHostname,
- dn: requestDomain,
+ dn: fctxt.getDomain() || requestHostname,
fc: logData.compiled,
fs: logData.raw
}));
- vAPI.tabs.replace(tabId, vAPI.getURL('document-blocked.html?details=') + query);
+ vAPI.tabs.replace(
+ fctxt.tabId,
+ vAPI.getURL('document-blocked.html?details=') + query
+ );
return { cancel: true };
};
@@ -293,10 +235,10 @@ var onBeforeRootFrameRequest = function(details) {
// https://github.com/gorhill/uBlock/issues/3208
// Mind case insensitivity.
-var toBlockDocResult = function(url, hostname, logData) {
+const toBlockDocResult = function(url, hostname, logData) {
if ( typeof logData.regex !== 'string' ) { return false; }
- var re = new RegExp(logData.regex, 'i'),
- match = re.exec(url.toLowerCase());
+ const re = new RegExp(logData.regex, 'i');
+ const match = re.exec(url.toLowerCase());
if ( match === null ) { return false; }
// https://github.com/chrisaljoudi/uBlock/issues/1128
@@ -315,31 +257,11 @@ var toBlockDocResult = function(url, hostname, logData) {
// `beacon`, so now we can block them according to the state of the
// "Disable hyperlink auditing/beacon" setting.
-var onBeforeBehindTheSceneRequest = function(details) {
- var µb = µBlock,
- pageStore = µb.pageStoreFromTabId(details.tabId);
+const onBeforeBehindTheSceneRequest = function(fctxt) {
+ const µb = µBlock;
+ const pageStore = µb.pageStoreFromTabId(fctxt.tabId);
if ( pageStore === null ) { return; }
- var µburi = µb.URI,
- context = pageStore.createContextFromPage(),
- requestType = details.type,
- requestURL = details.url;
-
- context.requestURL = requestURL;
- context.requestHostname = µburi.hostnameFromURI(requestURL);
- context.requestType = requestType;
-
- var normalURL;
- if ( details.tabId === vAPI.anyTabId && context.pageHostname === '' ) {
- normalURL = µb.normalizePageURL(0, details.documentUrl);
- context.pageHostname = µburi.hostnameFromURI(normalURL);
- context.pageDomain = µburi.domainFromHostname(context.pageHostname);
- context.rootHostname = context.pageHostname;
- context.rootDomain = context.pageDomain;
- }
-
- pageStore.logData = undefined;
-
// https://bugs.chromium.org/p/chromium/issues/detail?id=637577#c15
// Do not filter behind-the-scene network request of type `beacon`: there
// is no point. In any case, this will become a non-issue once
@@ -359,14 +281,14 @@ var onBeforeBehindTheSceneRequest = function(details) {
// requests. Hopefully this will not break stuff as it used to be the
// case.
- var result = 0;
+ let result = 0;
if (
- µburi.isNetworkURI(details.documentUrl) ||
+ µb.URI.isNetworkURI(fctxt.docOrigin) ||
µb.userSettings.advancedUserEnabled ||
- requestType === 'csp_report'
+ fctxt.type === 'csp_report'
) {
- result = pageStore.filterRequest(context);
+ result = pageStore.filterRequest(fctxt);
// The "any-tab" scope is not whitelist-able, and in such case we must
// use the origin URL as the scope. Most such requests aren't going to
@@ -374,30 +296,19 @@ var onBeforeBehindTheSceneRequest = function(details) {
// result only when the request is being blocked.
if (
result === 1 &&
- normalURL !== undefined &&
- µb.getNetFilteringSwitch(normalURL) === false
+ µb.getNetFilteringSwitch(fctxt.tabOrigin) === false
) {
result = 2;
- pageStore.logData = { engine: 'u', result: 2, raw: 'whitelisted' };
+ fctxt.filter = { engine: 'u', result: 2, raw: 'whitelisted' };
}
}
- pageStore.journalAddRequest(context.requestHostname, result);
+ pageStore.journalAddRequest(fctxt.getHostname(), result);
- if ( µb.logger.isEnabled() ) {
- µb.logger.writeOne(
- details.tabId,
- 'net',
- pageStore.logData,
- requestType,
- requestURL,
- context.rootHostname,
- context.rootHostname
- );
+ if ( µb.logger.enabled ) {
+ fctxt.setRealm('net').toLogger();
}
- context.dispose();
-
// Blocked?
if ( result === 1 ) {
return { cancel: true };
@@ -408,18 +319,17 @@ var onBeforeBehindTheSceneRequest = function(details) {
// https://github.com/gorhill/uBlock/issues/3140
-let onBeforeMaybeSpuriousCSPReport = (function() {
+const onBeforeMaybeSpuriousCSPReport = (function() {
let textDecoder;
return function(details) {
- let tabId = details.tabId;
+ const fctxt = µBlock.filteringContext.fromWebrequestDetails(details);
// Ignore behind-the-scene requests.
- if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
+ if ( fctxt.tabId < 0 ) { return; }
// Lookup the page store associated with this tab id.
- let µb = µBlock,
- pageStore = µb.pageStoreFromTabId(tabId);
+ const pageStore = µBlock.pageStoreFromTabId(fctxt.tabId);
if ( pageStore === null ) { return; }
// If uBO is disabled for the page, it can't possibly causes CSP
@@ -445,7 +355,7 @@ let onBeforeMaybeSpuriousCSPReport = (function() {
textDecoder !== undefined &&
details.method === 'POST'
) {
- let raw = details.requestBody && details.requestBody.raw;
+ const raw = details.requestBody && details.requestBody.raw;
if (
Array.isArray(raw) &&
raw.length !== 0 &&
@@ -458,14 +368,14 @@ let onBeforeMaybeSpuriousCSPReport = (function() {
} catch (ex) {
}
if ( data instanceof Object ) {
- let report = data['csp-report'];
+ const report = data['csp-report'];
if ( report instanceof Object ) {
- let blocked =
- report['blocked-uri'] || report['blockedURI'],
- validBlocked = typeof blocked === 'string',
- source =
- report['source-file'] || report['sourceFile'],
- validSource = typeof source === 'string';
+ const blocked =
+ report['blocked-uri'] || report['blockedURI'];
+ const validBlocked = typeof blocked === 'string';
+ const source =
+ report['source-file'] || report['sourceFile'];
+ const validSource = typeof source === 'string';
if (
(validBlocked || validSource) &&
(!validBlocked || !blocked.startsWith('data')) &&
@@ -478,18 +388,13 @@ let onBeforeMaybeSpuriousCSPReport = (function() {
}
}
- // Potentially spurious CSP report.
- if ( µb.logger.isEnabled() ) {
- let hostname = µb.URI.hostnameFromURI(details.url);
- µb.logger.writeOne(
- tabId,
- 'net',
- { result: 1, source: 'global', raw: 'no-spurious-csp-report' },
- 'csp_report',
- details.url,
- hostname,
- hostname
- );
+ // At this point, we have a potentially spurious CSP report.
+
+ if ( µBlock.logger.enabled ) {
+ fctxt.setRealm('net')
+ .setType('csp_report')
+ .setFilter({ result: 1, source: 'global', raw: 'no-spurious-csp-report' })
+ .toLogger();
}
return { cancel: true };
@@ -504,44 +409,49 @@ let onBeforeMaybeSpuriousCSPReport = (function() {
// - HTML filtering (requires ability to modify response body)
// - CSP injection
-var onHeadersReceived = function(details) {
- // Do not interfere with behind-the-scene requests.
- let tabId = details.tabId;
- if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
+const onHeadersReceived = function(details) {
+ const fctxt = µBlock.filteringContext.fromWebrequestDetails(details);
- let µb = µBlock,
- requestType = details.type,
- isRootDoc = requestType === 'main_frame',
- isDoc = isRootDoc || requestType === 'sub_frame';
+ // Do not interfere with behind-the-scene requests.
+ if ( fctxt.tabId < 0 ) { return; }
+
+ const µb = µBlock;
+ const requestType = details.type;
+ const isRootDoc = requestType === 'main_frame';
+ const isDoc = isRootDoc || requestType === 'sub_frame';
if ( isRootDoc ) {
- µb.tabContextManager.push(tabId, details.url);
+ µb.tabContextManager.push(details.tabId, details.url);
}
- let pageStore = µb.pageStoreFromTabId(tabId);
+ let pageStore = µb.pageStoreFromTabId(fctxt.tabId);
if ( pageStore === null ) {
if ( isRootDoc === false ) { return; }
- pageStore = µb.bindTabToPageStats(tabId, 'beforeRequest');
+ pageStore = µb.bindTabToPageStats(fctxt.tabId, 'beforeRequest');
}
if ( pageStore.getNetFilteringSwitch() === false ) { return; }
- if ( requestType === 'image' || requestType === 'media' ) {
- return foilLargeMediaElement(pageStore, details);
- }
-
- if ( isDoc === false ) { return; }
-
// Keep in mind response headers will be modified in-place if needed, so
// `details.responseHeaders` will always point to the modified response
// headers.
- let responseHeaders = details.responseHeaders;
+ const responseHeaders = details.responseHeaders;
+
+ if ( requestType === 'image' || requestType === 'media' ) {
+ return foilLargeMediaElement(
+ fctxt,
+ pageStore,
+ responseHeaders
+ );
+ }
+
+ if ( isDoc === false ) { return; }
// https://github.com/gorhill/uBlock/issues/2813
// Disable the blocking of large media elements if the document is itself
// a media element: the resource was not prevented from loading so no
// point to further block large media elements for the current document.
if ( isRootDoc ) {
- let contentType = headerValueFromName('content-type', responseHeaders);
+ const contentType = headerValueFromName('content-type', responseHeaders);
if ( reMediaContentTypes.test(contentType) ) {
pageStore.allowLargeMediaElementsUntil = Date.now() + 86400000;
return;
@@ -550,10 +460,10 @@ var onHeadersReceived = function(details) {
// At this point we have a HTML document.
- let filteredHTML = µb.canFilterResponseData &&
- filterDocument(pageStore, details) === true;
+ const filteredHTML = µb.canFilterResponseData &&
+ filterDocument(pageStore, fctxt, details) === true;
- let modifiedHeaders = injectCSP(pageStore, details) === true;
+ let modifiedHeaders = injectCSP(fctxt, pageStore, responseHeaders) === true;
// https://bugzilla.mozilla.org/show_bug.cgi?id=1376932
// Prevent document from being cached by the browser if we modified it,
@@ -577,7 +487,7 @@ var onHeadersReceived = function(details) {
}
};
-var reMediaContentTypes = /^(?:audio|image|video)\//;
+const reMediaContentTypes = /^(?:audio|image|video)\//;
/*******************************************************************************
@@ -603,13 +513,13 @@ var reMediaContentTypes = /^(?:audio|image|video)\//;
**/
-var filterDocument = (function() {
- var µb = µBlock,
- filterers = new Map(),
- domParser, xmlSerializer,
+const filterDocument = (function() {
+ const µb = µBlock;
+ const filterers = new Map();
+ let domParser, xmlSerializer,
utf8TextDecoder, textDecoder, textEncoder;
- var textDecode = function(encoding, buffer) {
+ const textDecode = function(encoding, buffer) {
if (
textDecoder !== undefined &&
textDecoder.encoding !== encoding
@@ -622,25 +532,25 @@ var filterDocument = (function() {
return textDecoder.decode(buffer);
};
- var reContentTypeDocument = /^(?:text\/html|application\/xhtml\+xml)/i,
- reContentTypeCharset = /charset=['"]?([^'" ]+)/i;
+ const reContentTypeDocument = /^(?:text\/html|application\/xhtml\+xml)/i;
+ const reContentTypeCharset = /charset=['"]?([^'" ]+)/i;
- var mimeFromContentType = function(contentType) {
- var match = reContentTypeDocument.exec(contentType);
+ const mimeFromContentType = function(contentType) {
+ const match = reContentTypeDocument.exec(contentType);
if ( match !== null ) {
return match[0].toLowerCase();
}
};
- var charsetFromContentType = function(contentType) {
- var match = reContentTypeCharset.exec(contentType);
+ const charsetFromContentType = function(contentType) {
+ const match = reContentTypeCharset.exec(contentType);
if ( match !== null ) {
return match[1].toLowerCase();
}
};
- var charsetFromDoc = function(doc) {
- var meta = doc.querySelector('meta[charset]');
+ const charsetFromDoc = function(doc) {
+ let meta = doc.querySelector('meta[charset]');
if ( meta !== null ) {
return meta.getAttribute('charset').toLowerCase();
}
@@ -652,7 +562,7 @@ var filterDocument = (function() {
}
};
- var streamClose = function(filterer, buffer) {
+ const streamClose = function(filterer, buffer) {
if ( buffer !== undefined ) {
filterer.stream.write(buffer);
} else if ( filterer.buffer !== undefined ) {
@@ -661,8 +571,8 @@ var filterDocument = (function() {
filterer.stream.close();
};
- var onStreamData = function(ev) {
- var filterer = filterers.get(this);
+ const onStreamData = function(ev) {
+ const filterer = filterers.get(this);
if ( filterer === undefined ) {
this.write(ev.data);
this.disconnect();
@@ -691,7 +601,7 @@ var filterDocument = (function() {
filterer.buffer = new Uint8Array(ev.data);
return;
}
- var buffer = new Uint8Array(
+ const buffer = new Uint8Array(
filterer.buffer.byteLength +
ev.data.byteLength
);
@@ -700,8 +610,8 @@ var filterDocument = (function() {
filterer.buffer = buffer;
};
- var onStreamStop = function() {
- var filterer = filterers.get(this);
+ const onStreamStop = function() {
+ const filterer = filterers.get(this);
filterers.delete(this);
if ( filterer === undefined || filterer.buffer === null ) {
this.close();
@@ -717,10 +627,10 @@ var filterDocument = (function() {
textEncoder = new TextEncoder();
}
- var doc;
+ let doc;
// If stream encoding is still unknnown, try to extract from document.
- var charsetFound = filterer.charset,
+ let charsetFound = filterer.charset,
charsetUsed = charsetFound;
if ( charsetFound === undefined ) {
if ( utf8TextDecoder === undefined ) {
@@ -759,7 +669,7 @@ var filterDocument = (function() {
}
}
- var modified = false;
+ let modified = false;
if ( filterer.selectors !== undefined ) {
if ( µb.htmlFilteringEngine.apply(doc, filterer) ) {
modified = true;
@@ -771,12 +681,12 @@ var filterDocument = (function() {
}
// https://stackoverflow.com/questions/6088972/get-doctype-of-an-html-as-string-with-javascript/10162353#10162353
- var doctypeStr = doc.doctype instanceof Object ?
+ const doctypeStr = doc.doctype instanceof Object ?
xmlSerializer.serializeToString(doc.doctype) + '\n' :
'';
// https://github.com/gorhill/uBlock/issues/3391
- var encodedStream = textEncoder.encode(
+ let encodedStream = textEncoder.encode(
doctypeStr +
doc.documentElement.outerHTML
);
@@ -790,26 +700,26 @@ var filterDocument = (function() {
streamClose(filterer, encodedStream);
};
- var onStreamError = function() {
+ const onStreamError = function() {
filterers.delete(this);
};
- return function(pageStore, details) {
+ return function(pageStore, fctxt, extras) {
// https://github.com/gorhill/uBlock/issues/3478
- var statusCode = details.statusCode || 0;
+ const statusCode = extras.statusCode || 0;
if ( statusCode !== 0 && (statusCode < 200 || statusCode >= 300) ) {
return;
}
- var hostname = µb.URI.hostnameFromURI(details.url);
+ const hostname = fctxt.getHostname();
if ( hostname === '' ) { return; }
- var domain = µb.URI.domainFromHostname(hostname);
+ const domain = fctxt.getDomain();
- var request = {
+ const request = {
stream: undefined,
- tabId: details.tabId,
- url: details.url,
+ tabId: fctxt.tabId,
+ url: fctxt.url,
hostname: hostname,
domain: domain,
entity: µb.URI.entityFromDomain(domain),
@@ -822,12 +732,12 @@ var filterDocument = (function() {
request.selectors = µb.htmlFilteringEngine.retrieve(request);
if ( request.selectors === undefined ) { return; }
- var headers = details.responseHeaders,
- contentType = headerValueFromName('content-type', headers);
+ const headers = extras.responseHeaders;
+ const contentType = headerValueFromName('content-type', headers);
if ( contentType !== '' ) {
request.mime = mimeFromContentType(contentType);
if ( request.mime === undefined ) { return; }
- var charset = charsetFromContentType(contentType);
+ let charset = charsetFromContentType(contentType);
if ( charset !== undefined ) {
charset = µb.textEncode.normalizeCharset(charset);
if ( charset === undefined ) { return; }
@@ -837,8 +747,8 @@ var filterDocument = (function() {
// https://bugzilla.mozilla.org/show_bug.cgi?id=1426789
if ( headerValueFromName('content-disposition', headers) ) { return; }
- var stream = request.stream =
- browser.webRequest.filterResponseData(details.requestId);
+ const stream = request.stream =
+ browser.webRequest.filterResponseData(extras.requestId);
stream.ondata = onStreamData;
stream.onstop = onStreamStop;
stream.onerror = onStreamError;
@@ -850,74 +760,39 @@ var filterDocument = (function() {
/******************************************************************************/
-var injectCSP = function(pageStore, details) {
- let µb = µBlock,
- tabId = details.tabId,
- requestURL = details.url,
- loggerEnabled = µb.logger.isEnabled(),
- logger = µb.logger,
- cspSubsets = [];
-
- let context = pageStore.createContextFromPage();
- context.requestHostname = µb.URI.hostnameFromURI(requestURL);
- if ( details.type !== 'main_frame' ) {
- context.pageHostname = context.pageDomain = context.requestHostname;
- }
- context.requestURL = requestURL;
+const injectCSP = function(fctxt, pageStore, responseHeaders) {
+ const µb = µBlock;
+ const loggerEnabled = µb.logger.enabled;
+ const cspSubsets = [];
// Start collecting policies >>>>>>>>
// ======== built-in policies
- let builtinDirectives = [];
+ const builtinDirectives = [];
- context.requestType = 'script';
- if ( pageStore.filterScripting(context.rootHostname, true) === 1 ) {
+ if ( pageStore.filterScripting(fctxt, true) === 1 ) {
builtinDirectives.push("script-src http: https:");
- if ( loggerEnabled === true ) {
- logger.writeOne(
- tabId,
- 'net',
- pageStore.logData,
- 'no-scripting',
- requestURL,
- context.rootHostname,
- context.pageHostname
- );
+ if ( loggerEnabled ) {
+ fctxt.setRealm('net').setType('scripting').toLogger();
}
} else {
- context.requestType = 'inline-script';
- if ( pageStore.filterRequest(context) === 1 ) {
+ fctxt.type = 'inline-script';
+ if ( pageStore.filterRequest(fctxt) === 1 ) {
builtinDirectives.push("script-src 'unsafe-eval' * blob: data:");
- }
- if ( loggerEnabled === true ) {
- logger.writeOne(
- tabId,
- 'net',
- pageStore.logData,
- 'inline-script',
- requestURL,
- context.rootHostname,
- context.pageHostname
- );
+ if ( loggerEnabled ) {
+ fctxt.setRealm('net').toLogger();
+ }
}
}
// https://github.com/gorhill/uBlock/issues/1539
// - Use a CSP to also forbid inline fonts if remote fonts are blocked.
- context.requestType = 'inline-font';
- if ( pageStore.filterRequest(context) === 1 ) {
+ fctxt.type = 'inline-font';
+ if ( pageStore.filterRequest(fctxt) === 1 ) {
builtinDirectives.push('font-src *');
- if ( loggerEnabled === true ) {
- logger.writeOne(
- tabId,
- 'net',
- pageStore.logData,
- 'inline-font',
- requestURL,
- context.rootHostname,
- context.pageHostname
- );
+ if ( loggerEnabled ) {
+ fctxt.setRealm('net').toLogger();
}
}
@@ -929,32 +804,30 @@ var injectCSP = function(pageStore, details) {
// Static filtering.
- let logDataEntries = [];
+ const logDataEntries = loggerEnabled ? [] : undefined;
µb.staticNetFilteringEngine.matchAndFetchData(
'csp',
- requestURL,
+ fctxt.url,
cspSubsets,
- loggerEnabled === true ? logDataEntries : undefined
+ logDataEntries
);
// URL filtering `allow` rules override static filtering.
if (
cspSubsets.length !== 0 &&
- µb.sessionURLFiltering.evaluateZ(context.rootHostname, requestURL, 'csp') === 2
+ µb.sessionURLFiltering.evaluateZ(
+ fctxt.getTabHostname(),
+ fctxt.url,
+ 'csp'
+ ) === 2
) {
- if ( loggerEnabled === true ) {
- logger.writeOne(
- tabId,
- 'net',
- µb.sessionURLFiltering.toLogData(),
- 'csp',
- requestURL,
- context.rootHostname,
- context.pageHostname
- );
+ if ( loggerEnabled ) {
+ fctxt.setRealm('net')
+ .setType('csp')
+ .setFilter(µb.sessionURLFiltering.toLogData())
+ .toLogger();
}
- context.dispose();
return;
}
@@ -962,45 +835,34 @@ var injectCSP = function(pageStore, details) {
if (
cspSubsets.length !== 0 &&
µb.userSettings.advancedUserEnabled &&
- µb.sessionFirewall.evaluateCellZY(context.rootHostname, context.rootHostname, '*') === 2
+ µb.sessionFirewall.evaluateCellZY(
+ fctxt.getTabHostname(),
+ fctxt.getTabHostname(),
+ '*'
+ ) === 2
) {
- if ( loggerEnabled === true ) {
- logger.writeOne(
- tabId,
- 'net',
- µb.sessionFirewall.toLogData(),
- 'csp',
- requestURL,
- context.rootHostname,
- context.pageHostname
- );
+ if ( loggerEnabled ) {
+ fctxt.setRealm('net')
+ .setType('csp')
+ .setFilter(µb.sessionFirewall.toLogData())
+ .toLogger();
}
- context.dispose();
return;
}
// <<<<<<<< All policies have been collected
// Static CSP policies will be applied.
- for ( let entry of logDataEntries ) {
- logger.writeOne(
- tabId,
- 'net',
- entry,
- 'csp',
- requestURL,
- context.rootHostname,
- context.pageHostname
- );
+ if ( logDataEntries !== undefined ) {
+ fctxt.setRealm('net').setType('csp');
+ for ( const entry of logDataEntries ) {
+ fctxt.setFilter(entry).toLogger();
+ }
}
- context.dispose();
+ if ( cspSubsets.length === 0 ) { return; }
- if ( cspSubsets.length === 0 ) {
- return;
- }
-
- µb.updateToolbarIcon(tabId, 0x02);
+ µb.updateToolbarIcon(fctxt.tabId, 0x02);
// Use comma to merge CSP directives.
// Ref.: https://www.w3.org/TR/CSP2/#implementation-considerations
@@ -1010,17 +872,19 @@ var injectCSP = function(pageStore, details) {
// if the current environment does not support merging headers:
// Firefox 58/webext and less can't merge CSP headers, so we will merge
// them here.
- let headers = details.responseHeaders;
if ( cantMergeCSPHeaders ) {
- let i = headerIndexFromName('content-security-policy', headers);
+ const i = headerIndexFromName(
+ 'content-security-policy',
+ responseHeaders
+ );
if ( i !== -1 ) {
- cspSubsets.unshift(headers[i].value.trim());
- headers.splice(i, 1);
+ cspSubsets.unshift(responseHeaders[i].value.trim());
+ responseHeaders.splice(i, 1);
}
}
- headers.push({
+ responseHeaders.push({
name: 'Content-Security-Policy',
value: cspSubsets.join(', ')
});
@@ -1033,27 +897,16 @@ var injectCSP = function(pageStore, details) {
// https://github.com/gorhill/uBlock/issues/1163
// "Block elements by size"
-var foilLargeMediaElement = function(pageStore, details) {
- var µb = µBlock;
-
- var i = headerIndexFromName('content-length', details.responseHeaders);
+const foilLargeMediaElement = function(fctxt, pageStore, responseHeaders) {
+ const i = headerIndexFromName('content-length', responseHeaders);
if ( i === -1 ) { return; }
- var tabId = details.tabId,
- size = parseInt(details.responseHeaders[i].value, 10) || 0,
- result = pageStore.filterLargeMediaElement(size);
+ const size = parseInt(responseHeaders[i].value, 10) || 0;
+ const result = pageStore.filterLargeMediaElement(fctxt, size);
if ( result === 0 ) { return; }
- if ( µb.logger.isEnabled() ) {
- µb.logger.writeOne(
- tabId,
- 'net',
- pageStore.logData,
- details.type,
- details.url,
- pageStore.tabHostname,
- pageStore.tabHostname
- );
+ if ( µBlock.logger.enabled ) {
+ fctxt.setRealm('net').toLogger();
}
return { cancel: true };
@@ -1063,8 +916,8 @@ var foilLargeMediaElement = function(pageStore, details) {
// Caller must ensure headerName is normalized to lower case.
-var headerIndexFromName = function(headerName, headers) {
- var i = headers.length;
+const headerIndexFromName = function(headerName, headers) {
+ let i = headers.length;
while ( i-- ) {
if ( headers[i].name.toLowerCase() === headerName ) {
return i;
@@ -1073,19 +926,19 @@ var headerIndexFromName = function(headerName, headers) {
return -1;
};
-var headerValueFromName = function(headerName, headers) {
- var i = headerIndexFromName(headerName, headers);
+const headerValueFromName = function(headerName, headers) {
+ const i = headerIndexFromName(headerName, headers);
return i !== -1 ? headers[i].value : '';
};
/******************************************************************************/
-let strictBlockBypasser = {
+const strictBlockBypasser = {
hostnameToDeadlineMap: new Map(),
cleanupTimer: undefined,
cleanup: function() {
- for ( let [ hostname, deadline ] of this.hostnameToDeadlineMap ) {
+ for ( const [ hostname, deadline ] of this.hostnameToDeadlineMap ) {
if ( deadline <= Date.now() ) {
this.hostnameToDeadlineMap.delete(hostname);
}
@@ -1114,7 +967,7 @@ let strictBlockBypasser = {
);
}
for (;;) {
- let deadline = this.hostnameToDeadlineMap.get(hostname);
+ const deadline = this.hostnameToDeadlineMap.get(hostname);
if ( deadline !== undefined ) {
if ( deadline > Date.now() ) {
this.hostnameToDeadlineMap.set(
@@ -1125,7 +978,7 @@ let strictBlockBypasser = {
}
this.hostnameToDeadlineMap.delete(hostname);
}
- let pos = hostname.indexOf('.');
+ const pos = hostname.indexOf('.');
if ( pos === -1 ) { break; }
hostname = hostname.slice(pos + 1);
}
@@ -1137,8 +990,8 @@ let strictBlockBypasser = {
return {
start: (function() {
- let suspendedTabs = new Set();
- let onBeforeReady = function(details) {
+ const suspendedTabs = new Set();
+ const onBeforeReady = function(details) {
if ( details.type !== 'main_frame' && details.tabId > 0 ) {
suspendedTabs.add(details.tabId);
console.info('uBO suspend tab %d, block %s', details.tabId, details.url);
@@ -1188,7 +1041,7 @@ return {
// https://github.com/gorhill/uBlock/issues/2067
// Force-reload tabs for which network requests were blocked
// during launch. This can happen only if tabs were "suspended".
- for ( let tabId of suspendedTabs ) {
+ for ( const tabId of suspendedTabs ) {
console.info('uBO suspend tab %d, force reload', tabId);
vAPI.tabs.reload(tabId);
}
diff --git a/src/js/ublock.js b/src/js/ublock.js
index 1df50ed83..d6ae70a0e 100644
--- a/src/js/ublock.js
+++ b/src/js/ublock.js
@@ -538,7 +538,7 @@ var matchBucket = function(url, hostname, bucket, start) {
// cosmetic filters.
µBlock.logCosmeticFilters = function(tabId, frameId) {
- if ( this.logger.isEnabled() ) {
+ if ( this.logger.enabled ) {
vAPI.tabs.injectScript(tabId, {
file: '/js/scriptlets/cosmetic-logger.js',
frameId: frameId,
diff --git a/src/js/uritools.js b/src/js/uritools.js
index addc03229..7225aee8f 100644
--- a/src/js/uritools.js
+++ b/src/js/uritools.js
@@ -1,7 +1,7 @@
/*******************************************************************************
uBlock Origin - a browser extension to block requests.
- Copyright (C) 2014-2018 Raymond Hill
+ Copyright (C) 2014-present 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
@@ -51,7 +51,7 @@ var reRFC3986 = /^([^:\/?#]+:)?(\/\/[^\/?#]*)?([^?#]*)(\?[^#]*)?(#.*)?/;
// Derived
var reSchemeFromURI = /^[^:\/?#]+:/;
var reAuthorityFromURI = /^(?:[^:\/?#]+:)?(\/\/[^\/?#]+)/;
-var reOriginFromURI = /^(?:[^:\/?#]+:)\/\/(?:[^\/?#]+)?/;
+var reOriginFromURI = /^(?:[^:\/?#]+:)\/\/[^\/?#]+/;
var reCommonHostnameFromURL = /^https?:\/\/([0-9a-z_][0-9a-z._-]*[0-9a-z])\//;
var rePathFromURI = /^(?:[^:\/?#]+:)?(?:\/\/[^\/?#]*)?([^?#]*)/;
var reMustNormalizeHostname = /[^0-9a-z._-]/;
@@ -225,7 +225,7 @@ URI.assemble = function(bits) {
/******************************************************************************/
URI.originFromURI = function(uri) {
- var matches = reOriginFromURI.exec(uri);
+ const matches = reOriginFromURI.exec(uri);
return matches !== null ? matches[0].toLowerCase() : '';
};
diff --git a/src/lib/publicsuffixlist.js b/src/lib/publicsuffixlist.js
index 1a04d78b9..cc7ae2dfc 100644
--- a/src/lib/publicsuffixlist.js
+++ b/src/lib/publicsuffixlist.js
@@ -37,14 +37,14 @@
/******************************************************************************/
-var exceptions = new Map();
-var rules = new Map();
+let exceptions = new Map();
+let rules = new Map();
// This value dictate how the search will be performed:
// < this.cutoffLength = indexOf()
// >= this.cutoffLength = binary search
-var cutoffLength = 256;
-var mustPunycode = /[^a-z0-9.-]/;
+const cutoffLength = 256;
+const mustPunycode = /[^a-z0-9.-]/;
/******************************************************************************/
@@ -284,7 +284,7 @@ function crystallize(store) {
/******************************************************************************/
-var selfieMagic = 1;
+const selfieMagic = 1;
function toSelfie() {
return {
@@ -311,12 +311,15 @@ function fromSelfie(selfie) {
root = root || window;
root.publicSuffixList = {
- 'version': '1.0',
- 'parse': parse,
- 'getDomain': getDomain,
- 'getPublicSuffix': getPublicSuffix,
- 'toSelfie': toSelfie,
- 'fromSelfie': fromSelfie,
+ version: '1.0',
+ parse: parse,
+ getDomain: getDomain,
+ getPublicSuffix: getPublicSuffix,
+ toSelfie: toSelfie,
+ fromSelfie: fromSelfie,
+ get empty() {
+ return rules.size === 0;
+ }
};
/******************************************************************************/
diff --git a/src/logger-ui.html b/src/logger-ui.html
index 0453f148a..5a01029f5 100644
--- a/src/logger-ui.html
+++ b/src/logger-ui.html
@@ -17,8 +17,9 @@