mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-16 13:56:29 +00:00
Bug 905392 - Need way to throw web-console-visible exception-message from JS-implemented webidl object. r=bz.
This commit is contained in:
parent
0cc3bcb43d
commit
b174788298
@ -26,6 +26,8 @@
|
||||
#include "nsPrintfCString.h"
|
||||
#include "prprf.h"
|
||||
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/DOMErrorBinding.h"
|
||||
#include "mozilla/dom/HTMLObjectElement.h"
|
||||
#include "mozilla/dom/HTMLObjectElementBinding.h"
|
||||
#include "mozilla/dom/HTMLSharedObjectElement.h"
|
||||
@ -185,6 +187,41 @@ ErrorResult::ReportJSException(JSContext* cx)
|
||||
JS_RemoveValueRoot(cx, &mJSException);
|
||||
}
|
||||
|
||||
void
|
||||
ErrorResult::ReportJSExceptionFromJSImplementation(JSContext* aCx)
|
||||
{
|
||||
MOZ_ASSERT(!mMightHaveUnreportedJSException,
|
||||
"Why didn't you tell us you planned to handle JS exceptions?");
|
||||
|
||||
dom::DOMError* domError;
|
||||
nsresult rv = UNWRAP_OBJECT(DOMError, aCx, &mJSException.toObject(),
|
||||
domError);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Unwrapping really shouldn't fail here, if mExceptionHandling is set to
|
||||
// eRethrowContentExceptions then the CallSetup destructor only stores an
|
||||
// exception if it unwraps to DOMError. If we reach this then either
|
||||
// mExceptionHandling wasn't set to eRethrowContentExceptions and we
|
||||
// shouldn't be calling ReportJSExceptionFromJSImplementation or something
|
||||
// went really wrong.
|
||||
NS_RUNTIMEABORT("We stored a non-DOMError exception!");
|
||||
}
|
||||
|
||||
nsString message;
|
||||
domError->GetMessage(message);
|
||||
|
||||
JSErrorReport errorReport;
|
||||
memset(&errorReport, 0, sizeof(JSErrorReport));
|
||||
errorReport.errorNumber = JSMSG_USER_DEFINED_ERROR;
|
||||
errorReport.ucmessage = message.get();
|
||||
errorReport.exnType = JSEXN_ERR;
|
||||
JS_ThrowReportedError(aCx, nullptr, &errorReport);
|
||||
JS_RemoveValueRoot(aCx, &mJSException);
|
||||
|
||||
// We no longer have a useful exception but we do want to signal that an error
|
||||
// occured.
|
||||
mResult = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
void
|
||||
ErrorResult::StealJSException(JSContext* cx,
|
||||
JS::MutableHandle<JS::Value> value)
|
||||
|
@ -85,7 +85,7 @@ Throw(JSContext* cx, nsresult rv)
|
||||
return false;
|
||||
}
|
||||
|
||||
template<bool mainThread>
|
||||
template<bool mainThread, bool reportJSContentExceptions = false>
|
||||
inline bool
|
||||
ThrowMethodFailedWithDetails(JSContext* cx, ErrorResult& rv,
|
||||
const char* ifaceName,
|
||||
@ -96,7 +96,11 @@ ThrowMethodFailedWithDetails(JSContext* cx, ErrorResult& rv,
|
||||
return false;
|
||||
}
|
||||
if (rv.IsJSException()) {
|
||||
rv.ReportJSException(cx);
|
||||
if (reportJSContentExceptions) {
|
||||
rv.ReportJSExceptionFromJSImplementation(cx);
|
||||
} else {
|
||||
rv.ReportJSException(cx);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (rv.IsNotEnoughArgsError()) {
|
||||
@ -183,8 +187,8 @@ IsDOMObject(JSObject* obj)
|
||||
}
|
||||
|
||||
#define UNWRAP_OBJECT(Interface, cx, obj, value) \
|
||||
UnwrapObject<prototypes::id::Interface, \
|
||||
mozilla::dom::Interface##Binding::NativeType>(cx, obj, value)
|
||||
mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface, \
|
||||
mozilla::dom::Interface##Binding::NativeType>(cx, obj, value)
|
||||
|
||||
// Some callers don't want to set an exception when unwrapping fails
|
||||
// (for example, overload resolution uses unwrapping to tell what sort
|
||||
|
@ -5,6 +5,9 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/CallbackObject.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/DOMErrorBinding.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIXPConnect.h"
|
||||
@ -40,8 +43,10 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
||||
ErrorResult& aRv,
|
||||
ExceptionHandling aExceptionHandling)
|
||||
ExceptionHandling aExceptionHandling,
|
||||
JSCompartment* aCompartment)
|
||||
: mCx(nullptr)
|
||||
, mCompartment(aCompartment)
|
||||
, mErrorResult(aRv)
|
||||
, mExceptionHandling(aExceptionHandling)
|
||||
{
|
||||
@ -123,25 +128,55 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
||||
mCx = cx;
|
||||
|
||||
// Make sure the JS engine doesn't report exceptions we want to re-throw
|
||||
if (mExceptionHandling == eRethrowExceptions) {
|
||||
if (mExceptionHandling == eRethrowContentExceptions ||
|
||||
mExceptionHandling == eRethrowExceptions) {
|
||||
mSavedJSContextOptions = JS_GetOptions(cx);
|
||||
JS_SetOptions(cx, mSavedJSContextOptions | JSOPTION_DONT_REPORT_UNCAUGHT);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CallbackObject::CallSetup::ShouldRethrowException(JS::Handle<JS::Value> aException)
|
||||
{
|
||||
if (mExceptionHandling == eRethrowExceptions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mExceptionHandling == eRethrowContentExceptions);
|
||||
|
||||
// For eRethrowContentExceptions we only want to throw an exception if the
|
||||
// object that was thrown is a DOMError object in the caller compartment
|
||||
// (which we stored in mCompartment).
|
||||
|
||||
if (!aException.isObject()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(mCx, &aException.toObject());
|
||||
obj = js::UncheckedUnwrap(obj, /* stopAtOuter = */ false);
|
||||
if (js::GetObjectCompartment(obj) != mCompartment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DOMError* domError;
|
||||
return NS_SUCCEEDED(UNWRAP_OBJECT(DOMError, mCx, obj, domError));
|
||||
}
|
||||
|
||||
CallbackObject::CallSetup::~CallSetup()
|
||||
{
|
||||
// First things first: if we have a JSContext, report any pending
|
||||
// errors on it, unless we were told to re-throw them.
|
||||
if (mCx) {
|
||||
bool dealtWithPendingException = false;
|
||||
if (mExceptionHandling == eRethrowExceptions) {
|
||||
if (mExceptionHandling == eRethrowContentExceptions ||
|
||||
mExceptionHandling == eRethrowExceptions) {
|
||||
// Restore the old context options
|
||||
JS_SetOptions(mCx, mSavedJSContextOptions);
|
||||
mErrorResult.MightThrowJSException();
|
||||
if (JS_IsExceptionPending(mCx)) {
|
||||
JS::Rooted<JS::Value> exn(mCx);
|
||||
if (JS_GetPendingException(mCx, exn.address())) {
|
||||
if (JS_GetPendingException(mCx, exn.address()) &&
|
||||
ShouldRethrowException(exn)) {
|
||||
mErrorResult.ThrowJSException(mCx, exn);
|
||||
JS_ClearPendingException(mCx);
|
||||
dealtWithPendingException = true;
|
||||
|
@ -78,7 +78,13 @@ public:
|
||||
}
|
||||
|
||||
enum ExceptionHandling {
|
||||
// Report any exception and don't throw it to the caller code.
|
||||
eReportExceptions,
|
||||
// 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
|
||||
// it.
|
||||
eRethrowContentExceptions,
|
||||
// Throw any exception to the caller code.
|
||||
eRethrowExceptions
|
||||
};
|
||||
|
||||
@ -118,8 +124,11 @@ protected:
|
||||
* non-null.
|
||||
*/
|
||||
public:
|
||||
// If aExceptionHandling == eRethrowContentExceptions then aCompartment
|
||||
// needs to be set to the caller's compartment.
|
||||
CallSetup(JS::Handle<JSObject*> aCallable, ErrorResult& aRv,
|
||||
ExceptionHandling aExceptionHandling);
|
||||
ExceptionHandling aExceptionHandling,
|
||||
JSCompartment* aCompartment = nullptr);
|
||||
~CallSetup();
|
||||
|
||||
JSContext* GetContext() const
|
||||
@ -131,9 +140,15 @@ protected:
|
||||
// We better not get copy-constructed
|
||||
CallSetup(const CallSetup&) MOZ_DELETE;
|
||||
|
||||
bool ShouldRethrowException(JS::Handle<JS::Value> aException);
|
||||
|
||||
// Members which can go away whenever
|
||||
JSContext* mCx;
|
||||
|
||||
// Caller's compartment. This will only have a sensible value if
|
||||
// mExceptionHandling == eRethrowContentExceptions.
|
||||
JSCompartment* mCompartment;
|
||||
|
||||
// And now members whose construction/destruction order we need to control.
|
||||
|
||||
// Put our nsAutoMicrotask first, so it gets destroyed after everything else
|
||||
|
@ -4807,15 +4807,26 @@ if (global.Failed()) {
|
||||
if needsCx and not (static and descriptor.workers):
|
||||
argsPre.append("cx")
|
||||
|
||||
needsUnwrap = isConstructor
|
||||
if needScopeObject(returnType, arguments, self.extendedAttributes,
|
||||
descriptor, descriptor.wrapperCache,
|
||||
not descriptor.interface.isJSImplemented()):
|
||||
needsUnwrap = False
|
||||
if isConstructor:
|
||||
needsUnwrap = True
|
||||
needsUnwrappedVar = False
|
||||
unwrappedVar = "obj"
|
||||
elif descriptor.interface.isJSImplemented():
|
||||
needsUnwrap = True
|
||||
needsUnwrappedVar = True
|
||||
argsPre.append("js::GetObjectCompartment(unwrappedObj.empty() ? obj : unwrappedObj.ref())")
|
||||
elif needScopeObject(returnType, arguments, self.extendedAttributes,
|
||||
descriptor, descriptor.wrapperCache, True):
|
||||
needsUnwrap = True
|
||||
needsUnwrappedVar = True
|
||||
argsPre.append("unwrappedObj.empty() ? obj : unwrappedObj.ref()")
|
||||
|
||||
if needsUnwrap and needsUnwrappedVar:
|
||||
# We cannot assign into obj because it's a Handle, not a
|
||||
# MutableHandle, so we need a separate Rooted.
|
||||
cgThings.append(CGGeneric("Maybe<JS::Rooted<JSObject*> > unwrappedObj;"))
|
||||
argsPre.append("unwrappedObj.empty() ? obj : unwrappedObj.ref()")
|
||||
needsUnwrap = True
|
||||
unwrappedVar = "unwrappedObj.ref()"
|
||||
|
||||
if idlNode.isMethod() and idlNode.isLegacycaller():
|
||||
# If we can have legacycaller with identifier, we can't
|
||||
@ -4844,7 +4855,7 @@ if (global.Failed()) {
|
||||
if needsUnwrap:
|
||||
# Something depends on having the unwrapped object, so unwrap it now.
|
||||
xraySteps = []
|
||||
if not isConstructor:
|
||||
if needsUnwrappedVar:
|
||||
xraySteps.append(
|
||||
CGGeneric("unwrappedObj.construct(cx, obj);"))
|
||||
|
||||
@ -4854,7 +4865,7 @@ if (global.Failed()) {
|
||||
CGGeneric(string.Template("""${obj} = js::CheckedUnwrap(${obj});
|
||||
if (!${obj}) {
|
||||
return false;
|
||||
}""").substitute({ 'obj' : 'obj' if isConstructor else 'unwrappedObj.ref()' })))
|
||||
}""").substitute({ 'obj' : unwrappedVar })))
|
||||
if isConstructor:
|
||||
# If we're called via an xray, we need to enter the underlying
|
||||
# object's compartment and then wrap up all of our arguments into
|
||||
@ -4915,8 +4926,12 @@ if (!${obj}) {
|
||||
self.idlNode.identifier.name))
|
||||
|
||||
def getErrorReport(self):
|
||||
return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");'
|
||||
jsImplemented = ""
|
||||
if self.descriptor.interface.isJSImplemented():
|
||||
jsImplemented = ", true"
|
||||
return CGGeneric('return ThrowMethodFailedWithDetails<%s%s>(cx, rv, "%s", "%s");'
|
||||
% (toStringBool(not self.descriptor.workers),
|
||||
jsImplemented,
|
||||
self.descriptor.interface.identifier.name,
|
||||
self.idlNode.identifier.name))
|
||||
|
||||
@ -9509,9 +9524,38 @@ class CGExampleRoot(CGThing):
|
||||
def jsImplName(name):
|
||||
return name + "JSImpl"
|
||||
|
||||
class CGJSImplMethod(CGNativeMember):
|
||||
class CGJSImplMember(CGNativeMember):
|
||||
"""
|
||||
Base class for generating code for the members of the implementation class
|
||||
for a JS-implemented WebIDL interface.
|
||||
"""
|
||||
def __init__(self, descriptorProvider, member, name, signature,
|
||||
extendedAttrs, breakAfter=True, passJSBitsAsNeeded=True,
|
||||
visibility="public", jsObjectsArePtr=False,
|
||||
variadicIsSequence=False):
|
||||
CGNativeMember.__init__(self, descriptorProvider, member, name,
|
||||
signature, extendedAttrs, breakAfter=breakAfter,
|
||||
passJSBitsAsNeeded=passJSBitsAsNeeded,
|
||||
visibility=visibility,
|
||||
jsObjectsArePtr=jsObjectsArePtr,
|
||||
variadicIsSequence=variadicIsSequence)
|
||||
self.body = self.getImpl()
|
||||
|
||||
def getArgs(self, returnType, argList):
|
||||
args = CGNativeMember.getArgs(self, returnType, argList)
|
||||
args.insert(0, Argument("JSCompartment*", "aCompartment"))
|
||||
return args
|
||||
|
||||
class CGJSImplMethod(CGJSImplMember):
|
||||
"""
|
||||
Class for generating code for the methods for a JS-implemented WebIDL
|
||||
interface.
|
||||
"""
|
||||
def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
|
||||
CGNativeMember.__init__(self, descriptor, method,
|
||||
self.signature = signature
|
||||
self.descriptor = descriptor
|
||||
self.isConstructor = isConstructor
|
||||
CGJSImplMember.__init__(self, descriptor, method,
|
||||
CGSpecializedMethod.makeNativeName(descriptor,
|
||||
method),
|
||||
signature,
|
||||
@ -9519,29 +9563,29 @@ class CGJSImplMethod(CGNativeMember):
|
||||
breakAfter=breakAfter,
|
||||
variadicIsSequence=True,
|
||||
passJSBitsAsNeeded=False)
|
||||
self.signature = signature
|
||||
self.descriptor = descriptor
|
||||
if isConstructor:
|
||||
self.body = self.getConstructorImpl()
|
||||
else:
|
||||
self.body = self.getImpl()
|
||||
|
||||
def getArgs(self, returnType, argList):
|
||||
if self.isConstructor:
|
||||
# Skip the JSCompartment bits for constructors; it's handled
|
||||
# manually in getImpl.
|
||||
return CGNativeMember.getArgs(self, returnType, argList)
|
||||
return CGJSImplMember.getArgs(self, returnType, argList)
|
||||
|
||||
def getImpl(self):
|
||||
callbackArgs = [arg.name for arg in self.getArgs(self.signature[0], self.signature[1])]
|
||||
return 'return mImpl->%s(%s);' % (self.name, ", ".join(callbackArgs))
|
||||
args = self.getArgs(self.signature[0], self.signature[1])
|
||||
if not self.isConstructor:
|
||||
return 'return mImpl->%s(%s);' % (self.name, ", ".join(arg.name for arg in args))
|
||||
|
||||
def getConstructorImpl(self):
|
||||
assert self.descriptor.interface.isJSImplemented()
|
||||
if self.name != 'Constructor':
|
||||
raise TypeError("Named constructors are not supported for JS implemented WebIDL. See bug 851287.")
|
||||
if len(self.signature[1]) != 0:
|
||||
args = self.getArgs(self.signature[0], self.signature[1])
|
||||
# The first two arguments to the constructor implementation are not
|
||||
# arguments to the WebIDL constructor, so don't pass them to __Init()
|
||||
assert args[0].argType == 'const GlobalObject&'
|
||||
assert args[1].argType == 'JSContext*'
|
||||
args = args[2:]
|
||||
constructorArgs = [arg.name for arg in args]
|
||||
constructorArgs = [arg.name for arg in args[2:]]
|
||||
constructorArgs.insert(0, "js::GetObjectCompartment(scopeObj)")
|
||||
initCall = """
|
||||
// Wrap the object before calling __Init so that __DOM_IMPL__ is available.
|
||||
nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(window);
|
||||
@ -9588,24 +9632,31 @@ def callbackGetterName(attr):
|
||||
def callbackSetterName(attr):
|
||||
return "Set" + MakeNativeName(attr.identifier.name)
|
||||
|
||||
class CGJSImplGetter(CGNativeMember):
|
||||
class CGJSImplGetter(CGJSImplMember):
|
||||
"""
|
||||
Class for generating code for the getters of attributes for a JS-implemented
|
||||
WebIDL interface.
|
||||
"""
|
||||
def __init__(self, descriptor, attr):
|
||||
CGNativeMember.__init__(self, descriptor, attr,
|
||||
CGJSImplMember.__init__(self, descriptor, attr,
|
||||
CGSpecializedGetter.makeNativeName(descriptor,
|
||||
attr),
|
||||
(attr.type, []),
|
||||
descriptor.getExtendedAttributes(attr,
|
||||
getter=True),
|
||||
passJSBitsAsNeeded=False)
|
||||
self.body = self.getImpl()
|
||||
|
||||
def getImpl(self):
|
||||
callbackArgs = [arg.name for arg in self.getArgs(self.member.type, [])]
|
||||
return 'return mImpl->%s(%s);' % (callbackGetterName(self.member), ", ".join(callbackArgs))
|
||||
|
||||
class CGJSImplSetter(CGNativeMember):
|
||||
class CGJSImplSetter(CGJSImplMember):
|
||||
"""
|
||||
Class for generating code for the setters of attributes for a JS-implemented
|
||||
WebIDL interface.
|
||||
"""
|
||||
def __init__(self, descriptor, attr):
|
||||
CGNativeMember.__init__(self, descriptor, attr,
|
||||
CGJSImplMember.__init__(self, descriptor, attr,
|
||||
CGSpecializedSetter.makeNativeName(descriptor,
|
||||
attr),
|
||||
(BuiltinTypes[IDLBuiltinType.Types.void],
|
||||
@ -9613,7 +9664,6 @@ class CGJSImplSetter(CGNativeMember):
|
||||
descriptor.getExtendedAttributes(attr,
|
||||
setter=True),
|
||||
passJSBitsAsNeeded=False)
|
||||
self.body = self.getImpl()
|
||||
|
||||
def getImpl(self):
|
||||
callbackArgs = [arg.name for arg in self.getArgs(BuiltinTypes[IDLBuiltinType.Types.void],
|
||||
@ -9929,11 +9979,13 @@ class FakeMember():
|
||||
return None
|
||||
|
||||
class CallbackMember(CGNativeMember):
|
||||
def __init__(self, sig, name, descriptorProvider, needThisHandling):
|
||||
def __init__(self, sig, name, descriptorProvider, needThisHandling, rethrowContentException=False):
|
||||
"""
|
||||
needThisHandling is True if we need to be able to accept a specified
|
||||
thisObj, False otherwise.
|
||||
"""
|
||||
assert not rethrowContentException or not needThisHandling
|
||||
|
||||
self.retvalType = sig[0]
|
||||
self.originalSig = sig
|
||||
args = sig[1]
|
||||
@ -9951,6 +10003,7 @@ class CallbackMember(CGNativeMember):
|
||||
# If needThisHandling, we generate ourselves as private and the caller
|
||||
# will handle generating public versions that handle the "this" stuff.
|
||||
visibility = "private" if needThisHandling else "public"
|
||||
self.rethrowContentException = rethrowContentException
|
||||
# We don't care, for callback codegen, whether our original member was
|
||||
# a method or attribute or whatnot. Just always pass FakeMember()
|
||||
# here.
|
||||
@ -10109,8 +10162,12 @@ class CallbackMember(CGNativeMember):
|
||||
if not self.needThisHandling:
|
||||
# Since we don't need this handling, we're the actual method that
|
||||
# will be called, so we need an aRethrowExceptions argument.
|
||||
return args + [Argument("ExceptionHandling", "aExceptionHandling",
|
||||
"eReportExceptions")]
|
||||
if self.rethrowContentException:
|
||||
args.insert(0, Argument("JSCompartment*", "aCompartment"))
|
||||
else:
|
||||
args.append(Argument("ExceptionHandling", "aExceptionHandling",
|
||||
"eReportExceptions"))
|
||||
return args
|
||||
# We want to allow the caller to pass in a "this" object, as
|
||||
# well as a JSContext.
|
||||
return [Argument("JSContext*", "cx"),
|
||||
@ -10120,13 +10177,22 @@ class CallbackMember(CGNativeMember):
|
||||
if self.needThisHandling:
|
||||
# It's been done for us already
|
||||
return ""
|
||||
callSetup = "CallSetup s(CallbackPreserveColor(), aRv"
|
||||
if self.rethrowContentException:
|
||||
# getArgs doesn't add the aExceptionHandling argument but does add
|
||||
# aCompartment for us.
|
||||
callSetup += ", eRethrowContentExceptions, aCompartment"
|
||||
else:
|
||||
callSetup += ", aExceptionHandling"
|
||||
callSetup += ");"
|
||||
return string.Template(
|
||||
"CallSetup s(CallbackPreserveColor(), aRv, aExceptionHandling);\n"
|
||||
"${callSetup}\n"
|
||||
"JSContext* cx = s.GetContext();\n"
|
||||
"if (!cx) {\n"
|
||||
" aRv.Throw(NS_ERROR_UNEXPECTED);\n"
|
||||
" return${errorReturn};\n"
|
||||
"}\n").substitute({
|
||||
"callSetup": callSetup,
|
||||
"errorReturn" : self.getDefaultRetval(),
|
||||
})
|
||||
|
||||
@ -10149,9 +10215,9 @@ class CallbackMember(CGNativeMember):
|
||||
idlObject.location))
|
||||
|
||||
class CallbackMethod(CallbackMember):
|
||||
def __init__(self, sig, name, descriptorProvider, needThisHandling):
|
||||
def __init__(self, sig, name, descriptorProvider, needThisHandling, rethrowContentException=False):
|
||||
CallbackMember.__init__(self, sig, name, descriptorProvider,
|
||||
needThisHandling)
|
||||
needThisHandling, rethrowContentException)
|
||||
def getRvalDecl(self):
|
||||
return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
|
||||
|
||||
@ -10189,10 +10255,10 @@ class CallbackOperationBase(CallbackMethod):
|
||||
"""
|
||||
Common class for implementing various callback operations.
|
||||
"""
|
||||
def __init__(self, signature, jsName, nativeName, descriptor, singleOperation):
|
||||
def __init__(self, signature, jsName, nativeName, descriptor, singleOperation, rethrowContentException=False):
|
||||
self.singleOperation = singleOperation
|
||||
self.methodName = jsName
|
||||
CallbackMethod.__init__(self, signature, nativeName, descriptor, singleOperation)
|
||||
CallbackMethod.__init__(self, signature, nativeName, descriptor, singleOperation, rethrowContentException)
|
||||
|
||||
def getThisObj(self):
|
||||
if not self.singleOperation:
|
||||
@ -10232,7 +10298,8 @@ class CallbackOperation(CallbackOperationBase):
|
||||
jsName = method.identifier.name
|
||||
CallbackOperationBase.__init__(self, signature,
|
||||
jsName, MakeNativeName(jsName),
|
||||
descriptor, descriptor.interface.isSingleOperationInterface())
|
||||
descriptor, descriptor.interface.isSingleOperationInterface(),
|
||||
rethrowContentException=descriptor.interface.isJSImplemented())
|
||||
|
||||
class CallbackGetter(CallbackMember):
|
||||
def __init__(self, attr, descriptor):
|
||||
@ -10242,7 +10309,8 @@ class CallbackGetter(CallbackMember):
|
||||
(attr.type, []),
|
||||
callbackGetterName(attr),
|
||||
descriptor,
|
||||
needThisHandling=False)
|
||||
needThisHandling=False,
|
||||
rethrowContentException=descriptor.interface.isJSImplemented())
|
||||
|
||||
def getRvalDecl(self):
|
||||
return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
|
||||
@ -10267,7 +10335,8 @@ class CallbackSetter(CallbackMember):
|
||||
[FakeArgument(attr.type, attr)]),
|
||||
callbackSetterName(attr),
|
||||
descriptor,
|
||||
needThisHandling=False)
|
||||
needThisHandling=False,
|
||||
rethrowContentException=descriptor.interface.isJSImplemented())
|
||||
|
||||
def getRvalDecl(self):
|
||||
# We don't need an rval
|
||||
@ -10296,7 +10365,7 @@ class CGJSImplInitOperation(CallbackOperationBase):
|
||||
def __init__(self, sig, descriptor):
|
||||
assert sig in descriptor.interface.ctor().signatures()
|
||||
CallbackOperationBase.__init__(self, (BuiltinTypes[IDLBuiltinType.Types.void], sig[1]),
|
||||
"__init", "__Init", descriptor, False)
|
||||
"__init", "__Init", descriptor, False, True)
|
||||
|
||||
class GlobalGenRoots():
|
||||
"""
|
||||
|
@ -70,11 +70,14 @@ public:
|
||||
// Facilities for throwing a preexisting JS exception value via this
|
||||
// ErrorResult. The contract is that any code which might end up calling
|
||||
// ThrowJSException() must call MightThrowJSException() even if no exception
|
||||
// is being thrown. Code that would call ReportJSException or
|
||||
// is being thrown. Code that would call ReportJSException* or
|
||||
// StealJSException as needed must first call WouldReportJSException even if
|
||||
// this ErrorResult has not failed.
|
||||
void ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn);
|
||||
void ReportJSException(JSContext* cx);
|
||||
// Used to implement throwing exceptions from the JS implementation of
|
||||
// bindings to callers of the binding.
|
||||
void ReportJSExceptionFromJSImplementation(JSContext* aCx);
|
||||
bool IsJSException() const { return ErrorCode() == NS_ERROR_DOM_JS_EXCEPTION; }
|
||||
|
||||
void ThrowNotEnoughArgsError() { mResult = NS_ERROR_XPC_NOT_ENOUGH_ARGS; }
|
||||
|
@ -359,30 +359,28 @@ RTCPeerConnection.prototype = {
|
||||
* ErrorMsg is passed in to detail which array-entry failed, if any.
|
||||
*/
|
||||
_mustValidateRTCConfiguration: function(rtcConfig, errorMsg) {
|
||||
var errorCtor = this._win.DOMError;
|
||||
function nicerNewURI(uriStr, errorMsg) {
|
||||
let ios = Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService);
|
||||
try {
|
||||
return ios.newURI(uriStr, null, null);
|
||||
} catch (e if (e.result == Cr.NS_ERROR_MALFORMED_URI)) {
|
||||
throw new Components.Exception(errorMsg + " - malformed URI: " + uriStr,
|
||||
Cr.NS_ERROR_MALFORMED_URI);
|
||||
throw new errorCtor("", errorMsg + " - malformed URI: " + uriStr);
|
||||
}
|
||||
}
|
||||
function mustValidateServer(server) {
|
||||
let url = nicerNewURI(server.url, errorMsg);
|
||||
if (url.scheme in { turn:1, turns:1 }) {
|
||||
if (!server.username) {
|
||||
throw new Components.Exception(errorMsg + " - missing username: " +
|
||||
server.url, Cr.NS_ERROR_MALFORMED_URI);
|
||||
throw new errorCtor("", errorMsg + " - missing username: " + server.url);
|
||||
}
|
||||
if (!server.credential) {
|
||||
throw new Components.Exception(errorMsg + " - missing credential: " +
|
||||
server.url, Cr.NS_ERROR_MALFORMED_URI);
|
||||
throw new errorCtor("", errorMsg + " - missing credential: " +
|
||||
server.url);
|
||||
}
|
||||
}
|
||||
else if (!(url.scheme in { stun:1, stuns:1 })) {
|
||||
throw new Components.Exception(errorMsg + " - improper scheme: " + url.scheme,
|
||||
Cr.NS_ERROR_MALFORMED_URI);
|
||||
throw new errorCtor("", errorMsg + " - improper scheme: " + url.scheme);
|
||||
}
|
||||
}
|
||||
if (rtcConfig.iceServers) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user