Commit 0b1c358e authored by Tomislav Jovanovic's avatar Tomislav Jovanovic
Browse files

Bug 17082439 - Part 3: Use actor messaging for tabs.detectLanguage, stop...

Bug 17082439 - Part 3: Use actor messaging for tabs.detectLanguage, stop loading MessageChannel.jsm, r=robwu

Differential Revision: https://phabricator.services.mozilla.com/D126623
parent e4133e5c
......@@ -47,7 +47,6 @@ const known_scripts = {
// Extensions
"resource://gre/modules/ExtensionProcessScript.jsm",
"resource://gre/modules/ExtensionUtils.jsm",
"resource://gre/modules/MessageChannel.jsm",
]),
frameScripts: new Set([
// Test related
......
......@@ -55,7 +55,6 @@ const known_scripts = {
// Extensions
"resource://gre/modules/ExtensionProcessScript.jsm",
"resource://gre/modules/ExtensionUtils.jsm",
"resource://gre/modules/MessageChannel.jsm",
]),
processScripts: new Set([
"chrome://global/content/process-content.js",
......
......@@ -989,7 +989,8 @@ this.tabs = class extends ExtensionAPI {
async detectLanguage(tabId) {
let tab = await promiseTabWhenReady(tabId);
return tab.sendMessage(context, "Extension:DetectLanguage");
let results = await tab.queryContent("DetectLanguage", {});
return results[0];
},
async executeScript(tabId, details) {
......
......@@ -4,7 +4,7 @@
add_task(async function testExecuteScript() {
let { MessageChannel } = ChromeUtils.import(
"resource://gre/modules/MessageChannel.jsm"
"resource://testing-common/MessageChannel.jsm"
);
function countMM(messageManagerMap) {
......
......@@ -10,7 +10,7 @@ AddonTestUtils.initMochitest(this);
add_task(async function testExecuteScript() {
let { MessageChannel } = ChromeUtils.import(
"resource://gre/modules/MessageChannel.jsm"
"resource://testing-common/MessageChannel.jsm"
);
// When the first extension is started, ProxyMessenger.init adds MessageChannel
......
......@@ -26,7 +26,7 @@ ChromeUtils.import("resource://gre/modules/ActorManagerParent.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
ContentTask: "resource://testing-common/ContentTask.jsm",
HttpServer: "resource://testing-common/httpd.js",
MessageChannel: "resource://gre/modules/MessageChannel.jsm",
MessageChannel: "resource://testing-common/MessageChannel.jsm",
TestUtils: "resource://testing-common/TestUtils.jsm",
});
......@@ -44,7 +44,7 @@ const REMOTE_CONTENT_SUBFRAMES = Services.appinfo.fissionAutostart;
function frameScript() {
const { MessageChannel } = ChromeUtils.import(
"resource://gre/modules/MessageChannel.jsm"
"resource://testing-common/MessageChannel.jsm"
);
const { Services } = ChromeUtils.import(
"resource://gre/modules/Services.jsm"
......
......@@ -60,7 +60,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ExtensionTelemetry: "resource://gre/modules/ExtensionTelemetry.jsm",
LightweightThemeManager: "resource://gre/modules/LightweightThemeManager.jsm",
Log: "resource://gre/modules/Log.jsm",
MessageChannel: "resource://gre/modules/MessageChannel.jsm",
NetUtil: "resource://gre/modules/NetUtil.jsm",
OS: "resource://gre/modules/osfile.jsm",
PluralForm: "resource://gre/modules/PluralForm.jsm",
......@@ -2886,8 +2885,6 @@ class Extension extends ExtensionData {
);
}
MessageChannel.abortResponses({ extensionId: this.id });
this.policy.active = false;
this.state = `Shutdown: Complete (${this.cleanupFile})`;
......
......@@ -33,7 +33,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ExtensionContent: "resource://gre/modules/ExtensionContent.jsm",
ExtensionPageChild: "resource://gre/modules/ExtensionPageChild.jsm",
ExtensionProcessScript: "resource://gre/modules/ExtensionProcessScript.jsm",
MessageChannel: "resource://gre/modules/MessageChannel.jsm",
NativeApp: "resource://gre/modules/NativeMessaging.jsm",
PerformanceCounters: "resource://gre/modules/PerformanceCounters.jsm",
PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
......@@ -67,9 +66,6 @@ const {
const { sharedData } = Services.cpmm;
const isContentProcess =
Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
const MSG_SET_ENABLED = "Extension:ActivityLog:SetEnabled";
const MSG_LOG = "Extension:ActivityLog:DoLog";
......@@ -525,9 +521,6 @@ class BrowserExtensionContent extends EventEmitter {
ExtensionManager.extensions.delete(this.id);
ExtensionContent.shutdownExtension(this);
Services.cpmm.removeMessageListener(this.MESSAGE_EMIT_EVENT, this);
if (isContentProcess) {
MessageChannel.abortResponses({ extensionId: this.id });
}
this.emit("shutdown");
}
......
......@@ -25,7 +25,6 @@ XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
XPCOMUtils.defineLazyModuleGetters(this, {
AppConstants: "resource://gre/modules/AppConstants.jsm",
ConsoleAPI: "resource://gre/modules/Console.jsm",
MessageChannel: "resource://gre/modules/MessageChannel.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
Schemas: "resource://gre/modules/Schemas.jsm",
SchemaRoot: "resource://gre/modules/Schemas.jsm",
......@@ -536,8 +535,6 @@ class BaseContext {
);
}
MessageChannel.setupMessageManagers([this.messageManager]);
let windowRef = new InnerWindowReference(contentWindow, this.innerWindowID);
Object.defineProperty(this, "active", {
configurable: true,
......@@ -673,33 +670,6 @@ class BaseContext {
this.onClose.delete(obj);
}
/**
* A wrapper around MessageChannel.sendMessage which adds the extension ID
* to the recipient object, and ensures replies are not processed after the
* context has been unloaded.
*
* @param {nsIMessageManager} target
* @param {string} messageName
* @param {object} data
* @param {object} [options]
* @param {object} [options.sender]
* @param {object} [options.recipient]
*
* @returns {Promise}
*/
sendMessage(target, messageName, data, options = {}) {
options.recipient = Object.assign(
{ extensionId: this.extension.id },
options.recipient
);
options.sender = options.sender || {};
options.sender.extensionId = this.extension.id;
options.sender.contextId = this.contextId;
return MessageChannel.sendMessage(target, messageName, data, options);
}
get lastError() {
this.checkedLastError = true;
return this._lastError;
......@@ -913,11 +883,6 @@ class BaseContext {
unload() {
this.unloaded = true;
MessageChannel.abortResponses({
extensionId: this.extension.id,
contextId: this.contextId,
});
for (let obj of this.onClose) {
obj.close();
}
......
......@@ -17,7 +17,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ExtensionProcessScript: "resource://gre/modules/ExtensionProcessScript.jsm",
ExtensionTelemetry: "resource://gre/modules/ExtensionTelemetry.jsm",
LanguageDetector: "resource:///modules/translation/LanguageDetector.jsm",
MessageChannel: "resource://gre/modules/MessageChannel.jsm",
Schemas: "resource://gre/modules/Schemas.jsm",
WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.jsm",
});
......@@ -1005,8 +1004,6 @@ DocumentManager = {
"inner-window-destroyed"(subject, topic, data) {
let windowId = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
MessageChannel.abortResponses({ innerWindowID: windowId });
// Close any existent content-script context for the destroyed window.
if (this.contexts.has(windowId)) {
let extensions = this.contexts.get(windowId);
......@@ -1110,45 +1107,27 @@ var ExtensionContent = {
return context;
},
handleDetectLanguage(global, target) {
let doc = target.content.document;
async handleDetectLanguage({ windows }) {
let wgc = WindowGlobalChild.getByInnerWindowId(windows[0]);
let doc = wgc.browsingContext.window.document;
await promiseDocumentReady(doc);
return promiseDocumentReady(doc).then(() => {
let elem = doc.documentElement;
// The CLD2 library can analyze HTML, but that uses more memory, and
// emscripten can't shrink its heap, so we use plain text instead.
let encoder = Cu.createDocumentEncoder("text/plain");
encoder.init(doc, "text/plain", Ci.nsIDocumentEncoder.SkipInvisibleContent);
let language =
elem.getAttribute("xml:lang") ||
elem.getAttribute("lang") ||
let result = await LanguageDetector.detectLanguage({
language:
doc.documentElement.getAttribute("xml:lang") ||
doc.documentElement.getAttribute("lang") ||
doc.contentLanguage ||
null;
// We only want the last element of the TLD here.
// Only country codes have any effect on the results, but other
// values cause no harm.
let tld = doc.location.hostname.match(/[a-z]*$/)[0];
// The CLD2 library used by the language detector is capable of
// analyzing raw HTML. Unfortunately, that takes much more memory,
// and since it's hosted by emscripten, and therefore can't shrink
// its heap after it's grown, it has a performance cost.
// So we send plain text instead.
let encoder = Cu.createDocumentEncoder("text/plain");
encoder.init(
doc,
"text/plain",
Ci.nsIDocumentEncoder.SkipInvisibleContent
);
let text = encoder.encodeToStringWithMaxLength(60 * 1024);
let encoding = doc.characterSet;
return LanguageDetector.detectLanguage({
language,
tld,
text,
encoding,
}).then(result => (result.language === "un" ? "und" : result.language));
null,
tld: doc.location.hostname.match(/[a-z]*$/)[0],
text: encoder.encodeToStringWithMaxLength(60 * 1024),
encoding: doc.characterSet,
});
return result.language === "un" ? "und" : result.language;
},
// Used to executeScript, insertCSS and removeCSS.
......@@ -1187,30 +1166,6 @@ var ExtensionContent = {
return Promise.reject({ message, fileName: path });
}
},
async receiveMessage(global, name, target) {
if (name === "Extension:DetectLanguage") {
return this.handleDetectLanguage(global, target);
}
},
// Helpers
*enumerateWindows(docShell) {
let docShells = docShell.getAllDocShellsInSubtree(
docShell.typeContent,
docShell.ENUMERATE_FORWARDS
);
for (let docShell of docShells) {
try {
yield docShell.domWindow;
} catch (e) {
// This can fail if the docShell is being destroyed, so just
// ignore the error.
}
}
},
};
/**
......@@ -1222,6 +1177,8 @@ class ExtensionContentChild extends JSProcessActorChild {
return;
}
switch (name) {
case "DetectLanguage":
return ExtensionContent.handleDetectLanguage(data);
case "Execute":
return ExtensionContent.handleActorExecute(data);
}
......
......@@ -12,9 +12,6 @@
var EXPORTED_SYMBOLS = ["ExtensionProcessScript", "ExtensionAPIRequestHandler"];
const { MessageChannel } = ChromeUtils.import(
"resource://gre/modules/MessageChannel.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
......@@ -74,8 +71,6 @@ class ExtensionGlobal {
this.global.addMessageListener("Extension:SetFrameData", this);
this.frameData = null;
MessageChannel.addListener(global, "Extension:DetectLanguage", this);
}
get messageFilterStrict() {
......@@ -104,24 +99,7 @@ class ExtensionGlobal {
if (data.viewType && WebExtensionPolicy.isExtensionProcess) {
ExtensionPageChild.expectViewLoad(this.global, data.viewType);
}
return;
}
// SetFrameData does not have a recipient extension, or it would be
// an extension process. Anything following this point must have
// a recipient extension, so check access to the window.
let policy = WebExtensionPolicy.getByID(recipient.extensionId);
if (!policy.canAccessWindow(this.global.content)) {
throw new Error("Extension cannot access window");
}
return ExtensionContent.receiveMessage(
this.global,
messageName,
target,
data,
recipient
);
}
}
......@@ -132,8 +110,6 @@ ExtensionManager = {
globals: new WeakMap(),
init() {
MessageChannel.setupMessageManagers([Services.cpmm]);
Services.cpmm.addMessageListener("Extension:Startup", this);
Services.cpmm.addMessageListener("Extension:Shutdown", this);
Services.cpmm.addMessageListener("Extension:FlushJarCache", this);
......
......@@ -34,7 +34,6 @@ EXTRA_JS_MODULES += [
"ExtensionUtils.jsm",
"FindContent.jsm",
"MatchURLFilters.jsm",
"MessageChannel.jsm",
"MessageManagerProxy.jsm",
"NativeManifests.jsm",
"NativeMessaging.jsm",
......@@ -53,6 +52,7 @@ EXTRA_COMPONENTS += [
TESTING_JS_MODULES += [
"ExtensionTestCommon.jsm",
"ExtensionXPCShellUtils.jsm",
"MessageChannel.jsm",
]
DIRS += [
......
......@@ -73,38 +73,6 @@ class TabBase {
}
}
/**
* Sends a message, via the given context, to the ExtensionContent running in
* this tab. The tab's current innerWindowID is automatically added to the
* recipient filter for the message, and is used to ensure that the message is
* not processed if the content process navigates to a different content page
* before the message is received.
*
* @param {BaseContext} context
* The context through which to send the message.
* @param {string} messageName
* The name of the message to send.
* @param {object} [data = {}]
* Arbitrary, structured-clonable message data to send.
* @param {object} [options]
* An options object, as accepted by BaseContext.sendMessage.
*
* @returns {Promise}
*/
sendMessage(context, messageName, data = {}, options = null) {
let { browser, innerWindowID } = this;
options = Object.assign({}, options);
options.recipient = Object.assign({ innerWindowID }, options.recipient);
return context.sendMessage(
browser.messageManager,
messageName,
data,
options
);
}
/**
* Capture the visible area of this tab, and return the result as a data: URI.
*
......
......@@ -31,7 +31,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ExtensionParent: "resource://gre/modules/ExtensionParent.jsm",
ExtensionTestUtils: "resource://testing-common/ExtensionXPCShellUtils.jsm",
FileUtils: "resource://gre/modules/FileUtils.jsm",
MessageChannel: "resource://gre/modules/MessageChannel.jsm",
MessageChannel: "resource://testing-common/MessageChannel.jsm",
NetUtil: "resource://gre/modules/NetUtil.jsm",
PromiseTestUtils: "resource://testing-common/PromiseTestUtils.jsm",
Schemas: "resource://gre/modules/Schemas.jsm",
......@@ -211,7 +211,7 @@ function handlingUserInputFrameScript() {
/* globals content */
// eslint-disable-next-line no-shadow
const { MessageChannel } = ChromeUtils.import(
"resource://gre/modules/MessageChannel.jsm"
"resource://testing-common/MessageChannel.jsm"
);
let handle;
......
......@@ -72,7 +72,7 @@ add_task(async function test_permissions() {
};
const { MessageChannel } = ChromeUtils.import(
"resource://gre/modules/MessageChannel.jsm"
"resource://testing-common/MessageChannel.jsm"
);
MessageChannel.addListener(this, "Test:Check", messageListener);
};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment