forked from mirrors/gecko-dev
156 lines
5.4 KiB
JavaScript
156 lines
5.4 KiB
JavaScript
/* 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/. */
|
|
|
|
"use strict";
|
|
|
|
/* global ExtensionAPI, XPCOMUtils */
|
|
|
|
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
|
|
|
function getInfoFrameScript(messageName) {
|
|
/* eslint-env mozilla/frame-script */
|
|
|
|
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
|
|
function getInnerWindowId(window) {
|
|
return window.windowUtils.currentInnerWindowID;
|
|
}
|
|
|
|
function getInnerWindowIDsForAllFrames(window) {
|
|
const innerWindowID = getInnerWindowId(window);
|
|
let ids = [innerWindowID];
|
|
|
|
if (window.frames) {
|
|
for (let i = 0; i < window.frames.length; i++) {
|
|
ids = ids.concat(getInnerWindowIDsForAllFrames(window.frames[i]));
|
|
}
|
|
}
|
|
|
|
return ids;
|
|
}
|
|
|
|
function getLoggedMessages(window, includePrivate = false) {
|
|
const ids = getInnerWindowIDsForAllFrames(window);
|
|
return getConsoleMessages(ids).concat(getScriptErrors(ids, includePrivate))
|
|
.sort((a, b) => a.timeStamp - b.timeStamp)
|
|
.map(m => m.message);
|
|
}
|
|
|
|
function getConsoleMessages(windowIds) {
|
|
const ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"]
|
|
.getService(Ci.nsIConsoleAPIStorage);
|
|
let messages = [];
|
|
for (const id of windowIds) {
|
|
messages = messages.concat(ConsoleAPIStorage.getEvents(id) || []);
|
|
}
|
|
return messages.map(evt => {
|
|
const {columnNumber, filename, level, lineNumber, timeStamp} = evt;
|
|
const args = evt.arguments.map(arg => {
|
|
return "" + arg;
|
|
}).join(", ");
|
|
const message = `[console.${level}(${args}) ${filename}:${lineNumber}:${columnNumber}]`;
|
|
return {timeStamp, message};
|
|
});
|
|
}
|
|
|
|
function getScriptErrors(windowIds, includePrivate = false) {
|
|
const messages = Services.console.getMessageArray() || [];
|
|
return messages.filter(message => {
|
|
if (message instanceof Ci.nsIScriptError) {
|
|
if (!includePrivate && message.isFromPrivateWindow) {
|
|
return false;
|
|
}
|
|
|
|
if (windowIds && !windowIds.includes(message.innerWindowID)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// If this is not an nsIScriptError and we need to do window-based
|
|
// filtering we skip this message.
|
|
return false;
|
|
}).map(error => {
|
|
const {timeStamp, message} = error;
|
|
return {timeStamp, message};
|
|
});
|
|
}
|
|
|
|
sendAsyncMessage(messageName, {
|
|
hasMixedActiveContentBlocked: docShell.hasMixedActiveContentBlocked,
|
|
hasMixedDisplayContentBlocked: docShell.hasMixedDisplayContentBlocked,
|
|
hasTrackingContentBlocked: docShell.hasTrackingContentBlocked,
|
|
log: getLoggedMessages(content),
|
|
});
|
|
}
|
|
|
|
this.tabExtras = class extends ExtensionAPI {
|
|
getAPI(context) {
|
|
const {tabManager} = context.extension;
|
|
const {Management: {global: {windowTracker}}} =
|
|
ChromeUtils.import("resource://gre/modules/Extension.jsm", {});
|
|
return {
|
|
tabExtras: {
|
|
async loadURIWithPostData(tabId, url, postData, postDataContentType) {
|
|
const tab = tabManager.get(tabId);
|
|
if (!tab || !tab.browser) {
|
|
return Promise.reject("Invalid tab");
|
|
}
|
|
|
|
try {
|
|
new URL(url);
|
|
} catch (_) {
|
|
return Promise.reject("Invalid url");
|
|
}
|
|
|
|
if (typeof postData !== "string" && !(postData instanceof String)) {
|
|
return Promise.reject("postData must be a string");
|
|
}
|
|
|
|
const stringStream = Cc["@mozilla.org/io/string-input-stream;1"]
|
|
.createInstance(Ci.nsIStringInputStream);
|
|
stringStream.data = postData;
|
|
const post = Cc["@mozilla.org/network/mime-input-stream;1"]
|
|
.createInstance(Ci.nsIMIMEInputStream);
|
|
post.addHeader("Content-Type", postDataContentType ||
|
|
"application/x-www-form-urlencoded");
|
|
post.setData(stringStream);
|
|
|
|
return new Promise(resolve => {
|
|
const listener = {
|
|
onLocationChange(browser, webProgress, request, locationURI, flags) {
|
|
if (webProgress.isTopLevel &&
|
|
browser === tab.browser &&
|
|
locationURI.spec === url) {
|
|
windowTracker.removeListener("progress", listener);
|
|
resolve();
|
|
}
|
|
},
|
|
};
|
|
windowTracker.addListener("progress", listener);
|
|
|
|
let loadURIOptions = {
|
|
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({}),
|
|
postData: post,
|
|
};
|
|
tab.browser.webNavigation.loadURI(url, loadURIOptions);
|
|
});
|
|
},
|
|
async getWebcompatInfo(tabId) {
|
|
return new Promise(resolve => {
|
|
const messageName = "WebExtension:GetWebcompatInfo";
|
|
const code = `${getInfoFrameScript.toString()};getInfoFrameScript("${messageName}")`;
|
|
const mm = tabManager.get(tabId).browser.messageManager;
|
|
mm.loadFrameScript(`data:,${encodeURI(code)}`, false);
|
|
mm.addMessageListener(messageName, function receiveFn(message) {
|
|
mm.removeMessageListener(messageName, receiveFn);
|
|
resolve(message.json);
|
|
});
|
|
});
|
|
},
|
|
},
|
|
};
|
|
}
|
|
};
|