Bug 1339559 - Identify script that resulted in non-structured-clonable data
MozReview-Commit-ID: AURB4Qpwimh
--- a/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
@@ -111,30 +111,42 @@ add_task(function* testExecuteScript() {
browser.test.assertTrue(/\/file_iframe_document\.html$/.test(result[0]), "Result is correct");
}),
browser.tabs.executeScript({
code: "window",
}).then(result => {
browser.test.fail("Expected error when returning non-structured-clonable object");
}, error => {
- browser.test.assertEq("Script returned non-structured-clonable data",
+ browser.test.assertEq("<anonymous code>", error.fileName, "Got expected fileName");
+ browser.test.assertEq("Script '<anonymous code>' result is non-structured-clonable data",
error.message, "Got expected error");
}),
browser.tabs.executeScript({
code: "Promise.resolve(window)",
}).then(result => {
browser.test.fail("Expected error when returning non-structured-clonable object");
}, error => {
- browser.test.assertEq("Script returned non-structured-clonable data",
+ browser.test.assertEq("<anonymous code>", error.fileName, "Got expected fileName");
+ browser.test.assertEq("Script '<anonymous code>' result is non-structured-clonable data",
error.message, "Got expected error");
}),
browser.tabs.executeScript({
+ file: "script3.js",
+ }).then(result => {
+ browser.test.fail("Expected error when returning non-structured-clonable object");
+ }, error => {
+ const expected = /Script '.*script3.js' result is non-structured-clonable data/;
+ browser.test.assertTrue(expected.test(error.message), "Got expected error");
+ browser.test.assertTrue(error.fileName.endsWith("script3.js"), "Got expected fileName");
+ }),
+
+ browser.tabs.executeScript({
frameId: Number.MAX_SAFE_INTEGER,
code: "42",
}).then(result => {
browser.test.fail("Expected error when specifying invalid frame ID");
}, error => {
let details = {
frame_id: Number.MAX_SAFE_INTEGER,
matchesHost: ["http://mochi.test/", "http://example.com/"],
@@ -231,16 +243,18 @@ add_task(function* testExecuteScript() {
background,
files: {
"script.js": function() {
browser.runtime.sendMessage("script ran");
},
"script2.js": "27",
+
+ "script3.js": "window",
},
});
yield extension.startup();
yield extension.awaitFinish("executeScript");
yield extension.unload();
--- a/mobile/android/components/extensions/test/mochitest/test_ext_tabs_executeScript.html
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_tabs_executeScript.html
@@ -94,30 +94,42 @@ add_task(function* testExecuteScript() {
browser.test.assertTrue(/\/file_iframe_document\.html$/.test(result[0]), "Result is correct");
}),
browser.tabs.executeScript({
code: "window",
}).then(result => {
browser.test.fail("Expected error when returning non-structured-clonable object");
}, error => {
- browser.test.assertEq("Script returned non-structured-clonable data",
+ browser.test.assertEq("<anonymous code>", error.fileName, "Got expected fileName");
+ browser.test.assertEq("Script '<anonymous code>' result is non-structured-clonable data",
error.message, "Got expected error");
}),
browser.tabs.executeScript({
code: "Promise.resolve(window)",
}).then(result => {
browser.test.fail("Expected error when returning non-structured-clonable object");
}, error => {
- browser.test.assertEq("Script returned non-structured-clonable data",
+ browser.test.assertEq("<anonymous code>", error.fileName, "Got expected fileName");
+ browser.test.assertEq("Script '<anonymous code>' result is non-structured-clonable data",
error.message, "Got expected error");
}),
browser.tabs.executeScript({
+ file: "script3.js",
+ }).then(result => {
+ browser.test.fail("Expected error when returning non-structured-clonable object");
+ }, error => {
+ const expected = /Script '.*script3.js' result is non-structured-clonable data/;
+ browser.test.assertTrue(expected.test(error.message), "Got expected error");
+ browser.test.assertTrue(error.fileName.endsWith("script3.js"), "Got expected fileName");
+ }),
+
+ browser.tabs.executeScript({
frameId: Number.MAX_SAFE_INTEGER,
code: "42",
}).then(result => {
browser.test.fail("Expected error when specifying invalid frame ID");
}, error => {
let details = {
frame_id: Number.MAX_SAFE_INTEGER,
matchesHost: ["http://mochi.test/", "http://example.com/"],
@@ -217,16 +229,18 @@ add_task(function* testExecuteScript() {
background,
files: {
"script.js": function() {
browser.runtime.sendMessage("script ran");
},
"script2.js": "27",
+
+ "script3.js": "window",
},
});
yield extension.startup();
yield extension.awaitFinish("executeScript");
yield extension.unload();
--- a/toolkit/components/extensions/ExtensionCommon.jsm
+++ b/toolkit/components/extensions/ExtensionCommon.jsm
@@ -227,27 +227,26 @@ class BaseContext {
*
* @param {Error|object} error
* @returns {Error}
*/
normalizeError(error) {
if (error instanceof this.cloneScope.Error) {
return error;
}
- let message;
- if (instanceOf(error, "Object") || error instanceof ExtensionError) {
+ let message, fileName;
+ if (instanceOf(error, "Object") || error instanceof ExtensionError ||
+ typeof error == "object" && this.principal.subsumes(Cu.getObjectPrincipal(error))) {
message = error.message;
- } else if (typeof error == "object" &&
- this.principal.subsumes(Cu.getObjectPrincipal(error))) {
- message = error.message;
+ fileName = error.fileName;
} else {
Cu.reportError(error);
}
message = message || "An unexpected error occurred";
- return new this.cloneScope.Error(message);
+ return new this.cloneScope.Error(message, fileName);
}
/**
* Sets the value of `.lastError` to `error`, calls the given
* callback, and reports an error if the value has not been checked
* when the callback returns.
*
* @param {object} error An object with a `message` property. May
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -1012,17 +1012,20 @@ class ExtensionGlobal {
// Used to executeScript, insertCSS and removeCSS.
handleExtensionExecute(target, extensionId, options) {
return DocumentManager.executeScript(target, extensionId, options).then(result => {
try {
// Make sure we can structured-clone the result value before
// we try to send it back over the message manager.
Cu.cloneInto(result, target);
} catch (e) {
- return Promise.reject({message: "Script returned non-structured-clonable data"});
+ const {js} = options;
+ const fileName = js.length ? js[js.length - 1] : "<anonymous code>";
+ const message = `Script '${fileName}' result is non-structured-clonable data`;
+ return Promise.reject({message, fileName});
}
return result;
});
}
handleWebNavigationGetFrame({frameId}) {
return WebNavigationFrames.getFrame(this.global.docShell, frameId);
}
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -596,17 +596,17 @@ ParentAPIManager = {
result = result || Promise.resolve();
result.then(result => {
result = result instanceof SpreadArgs ? [...result] : [result];
reply({result});
}, error => {
error = context.normalizeError(error);
- reply({error: {message: error.message}});
+ reply({error: {message: error.message, fileName: error.fileName}});
});
}
} catch (e) {
if (data.callId) {
let error = context.normalizeError(e);
reply({error: {message: error.message}});
} else {
Cu.reportError(e);