1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/dom/DOMException.h"
9 #include "js/OldDebugAPI.h"
10 #include "mozilla/ArrayUtils.h"
11 #include "mozilla/HoldDropJSObjects.h"
12 #include "mozilla/dom/Exceptions.h"
13 #include "nsContentUtils.h"
15 #include "nsIClassInfoImpl.h"
16 #include "nsIDocument.h"
17 #include "nsIDOMDOMException.h"
18 #include "nsIException.h"
19 #include "nsIProgrammingLanguage.h"
22 #include "xpcprivate.h"
24 #include "mozilla/dom/DOMExceptionBinding.h"
25 #include "mozilla/ErrorResult.h"
27 using namespace mozilla
;
29 enum DOM4ErrorTypeCodeMap
{
30 /* DOM4 errors from http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#domexception */
31 IndexSizeError
= nsIDOMDOMException::INDEX_SIZE_ERR
,
32 HierarchyRequestError
= nsIDOMDOMException::HIERARCHY_REQUEST_ERR
,
33 WrongDocumentError
= nsIDOMDOMException::WRONG_DOCUMENT_ERR
,
34 InvalidCharacterError
= nsIDOMDOMException::INVALID_CHARACTER_ERR
,
35 NoModificationAllowedError
= nsIDOMDOMException::NO_MODIFICATION_ALLOWED_ERR
,
36 NotFoundError
= nsIDOMDOMException::NOT_FOUND_ERR
,
37 NotSupportedError
= nsIDOMDOMException::NOT_SUPPORTED_ERR
,
38 // Can't remove until setNamedItem is removed
39 InUseAttributeError
= nsIDOMDOMException::INUSE_ATTRIBUTE_ERR
,
40 InvalidStateError
= nsIDOMDOMException::INVALID_STATE_ERR
,
41 SyntaxError
= nsIDOMDOMException::SYNTAX_ERR
,
42 InvalidModificationError
= nsIDOMDOMException::INVALID_MODIFICATION_ERR
,
43 NamespaceError
= nsIDOMDOMException::NAMESPACE_ERR
,
44 InvalidAccessError
= nsIDOMDOMException::INVALID_ACCESS_ERR
,
45 TypeMismatchError
= nsIDOMDOMException::TYPE_MISMATCH_ERR
,
46 SecurityError
= nsIDOMDOMException::SECURITY_ERR
,
47 NetworkError
= nsIDOMDOMException::NETWORK_ERR
,
48 AbortError
= nsIDOMDOMException::ABORT_ERR
,
49 URLMismatchError
= nsIDOMDOMException::URL_MISMATCH_ERR
,
50 QuotaExceededError
= nsIDOMDOMException::QUOTA_EXCEEDED_ERR
,
51 TimeoutError
= nsIDOMDOMException::TIMEOUT_ERR
,
52 InvalidNodeTypeError
= nsIDOMDOMException::INVALID_NODE_TYPE_ERR
,
53 DataCloneError
= nsIDOMDOMException::DATA_CLONE_ERR
,
54 InvalidPointerId
= nsIDOMDOMException::INVALID_POINTER_ERR
,
57 /* XXX Should be JavaScript native errors */
61 /* IndexedDB errors http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#exceptions */
65 TransactionInactiveError
= 0,
69 /* File API errors http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException */
72 /* FileHandle API errors */
73 FileHandleInactiveError
= 0,
75 /* WebCrypto errors https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#dfn-DataError */
78 /* Bluetooth API errors */
84 BtUnsupportedError
= 0,
85 BtParmInvalidError
= 0,
87 BtAuthFailureError
= 0,
88 BtRmtDevDownError
= 0,
89 BtAuthRejectedError
= 0,
92 #define DOM4_MSG_DEF(name, message, nsresult) {(nsresult), name, #name, message},
93 #define DOM_MSG_DEF(val, message) {(val), NS_ERROR_GET_CODE(val), #val, message},
95 static const struct ResultStruct
100 const char* mMessage
;
101 } sDOMErrorMsgMap
[] = {
102 #include "domerr.msg"
109 NSResultToNameAndMessage(nsresult aNSResult
,
117 for (uint32_t idx
= 0; idx
< ArrayLength(sDOMErrorMsgMap
); idx
++) {
118 if (aNSResult
== sDOMErrorMsgMap
[idx
].mNSResult
) {
119 aName
.Rebind(sDOMErrorMsgMap
[idx
].mName
,
120 strlen(sDOMErrorMsgMap
[idx
].mName
));
121 aMessage
.Rebind(sDOMErrorMsgMap
[idx
].mMessage
,
122 strlen(sDOMErrorMsgMap
[idx
].mMessage
));
123 *aCode
= sDOMErrorMsgMap
[idx
].mCode
;
128 NS_WARNING("Huh, someone is throwing non-DOM errors using the DOM module!");
134 NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult
, nsACString
& aName
,
135 nsACString
& aMessage
, uint16_t* aCode
)
140 NSResultToNameAndMessage(aNSResult
, name
, message
, &code
);
142 if (!name
.IsEmpty() && !message
.IsEmpty()) {
151 return NS_ERROR_NOT_AVAILABLE
;
157 bool Exception::sEverMadeOneFromFactory
= false;
159 NS_IMPL_CLASSINFO(Exception
, nullptr, nsIClassInfo::DOM_OBJECT
,
161 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Exception
)
162 NS_INTERFACE_MAP_ENTRY(nsIException
)
163 NS_INTERFACE_MAP_ENTRY(nsIXPCException
)
164 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIException
)
165 NS_IMPL_QUERY_CLASSINFO(Exception
)
168 NS_IMPL_CYCLE_COLLECTING_ADDREF(Exception
)
169 NS_IMPL_CYCLE_COLLECTING_RELEASE(Exception
)
171 NS_IMPL_CYCLE_COLLECTION_CLASS(Exception
)
173 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Exception
)
174 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation
)
175 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInner
)
176 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
177 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
179 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception
)
180 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
181 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mThrownJSVal
);
182 NS_IMPL_CYCLE_COLLECTION_TRACE_END
184 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Exception
)
185 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation
)
186 NS_IMPL_CYCLE_COLLECTION_UNLINK(mInner
)
187 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
188 tmp
->mThrownJSVal
.setNull();
189 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
191 NS_IMPL_CI_INTERFACE_GETTER(Exception
, nsIXPCException
)
193 Exception::Exception(const nsACString
& aMessage
,
195 const nsACString
& aName
,
196 nsIStackFrame
*aLocation
,
205 // A little hack... The nsIGenericModule nsIClassInfo scheme relies on there
206 // having been at least one instance made via the factory. Otherwise, the
207 // shared factory/classinsance object never gets created and our QI getter
208 // for our instance's pointer to our nsIClassInfo will always return null.
209 // This is bad because it means that wrapped exceptions will never have a
210 // shared prototype. So... We force one to be created via the factory
211 // *once* and then go about our business.
212 if (!sEverMadeOneFromFactory
) {
213 nsCOMPtr
<nsIXPCException
> e
=
214 do_CreateInstance(XPC_EXCEPTION_CONTRACTID
);
215 sEverMadeOneFromFactory
= true;
218 nsCOMPtr
<nsIStackFrame
> location
;
220 location
= aLocation
;
222 location
= GetCurrentJSStack();
223 // it is legal for there to be no active JS stack, if C++ code
224 // is operating on a JS-implemented interface pointer without
225 // having been called in turn by JS. This happens in the JS
226 // component loader, and will become more common as additional
227 // components are implemented in JS.
229 // We want to trim off any leading native 'dataless' frames
234 if (NS_FAILED(location
->GetLanguage(&language
)) ||
235 language
== nsIProgrammingLanguage::JAVASCRIPT
||
236 NS_FAILED(location
->GetLineNumber(&lineNumber
)) ||
240 nsCOMPtr
<nsIStackFrame
> caller
;
241 if (NS_FAILED(location
->GetCaller(getter_AddRefs(caller
))) || !caller
) {
248 Initialize(aMessage
, aResult
, aName
, location
, aData
, nullptr);
251 Exception::Exception()
259 Exception::~Exception()
262 MOZ_ASSERT(NS_IsMainThread());
264 mozilla::DropJSObjects(this);
269 Exception::StealJSVal(JS::Value
* aVp
)
271 MOZ_ASSERT(NS_IsMainThread());
275 mThrownJSVal
.setNull();
277 mozilla::DropJSObjects(this);
278 mHoldingJSVal
= false;
286 Exception::StowJSVal(JS::Value
& aVp
)
288 MOZ_ASSERT(NS_IsMainThread());
291 if (!mHoldingJSVal
) {
292 mozilla::HoldJSObjects(this);
293 mHoldingJSVal
= true;
297 /* readonly attribute AUTF8String message; */
299 Exception::GetMessageMoz(nsACString
& aMessage
)
301 NS_ENSURE_TRUE(mInitialized
, NS_ERROR_NOT_INITIALIZED
);
303 aMessage
.Assign(mMessage
);
307 /* readonly attribute nsresult result; */
309 Exception::GetResult(nsresult
* aResult
)
311 NS_ENSURE_ARG_POINTER(aResult
);
312 NS_ENSURE_TRUE(mInitialized
, NS_ERROR_NOT_INITIALIZED
);
318 /* readonly attribute AUTF8String name; */
320 Exception::GetName(nsACString
& aName
)
322 NS_ENSURE_TRUE(mInitialized
, NS_ERROR_NOT_INITIALIZED
);
324 if (!mName
.IsEmpty()) {
329 const char* name
= nullptr;
330 nsXPCException::NameAndFormatForNSResult(mResult
, &name
, nullptr);
340 /* readonly attribute AString filename; */
342 Exception::GetFilename(nsAString
& aFilename
)
344 NS_ENSURE_TRUE(mInitialized
, NS_ERROR_NOT_INITIALIZED
);
347 return mLocation
->GetFilename(aFilename
);
350 aFilename
.Assign(mFilename
);
354 /* readonly attribute uint32_t lineNumber; */
356 Exception::GetLineNumber(uint32_t *aLineNumber
)
358 NS_ENSURE_ARG_POINTER(aLineNumber
);
359 NS_ENSURE_TRUE(mInitialized
, NS_ERROR_NOT_INITIALIZED
);
363 nsresult rv
= mLocation
->GetLineNumber(&lineno
);
364 *aLineNumber
= lineno
;
368 *aLineNumber
= mLineNumber
;
372 /* readonly attribute uint32_t columnNumber; */
374 Exception::GetColumnNumber(uint32_t* aColumnNumber
)
376 NS_ENSURE_ARG_POINTER(aColumnNumber
);
377 NS_ENSURE_TRUE(mInitialized
, NS_ERROR_NOT_INITIALIZED
);
383 /* readonly attribute nsIStackFrame location; */
385 Exception::GetLocation(nsIStackFrame
** aLocation
)
387 NS_ENSURE_ARG_POINTER(aLocation
);
388 NS_ENSURE_TRUE(mInitialized
, NS_ERROR_NOT_INITIALIZED
);
390 nsCOMPtr
<nsIStackFrame
> location
= mLocation
;
391 location
.forget(aLocation
);
395 /* readonly attribute nsISupports data; */
397 Exception::GetData(nsISupports
** aData
)
399 NS_ENSURE_ARG_POINTER(aData
);
400 NS_ENSURE_TRUE(mInitialized
, NS_ERROR_NOT_INITIALIZED
);
402 nsCOMPtr
<nsISupports
> data
= mData
;
407 /* readonly attribute nsIException inner; */
409 Exception::GetInner(nsIException
** aException
)
411 NS_ENSURE_ARG_POINTER(aException
);
412 NS_ENSURE_TRUE(mInitialized
, NS_ERROR_NOT_INITIALIZED
);
414 nsCOMPtr
<nsIException
> inner
= mInner
;
415 inner
.forget(aException
);
419 /* AUTF8String toString (); */
421 Exception::ToString(nsACString
& _retval
)
423 NS_ENSURE_TRUE(mInitialized
, NS_ERROR_NOT_INITIALIZED
);
425 static const char defaultMsg
[] = "<no message>";
426 static const char defaultLocation
[] = "<unknown>";
427 static const char format
[] =
428 "[Exception... \"%s\" nsresult: \"0x%x (%s)\" location: \"%s\" data: %s]";
433 // we need to free this if it does not fail
434 nsresult rv
= mLocation
->ToString(location
);
435 NS_ENSURE_SUCCESS(rv
, rv
);
438 if (location
.IsEmpty()) {
439 location
.Assign(defaultLocation
);
442 const char* msg
= mMessage
.IsEmpty() ? nullptr : mMessage
.get();
444 const char* resultName
= mName
.IsEmpty() ? nullptr: mName
.get();
446 !nsXPCException::NameAndFormatForNSResult(mResult
, &resultName
,
447 (!msg
) ? &msg
: nullptr)) {
451 resultName
= "<unknown>";
453 const char* data
= mData
? "yes" : "no";
456 _retval
.AppendPrintf(format
, msg
, mResult
, resultName
,
457 location
.get(), data
);
461 /* void initialize (in AUTF8String aMessage, in nsresult aResult,
462 * in AUTF8String aName, in nsIStackFrame aLocation,
463 * in nsISupports aData, in nsIException aInner); */
465 Exception::Initialize(const nsACString
& aMessage
, nsresult aResult
,
466 const nsACString
& aName
, nsIStackFrame
*aLocation
,
467 nsISupports
*aData
, nsIException
*aInner
)
469 NS_ENSURE_FALSE(mInitialized
, NS_ERROR_ALREADY_INITIALIZED
);
476 mLocation
= aLocation
;
479 nsXPConnect
* xpc
= nsXPConnect::XPConnect();
480 rv
= xpc
->GetCurrentJSStack(getter_AddRefs(mLocation
));
494 Exception::WrapObject(JSContext
* cx
)
496 return ExceptionBinding::Wrap(cx
, this);
500 Exception::GetMessageMoz(nsString
& retval
)
504 DebugOnly
<nsresult
> rv
=
507 MOZ_ASSERT(NS_SUCCEEDED(rv
));
508 CopyUTF8toUTF16(str
, retval
);
512 Exception::Result() const
514 return (uint32_t)mResult
;
518 Exception::GetName(nsString
& retval
)
522 DebugOnly
<nsresult
> rv
=
525 MOZ_ASSERT(NS_SUCCEEDED(rv
));
526 CopyUTF8toUTF16(str
, retval
);
530 Exception::LineNumber() const
534 if (NS_SUCCEEDED(mLocation
->GetLineNumber(&lineno
))) {
544 Exception::ColumnNumber() const
549 already_AddRefed
<nsIStackFrame
>
550 Exception::GetLocation() const
552 nsCOMPtr
<nsIStackFrame
> location
= mLocation
;
553 return location
.forget();
556 already_AddRefed
<nsISupports
>
557 Exception::GetInner() const
559 nsCOMPtr
<nsIException
> inner
= mInner
;
560 return inner
.forget();
563 already_AddRefed
<nsISupports
>
564 Exception::GetData() const
566 nsCOMPtr
<nsISupports
> data
= mData
;
567 return data
.forget();
571 Exception::GetStack(nsAString
& aStack
, ErrorResult
& aRv
) const
574 aRv
= mLocation
->GetFormattedStack(aStack
);
579 Exception::Stringify(nsString
& retval
)
583 DebugOnly
<nsresult
> rv
=
586 MOZ_ASSERT(NS_SUCCEEDED(rv
));
587 CopyUTF8toUTF16(str
, retval
);
590 NS_IMPL_ADDREF_INHERITED(DOMException
, Exception
)
591 NS_IMPL_RELEASE_INHERITED(DOMException
, Exception
)
592 NS_INTERFACE_MAP_BEGIN(DOMException
)
593 NS_INTERFACE_MAP_ENTRY(nsIDOMDOMException
)
594 NS_INTERFACE_MAP_END_INHERITING(Exception
)
596 DOMException::DOMException(nsresult aRv
, const nsACString
& aMessage
,
597 const nsACString
& aName
, uint16_t aCode
)
598 : Exception(EmptyCString(), aRv
, EmptyCString(), nullptr, nullptr),
607 DOMException::GetCode(uint16_t* aCode
)
609 NS_ENSURE_ARG_POINTER(aCode
);
612 // Warn only when the code was changed (other than DOM Core)
613 // or the code is useless (zero)
614 if (NS_ERROR_GET_MODULE(mResult
) != NS_ERROR_MODULE_DOM
|| !mCode
) {
615 nsCOMPtr
<nsIDocument
> doc
= nsContentUtils::GetDocumentFromCaller();
617 doc
->WarnOnceAbout(nsIDocument::eDOMExceptionCode
);
625 DOMException::ToString(nsACString
& aReturn
)
629 static const char defaultMsg
[] = "<no message>";
630 static const char defaultLocation
[] = "<unknown>";
631 static const char defaultName
[] = "<unknown>";
632 static const char format
[] =
633 "[Exception... \"%s\" code: \"%d\" nsresult: \"0x%x (%s)\" location: \"%s\"]";
635 nsAutoCString location
;
639 mInner
->GetFilename(filename
);
641 if (!filename
.IsEmpty()) {
642 uint32_t line_nr
= 0;
644 mInner
->GetLineNumber(&line_nr
);
646 char *temp
= PR_smprintf("%s Line: %d",
647 NS_ConvertUTF16toUTF8(filename
).get(),
650 location
.Assign(temp
);
651 PR_smprintf_free(temp
);
656 if (location
.IsEmpty()) {
657 location
= defaultLocation
;
660 const char* msg
= !mMessage
.IsEmpty() ? mMessage
.get() : defaultMsg
;
661 const char* resultName
= !mName
.IsEmpty() ? mName
.get() : defaultName
;
663 aReturn
.AppendPrintf(format
, msg
, mCode
, mResult
, resultName
,
670 DOMException::GetName(nsString
& retval
)
672 CopyUTF8toUTF16(mName
, retval
);
676 DOMException::GetMessageMoz(nsString
& retval
)
678 CopyUTF8toUTF16(mMessage
, retval
);
682 DOMException::WrapObject(JSContext
* aCx
)
684 return DOMExceptionBinding::Wrap(aCx
, this);
687 /* static */already_AddRefed
<DOMException
>
688 DOMException::Create(nsresult aRv
)
693 NSResultToNameAndMessage(aRv
, name
, message
, &code
);
694 nsRefPtr
<DOMException
> inst
=
695 new DOMException(aRv
, message
, name
, code
);
696 return inst
.forget();
700 } // namespace mozilla