code review: saner way to find a popup's opener tab id

This commit is contained in:
gorhill 2017-01-08 17:52:38 -05:00
parent eca33ea659
commit 3b0d3e3330
2 changed files with 61 additions and 38 deletions

View File

@ -160,6 +160,7 @@ var contentObserver = {
cpMessageName: hostName + ':shouldLoad',
popupMessageName: hostName + ':shouldLoadPopup',
ignoredPopups: new WeakMap(),
uniquePopupEventId: 1,
uniqueSandboxId: 1,
modernFirefox: Services.vc.compare(Services.appinfo.platformVersion, '44') > 0,
@ -466,35 +467,44 @@ var contentObserver = {
this.removeEventListener('keydown', contObs.ignorePopup, true);
this.removeEventListener('mousedown', contObs.ignorePopup, true);
},
lookupPopupOpenerURL: function(popup) {
var opener, openerURL;
lookupPopupOpener: function(popup) {
for (;;) {
opener = popup.opener;
if ( !opener ) { break; }
let opener = popup.opener;
if ( !opener ) { return; }
if ( opener.top ) { opener = opener.top; }
if ( opener === popup ) { break; }
if ( !opener.location ) { break; }
if ( !this.reGoodPopupURLs.test(opener.location.href) ) { break; }
openerURL = opener.location.href;
if ( opener === popup ) { return; }
if ( !opener.location ) { return; }
if ( this.reValidPopups.test(opener.location.protocol) ) {
return opener;
}
// https://github.com/uBlockOrigin/uAssets/issues/255
// - Mind chained about:blank popups.
if ( openerURL !== 'about:blank' ) { break; }
if ( opener.location.href !== 'about:blank' ) { return; }
popup = opener;
}
return openerURL;
},
reGoodPopupURLs: /^(?:about:blank|blob:|data:|https?:|javascript:)/,
reValidPopups: /^(?:blob|data|https?|javascript):/,
observe: function(subject, topic) {
// https://github.com/gorhill/uBlock/issues/2290
if ( topic === 'content-document-global-created' ) {
if ( subject !== subject.top ) { return; }
if ( this.ignoredPopups.has(subject) ) { return; }
let openerURL = this.lookupPopupOpenerURL(subject);
if ( !openerURL ) { return; }
let messager = getMessageManager(subject);
if ( !messager ) { return; }
messager.sendAsyncMessage(this.popupMessageName, openerURL);
let opener = this.lookupPopupOpener(subject);
if ( !opener ) { return; }
let popupMessager = getMessageManager(subject);
if ( !popupMessager ) { return; }
let openerMessager = getMessageManager(opener);
if ( !openerMessager ) { return; }
popupMessager.sendAsyncMessage(this.popupMessageName, {
id: this.uniquePopupEventId,
popup: true
});
openerMessager.sendAsyncMessage(this.popupMessageName, {
id: this.uniquePopupEventId,
opener: true
});
this.uniquePopupEventId += 1;
return;
}

View File

@ -2362,32 +2362,45 @@ vAPI.net.registerListeners = function() {
}
var shouldLoadPopupListenerMessageName = location.host + ':shouldLoadPopup';
var shouldLoadPopupListenerEntries = [];
var shouldLoadPopupListener = function(e) {
if ( typeof vAPI.tabs.onPopupCreated !== 'function' ) { return; }
var target = e.target,
openerURL = e.data,
popupTabId = tabWatcher.tabIdFromTarget(target),
openerTabId,
uri;
data = e.data,
now = Date.now(),
entries = shouldLoadPopupListenerEntries,
entry;
for ( var browser of tabWatcher.browsers() ) {
uri = browser.currentURI;
// Probably isn't the best method to identify the source tab.
// https://github.com/gorhill/uBlock/issues/450
// Skip entry if no valid URI available.
// Apparently URI can be undefined under some circumstances: I
// believe this may have to do with those very temporary
// browser objects created when opening a new tab, i.e. related
// to https://github.com/gorhill/uBlock/issues/212
if ( !uri || uri.spec !== openerURL ) { continue; }
openerTabId = tabWatcher.tabIdFromTarget(browser);
if ( openerTabId === popupTabId ) { continue; }
vAPI.tabs.onPopupCreated(popupTabId, openerTabId);
break;
var i = entries.length;
while ( i-- ) {
entry = entries[i];
if ( entry.id === data.id ) {
entries.splice(i, 1);
break;
}
if ( entry.expire <= now ) {
entries.splice(i, 1);
}
entry = undefined;
}
if ( !entry ) {
entry = {
id: data.id,
popupTabId: undefined,
openerTabId: undefined,
expire: now + 10000
};
entries.push(entry);
}
var tabId = tabWatcher.tabIdFromTarget(target);
if ( data.popup ) {
entry.popupTabId = tabId;
} else /* if ( data.opener ) */ {
entry.openerTabId = tabId;
}
if ( entry.popupTabId && entry.openerTabId ) {
vAPI.tabs.onPopupCreated(entry.popupTabId, entry.openerTabId);
}
};