1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-10-06 09:37:12 +02:00
This commit is contained in:
gorhill 2015-05-17 10:32:40 -04:00
parent 087cd4e645
commit d41408ebbc
3 changed files with 116 additions and 63 deletions

View File

@ -53,6 +53,7 @@ const contentObserver = {
contractID: '@' + hostName + '/content-policy;1', contractID: '@' + hostName + '/content-policy;1',
ACCEPT: Ci.nsIContentPolicy.ACCEPT, ACCEPT: Ci.nsIContentPolicy.ACCEPT,
MAIN_FRAME: Ci.nsIContentPolicy.TYPE_DOCUMENT, MAIN_FRAME: Ci.nsIContentPolicy.TYPE_DOCUMENT,
SUB_FRAME: Ci.nsIContentPolicy.TYPE_SUBDOCUMENT,
contentBaseURI: 'chrome://' + hostName + '/content/js/', contentBaseURI: 'chrome://' + hostName + '/content/js/',
cpMessageName: hostName + ':shouldLoad', cpMessageName: hostName + ':shouldLoad',
ignoredPopups: new WeakMap(), ignoredPopups: new WeakMap(),
@ -132,12 +133,14 @@ const contentObserver = {
if ( type === this.MAIN_FRAME ) { if ( type === this.MAIN_FRAME ) {
context = context.contentWindow || context; context = context.contentWindow || context;
if (
if ( context.opener && context.opener !== context context.opener &&
&& this.ignoredPopups.has(context) === false ) { context.opener !== context &&
this.ignoredPopups.has(context) === false
) {
openerURL = context.opener.location.href; openerURL = context.opener.location.href;
} }
} else if ( type === 7 ) { // SUB_DOCUMENT } else if ( type === this.SUB_FRAME ) {
context = context.contentWindow; context = context.contentWindow;
} else { } else {
context = (context.ownerDocument || context).defaultView; context = (context.ownerDocument || context).defaultView;
@ -151,7 +154,6 @@ const contentObserver = {
let isTopLevel = context === context.top; let isTopLevel = context === context.top;
let parentFrameId; let parentFrameId;
if ( isTopLevel ) { if ( isTopLevel ) {
parentFrameId = -1; parentFrameId = -1;
} else if ( context.parent === context.top ) { } else if ( context.parent === context.top ) {
@ -165,7 +167,7 @@ const contentObserver = {
frameId: isTopLevel ? 0 : this.getFrameId(context), frameId: isTopLevel ? 0 : this.getFrameId(context),
openerURL: openerURL, openerURL: openerURL,
parentFrameId: parentFrameId, parentFrameId: parentFrameId,
type: type, rawtype: type,
url: location.spec url: location.spec
}; };

View File

@ -962,7 +962,8 @@ var httpObserver = {
REQDATAKEY: location.host + 'reqdata', REQDATAKEY: location.host + 'reqdata',
ABORT: Components.results.NS_BINDING_ABORTED, ABORT: Components.results.NS_BINDING_ABORTED,
ACCEPT: Components.results.NS_SUCCEEDED, ACCEPT: Components.results.NS_SUCCEEDED,
// Request types: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIContentPolicy#Constants // Request types:
// https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIContentPolicy#Constants
MAIN_FRAME: Ci.nsIContentPolicy.TYPE_DOCUMENT, MAIN_FRAME: Ci.nsIContentPolicy.TYPE_DOCUMENT,
VALID_CSP_TARGETS: 1 << Ci.nsIContentPolicy.TYPE_DOCUMENT | VALID_CSP_TARGETS: 1 << Ci.nsIContentPolicy.TYPE_DOCUMENT |
1 << Ci.nsIContentPolicy.TYPE_SUBDOCUMENT, 1 << Ci.nsIContentPolicy.TYPE_SUBDOCUMENT,
@ -979,7 +980,6 @@ var httpObserver = {
14: 'font', 14: 'font',
21: 'image' 21: 'image'
}, },
lastRequest: [{}, {}],
get componentRegistrar() { get componentRegistrar() {
return Components.manager.QueryInterface(Ci.nsIComponentRegistrar); return Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
@ -1010,6 +1010,8 @@ var httpObserver = {
}, },
register: function() { register: function() {
this.pendingRingBufferInit();
Services.obs.addObserver(this, 'http-on-opening-request', true); Services.obs.addObserver(this, 'http-on-opening-request', true);
Services.obs.addObserver(this, 'http-on-examine-response', true); Services.obs.addObserver(this, 'http-on-examine-response', true);
@ -1049,6 +1051,79 @@ var httpObserver = {
); );
}, },
PendingRequest: function() {
this.frameId = 0;
this.parentFrameId = 0;
this.rawtype = 0;
this.sourceTabId = null;
this.tabId = 0;
this._key = ''; // key is url, from URI.spec
},
// If all work fine, this map should not grow indefinitely. It can have
// stale items in it, but these will be taken care of when entries in
// the ring buffer are overwritten.
pendingURLToIndex: new Map(),
pendingWritePointer: 0,
pendingRingBuffer: new Array(32),
pendingRingBufferInit: function() {
// Use and reuse pre-allocated PendingRequest objects = less memory
// churning.
var i = this.pendingRingBuffer.length;
while ( i-- ) {
this.pendingRingBuffer[i] = new this.PendingRequest();
}
},
createPendingRequest: function(url) {
var bucket;
var i = this.pendingWritePointer;
this.pendingWritePointer = i + 1 & 31;
var preq = this.pendingRingBuffer[i];
// Cleanup unserviced pending request
if ( preq._key !== '' ) {
bucket = this.pendingURLToIndex.get(preq._key);
if ( Array.isArray(bucket) ) {
// Assuming i in array
var pos = bucket.indexOf(i);
bucket.splice(pos, 1);
if ( bucket.length === 1 ) {
this.pendingURLToIndex.set(preq._key, bucket[0]);
}
} else if ( typeof bucket === 'number' ) {
// Assuming bucket === i
this.pendingURLToIndex.delete(preq._key);
}
}
// Would be much simpler if a url could not appear more than once.
bucket = this.pendingURLToIndex.get(url);
if ( bucket === undefined ) {
this.pendingURLToIndex.set(url, i);
} else if ( Array.isArray(bucket) ) {
bucket = bucket.push(i);
} else {
bucket = [bucket, i];
}
preq._key = url;
return preq;
},
lookupPendingRequest: function(url) {
var i = this.pendingURLToIndex.get(url);
if ( i === undefined ) {
return null;
}
if ( Array.isArray(i) ) {
var bucket = i;
i = bucket.shift();
if ( bucket.length === 1 ) {
this.pendingURLToIndex.set(url, bucket[0]);
}
} else {
this.pendingURLToIndex.delete(url);
}
var preq = this.pendingRingBuffer[i];
preq._key = ''; // mark as "serviced"
return preq;
},
handlePopup: function(URI, tabId, sourceTabId) { handlePopup: function(URI, tabId, sourceTabId) {
if ( !sourceTabId ) { if ( !sourceTabId ) {
return false; return false;
@ -1069,7 +1144,7 @@ var httpObserver = {
handleRequest: function(channel, URI, details) { handleRequest: function(channel, URI, details) {
var onBeforeRequest = vAPI.net.onBeforeRequest; var onBeforeRequest = vAPI.net.onBeforeRequest;
var type = this.typeMap[details.type] || 'other'; var type = this.typeMap[details.rawtype] || 'other';
if ( onBeforeRequest.types && onBeforeRequest.types.has(type) === false ) { if ( onBeforeRequest.types && onBeforeRequest.types.has(type) === false ) {
return false; return false;
@ -1093,14 +1168,6 @@ var httpObserver = {
return true; return true;
} }
/*if ( result.redirectUrl ) {
channel.redirectionLimit = 1;
channel.redirectTo(
Services.io.newURI(result.redirectUrl, null, null)
);
return true;
}*/
return false; return false;
}, },
@ -1160,55 +1227,37 @@ var httpObserver = {
// http-on-opening-request // http-on-opening-request
var lastRequest = this.lastRequest[0]; //console.log('http-on-opening-request:', URI.spec);
if ( lastRequest.url !== URI.spec ) { var pendingRequest = this.lookupPendingRequest(URI.spec);
if ( this.lastRequest[1].url === URI.spec ) {
lastRequest = this.lastRequest[1];
} else {
lastRequest.url = null;
}
}
if ( lastRequest.url === null ) { // Behind-the-scene request
lastRequest.type = channel.loadInfo && channel.loadInfo.contentPolicyType || 1; if ( pendingRequest === null ) {
result = this.handleRequest(channel, URI, { var rawtype = channel.loadInfo && channel.loadInfo.contentPolicyType || 1;
tabId: vAPI.noTabId, if ( this.handleRequest(channel, URI, { tabId: vAPI.noTabId, rawtype: rawtype }) ) {
type: lastRequest.type
});
if ( result === true ) {
return;
}
if ( channel instanceof Ci.nsIWritablePropertyBag === false ) {
return; return;
} }
// Carry data for behind-the-scene redirects // Carry data for behind-the-scene redirects
channel.setProperty( if ( channel instanceof Ci.nsIWritablePropertyBag ) {
this.REQDATAKEY, channel.setProperty( this.REQDATAKEY, [0, -1, null, vAPI.noTabId, rawtype]);
[lastRequest.type, vAPI.noTabId, null, 0, -1] }
);
return; return;
} }
// Important! When loading file via XHR for mirroring, if ( this.handleRequest(channel, URI, pendingRequest) ) {
// the URL will be the same, so it could fall into an infinite loop
lastRequest.url = null;
if ( this.handleRequest(channel, URI, lastRequest) ) {
return; return;
} }
// If request is not handled we may use the data in on-modify-request // If request is not handled we may use the data in on-modify-request
if ( channel instanceof Ci.nsIWritablePropertyBag ) { if ( channel instanceof Ci.nsIWritablePropertyBag ) {
channel.setProperty(this.REQDATAKEY, [ channel.setProperty(this.REQDATAKEY, [
lastRequest.frameId, pendingRequest.frameId,
lastRequest.parentFrameId, pendingRequest.parentFrameId,
lastRequest.sourceTabId, pendingRequest.sourceTabId,
lastRequest.tabId, pendingRequest.tabId,
lastRequest.type pendingRequest.rawtype
]); ]);
} }
}, },
@ -1240,7 +1289,7 @@ var httpObserver = {
frameId: channelData[0], frameId: channelData[0],
parentFrameId: channelData[1], parentFrameId: channelData[1],
tabId: channelData[3], tabId: channelData[3],
type: channelData[4] rawtype: channelData[4]
}; };
if ( this.handleRequest(newChannel, URI, details) ) { if ( this.handleRequest(newChannel, URI, details) ) {
@ -1276,6 +1325,10 @@ vAPI.net.registerListeners = function() {
var shouldLoadListenerMessageName = location.host + ':shouldLoad'; var shouldLoadListenerMessageName = location.host + ':shouldLoad';
var shouldLoadListener = function(e) { var shouldLoadListener = function(e) {
// Non blocking: it is assumed that the http observer is fired after
// shouldLoad recorded the pending requests. If this is not the case,
// a request would end up being categorized as a behind-the-scene
// requests.
var details = e.data; var details = e.data;
var tabId = vAPI.tabs.getTabId(e.target); var tabId = vAPI.tabs.getTabId(e.target);
var sourceTabId = null; var sourceTabId = null;
@ -1307,16 +1360,14 @@ vAPI.net.registerListeners = function() {
} }
} }
var lastRequest = httpObserver.lastRequest; //console.log('shouldLoadListener:', details.url);
lastRequest[1] = lastRequest[0];
lastRequest[0] = { var pendingReq = httpObserver.createPendingRequest(details.url);
frameId: details.frameId, pendingReq.frameId = details.frameId;
parentFrameId: details.parentFrameId, pendingReq.parentFrameId = details.parentFrameId;
sourceTabId: sourceTabId, pendingReq.rawtype = details.rawtype;
tabId: tabId, pendingReq.sourceTabId = sourceTabId;
type: details.type, pendingReq.tabId = tabId;
url: details.url
};
}; };
vAPI.messaging.globalMessageManager.addMessageListener( vAPI.messaging.globalMessageManager.addMessageListener(

View File

@ -195,7 +195,7 @@ window.addEventListener('pageshow', vAPI.messaging.toggleListener, true);
// we are not a top window (because element picker can still // we are not a top window (because element picker can still
// be injected in top window). // be injected in top window).
if ( window !== window.top ) { if ( window !== window.top ) {
// Can anything be done? // Can anything be done?
} }
/******************************************************************************/ /******************************************************************************/