зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1107592 part 2. Allow chrome JS to directly throw content DOMExceptions that will propagate out to the web script. r=peterv
This commit is contained in:
Родитель
7af8dba16f
Коммит
8fd98d4057
|
@ -34,6 +34,8 @@
|
||||||
#include "mozilla/dom/ScriptSettings.h"
|
#include "mozilla/dom/ScriptSettings.h"
|
||||||
#include "mozilla/dom/DOMError.h"
|
#include "mozilla/dom/DOMError.h"
|
||||||
#include "mozilla/dom/DOMErrorBinding.h"
|
#include "mozilla/dom/DOMErrorBinding.h"
|
||||||
|
#include "mozilla/dom/DOMException.h"
|
||||||
|
#include "mozilla/dom/DOMExceptionBinding.h"
|
||||||
#include "mozilla/dom/ElementBinding.h"
|
#include "mozilla/dom/ElementBinding.h"
|
||||||
#include "mozilla/dom/HTMLObjectElement.h"
|
#include "mozilla/dom/HTMLObjectElement.h"
|
||||||
#include "mozilla/dom/HTMLObjectElementBinding.h"
|
#include "mozilla/dom/HTMLObjectElementBinding.h"
|
||||||
|
@ -216,6 +218,10 @@ ErrorResult::ReportJSException(JSContext* cx)
|
||||||
// If JS_WrapValue failed, not much we can do about it... No matter
|
// If JS_WrapValue failed, not much we can do about it... No matter
|
||||||
// what, go ahead and unroot mJSException.
|
// what, go ahead and unroot mJSException.
|
||||||
js::RemoveRawValueRoot(cx, &mJSException);
|
js::RemoveRawValueRoot(cx, &mJSException);
|
||||||
|
|
||||||
|
// We no longer have a useful exception but we do want to signal that an error
|
||||||
|
// occured.
|
||||||
|
mResult = NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -224,15 +230,52 @@ ErrorResult::ReportJSExceptionFromJSImplementation(JSContext* aCx)
|
||||||
MOZ_ASSERT(!mMightHaveUnreportedJSException,
|
MOZ_ASSERT(!mMightHaveUnreportedJSException,
|
||||||
"Why didn't you tell us you planned to handle JS exceptions?");
|
"Why didn't you tell us you planned to handle JS exceptions?");
|
||||||
|
|
||||||
|
dom::DOMException* domException;
|
||||||
|
nsresult rv =
|
||||||
|
UNWRAP_OBJECT(DOMException, &mJSException.toObject(), domException);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
// We actually have to create a new DOMException object, because the one we
|
||||||
|
// have has a stack that includes the chrome code that threw it, and in
|
||||||
|
// particular has the wrong file/line/column information.
|
||||||
|
nsString message;
|
||||||
|
domException->GetMessageMoz(message);
|
||||||
|
nsString name;
|
||||||
|
domException->GetName(name);
|
||||||
|
nsRefPtr<dom::DOMException> newException =
|
||||||
|
new dom::DOMException(nsresult(domException->Result()),
|
||||||
|
NS_ConvertUTF16toUTF8(message),
|
||||||
|
NS_ConvertUTF16toUTF8(name),
|
||||||
|
domException->Code());
|
||||||
|
JS::Rooted<JS::Value> reflector(aCx);
|
||||||
|
if (!GetOrCreateDOMReflector(aCx, newException, &reflector)) {
|
||||||
|
// Well, that threw _an_ exception. Let's forget ours. We can just
|
||||||
|
// unroot and not change the value, since mJSException is completely
|
||||||
|
// ignored if mResult is not NS_ERROR_DOM_JS_EXCEPTION and we plan to
|
||||||
|
// change mResult to a different value.
|
||||||
|
js::RemoveRawValueRoot(aCx, &mJSException);
|
||||||
|
|
||||||
|
// We no longer have a useful exception but we do want to signal that an
|
||||||
|
// error occured.
|
||||||
|
mResult = NS_ERROR_FAILURE;
|
||||||
|
|
||||||
|
// But do make sure to not ReportJSException here, since we don't have one.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mJSException = reflector;
|
||||||
|
ReportJSException(aCx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dom::DOMError* domError;
|
dom::DOMError* domError;
|
||||||
nsresult rv = UNWRAP_OBJECT(DOMError, &mJSException.toObject(), domError);
|
rv = UNWRAP_OBJECT(DOMError, &mJSException.toObject(), domError);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
// Unwrapping really shouldn't fail here, if mExceptionHandling is set to
|
// Unwrapping really shouldn't fail here: if mExceptionHandling is set to
|
||||||
// eRethrowContentExceptions then the CallSetup destructor only stores an
|
// eRethrowContentExceptions then the CallSetup destructor only stores an
|
||||||
// exception if it unwraps to DOMError. If we reach this then either
|
// exception if it unwraps to DOMError or DOMException. If we reach this
|
||||||
// mExceptionHandling wasn't set to eRethrowContentExceptions and we
|
// then either mExceptionHandling wasn't set to eRethrowContentExceptions
|
||||||
// shouldn't be calling ReportJSExceptionFromJSImplementation or something
|
// and we shouldn't be calling ReportJSExceptionFromJSImplementation or
|
||||||
// went really wrong.
|
// something went really wrong.
|
||||||
NS_RUNTIMEABORT("We stored a non-DOMError exception!");
|
NS_RUNTIMEABORT("We stored a non-DOMError exception!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include "mozilla/dom/BindingUtils.h"
|
#include "mozilla/dom/BindingUtils.h"
|
||||||
#include "mozilla/dom/DOMError.h"
|
#include "mozilla/dom/DOMError.h"
|
||||||
#include "mozilla/dom/DOMErrorBinding.h"
|
#include "mozilla/dom/DOMErrorBinding.h"
|
||||||
|
#include "mozilla/dom/DOMException.h"
|
||||||
|
#include "mozilla/dom/DOMExceptionBinding.h"
|
||||||
#include "jsfriendapi.h"
|
#include "jsfriendapi.h"
|
||||||
#include "nsIScriptGlobalObject.h"
|
#include "nsIScriptGlobalObject.h"
|
||||||
#include "nsIXPConnect.h"
|
#include "nsIXPConnect.h"
|
||||||
|
@ -190,8 +192,8 @@ CallbackObject::CallSetup::ShouldRethrowException(JS::Handle<JS::Value> aExcepti
|
||||||
MOZ_ASSERT(mExceptionHandling == eRethrowContentExceptions);
|
MOZ_ASSERT(mExceptionHandling == eRethrowContentExceptions);
|
||||||
|
|
||||||
// For eRethrowContentExceptions we only want to throw an exception if the
|
// For eRethrowContentExceptions we only want to throw an exception if the
|
||||||
// object that was thrown is a DOMError object in the caller compartment
|
// object that was thrown is a DOMError or DOMException object in the caller
|
||||||
// (which we stored in mCompartment).
|
// compartment (which we stored in mCompartment).
|
||||||
|
|
||||||
if (!aException.isObject()) {
|
if (!aException.isObject()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -204,7 +206,9 @@ CallbackObject::CallSetup::ShouldRethrowException(JS::Handle<JS::Value> aExcepti
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMError* domError;
|
DOMError* domError;
|
||||||
return NS_SUCCEEDED(UNWRAP_OBJECT(DOMError, obj, domError));
|
DOMException* domException;
|
||||||
|
return NS_SUCCEEDED(UNWRAP_OBJECT(DOMError, obj, domError)) ||
|
||||||
|
NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException));
|
||||||
}
|
}
|
||||||
|
|
||||||
CallbackObject::CallSetup::~CallSetup()
|
CallbackObject::CallSetup::~CallSetup()
|
||||||
|
|
|
@ -85,8 +85,8 @@ public:
|
||||||
// Report any exception and don't throw it to the caller code.
|
// Report any exception and don't throw it to the caller code.
|
||||||
eReportExceptions,
|
eReportExceptions,
|
||||||
// Throw an exception to the caller code if the thrown exception is a
|
// Throw an exception to the caller code if the thrown exception is a
|
||||||
// binding object for a DOMError from the caller's scope, otherwise report
|
// binding object for a DOMError or DOMException from the caller's scope,
|
||||||
// it.
|
// otherwise report it.
|
||||||
eRethrowContentExceptions,
|
eRethrowContentExceptions,
|
||||||
// Throw any exception to the caller code.
|
// Throw any exception to the caller code.
|
||||||
eRethrowExceptions
|
eRethrowExceptions
|
||||||
|
|
|
@ -14,7 +14,10 @@ function TestInterfaceJS(anyArg, objectArg) {}
|
||||||
TestInterfaceJS.prototype = {
|
TestInterfaceJS.prototype = {
|
||||||
classID: Components.ID("{2ac4e026-cf25-47d5-b067-78d553c3cad8}"),
|
classID: Components.ID("{2ac4e026-cf25-47d5-b067-78d553c3cad8}"),
|
||||||
contractID: "@mozilla.org/dom/test-interface-js;1",
|
contractID: "@mozilla.org/dom/test-interface-js;1",
|
||||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
|
||||||
|
Ci.nsIDOMGlobalPropertyInitializer]),
|
||||||
|
|
||||||
|
init: function(win) { this._win = win; },
|
||||||
|
|
||||||
__init: function (anyArg, objectArg, dictionaryArg) {
|
__init: function (anyArg, objectArg, dictionaryArg) {
|
||||||
this._anyAttr = undefined;
|
this._anyAttr = undefined;
|
||||||
|
@ -59,6 +62,15 @@ TestInterfaceJS.prototype = {
|
||||||
|
|
||||||
testSequenceOverload: function(arg) {},
|
testSequenceOverload: function(arg) {},
|
||||||
testSequenceUnion: function(arg) {},
|
testSequenceUnion: function(arg) {},
|
||||||
|
|
||||||
|
testThrowDOMError: function() {
|
||||||
|
throw new this._win.DOMError("NotSupportedError", "We are a DOMError");
|
||||||
|
},
|
||||||
|
|
||||||
|
testThrowDOMException: function() {
|
||||||
|
throw new this._win.DOMException("We are a DOMException",
|
||||||
|
"NotSupportedError");
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJS])
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestInterfaceJS])
|
||||||
|
|
|
@ -53,3 +53,5 @@ skip-if = debug == false
|
||||||
[test_traceProtos.html]
|
[test_traceProtos.html]
|
||||||
[test_sequence_detection.html]
|
[test_sequence_detection.html]
|
||||||
skip-if = debug == false
|
skip-if = debug == false
|
||||||
|
[test_exception_options_from_jsimplemented.html]
|
||||||
|
skip-if = debug == false
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1107592
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 1107592</title>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
/** Test for Bug 1107592 **/
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
function doTest() {
|
||||||
|
var t = new TestInterfaceJS();
|
||||||
|
try {
|
||||||
|
t.testThrowDOMError();
|
||||||
|
} catch (e) {
|
||||||
|
ok(e instanceof Error, "Should have an Error here");
|
||||||
|
ok(!(e instanceof DOMException), "Should not have DOMException here");
|
||||||
|
ok(!("code" in e), "Should not have a 'code' property");
|
||||||
|
ise(e.name, "Error", "Should not have an interesting name here");
|
||||||
|
ise(e.message, "We are a DOMError", "Should have the right message");
|
||||||
|
ise(e.stack,
|
||||||
|
"doTest@http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html:20:7\n",
|
||||||
|
"Exception stack should still only show our code");
|
||||||
|
ise(e.fileName,
|
||||||
|
"http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html",
|
||||||
|
"Should have the right file name");
|
||||||
|
ise(e.lineNumber, 20, "Should have the right line number");
|
||||||
|
ise(e.columnNumber, 6, "Should have the right column number");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
t.testThrowDOMException();
|
||||||
|
} catch (e) {
|
||||||
|
ok(e instanceof Error, "Should also have an Error here");
|
||||||
|
ok(e instanceof DOMException, "Should have DOMException here");
|
||||||
|
ise(e.name, "NotSupportedError", "Should have the right name here");
|
||||||
|
ise(e.message, "We are a DOMException",
|
||||||
|
"Should also have the right message");
|
||||||
|
ise(e.code, DOMException.NOT_SUPPORTED_ERR,
|
||||||
|
"Should have the right 'code'");
|
||||||
|
ise(e.stack,
|
||||||
|
"doTest@http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html:38:6\n",
|
||||||
|
"Exception stack should still only show our code");
|
||||||
|
ise(e.filename,
|
||||||
|
"http://mochi.test:8888/tests/dom/bindings/test/test_exception_options_from_jsimplemented.html",
|
||||||
|
"Should still have the right file name");
|
||||||
|
ise(e.lineNumber, 38, "Should still have the right line number");
|
||||||
|
todo_is(e.columnNumber, 6,
|
||||||
|
"No column number support for DOMException yet");
|
||||||
|
}
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]},
|
||||||
|
doTest);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1107592">Mozilla Bug 1107592</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -48,4 +48,11 @@ interface TestInterfaceJS {
|
||||||
void testSequenceOverload(DOMString arg);
|
void testSequenceOverload(DOMString arg);
|
||||||
|
|
||||||
void testSequenceUnion((sequence<DOMString> or DOMString) arg);
|
void testSequenceUnion((sequence<DOMString> or DOMString) arg);
|
||||||
|
|
||||||
|
// Tests for exception-throwing behavior
|
||||||
|
[Throws]
|
||||||
|
void testThrowDOMError();
|
||||||
|
|
||||||
|
[Throws]
|
||||||
|
void testThrowDOMException();
|
||||||
};
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче