uBlock/src/js/filtering-context.js

284 lines
9.4 KiB
JavaScript
Raw Normal View History

/*******************************************************************************
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 ) {
const normalURL = µBlock.normalizePageURL(0, details.documentUrl);
this.setTabOriginFromURL(normalURL);
this.setDocOriginFromURL(normalURL);
} 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();