mirror of
https://github.com/gorhill/uBlock.git
synced 2024-10-06 09:37:12 +02:00
code review: make onHeadersReceive() able to cancel responses
This commit is contained in:
parent
064ef87f73
commit
3d472beb1b
@ -1749,9 +1749,6 @@ var httpObserver = {
|
|||||||
ACCEPT: Components.results.NS_SUCCEEDED,
|
ACCEPT: Components.results.NS_SUCCEEDED,
|
||||||
// Request types:
|
// Request types:
|
||||||
// https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIContentPolicy#Constants
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIContentPolicy#Constants
|
||||||
MAIN_FRAME: Ci.nsIContentPolicy.TYPE_DOCUMENT,
|
|
||||||
VALID_CSP_TARGETS: 1 << Ci.nsIContentPolicy.TYPE_DOCUMENT |
|
|
||||||
1 << Ci.nsIContentPolicy.TYPE_SUBDOCUMENT,
|
|
||||||
typeMap: {
|
typeMap: {
|
||||||
1: 'other',
|
1: 'other',
|
||||||
2: 'script',
|
2: 'script',
|
||||||
@ -1769,6 +1766,10 @@ var httpObserver = {
|
|||||||
19: 'beacon',
|
19: 'beacon',
|
||||||
21: 'image'
|
21: 'image'
|
||||||
},
|
},
|
||||||
|
onBeforeRequest: function(){},
|
||||||
|
onBeforeRequestTypes: null,
|
||||||
|
onHeadersReceived: function(){},
|
||||||
|
onHeadersReceivedTypes: null,
|
||||||
|
|
||||||
get componentRegistrar() {
|
get componentRegistrar() {
|
||||||
return Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
return Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||||
@ -1935,14 +1936,12 @@ var httpObserver = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleRequest: function(channel, URI, details) {
|
handleRequest: function(channel, URI, details) {
|
||||||
var onBeforeRequest = vAPI.net.onBeforeRequest;
|
|
||||||
var type = this.typeMap[details.rawtype] || 'other';
|
var type = this.typeMap[details.rawtype] || 'other';
|
||||||
|
if ( this.onBeforeRequestTypes && this.onBeforeRequestTypes.has(type) === false ) {
|
||||||
if ( onBeforeRequest.types && onBeforeRequest.types.has(type) === false ) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = onBeforeRequest.callback({
|
var result = this.onBeforeRequest({
|
||||||
frameId: details.frameId,
|
frameId: details.frameId,
|
||||||
hostname: URI.asciiHost,
|
hostname: URI.asciiHost,
|
||||||
parentFrameId: details.parentFrameId,
|
parentFrameId: details.parentFrameId,
|
||||||
@ -1963,65 +1962,85 @@ var httpObserver = {
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getResponseHeader: function(channel, name) {
|
||||||
|
var value;
|
||||||
|
try {
|
||||||
|
value = channel.getResponseHeader(name);
|
||||||
|
} catch (ex) {
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleResponseHeaders: function(channel, URI, channelData) {
|
||||||
|
var type = this.typeMap[channelData[4]] || 'other';
|
||||||
|
if ( this.onHeadersReceivedTypes && this.onHeadersReceivedTypes.has(type) === false ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'Content-Security-Policy' MUST come last in the array. Need to
|
||||||
|
// revised this eventually.
|
||||||
|
var responseHeaders = [];
|
||||||
|
var value = this.getResponseHeader(channel, 'Content-Security-Policy');
|
||||||
|
if ( value !== undefined ) {
|
||||||
|
responseHeaders.push({ name: 'Content-Security-Policy', value: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = this.onHeadersReceived({
|
||||||
|
hostname: URI.asciiHost,
|
||||||
|
parentFrameId: channelData[1],
|
||||||
|
responseHeaders: responseHeaders,
|
||||||
|
tabId: channelData[3],
|
||||||
|
type: this.typeMap[channelData[4]] || 'other',
|
||||||
|
url: URI.asciiSpec
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( !result ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( result.cancel ) {
|
||||||
|
channel.cancel(this.ABORT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( result.responseHeaders ) {
|
||||||
|
channel.setResponseHeader(
|
||||||
|
'Content-Security-Policy',
|
||||||
|
result.responseHeaders.pop().value,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
observe: function(channel, topic) {
|
observe: function(channel, topic) {
|
||||||
if ( channel instanceof Ci.nsIHttpChannel === false ) {
|
if ( channel instanceof Ci.nsIHttpChannel === false ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var URI = channel.URI;
|
var URI = channel.URI;
|
||||||
var channelData, result;
|
|
||||||
|
|
||||||
if ( topic === 'http-on-examine-response' ) {
|
if ( topic === 'http-on-examine-response' ) {
|
||||||
if ( !(channel instanceof Ci.nsIWritablePropertyBag) ) {
|
if ( channel instanceof Ci.nsIWritablePropertyBag === false ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var channelData;
|
||||||
try {
|
try {
|
||||||
channelData = channel.getProperty(this.REQDATAKEY);
|
channelData = channel.getProperty(this.REQDATAKEY);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !channelData ) {
|
if ( !channelData ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (1 << channelData[4] & this.VALID_CSP_TARGETS) === 0 ) {
|
this.handleResponseHeaders(channel, URI, channelData);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
topic = 'Content-Security-Policy';
|
|
||||||
|
|
||||||
try {
|
|
||||||
result = channel.getResponseHeader(topic);
|
|
||||||
} catch (ex) {
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = vAPI.net.onHeadersReceived.callback({
|
|
||||||
hostname: URI.asciiHost,
|
|
||||||
parentFrameId: channelData[1],
|
|
||||||
responseHeaders: result ? [{name: topic, value: result}] : [],
|
|
||||||
tabId: channelData[3],
|
|
||||||
type: this.typeMap[channelData[4]] || 'other',
|
|
||||||
url: URI.asciiSpec
|
|
||||||
});
|
|
||||||
|
|
||||||
if ( result ) {
|
|
||||||
channel.setResponseHeader(
|
|
||||||
topic,
|
|
||||||
result.responseHeaders.pop().value,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// http-on-opening-request
|
// http-on-opening-request
|
||||||
|
|
||||||
//console.log('http-on-opening-request:', URI.spec);
|
|
||||||
|
|
||||||
var pendingRequest = this.lookupPendingRequest(URI.spec);
|
var pendingRequest = this.lookupPendingRequest(URI.spec);
|
||||||
var rawtype = channel.loadInfo && channel.loadInfo.contentPolicyType || 1;
|
var rawtype = channel.loadInfo && channel.loadInfo.contentPolicyType || 1;
|
||||||
|
|
||||||
@ -2108,6 +2127,7 @@ var httpObserver = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
vAPI.net = {};
|
vAPI.net = {};
|
||||||
@ -2118,9 +2138,19 @@ vAPI.net.registerListeners = function() {
|
|||||||
// Since it's not used
|
// Since it's not used
|
||||||
this.onBeforeSendHeaders = null;
|
this.onBeforeSendHeaders = null;
|
||||||
|
|
||||||
this.onBeforeRequest.types = this.onBeforeRequest.types ?
|
if ( typeof this.onBeforeRequest.callback === 'function' ) {
|
||||||
new Set(this.onBeforeRequest.types) :
|
httpObserver.onBeforeRequest = this.onBeforeRequest.callback;
|
||||||
null;
|
httpObserver.onBeforeRequestTypes = this.onBeforeRequest.types ?
|
||||||
|
new Set(this.onBeforeRequest.types) :
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( typeof this.onHeadersReceived.callback === 'function' ) {
|
||||||
|
httpObserver.onHeadersReceived = this.onHeadersReceived.callback;
|
||||||
|
httpObserver.onHeadersReceivedTypes = this.onHeadersReceived.types ?
|
||||||
|
new Set(this.onHeadersReceived.types) :
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
var shouldBlockPopup = function(details) {
|
var shouldBlockPopup = function(details) {
|
||||||
var sourceTabId = null;
|
var sourceTabId = null;
|
||||||
|
@ -331,28 +331,33 @@ var onHeadersReceived = function(details) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special handling for root document.
|
var requestType = details.type;
|
||||||
if ( details.type === 'main_frame' ) {
|
|
||||||
|
if ( requestType === 'main_frame' ) {
|
||||||
return onRootFrameHeadersReceived(details);
|
return onRootFrameHeadersReceived(details);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just in case...
|
if ( requestType === 'sub_frame' ) {
|
||||||
if ( details.type !== 'sub_frame' ) {
|
return onFrameHeadersReceived(details);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// If we reach this point, we are dealing with a sub_frame
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var onRootFrameHeadersReceived = function(details) {
|
||||||
|
var µb = µBlock;
|
||||||
|
var tabId = details.tabId;
|
||||||
|
|
||||||
|
µb.tabContextManager.push(tabId, details.url);
|
||||||
|
|
||||||
// Lookup the page store associated with this tab id.
|
// Lookup the page store associated with this tab id.
|
||||||
var µb = µBlock;
|
|
||||||
var pageStore = µb.pageStoreFromTabId(tabId);
|
var pageStore = µb.pageStoreFromTabId(tabId);
|
||||||
if ( !pageStore ) {
|
if ( !pageStore ) {
|
||||||
return;
|
pageStore = µb.bindTabToPageStats(tabId, 'beforeRequest');
|
||||||
}
|
}
|
||||||
|
// I can't think of how pageStore could be null at this point.
|
||||||
|
|
||||||
// Frame id of frame request is their own id, while the request is made
|
var context = pageStore.createContextFromPage();
|
||||||
// in the context of the parent.
|
|
||||||
var context = pageStore.createContextFromFrameId(details.parentFrameId);
|
|
||||||
context.requestURL = details.url;
|
context.requestURL = details.url;
|
||||||
context.requestHostname = details.hostname;
|
context.requestHostname = details.hostname;
|
||||||
context.requestType = 'inline-script';
|
context.requestType = 'inline-script';
|
||||||
@ -385,20 +390,19 @@ var onHeadersReceived = function(details) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var onRootFrameHeadersReceived = function(details) {
|
var onFrameHeadersReceived = function(details) {
|
||||||
var tabId = details.tabId;
|
|
||||||
var µb = µBlock;
|
var µb = µBlock;
|
||||||
|
var tabId = details.tabId;
|
||||||
µb.tabContextManager.push(tabId, details.url);
|
|
||||||
|
|
||||||
// Lookup the page store associated with this tab id.
|
// Lookup the page store associated with this tab id.
|
||||||
var pageStore = µb.pageStoreFromTabId(tabId);
|
var pageStore = µb.pageStoreFromTabId(tabId);
|
||||||
if ( !pageStore ) {
|
if ( !pageStore ) {
|
||||||
pageStore = µb.bindTabToPageStats(tabId, 'beforeRequest');
|
return;
|
||||||
}
|
}
|
||||||
// I can't think of how pageStore could be null at this point.
|
|
||||||
|
|
||||||
var context = pageStore.createContextFromPage();
|
// Frame id of frame request is their own id, while the request is made
|
||||||
|
// in the context of the parent.
|
||||||
|
var context = pageStore.createContextFromFrameId(details.parentFrameId);
|
||||||
context.requestURL = details.url;
|
context.requestURL = details.url;
|
||||||
context.requestHostname = details.hostname;
|
context.requestHostname = details.hostname;
|
||||||
context.requestType = 'inline-script';
|
context.requestType = 'inline-script';
|
||||||
|
Loading…
Reference in New Issue
Block a user