Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: lib/popupBlocker.js

Issue 29336278: Issue 3651 - Fix popup blocking with dynamically created openers and invisible redirects (Closed)
Patch Set: Created Feb. 11, 2016, 5:22 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/popupBlocker.js
===================================================================
--- a/lib/popupBlocker.js
+++ b/lib/popupBlocker.js
@@ -25,14 +25,69 @@
let {checkWhitelisted} = require("whitelisting");
let {logRequest} = require("devtools");
-let tabsLoading = {};
+let loadingPopups = Object.create(null);
-function checkPotentialPopup(tabId, url, sourcePage, documentHost, specificOnly)
+function hasLoadingPopups()
{
- let urlObj = new URL(url || "about:blank");
+ return Object.keys(loadingPopups).length > 0;
Wladimir Palant 2016/02/12 15:43:43 With this being called from onCreatedNavigationTar
Sebastian Noack 2016/02/12 15:52:13 V8 is optimized for usage of Object.keys() like he
+}
+
+function forgetPopup(tabId)
+{
+ delete loadingPopups[tabId];
+
+ if (!hasLoadingPopups())
+ {
+ chrome.webRequest.onBeforeRequest.removeListener(onBeforeRequest);
+ chrome.webNavigation.onCompleted.removeListener(onCompleted);
+ chrome.tabs.onRemoved.removeListener(forgetPopup);
+ }
+}
+
+function getFrame(tabId, processId, frameId, callback)
+{
+ chrome.webNavigation.getFrame(
+ {
+ tabId: tabId,
+ processId: processId,
+ frameId: frameId
+ },
+ details =>
+ {
+ let {url, parentFrameId} = details;
+ let frame = {url: new URL(url), parent: null};
+
+ if (parentFrameId != -1)
+ {
+ getFrame(
+ tabId, processId, parentFrameId,
+ parentFrame =>
+ {
+ frame.parent = parentFrame;
+ callback(frame);
+ }
+ );
+ }
+ else
+ {
+ callback(frame);
+ }
+ }
+ );
+}
+
+function checkPotentialPopup(tabId, popup)
+{
+ let urlObj = new URL(popup.url || "about:blank");
let urlString = stringifyURL(urlObj);
+ let documentHost = extractHostFromFrame(popup.sourceFrame);
let thirdParty = isThirdParty(urlObj, documentHost);
+ let specificOnly = !!checkWhitelisted(
+ popup.sourcePage, popup.sourceFrame,
+ RegExpFilter.typeMap.GENERICBLOCK
+ );
+
let filter = defaultMatcher.matchesAny(
urlString, RegExpFilter.typeMap.POPUP,
documentHost, thirdParty, null, specificOnly
@@ -42,48 +97,72 @@
chrome.tabs.remove(tabId);
logRequest(
- sourcePage, urlString, "POPUP", documentHost,
- thirdParty, null, specificOnly, filter
+ popup.sourcePage, urlString, "POPUP",
+ documentHost, thirdParty, null,
+ specificOnly, filter
);
}
+function onBeforeRequest(details)
+{
+ let popup = loadingPopups[details.tabId];
+ if (popup)
+ {
+ popup.url = details.url;
+ if (popup.sourceFrame)
+ checkPotentialPopup(details.tabId, popup);
+ }
+}
+
+function onCompleted(details)
+{
+ if (details.frameId == 0 && details.url != "about:blank")
+ forgetPopup(details.tabId);
Wladimir Palant 2016/02/12 15:43:43 Will this cause a memory leak if a website opens a
Sebastian Noack 2016/02/12 15:52:13 Yes, just as with the previous implementation. But
+}
+
+function onSourceFrameRetrieved(tabId, frame)
+{
+ let popup = loadingPopups[tabId];
+ if (popup)
+ {
+ if (checkWhitelisted(popup.sourcePage, frame))
+ {
+ forgetPopup(tabId);
+ }
+ else
+ {
+ popup.sourceFrame = frame;
+ checkPotentialPopup(tabId, popup);
+ }
+ }
+}
+
chrome.webNavigation.onCreatedNavigationTarget.addListener(details =>
{
- let sourcePage = new ext.Page({id: details.sourceTabId});
- let sourceFrame = ext.getFrame(details.sourceTabId, details.sourceFrameId);
+ if (!hasLoadingPopups())
+ {
+ chrome.webRequest.onBeforeRequest.addListener(
+ onBeforeRequest,
+ {
+ urls: ["<all_urls>"],
+ types: ["main_frame"]
+ }
+ );
- if (checkWhitelisted(sourcePage, sourceFrame))
- return;
-
- let documentHost = extractHostFromFrame(sourceFrame);
- if (!documentHost)
- return;
-
- let specificOnly = !!checkWhitelisted(sourcePage, sourceFrame,
- RegExpFilter.typeMap.GENERICBLOCK);
-
- tabsLoading[details.tabId] = {
- page: sourcePage,
- documentHost: documentHost,
- specificOnly: specificOnly
- };
- checkPotentialPopup(details.tabId, details.url, sourcePage,
- documentHost, specificOnly);
-});
-
-chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) =>
-{
- if (!(tabId in tabsLoading))
- return;
-
- if ("url" in changeInfo)
- {
- let source = tabsLoading[tabId];
- checkPotentialPopup(tabId, tab.url, source.page,
- source.documentHost,
- source.specificOnly);
+ chrome.webNavigation.onCompleted.addListener(onCompleted);
+ chrome.tabs.onRemoved.addListener(forgetPopup);
}
- if ("status" in changeInfo && changeInfo.status == "complete" && tab.url != "about:blank")
- delete tabsLoading[tabId];
+ loadingPopups[details.tabId] = {
+ url: details.url,
+ sourcePage: new ext.Page({id: details.sourceTabId}),
+ sourceFrame: null
+ };
+
+ getFrame(
+ details.sourceTabId,
+ details.sourceProcessId,
+ details.sourceFrameId,
+ onSourceFrameRetrieved.bind(null, details.tabId)
+ );
});
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld