You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
671 lines
22 KiB
671 lines
22 KiB
/*******************************************************************************
|
|
|
|
uMatrix - a browser extension to black/white list requests.
|
|
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
|
|
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/uMatrix
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
/******************************************************************************/
|
|
|
|
// Start isolation from global scope
|
|
|
|
µMatrix.webRequest = (( ) => {
|
|
|
|
/******************************************************************************/
|
|
|
|
// Intercept and filter web requests according to white and black lists.
|
|
|
|
const onBeforeRootFrameRequestHandler = function(fctxt) {
|
|
const µm = µMatrix;
|
|
const desURL = fctxt.url;
|
|
const desHn = fctxt.getHostname();
|
|
const type = fctxt.type;
|
|
const tabId = fctxt.tabId;
|
|
const srcHn = fctxt.getTabHostname();
|
|
|
|
// Disallow request as per matrix?
|
|
const blocked = µm.mustBlock(srcHn, desHn, type);
|
|
|
|
const pageStore = µm.bindTabToPageStats(tabId);
|
|
if ( pageStore !== null ) {
|
|
pageStore.recordRequest(type, desURL, blocked);
|
|
pageStore.perLoadAllowedRequestCount = 0;
|
|
pageStore.perLoadBlockedRequestCount = 0;
|
|
pageStore.perLoadBlockedReferrerCount = 0;
|
|
if ( blocked !== true ) {
|
|
µm.cookieHunter.recordPageCookies(pageStore);
|
|
}
|
|
if ( fctxt.aliasURL !== undefined ) {
|
|
pageStore.hasHostnameAliases = true;
|
|
}
|
|
}
|
|
if ( µm.logger.enabled ) {
|
|
fctxt.setRealm('network').setFilter(blocked).toLogger();
|
|
}
|
|
|
|
// Not blocked
|
|
if ( blocked !== true ) {
|
|
const redirectUrl = maybeRedirectRootFrame(desHn, desURL);
|
|
if ( redirectUrl !== desURL ) {
|
|
return { redirectUrl };
|
|
}
|
|
if ( µm.tMatrix.evaluateSwitchZ('cname-reveal', srcHn) === false ) {
|
|
return { cancel: false };
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Blocked
|
|
const query = encodeURIComponent(
|
|
JSON.stringify({ url: desURL, hn: desHn, type, why: '?' })
|
|
);
|
|
|
|
vAPI.tabs.replace(tabId, vAPI.getURL('main-blocked.html?details=') + query);
|
|
|
|
return { cancel: true };
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
// https://twitter.com/thatcks/status/958776519765225473
|
|
|
|
const maybeRedirectRootFrame = function(hostname, url) {
|
|
const µm = µMatrix;
|
|
if ( µm.rawSettings.enforceEscapedFragment !== true ) { return url; }
|
|
const block1pScripts = µm.mustBlock(hostname, hostname, 'script');
|
|
const reEscapedFragment = /[?&]_escaped_fragment_=/;
|
|
if ( reEscapedFragment.test(url) ) {
|
|
return block1pScripts ? url : url.replace(reEscapedFragment, '#!') ;
|
|
}
|
|
if ( block1pScripts === false ) { return url; }
|
|
const pos = url.indexOf('#!');
|
|
if ( pos === -1 ) { return url; }
|
|
const separator = url.lastIndexOf('?', pos) === -1 ? '?' : '&';
|
|
return url.slice(0, pos) +
|
|
separator + '_escaped_fragment_=' +
|
|
url.slice(pos + 2);
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
// Intercept and filter web requests according to white and black lists.
|
|
|
|
const onBeforeRequestHandler = function(details) {
|
|
const µm = µMatrix;
|
|
const fctxt = µm.filteringContext.fromWebrequestDetails(details);
|
|
const µmuri = µm.URI;
|
|
const desURL = fctxt.url;
|
|
const desScheme = µmuri.schemeFromURI(desURL);
|
|
|
|
if ( µmuri.isNetworkScheme(desScheme) === false ) {
|
|
return { cancel: false };
|
|
}
|
|
|
|
const type = fctxt.type;
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/303
|
|
// Wherever the main doc comes from, create a receiver page URL: synthetize
|
|
// one if needed.
|
|
if ( type === 'doc' && details.parentFrameId === -1 ) {
|
|
return onBeforeRootFrameRequestHandler(fctxt);
|
|
}
|
|
|
|
// Re-classify orphan HTTP requests as behind-the-scene requests. There is
|
|
// not much else which can be done, because there are URLs
|
|
// which cannot be handled by µMatrix, i.e. `opera://startpage`,
|
|
// as this would lead to complications with no obvious solution, like how
|
|
// to scope on unknown scheme? Etc.
|
|
// https://github.com/gorhill/httpswitchboard/issues/191
|
|
// https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275
|
|
const tabContext = µm.tabContextManager.mustLookup(details.tabId);
|
|
const tabId = fctxt.tabId;
|
|
const srcHn = fctxt.getTabHostname();
|
|
const desHn = fctxt.getHostname();
|
|
let specificity = 0;
|
|
|
|
let blocked = µm.tMatrix.mustBlock(srcHn, desHn, type);
|
|
if ( blocked ) {
|
|
specificity = µm.tMatrix.specificityRegister;
|
|
}
|
|
|
|
// Record request.
|
|
// https://github.com/gorhill/httpswitchboard/issues/342
|
|
// The way requests are handled now, it may happen at this point some
|
|
// processing has already been performed, and that a synthetic URL has
|
|
// been constructed for logging purpose. Use this synthetic URL if
|
|
// it is available.
|
|
const pageStore = µm.mustPageStoreFromTabId(tabId);
|
|
|
|
// Enforce strict secure connection?
|
|
if ( tabContext.secure && µmuri.isSecureScheme(desScheme) === false ) {
|
|
pageStore.hasMixedContent = true;
|
|
if ( blocked === false ) {
|
|
blocked = µm.tMatrix.evaluateSwitchZ('https-strict', srcHn);
|
|
}
|
|
}
|
|
|
|
if ( fctxt.aliasURL !== undefined ) {
|
|
pageStore.hasHostnameAliases = true;
|
|
}
|
|
|
|
pageStore.recordRequest(type, desURL, blocked);
|
|
if ( µm.logger.enabled ) {
|
|
fctxt.setRealm('network').setFilter(blocked).toLogger();
|
|
}
|
|
|
|
if ( blocked ) {
|
|
pageStore.cacheBlockedCollapsible(type, desURL, specificity);
|
|
return { cancel: true };
|
|
}
|
|
|
|
if ( µm.tMatrix.evaluateSwitchZ('cname-reveal', srcHn) === false ) {
|
|
return { cancel: false };
|
|
}
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
// Sanitize outgoing headers as per user settings.
|
|
|
|
const onBeforeSendHeadersHandler = function(details) {
|
|
const µm = µMatrix;
|
|
const µmuri = µm.URI;
|
|
const fctxt = µm.filteringContext.fromWebrequestDetails(details);
|
|
|
|
// Ignore non-network schemes
|
|
if ( µmuri.isNetworkScheme(µmuri.schemeFromURI(fctxt.url)) === false ) {
|
|
return;
|
|
}
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/342
|
|
// Is this hyperlink auditing?
|
|
// If yes, create a synthetic URL for reporting hyperlink auditing
|
|
// in request log. This way the user is better informed of what went
|
|
// on.
|
|
|
|
// https://html.spec.whatwg.org/multipage/links.html#hyperlink-auditing
|
|
//
|
|
// Target URL = the href of the link
|
|
// Doc URL = URL of the document containing the target URL
|
|
// Ping URLs = servers which will be told that user clicked target URL
|
|
//
|
|
// `Content-Type` = `text/ping` (always present)
|
|
// `Ping-To` = target URL (always present)
|
|
// `Ping-From` = doc URL
|
|
// `Referer` = doc URL
|
|
// request URL = URL which will receive the information
|
|
//
|
|
// With hyperlink-auditing, removing header(s) is pointless, the whole
|
|
// request must be cancelled.
|
|
|
|
if ( onBeforeSendPing(fctxt, details) ) {
|
|
return { cancel: true };
|
|
}
|
|
|
|
// If we reach this point, request is not blocked, so what is left to do
|
|
// is to sanitize headers.
|
|
|
|
let modified = false;
|
|
|
|
// Process `Cookie` header.
|
|
|
|
if ( onBeforeSendCookie(fctxt, details) ) {
|
|
modified = true;
|
|
}
|
|
|
|
// Process `Referer` header.
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/222#issuecomment-44828402
|
|
|
|
// https://github.com/gorhill/uMatrix/issues/320
|
|
// http://tools.ietf.org/html/rfc6454#section-7.3
|
|
// "The user agent MAY include an Origin header field in any HTTP
|
|
// "request.
|
|
// "The user agent MUST NOT include more than one Origin header field in
|
|
// "any HTTP request.
|
|
// "Whenever a user agent issues an HTTP request from a "privacy-
|
|
// "sensitive" context, the user agent MUST send the value "null" in the
|
|
// "Origin header field."
|
|
|
|
// https://github.com/gorhill/uMatrix/issues/358
|
|
// Do not spoof `Origin` header for the time being.
|
|
|
|
// https://github.com/gorhill/uMatrix/issues/773
|
|
// For non-GET requests, remove `Referer` header instead of spoofing it.
|
|
|
|
if ( onBeforeSendReferrer(fctxt, details) ) {
|
|
modified = true;
|
|
}
|
|
|
|
if ( modified !== true ) { return; }
|
|
|
|
µm.updateToolbarIcon(fctxt.tabId);
|
|
|
|
return { requestHeaders: details.requestHeaders };
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const onBeforeSendPing = function(fctxt, details) {
|
|
const requestHeaders = details.requestHeaders;
|
|
const iHeader = headerIndexFromName('ping-to', requestHeaders);
|
|
if ( iHeader === -1 ) { return false; }
|
|
|
|
const headerValue = requestHeaders[iHeader].value;
|
|
if ( headerValue === '' ) { return false; }
|
|
|
|
const µm = µMatrix;
|
|
const blocked = µm.userSettings.processHyperlinkAuditing;
|
|
|
|
const pageStore = µm.mustPageStoreFromTabId(fctxt.tabId);
|
|
pageStore.recordRequest(
|
|
'other',
|
|
fctxt.url + '{Ping-To:' + headerValue + '}',
|
|
blocked
|
|
);
|
|
|
|
if ( µm.logger.enabled ) {
|
|
fctxt.setRealm('network')
|
|
.setType('ping')
|
|
.setFilter(blocked)
|
|
.toLogger();
|
|
}
|
|
|
|
if ( blocked === false ) { return false; }
|
|
|
|
µm.hyperlinkAuditingFoiledCounter += 1;
|
|
return true;
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const onBeforeSendCookie = function(fctxt, details) {
|
|
const requestHeaders = details.requestHeaders;
|
|
const iHeader = headerIndexFromName('cookie', requestHeaders);
|
|
if ( iHeader === -1 ) { return false; }
|
|
|
|
const µm = µMatrix;
|
|
const blocked = µm.mustBlock(
|
|
fctxt.getTabHostname(),
|
|
fctxt.getHostname(),
|
|
'cookie'
|
|
);
|
|
if ( blocked === false ) { return false; }
|
|
|
|
const headerValue = requestHeaders[iHeader].value;
|
|
requestHeaders.splice(iHeader, 1);
|
|
µm.cookieHeaderFoiledCounter++;
|
|
|
|
if ( fctxt.type === 'doc' ) {
|
|
const pageStore = µm.mustPageStoreFromTabId(fctxt.tabId);
|
|
pageStore.perLoadBlockedRequestCount++;
|
|
if ( µm.logger.enabled ) {
|
|
fctxt.setRealm('network')
|
|
.setType('COOKIE')
|
|
.setFilter({ value: headerValue, change: -1 })
|
|
.toLogger();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
const onBeforeSendReferrer = function(fctxt, details) {
|
|
const requestHeaders = details.requestHeaders;
|
|
const iHeader = headerIndexFromName('referer', requestHeaders);
|
|
if ( iHeader === -1 ) { return false; }
|
|
|
|
const referrer = requestHeaders[iHeader].value;
|
|
if ( referrer === '' ) { return false; }
|
|
|
|
const toDomain = vAPI.domainFromHostname(fctxt.getHostname());
|
|
if ( toDomain === '' || toDomain === vAPI.domainFromURI(referrer) ) {
|
|
return false;
|
|
}
|
|
|
|
const µm = µMatrix;
|
|
const pageStore = µm.mustPageStoreFromTabId(fctxt.tabId);
|
|
pageStore.has3pReferrer = true;
|
|
|
|
const mustSpoof =
|
|
µm.tMatrix.evaluateSwitchZ('referrer-spoof', fctxt.getTabHostname());
|
|
if ( mustSpoof === false ) { return false; }
|
|
|
|
let spoofedReferrer;
|
|
if ( details.method === 'GET' ) {
|
|
spoofedReferrer = requestHeaders[iHeader].value =
|
|
fctxt.originFromURI(fctxt.url) + '/';
|
|
} else {
|
|
requestHeaders.splice(iHeader, 1);
|
|
}
|
|
|
|
if ( pageStore.perLoadBlockedReferrerCount === 0 ) {
|
|
pageStore.perLoadBlockedRequestCount += 1;
|
|
if ( µm.logger.enabled ) {
|
|
fctxt.setRealm('network')
|
|
.setType('REFERER')
|
|
.setFilter({ value: referrer, change: -1 })
|
|
.toLogger();
|
|
if ( spoofedReferrer !== undefined ) {
|
|
fctxt.setRealm('network')
|
|
.setType('REFERER')
|
|
.setFilter({ value: spoofedReferrer, change: +1 })
|
|
.toLogger();
|
|
}
|
|
}
|
|
}
|
|
pageStore.perLoadBlockedReferrerCount += 1;
|
|
|
|
return true;
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
// To prevent inline javascript from being executed.
|
|
|
|
// Prevent inline scripting using `Content-Security-Policy`:
|
|
// https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html
|
|
|
|
// This fixes:
|
|
// https://github.com/gorhill/httpswitchboard/issues/35
|
|
|
|
const onHeadersReceivedHandler = function(details) {
|
|
const µm = µMatrix;
|
|
const fctxt = µm.filteringContext.fromWebrequestDetails(details);
|
|
const requestType = fctxt.type;
|
|
const headers = details.responseHeaders;
|
|
|
|
// https://github.com/gorhill/uMatrix/issues/145
|
|
// Check if the main_frame is a download
|
|
if ( requestType === 'doc' ) {
|
|
const contentType = typeFromHeaders(headers);
|
|
if ( contentType !== undefined ) {
|
|
details.type = contentType;
|
|
return onBeforeRootFrameRequestHandler(fctxt);
|
|
}
|
|
}
|
|
|
|
const csp = [];
|
|
const cspReport = [];
|
|
const srcHn = fctxt.getTabHostname();
|
|
const desHn = fctxt.getHostname();
|
|
|
|
// Inline script tags.
|
|
if ( µm.mustBlock(srcHn, desHn, 'script' ) ) {
|
|
csp.push(µm.cspNoInlineScript);
|
|
}
|
|
|
|
// Inline style tags.
|
|
if ( µm.mustBlock(srcHn, desHn, 'css' ) ) {
|
|
csp.push(µm.cspNoInlineStyle);
|
|
}
|
|
|
|
if ( µm.tMatrix.evaluateSwitchZ('no-workers', srcHn) ) {
|
|
csp.push(µm.cspNoWorker);
|
|
} else if ( µm.rawSettings.disableCSPReportInjection === false ) {
|
|
cspReport.push(µm.cspNoWorker);
|
|
}
|
|
|
|
if ( csp.length === 0 && cspReport.length === 0 ) { return; }
|
|
|
|
// https://github.com/gorhill/uMatrix/issues/967
|
|
// Inject a new CSP header rather than modify an existing one, except
|
|
// 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.
|
|
|
|
if ( csp.length !== 0 ) {
|
|
const cspRight = csp.join(', ');
|
|
let cspTotal = cspRight;
|
|
if ( µm.cantMergeCSPHeaders ) {
|
|
let i = headerIndexFromName(
|
|
'content-security-policy',
|
|
headers
|
|
);
|
|
if ( i !== -1 ) {
|
|
cspTotal = headers[i].value.trim() + ', ' + cspTotal;
|
|
headers.splice(i, 1);
|
|
}
|
|
}
|
|
headers.push({
|
|
name: 'Content-Security-Policy',
|
|
value: cspTotal
|
|
});
|
|
if ( µm.logger.enabled && requestType === 'doc' ) {
|
|
fctxt.setRealm('network')
|
|
.setType('CSP')
|
|
.setFilter({ value: cspRight, change: +1 })
|
|
.toLogger();
|
|
}
|
|
}
|
|
|
|
if ( cspReport.length !== 0 ) {
|
|
const cspRight = cspReport.join(', ');
|
|
let cspTotal = cspRight;
|
|
if ( µm.cantMergeCSPHeaders ) {
|
|
let i = headerIndexFromName(
|
|
'content-security-policy-report-only',
|
|
headers
|
|
);
|
|
if ( i !== -1 ) {
|
|
cspTotal = headers[i].value.trim() + ', ' + cspTotal;
|
|
headers.splice(i, 1);
|
|
}
|
|
}
|
|
headers.push({
|
|
name: 'Content-Security-Policy-Report-Only',
|
|
value: cspTotal
|
|
});
|
|
}
|
|
|
|
return { responseHeaders: headers };
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1302667
|
|
// https://github.com/gorhill/uMatrix/issues/967#issuecomment-373002011
|
|
|
|
window.addEventListener('webextFlavor', function() {
|
|
if ( vAPI.webextFlavor.soup.has('firefox') === false ) { return; }
|
|
if ( vAPI.webextFlavor.major <= 57 ) {
|
|
µMatrix.cspNoWorker =
|
|
"child-src 'none'; frame-src data: blob: *; report-uri about:blank";
|
|
}
|
|
if ( vAPI.webextFlavor.major <= 58 ) {
|
|
µMatrix.cantMergeCSPHeaders = true;
|
|
}
|
|
}, { once: true });
|
|
|
|
/******************************************************************************/
|
|
|
|
// Caller must ensure headerName is normalized to lower case.
|
|
|
|
const headerIndexFromName = function(headerName, headers) {
|
|
let i = headers.length;
|
|
while ( i-- ) {
|
|
if ( headers[i].name.toLowerCase() === headerName ) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
// Extract request type from content headers.
|
|
|
|
const typeFromHeaders = function(headers) {
|
|
const i = headerIndexFromName('content-type', headers);
|
|
if ( i === -1 ) { return; }
|
|
const mime = headers[i].value.toLowerCase();
|
|
if ( mime.startsWith('image/') ) { return 'image'; }
|
|
if ( mime.startsWith('video/') || mime.startsWith('audio/') ) {
|
|
return 'media';
|
|
}
|
|
};
|
|
|
|
/*******************************************************************************
|
|
|
|
Use a `http-equiv` `meta` tag to enforce CSP directives for documents
|
|
which protocol is `file:` (which do not cause our webRequest.onHeadersReceived
|
|
handler to be called).
|
|
|
|
Idea borrowed from NoScript:
|
|
https://github.com/hackademix/noscript/commit/6e80d3f13077
|
|
|
|
**/
|
|
|
|
(( ) => {
|
|
if (
|
|
typeof self.browser !== 'object' ||
|
|
typeof browser.contentScripts !== 'object'
|
|
) {
|
|
return;
|
|
}
|
|
|
|
const csRules = [
|
|
{
|
|
name: 'script',
|
|
file: '/js/contentscript-no-inline-script.js',
|
|
pending: undefined,
|
|
registered: undefined,
|
|
mustRegister: false
|
|
},
|
|
];
|
|
|
|
const csSwitches = [
|
|
{
|
|
name: 'no-workers',
|
|
file: '/js/contentscript-no-workers.js',
|
|
pending: undefined,
|
|
registered: undefined,
|
|
mustRegister: false
|
|
},
|
|
];
|
|
|
|
const register = function(entry) {
|
|
if ( entry.pending !== undefined ) { return; }
|
|
entry.pending = browser.contentScripts.register({
|
|
js: [ { file: entry.file } ],
|
|
matches: [ 'file:///*' ],
|
|
runAt: 'document_start'
|
|
}).then(
|
|
result => {
|
|
if ( entry.mustRegister ) {
|
|
entry.registered = result;
|
|
}
|
|
entry.pending = undefined;
|
|
},
|
|
( ) => {
|
|
entry.registered = undefined;
|
|
entry.pending = undefined;
|
|
}
|
|
);
|
|
};
|
|
|
|
const unregister = function(entry) {
|
|
if ( entry.registered === undefined ) { return; }
|
|
entry.registered.unregister();
|
|
entry.registered = undefined;
|
|
};
|
|
|
|
const handler = function(ev) {
|
|
const matrix = ev && ev.detail;
|
|
if ( matrix !== µMatrix.tMatrix ) { return; }
|
|
for ( const cs of csRules ) {
|
|
cs.mustRegister = matrix.mustBlock('file-scheme', 'file-scheme', cs.name);
|
|
if ( cs.mustRegister === (cs.registered !== undefined) ) { continue; }
|
|
if ( cs.mustRegister ) {
|
|
register(cs);
|
|
} else {
|
|
unregister(cs);
|
|
}
|
|
}
|
|
for ( const cs of csSwitches ) {
|
|
cs.mustRegister = matrix.evaluateSwitchZ(cs.name, 'file-scheme');
|
|
if ( cs.mustRegister === (cs.registered !== undefined) ) { continue; }
|
|
if ( cs.mustRegister ) {
|
|
register(cs);
|
|
} else {
|
|
unregister(cs);
|
|
}
|
|
}
|
|
};
|
|
|
|
window.addEventListener('matrixRulesetChange', handler);
|
|
})();
|
|
|
|
/******************************************************************************/
|
|
|
|
return {
|
|
start: (( ) => {
|
|
vAPI.net = new vAPI.Net();
|
|
|
|
if (
|
|
vAPI.net.canSuspend() &&
|
|
µMatrix.rawSettings.suspendTabsUntilReady !== 'no' ||
|
|
vAPI.net.canSuspend() !== true &&
|
|
µMatrix.rawSettings.suspendTabsUntilReady === 'yes'
|
|
) {
|
|
vAPI.net.suspend(true);
|
|
}
|
|
|
|
return function() {
|
|
vAPI.net.setSuspendableListener(onBeforeRequestHandler);
|
|
// https://github.com/uBlockOrigin/uMatrix-issues/issues/74#issuecomment-450687707
|
|
// https://groups.google.com/a/chromium.org/forum/#!topic/chromium-extensions/vYIaeezZwfQ
|
|
// Chromium 72+: use `extraHeaders` to keep the ability to access
|
|
// the `Cookie`, `Referer` headers.
|
|
const beforeSendHeadersExtra = [ 'blocking', 'requestHeaders' ];
|
|
const wrObsho = browser.webRequest.OnBeforeSendHeadersOptions;
|
|
if (
|
|
wrObsho instanceof Object &&
|
|
wrObsho.hasOwnProperty('EXTRA_HEADERS')
|
|
) {
|
|
beforeSendHeadersExtra.push(wrObsho.EXTRA_HEADERS);
|
|
}
|
|
vAPI.net.addListener(
|
|
'onBeforeSendHeaders',
|
|
onBeforeSendHeadersHandler,
|
|
{ },
|
|
beforeSendHeadersExtra
|
|
);
|
|
vAPI.net.addListener(
|
|
'onHeadersReceived',
|
|
onHeadersReceivedHandler,
|
|
{
|
|
types: [ 'main_frame', 'sub_frame' ],
|
|
urls: [ 'http://*/*', 'https://*/*' ],
|
|
},
|
|
[ 'blocking', 'responseHeaders' ]
|
|
);
|
|
vAPI.net.unsuspend(true);
|
|
};
|
|
})(),
|
|
};
|
|
|
|
/******************************************************************************/
|
|
|
|
})();
|
|
|
|
/******************************************************************************/
|
|
|