/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* eslint no-unused-vars: ["error", {args: "none"}] */ var EXPORTED_SYMBOLS = ["PopupBlockingChild"]; const {ActorChild} = ChromeUtils.import("resource://gre/modules/ActorChild.jsm"); const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); class PopupBlockingChild extends ActorChild { constructor(dispatcher) { super(dispatcher); this.popupData = null; this.popupDataInternal = null; this.mm.addEventListener("pageshow", this, true); this.mm.addEventListener("pagehide", this, true); this.mm.addMessageListener("PopupBlocking:UnblockPopup", this); this.mm.addMessageListener("PopupBlocking:GetBlockedPopupList", this); } receiveMessage(msg) { switch (msg.name) { case "PopupBlocking:UnblockPopup": { let i = msg.data.index; if (this.popupData && this.popupData[i]) { let data = this.popupData[i]; let internals = this.popupDataInternal[i]; let dwi = internals.requestingWindow; // If we have a requesting window and the requesting document is // still the current document, open the popup. if (dwi && dwi.document == internals.requestingDocument) { dwi.open(data.popupWindowURIspec, data.popupWindowName, data.popupWindowFeatures); } } break; } case "PopupBlocking:GetBlockedPopupList": { let popupData = []; let length = this.popupData ? this.popupData.length : 0; // Limit 15 popup URLs to be reported through the UI length = Math.min(length, 15); for (let i = 0; i < length; i++) { let popupWindowURIspec = this.popupData[i].popupWindowURIspec; if (popupWindowURIspec == this.mm.content.location.href) { popupWindowURIspec = ""; } else { // Limit 500 chars to be sent because the URI will be cropped // by the UI anyway, and data: URIs can be significantly larger. popupWindowURIspec = popupWindowURIspec.substring(0, 500); } popupData.push({popupWindowURIspec}); } this.mm.sendAsyncMessage("PopupBlocking:ReplyGetBlockedPopupList", {popupData}); break; } } } handleEvent(ev) { switch (ev.type) { case "DOMPopupBlocked": return this.onPopupBlocked(ev); case "pageshow": return this._removeIrrelevantPopupData(); case "pagehide": return this._removeIrrelevantPopupData(ev.target); } return undefined; } onPopupBlocked(ev) { if (!this.popupData) { this.popupData = []; this.popupDataInternal = []; } // Avoid spamming the parent process with too many blocked popups. if (this.popupData.length >= PopupBlockingChild.maxReportedPopups) { return; } let obj = { popupWindowURIspec: ev.popupWindowURI ? ev.popupWindowURI.spec : "about:blank", popupWindowFeatures: ev.popupWindowFeatures, popupWindowName: ev.popupWindowName, }; let internals = { requestingWindow: ev.requestingWindow, requestingDocument: ev.requestingWindow.document, }; this.popupData.push(obj); this.popupDataInternal.push(internals); this.updateBlockedPopups(true); } _removeIrrelevantPopupData(removedDoc = null) { if (this.popupData) { let i = 0; let oldLength = this.popupData.length; while (i < this.popupData.length) { let {requestingWindow, requestingDocument} = this.popupDataInternal[i]; // Filter out irrelevant reports. if (requestingWindow && requestingWindow.document == requestingDocument && requestingDocument != removedDoc) { i++; } else { this.popupData.splice(i, 1); this.popupDataInternal.splice(i, 1); } } if (this.popupData.length == 0) { this.popupData = null; this.popupDataInternal = null; } if (!this.popupData || oldLength > this.popupData.length) { this.updateBlockedPopups(false); } } } updateBlockedPopups(freshPopup) { this.mm.sendAsyncMessage("PopupBlocking:UpdateBlockedPopups", { count: this.popupData ? this.popupData.length : 0, freshPopup, }); } } XPCOMUtils.defineLazyPreferenceGetter(PopupBlockingChild, "maxReportedPopups", "privacy.popups.maxReported");