|
|
@ -202,7 +202,7 @@ var onBeforeRootFrameRequestHandler = function(details) {
|
|
|
|
if ( tabId < 0 ) {
|
|
|
|
if ( tabId < 0 ) {
|
|
|
|
tabId = µm.behindTheSceneTabId;
|
|
|
|
tabId = µm.behindTheSceneTabId;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// It's a root frame, bind to a new page stats store
|
|
|
|
// It's a root frame, bind to a new page store
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
µm.bindTabToPageStats(tabId, details.url);
|
|
|
|
µm.bindTabToPageStats(tabId, details.url);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -255,20 +255,53 @@ var onBeforeRootFrameRequestHandler = function(details) {
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
// Process a request.
|
|
|
|
// Intercept and filter web requests according to white and black lists.
|
|
|
|
//
|
|
|
|
|
|
|
|
// This can be called from the context of onBeforeSendRequest() or
|
|
|
|
var onBeforeRequestHandler = function(details) {
|
|
|
|
// onBeforeSendHeaders().
|
|
|
|
var µm = µMatrix;
|
|
|
|
|
|
|
|
var µmuri = µm.URI.set(details.url);
|
|
|
|
|
|
|
|
var requestScheme = µmuri.scheme;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// rhill 2014-02-17: Ignore 'filesystem:': this can happen when listening
|
|
|
|
|
|
|
|
// to 'chrome-extension://'.
|
|
|
|
|
|
|
|
if ( requestScheme === 'filesystem' ) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// console.debug('onBeforeRequestHandler()> "%s": %o', details.url, details);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var requestType = requestTypeNormalizer[details.type];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/303
|
|
|
|
|
|
|
|
// Wherever the main doc comes from, create a receiver page URL: synthetize
|
|
|
|
|
|
|
|
// one if needed.
|
|
|
|
|
|
|
|
if ( requestType === 'doc' && details.parentFrameId < 0 ) {
|
|
|
|
|
|
|
|
return onBeforeRootFrameRequestHandler(details);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var requestURL = details.url;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Is it µMatrix's noop css file?
|
|
|
|
|
|
|
|
if ( requestType === 'css' && requestURL.slice(0, µm.noopCSSURL.length) === µm.noopCSSURL ) {
|
|
|
|
|
|
|
|
return onBeforeChromeExtensionRequestHandler(details);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Ignore non-http schemes
|
|
|
|
|
|
|
|
if ( requestScheme.indexOf('http') !== 0 ) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Do not block myself from updating assets
|
|
|
|
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/202
|
|
|
|
|
|
|
|
if ( requestType === 'xhr' && requestURL.slice(0, µm.projectServerRoot.length) === µm.projectServerRoot ) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var processRequest = function(µm, details) {
|
|
|
|
|
|
|
|
var µmuri = µm.URI;
|
|
|
|
|
|
|
|
var requestURL = µmuri.set(details.url).normalizedURI();
|
|
|
|
|
|
|
|
var requestHostname = µmuri.hostname;
|
|
|
|
var requestHostname = µmuri.hostname;
|
|
|
|
|
|
|
|
|
|
|
|
// rhill 2013-12-15:
|
|
|
|
// rhill 2013-12-15:
|
|
|
|
// Try to transpose generic `other` category into something more
|
|
|
|
// Try to transpose generic `other` category into something more
|
|
|
|
// meaningful.
|
|
|
|
// meaningful.
|
|
|
|
var requestType = requestTypeNormalizer[details.type];
|
|
|
|
|
|
|
|
if ( requestType === 'other' ) {
|
|
|
|
if ( requestType === 'other' ) {
|
|
|
|
requestType = µm.transposeType(requestType, µmuri.path);
|
|
|
|
requestType = µm.transposeType(requestType, µmuri.path);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -294,7 +327,7 @@ var processRequest = function(µm, details) {
|
|
|
|
// processing has already been performed, and that a synthetic URL has
|
|
|
|
// processing has already been performed, and that a synthetic URL has
|
|
|
|
// been constructed for logging purpose. Use this synthetic URL if
|
|
|
|
// been constructed for logging purpose. Use this synthetic URL if
|
|
|
|
// it is available.
|
|
|
|
// it is available.
|
|
|
|
pageStore.recordRequest(requestType, details.µmRequestURL || requestURL, block);
|
|
|
|
pageStore.recordRequest(requestType, requestURL, block);
|
|
|
|
|
|
|
|
|
|
|
|
// whitelisted?
|
|
|
|
// whitelisted?
|
|
|
|
if ( !block ) {
|
|
|
|
if ( !block ) {
|
|
|
@ -323,64 +356,6 @@ var processRequest = function(µm, details) {
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
// Intercept and filter web requests according to white and black lists.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var onBeforeRequestHandler = function(details) {
|
|
|
|
|
|
|
|
var µm = µMatrix;
|
|
|
|
|
|
|
|
var µmuri = µm.URI;
|
|
|
|
|
|
|
|
var requestURL = details.url;
|
|
|
|
|
|
|
|
var requestScheme = µmuri.schemeFromURI(requestURL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// rhill 2014-02-17: Ignore 'filesystem:': this can happen when listening
|
|
|
|
|
|
|
|
// to 'chrome-extension://'.
|
|
|
|
|
|
|
|
if ( requestScheme === 'filesystem' ) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// console.debug('onBeforeRequestHandler()> "%s": %o', details.url, details);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var requestType = requestTypeNormalizer[details.type];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/303
|
|
|
|
|
|
|
|
// Wherever the main doc comes from, create a receiver page URL: synthetize
|
|
|
|
|
|
|
|
// one if needed.
|
|
|
|
|
|
|
|
if ( requestType === 'doc' && details.parentFrameId < 0 ) {
|
|
|
|
|
|
|
|
return onBeforeRootFrameRequestHandler(details);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Is it µMatrix's noop css file?
|
|
|
|
|
|
|
|
if ( requestType === 'css' && requestURL.slice(0, µm.noopCSSURL.length) === µm.noopCSSURL ) {
|
|
|
|
|
|
|
|
return onBeforeChromeExtensionRequestHandler(details);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Ignore non-http schemes
|
|
|
|
|
|
|
|
if ( requestScheme.indexOf('http') !== 0 ) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Do not block myself from updating assets
|
|
|
|
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/202
|
|
|
|
|
|
|
|
if ( requestType === 'xhr' && requestURL.slice(0, µm.projectServerRoot.length) === µm.projectServerRoot ) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/342
|
|
|
|
|
|
|
|
// If the request cannot be bound to a specific tab, delay request
|
|
|
|
|
|
|
|
// handling to onBeforeSendHeaders(), maybe there the referrer
|
|
|
|
|
|
|
|
// information will allow us to properly bind the request to the tab
|
|
|
|
|
|
|
|
// from which it originates.
|
|
|
|
|
|
|
|
// Important: since it is not possible to redirect requests at
|
|
|
|
|
|
|
|
// onBeforeSendHeaders() point, we can't delay when the request type is
|
|
|
|
|
|
|
|
// `sub_frame`.
|
|
|
|
|
|
|
|
if ( requestType !== 'frame' && details.tabId < 0 ) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return processRequest(µm, details);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This is where tabless requests are processed, as here there may be a chance
|
|
|
|
// This is where tabless requests are processed, as here there may be a chance
|
|
|
|
// we can bind a request to a specific tab, as headers may contain useful
|
|
|
|
// we can bind a request to a specific tab, as headers may contain useful
|
|
|
|
// information to accomplish this.
|
|
|
|
// information to accomplish this.
|
|
|
@ -390,62 +365,9 @@ var onBeforeRequestHandler = function(details) {
|
|
|
|
var onBeforeSendHeadersHandler = function(details) {
|
|
|
|
var onBeforeSendHeadersHandler = function(details) {
|
|
|
|
|
|
|
|
|
|
|
|
var µm = µMatrix;
|
|
|
|
var µm = µMatrix;
|
|
|
|
var requestURL = details.url;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// console.debug('onBeforeSendHeadersHandler()> "%s": %o', details.url, details);
|
|
|
|
// console.debug('onBeforeSendHeadersHandler()> "%s": %o', details.url, details);
|
|
|
|
|
|
|
|
|
|
|
|
// Do not block myself from updating assets
|
|
|
|
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/202
|
|
|
|
|
|
|
|
var requestType = requestTypeNormalizer[details.type];
|
|
|
|
|
|
|
|
if ( requestType === 'xhr' && requestURL.slice(0, µm.projectServerRoot.length) === µm.projectServerRoot ) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/342
|
|
|
|
|
|
|
|
// Is this hyperlink auditing?
|
|
|
|
|
|
|
|
// If yes, create a synthetic URL for reporting hyperlink auditing
|
|
|
|
|
|
|
|
// record requests. This way the user is better informed of what went
|
|
|
|
|
|
|
|
// on.
|
|
|
|
|
|
|
|
var linkAuditor = hyperlinkAuditorFromHeaders(details.requestHeaders);
|
|
|
|
|
|
|
|
if ( linkAuditor ) {
|
|
|
|
|
|
|
|
details.µmRequestURL = requestURL + '{Ping-To:' + linkAuditor + '}';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If we are dealing with a behind-the-scene request, make a last attempt
|
|
|
|
|
|
|
|
// to bind the request to a specific tab by using the referrer or the
|
|
|
|
|
|
|
|
// `Ping-From` header if any of these exists.
|
|
|
|
|
|
|
|
var r;
|
|
|
|
|
|
|
|
if ( details.tabId < 0 ) {
|
|
|
|
|
|
|
|
details.tabId = tabIdFromHeaders(µm, details.requestHeaders) || -1;
|
|
|
|
|
|
|
|
// Do not process `main_frame`/`sub_frame` requests, these were handled
|
|
|
|
|
|
|
|
// unconditionally at onBeforeRequest() time (because of potential
|
|
|
|
|
|
|
|
// need to redirect).
|
|
|
|
|
|
|
|
if ( requestType !== 'doc' && requestType !== 'frame' ) {
|
|
|
|
|
|
|
|
r = processRequest(µm, details);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If the request was not cancelled above, check whether hyperlink auditing
|
|
|
|
|
|
|
|
// is globally forbidden.
|
|
|
|
|
|
|
|
if ( !r ) {
|
|
|
|
|
|
|
|
if ( linkAuditor && µm.userSettings.processHyperlinkAuditing ) {
|
|
|
|
|
|
|
|
r = { 'cancel': true };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Block request?
|
|
|
|
|
|
|
|
if ( r ) {
|
|
|
|
|
|
|
|
// Count number of hyperlink auditing foiled, even attempts blocked
|
|
|
|
|
|
|
|
// through the matrix.
|
|
|
|
|
|
|
|
if ( linkAuditor ) {
|
|
|
|
|
|
|
|
µm.hyperlinkAuditingFoiledCounter += 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If we reach this point, request is not blocked, so what is left to do
|
|
|
|
|
|
|
|
// is to sanitize headers.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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 HTTP Switchboard, i.e. `opera://startpage`,
|
|
|
|
// which cannot be handled by HTTP Switchboard, i.e. `opera://startpage`,
|
|
|
@ -460,6 +382,28 @@ var onBeforeSendHeadersHandler = function(details) {
|
|
|
|
pageStore = µm.pageStatsFromTabId(tabId);
|
|
|
|
pageStore = µm.pageStatsFromTabId(tabId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
var requestURL = details.url;
|
|
|
|
|
|
|
|
var requestType = requestTypeNormalizer[details.type];
|
|
|
|
|
|
|
|
if ( requestType === 'other' ) {
|
|
|
|
|
|
|
|
var linkAuditor = hyperlinkAuditorFromHeaders(details.requestHeaders);
|
|
|
|
|
|
|
|
if ( linkAuditor ) {
|
|
|
|
|
|
|
|
var block = µm.userSettings.processHyperlinkAuditing;
|
|
|
|
|
|
|
|
pageStore.recordRequest('other', requestURL + '{Ping-To:' + linkAuditor + '}', block);
|
|
|
|
|
|
|
|
if ( block ) {
|
|
|
|
|
|
|
|
µm.hyperlinkAuditingFoiledCounter += 1;
|
|
|
|
|
|
|
|
return { 'cancel': true };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If we reach this point, request is not blocked, so what is left to do
|
|
|
|
|
|
|
|
// is to sanitize headers.
|
|
|
|
|
|
|
|
|
|
|
|
var reqHostname = µm.hostnameFromURL(requestURL);
|
|
|
|
var reqHostname = µm.hostnameFromURL(requestURL);
|
|
|
|
var changed = false;
|
|
|
|
var changed = false;
|
|
|
|
|
|
|
|
|
|
|
@ -710,7 +654,7 @@ var onMainDocHeadersReceived = function(details) {
|
|
|
|
|
|
|
|
|
|
|
|
// Enforce strict HTTPS?
|
|
|
|
// Enforce strict HTTPS?
|
|
|
|
if ( requestScheme === 'https' && µm.tMatrix.evaluateSwitchZ('https-strict', pageStats.pageHostname) ) {
|
|
|
|
if ( requestScheme === 'https' && µm.tMatrix.evaluateSwitchZ('https-strict', pageStats.pageHostname) ) {
|
|
|
|
csp += "default-src https: data: 'unsafe-inline' 'unsafe-eval'";
|
|
|
|
csp += "default-src https: data: chrome-search: 'unsafe-inline' 'unsafe-eval'";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/181
|
|
|
|
// https://github.com/gorhill/httpswitchboard/issues/181
|
|
|
|