|
|
@ -272,7 +272,7 @@ var onBeforeRequestHandler = function(details) {
|
|
|
|
|
|
|
|
|
|
|
|
// console.debug('onBeforeRequestHandler()> "%s": %o', details.url, details);
|
|
|
|
// console.debug('onBeforeRequestHandler()> "%s": %o', details.url, details);
|
|
|
|
|
|
|
|
|
|
|
|
var requestType = requestTypeNormalizer[details.type];
|
|
|
|
var requestType = requestTypeNormalizer[details.type] || 'other';
|
|
|
|
|
|
|
|
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/303
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/303
|
|
|
|
// Wherever the main doc comes from, create a receiver page URL: synthetize
|
|
|
|
// Wherever the main doc comes from, create a receiver page URL: synthetize
|
|
|
@ -284,7 +284,7 @@ var onBeforeRequestHandler = function(details) {
|
|
|
|
var requestURL = details.url;
|
|
|
|
var requestURL = details.url;
|
|
|
|
|
|
|
|
|
|
|
|
// Is it µMatrix's noop css file?
|
|
|
|
// Is it µMatrix's noop css file?
|
|
|
|
if ( requestType === 'css' && requestURL.slice(0, µm.noopCSSURL.length) === µm.noopCSSURL ) {
|
|
|
|
if ( requestType === 'css' && requestURL.lastIndexOf(µm.noopCSSURL, 0) === 0 ) {
|
|
|
|
return onBeforeChromeExtensionRequestHandler(details);
|
|
|
|
return onBeforeChromeExtensionRequestHandler(details);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -295,19 +295,12 @@ var onBeforeRequestHandler = function(details) {
|
|
|
|
|
|
|
|
|
|
|
|
// Do not block myself from updating assets
|
|
|
|
// Do not block myself from updating assets
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/202
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/202
|
|
|
|
if ( requestType === 'xhr' && requestURL.slice(0, µm.projectServerRoot.length) === µm.projectServerRoot ) {
|
|
|
|
if ( requestType === 'xhr' && requestURL.lastIndexOf(µm.projectServerRoot, 0) === 0 ) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var requestHostname = µmuri.hostname;
|
|
|
|
var requestHostname = µmuri.hostname;
|
|
|
|
|
|
|
|
|
|
|
|
// rhill 2013-12-15:
|
|
|
|
|
|
|
|
// Try to transpose generic `other` category into something more
|
|
|
|
|
|
|
|
// meaningful.
|
|
|
|
|
|
|
|
if ( requestType === 'other' ) {
|
|
|
|
|
|
|
|
requestType = µm.transposeType(requestType, µmuri.path);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Re-classify orphan HTTP requests as behind-the-scene requests. There is
|
|
|
|
// Re-classify orphan HTTP requests as behind-the-scene requests. There is
|
|
|
|
// not much else which can be done, because there are URLs
|
|
|
|
// not much else which can be done, because there are URLs
|
|
|
|
// which cannot be handled by µMatrix, i.e. `opera://startpage`,
|
|
|
|
// which cannot be handled by µMatrix, i.e. `opera://startpage`,
|
|
|
@ -361,11 +354,7 @@ var onBeforeRequestHandler = function(details) {
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
// This is where tabless requests are processed, as here there may be a chance
|
|
|
|
// Sanitize outgoing headers as per user settings.
|
|
|
|
// we can bind a request to a specific tab, as headers may contain useful
|
|
|
|
|
|
|
|
// information to accomplish this.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Also we sanitize outgoing headers as per user settings.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var onBeforeSendHeadersHandler = function(details) {
|
|
|
|
var onBeforeSendHeadersHandler = function(details) {
|
|
|
|
|
|
|
|
|
|
|
@ -392,11 +381,27 @@ var onBeforeSendHeadersHandler = function(details) {
|
|
|
|
// If yes, create a synthetic URL for reporting 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
|
|
|
|
// in request log. This way the user is better informed of what went
|
|
|
|
// on.
|
|
|
|
// on.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// http://www.whatwg.org/specs/web-apps/current-work/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.
|
|
|
|
|
|
|
|
|
|
|
|
var requestURL = details.url;
|
|
|
|
var requestURL = details.url;
|
|
|
|
var requestType = requestTypeNormalizer[details.type];
|
|
|
|
var requestType = requestTypeNormalizer[details.type] || 'other';
|
|
|
|
if ( requestType === 'other' ) {
|
|
|
|
if ( requestType === 'other' ) {
|
|
|
|
var linkAuditor = hyperlinkAuditorFromHeaders(details.requestHeaders);
|
|
|
|
var linkAuditor = details.requestHeaders.getHeader('ping-to');
|
|
|
|
if ( linkAuditor ) {
|
|
|
|
if ( linkAuditor !== '' ) {
|
|
|
|
var block = µm.userSettings.processHyperlinkAuditing;
|
|
|
|
var block = µm.userSettings.processHyperlinkAuditing;
|
|
|
|
pageStore.recordRequest('other', requestURL + '{Ping-To:' + linkAuditor + '}', block);
|
|
|
|
pageStore.recordRequest('other', requestURL + '{Ping-To:' + linkAuditor + '}', block);
|
|
|
|
µm.updateBadgeAsync(tabId);
|
|
|
|
µm.updateBadgeAsync(tabId);
|
|
|
@ -411,123 +416,41 @@ var onBeforeSendHeadersHandler = function(details) {
|
|
|
|
// is to sanitize headers.
|
|
|
|
// is to sanitize headers.
|
|
|
|
|
|
|
|
|
|
|
|
var reqHostname = µm.hostnameFromURL(requestURL);
|
|
|
|
var reqHostname = µm.hostnameFromURL(requestURL);
|
|
|
|
var changed = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( µm.mustBlock(pageStore.pageHostname, reqHostname, 'cookie') ) {
|
|
|
|
if ( µm.mustBlock(pageStore.pageHostname, reqHostname, 'cookie') ) {
|
|
|
|
changed = foilCookieHeaders(µm, details) || changed;
|
|
|
|
if ( details.requestHeaders.setHeader('cookie', '') ) {
|
|
|
|
|
|
|
|
µm.cookieHeaderFoiledCounter++;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( µm.tMatrix.evaluateSwitchZ('referrer-spoof', pageStore.pageHostname) ) {
|
|
|
|
if ( µm.tMatrix.evaluateSwitchZ('referrer-spoof', pageStore.pageHostname) ) {
|
|
|
|
changed = foilRefererHeaders(µm, reqHostname, details) || changed;
|
|
|
|
foilRefererHeaders(µm, reqHostname, details);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( µm.tMatrix.evaluateSwitchZ('ua-spoof', pageStore.pageHostname) ) {
|
|
|
|
if ( µm.tMatrix.evaluateSwitchZ('ua-spoof', pageStore.pageHostname) ) {
|
|
|
|
changed = foilUserAgent(µm, details) || changed;
|
|
|
|
details.requestHeaders.setHeader('user-agent', µm.userAgentReplaceStr);
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/252
|
|
|
|
|
|
|
|
// To avoid potential mismatch between the user agent from HTTP headers
|
|
|
|
|
|
|
|
// and the user agent from subrequests and the window.navigator object,
|
|
|
|
|
|
|
|
// I could always store here the effective user agent, but I am really
|
|
|
|
|
|
|
|
// not convinced it is worth the added overhead given the low
|
|
|
|
|
|
|
|
// probability and the benign consequence if it ever happen. Can always
|
|
|
|
|
|
|
|
// be revised if ever I become aware a mismatch is a terrible thing
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( changed ) {
|
|
|
|
|
|
|
|
// console.debug('onBeforeSendHeadersHandler()> CHANGED "%s": %o', requestURL, details);
|
|
|
|
|
|
|
|
return { requestHeaders: details.requestHeaders };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// http://www.whatwg.org/specs/web-apps/current-work/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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var hyperlinkAuditorFromHeaders = function(headers) {
|
|
|
|
|
|
|
|
var i = headers.length;
|
|
|
|
|
|
|
|
while ( i-- ) {
|
|
|
|
|
|
|
|
if ( headers[i].name.toLowerCase() === 'ping-to' ) {
|
|
|
|
|
|
|
|
return headers[i].value;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var foilCookieHeaders = function(µm, details) {
|
|
|
|
|
|
|
|
var changed = false;
|
|
|
|
|
|
|
|
var headers = details.requestHeaders;
|
|
|
|
|
|
|
|
var header;
|
|
|
|
|
|
|
|
var i = headers.length;
|
|
|
|
|
|
|
|
while ( i-- ) {
|
|
|
|
|
|
|
|
header = headers[i];
|
|
|
|
|
|
|
|
if ( header.name.toLowerCase() !== 'cookie' ) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// console.debug('foilCookieHeaders()> foiled browser attempt to send cookie(s) to "%s"', details.url);
|
|
|
|
|
|
|
|
headers.splice(i, 1);
|
|
|
|
|
|
|
|
µm.cookieHeaderFoiledCounter++;
|
|
|
|
|
|
|
|
changed = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return changed;
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
var foilRefererHeaders = function(µm, toHostname, details) {
|
|
|
|
var foilRefererHeaders = function(µm, toHostname, details) {
|
|
|
|
var headers = details.requestHeaders;
|
|
|
|
var referer = details.requestHeaders.getHeader('referer');
|
|
|
|
var i = headers.length, header;
|
|
|
|
if ( referer === '' ) {
|
|
|
|
while ( i-- ) {
|
|
|
|
return;
|
|
|
|
header = headers[i];
|
|
|
|
|
|
|
|
if ( header.name.toLowerCase() === 'referer' ) {
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( i === -1 ) {
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var µmuri = µm.URI;
|
|
|
|
var µmuri = µm.URI;
|
|
|
|
var fromDomain = µmuri.domainFromURI(header.value);
|
|
|
|
if ( µmuri.domainFromHostname(toHostname) === µmuri.domainFromURI(referer) ) {
|
|
|
|
var toDomain = µmuri.domainFromHostname(toHostname);
|
|
|
|
return;
|
|
|
|
if ( toDomain === fromDomain ) {
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//console.debug('foilRefererHeaders()> foiled referer for "%s"', details.url);
|
|
|
|
//console.debug('foilRefererHeaders()> foiled referer for "%s"', details.url);
|
|
|
|
//console.debug('\treferrer "%s"', header.value);
|
|
|
|
//console.debug('\treferrer "%s"', header.value);
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/222#issuecomment-44828402
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/222#issuecomment-44828402
|
|
|
|
header.value = µmuri.schemeFromURI(details.url) + '://' + toHostname + '/';
|
|
|
|
details.requestHeaders.setHeader(
|
|
|
|
//console.debug('\treplaced with "%s"', header.value);
|
|
|
|
'referer',
|
|
|
|
|
|
|
|
µmuri.schemeFromURI(details.url) + '://' + toHostname + '/'
|
|
|
|
|
|
|
|
);
|
|
|
|
µm.refererHeaderFoiledCounter++;
|
|
|
|
µm.refererHeaderFoiledCounter++;
|
|
|
|
return true;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var foilUserAgent = function(µm, details) {
|
|
|
|
|
|
|
|
var headers = details.requestHeaders;
|
|
|
|
|
|
|
|
var header;
|
|
|
|
|
|
|
|
var i = 0;
|
|
|
|
|
|
|
|
while ( header = headers[i] ) {
|
|
|
|
|
|
|
|
if ( header.name.toLowerCase() === 'user-agent' ) {
|
|
|
|
|
|
|
|
header.value = µm.userAgentReplaceStr;
|
|
|
|
|
|
|
|
return true; // Assuming only one `user-agent` entry
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
i += 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/******************************************************************************/
|
|
|
@ -549,7 +472,7 @@ var onHeadersReceived = function(details) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var requestType = requestTypeNormalizer[details.type];
|
|
|
|
var requestType = requestTypeNormalizer[details.type] || 'other';
|
|
|
|
if ( requestType === 'frame' ) {
|
|
|
|
if ( requestType === 'frame' ) {
|
|
|
|
return onSubDocHeadersReceived(details);
|
|
|
|
return onSubDocHeadersReceived(details);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -731,7 +654,7 @@ var onSubDocHeadersReceived = function(details) {
|
|
|
|
|
|
|
|
|
|
|
|
var onErrorOccurredHandler = function(details) {
|
|
|
|
var onErrorOccurredHandler = function(details) {
|
|
|
|
// console.debug('onErrorOccurred()> "%s": %o', details.url, details);
|
|
|
|
// console.debug('onErrorOccurred()> "%s": %o', details.url, details);
|
|
|
|
var requestType = requestTypeNormalizer[details.type];
|
|
|
|
var requestType = requestTypeNormalizer[details.type] || 'other';
|
|
|
|
|
|
|
|
|
|
|
|
// Ignore all that is not a main document
|
|
|
|
// Ignore all that is not a main document
|
|
|
|
if ( requestType !== 'doc'|| details.parentFrameId >= 0 ) {
|
|
|
|
if ( requestType !== 'doc'|| details.parentFrameId >= 0 ) {
|
|
|
@ -788,7 +711,8 @@ var requestTypeNormalizer = {
|
|
|
|
'image' : 'image',
|
|
|
|
'image' : 'image',
|
|
|
|
'object' : 'plugin',
|
|
|
|
'object' : 'plugin',
|
|
|
|
'xmlhttprequest': 'xhr',
|
|
|
|
'xmlhttprequest': 'xhr',
|
|
|
|
'other' : 'other'
|
|
|
|
'other' : 'other',
|
|
|
|
|
|
|
|
'font' : 'css'
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/******************************************************************************/
|
|
|
@ -808,10 +732,6 @@ vAPI.net.onBeforeSendHeaders = {
|
|
|
|
"http://*/*",
|
|
|
|
"http://*/*",
|
|
|
|
"https://*/*"
|
|
|
|
"https://*/*"
|
|
|
|
],
|
|
|
|
],
|
|
|
|
types: [
|
|
|
|
|
|
|
|
"main_frame",
|
|
|
|
|
|
|
|
"sub_frame"
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
extra: [ 'blocking', 'requestHeaders' ],
|
|
|
|
extra: [ 'blocking', 'requestHeaders' ],
|
|
|
|
callback: onBeforeSendHeadersHandler
|
|
|
|
callback: onBeforeSendHeadersHandler
|
|
|
|
};
|
|
|
|
};
|
|
|
|