1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/DOMException.h"
9 #include "mozilla/ArrayUtils.h"
10 #include "mozilla/HoldDropJSObjects.h"
11 #include "mozilla/dom/Exceptions.h"
12 #include "nsContentUtils.h"
14 #include "mozilla/dom/Document.h"
15 #include "nsIException.h"
17 #include "xpcprivate.h"
19 #include "mozilla/dom/DOMExceptionBinding.h"
20 #include "mozilla/ErrorResult.h"
22 using namespace mozilla
;
23 using namespace mozilla::dom
;
25 enum DOM4ErrorTypeCodeMap
{
27 http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#domexception */
28 IndexSizeError
= DOMException_Binding::INDEX_SIZE_ERR
,
29 HierarchyRequestError
= DOMException_Binding::HIERARCHY_REQUEST_ERR
,
30 WrongDocumentError
= DOMException_Binding::WRONG_DOCUMENT_ERR
,
31 InvalidCharacterError
= DOMException_Binding::INVALID_CHARACTER_ERR
,
32 NoModificationAllowedError
=
33 DOMException_Binding::NO_MODIFICATION_ALLOWED_ERR
,
34 NotFoundError
= DOMException_Binding::NOT_FOUND_ERR
,
35 NotSupportedError
= DOMException_Binding::NOT_SUPPORTED_ERR
,
36 // Can't remove until setNamedItem is removed
37 InUseAttributeError
= DOMException_Binding::INUSE_ATTRIBUTE_ERR
,
38 InvalidStateError
= DOMException_Binding::INVALID_STATE_ERR
,
39 SyntaxError
= DOMException_Binding::SYNTAX_ERR
,
40 InvalidModificationError
= DOMException_Binding::INVALID_MODIFICATION_ERR
,
41 NamespaceError
= DOMException_Binding::NAMESPACE_ERR
,
42 InvalidAccessError
= DOMException_Binding::INVALID_ACCESS_ERR
,
43 TypeMismatchError
= DOMException_Binding::TYPE_MISMATCH_ERR
,
44 SecurityError
= DOMException_Binding::SECURITY_ERR
,
45 NetworkError
= DOMException_Binding::NETWORK_ERR
,
46 AbortError
= DOMException_Binding::ABORT_ERR
,
47 URLMismatchError
= DOMException_Binding::URL_MISMATCH_ERR
,
48 QuotaExceededError
= DOMException_Binding::QUOTA_EXCEEDED_ERR
,
49 TimeoutError
= DOMException_Binding::TIMEOUT_ERR
,
50 InvalidNodeTypeError
= DOMException_Binding::INVALID_NODE_TYPE_ERR
,
51 DataCloneError
= DOMException_Binding::DATA_CLONE_ERR
,
55 /* XXX Should be JavaScript native errors */
60 http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#exceptions */
64 TransactionInactiveError
= 0,
68 /* File API errors http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException */
71 /* FileHandle API errors */
72 FileHandleInactiveError
= 0,
75 https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#dfn-DataError
83 #define DOM4_MSG_DEF(name, message, nsresult) \
84 {(nsresult), name, #name, message},
85 #define DOM_MSG_DEF(val, message) \
86 {(val), NS_ERROR_GET_CODE(val), #val, message},
88 static constexpr struct ResultStruct
{
93 } sDOMErrorMsgMap
[] = {
100 static void NSResultToNameAndMessage(nsresult aNSResult
, nsCString
& aName
,
101 nsCString
& aMessage
, uint16_t* aCode
) {
105 for (uint32_t idx
= 0; idx
< ArrayLength(sDOMErrorMsgMap
); idx
++) {
106 if (aNSResult
== sDOMErrorMsgMap
[idx
].mNSResult
) {
107 aName
.Rebind(sDOMErrorMsgMap
[idx
].mName
,
108 strlen(sDOMErrorMsgMap
[idx
].mName
));
109 aMessage
.Rebind(sDOMErrorMsgMap
[idx
].mMessage
,
110 strlen(sDOMErrorMsgMap
[idx
].mMessage
));
111 *aCode
= sDOMErrorMsgMap
[idx
].mCode
;
116 NS_WARNING("Huh, someone is throwing non-DOM errors using the DOM module!");
119 nsresult
NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult
,
121 nsACString
& aMessage
,
126 NSResultToNameAndMessage(aNSResult
, name
, message
, &code
);
128 if (!name
.IsEmpty() && !message
.IsEmpty()) {
137 return NS_ERROR_NOT_AVAILABLE
;
140 namespace mozilla::dom
{
142 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Exception
)
143 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
144 NS_INTERFACE_MAP_ENTRY(Exception
)
145 NS_INTERFACE_MAP_ENTRY(nsIException
)
146 NS_INTERFACE_MAP_ENTRY(nsISupports
)
149 NS_IMPL_CYCLE_COLLECTING_ADDREF(Exception
)
150 NS_IMPL_CYCLE_COLLECTING_RELEASE(Exception
)
152 NS_IMPL_CYCLE_COLLECTION_CLASS(Exception
)
154 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Exception
)
155 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation
)
156 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData
)
157 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
159 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception
)
160 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
161 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mThrownJSVal
)
162 NS_IMPL_CYCLE_COLLECTION_TRACE_END
164 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Exception
)
165 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation
)
166 NS_IMPL_CYCLE_COLLECTION_UNLINK(mData
)
167 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
168 tmp
->mThrownJSVal
.setNull();
169 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
171 Exception::Exception(const nsACString
& aMessage
, nsresult aResult
,
172 const nsACString
& aName
, nsIStackFrame
* aLocation
,
174 : mMessage(aMessage
),
178 mHoldingJSVal(false) {
180 mLocation
= aLocation
;
182 mLocation
= GetCurrentJSStack();
183 // it is legal for there to be no active JS stack, if C++ code
184 // is operating on a JS-implemented interface pointer without
185 // having been called in turn by JS. This happens in the JS
190 Exception::~Exception() {
192 MOZ_ASSERT(NS_IsMainThread());
194 mozilla::DropJSObjects(this);
198 bool Exception::StealJSVal(JS::Value
* aVp
) {
199 MOZ_ASSERT(NS_IsMainThread());
204 mozilla::DropJSObjects(this);
205 mHoldingJSVal
= false;
212 void Exception::StowJSVal(JS::Value
& aVp
) {
213 MOZ_ASSERT(NS_IsMainThread());
216 if (!mHoldingJSVal
) {
217 mozilla::HoldJSObjects(this);
218 mHoldingJSVal
= true;
222 void Exception::GetName(nsAString
& aName
) {
223 if (!mName
.IsEmpty()) {
224 CopyUTF8toUTF16(mName
, aName
);
228 const char* name
= nullptr;
229 nsXPCException::NameAndFormatForNSResult(mResult
, &name
, nullptr);
232 CopyUTF8toUTF16(mozilla::MakeStringSpan(name
), aName
);
237 void Exception::GetFilename(JSContext
* aCx
, nsAString
& aFilename
) {
239 mLocation
->GetFilename(aCx
, aFilename
);
243 aFilename
.Truncate();
246 void Exception::ToString(JSContext
* aCx
, nsACString
& _retval
) {
247 static const char defaultMsg
[] = "<no message>";
248 static const char defaultLocation
[] = "<unknown>";
249 static const char format
[] = "[Exception... \"%s\" nsresult: \"0x%" PRIx32
250 " (%s)\" location: \"%s\" data: %s]";
255 // we need to free this if it does not fail
256 mLocation
->ToString(aCx
, location
);
259 if (location
.IsEmpty()) {
260 location
.Assign(defaultLocation
);
263 const char* msg
= mMessage
.IsEmpty() ? nullptr : mMessage
.get();
265 const char* resultName
= mName
.IsEmpty() ? nullptr : mName
.get();
266 if (!resultName
&& !nsXPCException::NameAndFormatForNSResult(
267 mResult
, &resultName
, (!msg
) ? &msg
: nullptr)) {
271 resultName
= "<unknown>";
273 const char* data
= mData
? "yes" : "no";
276 _retval
.AppendPrintf(format
, msg
, static_cast<uint32_t>(mResult
), resultName
,
277 location
.get(), data
);
280 JSObject
* Exception::WrapObject(JSContext
* cx
,
281 JS::Handle
<JSObject
*> aGivenProto
) {
282 return Exception_Binding::Wrap(cx
, this, aGivenProto
);
285 void Exception::GetMessageMoz(nsString
& retval
) {
286 CopyUTF8toUTF16(mMessage
, retval
);
289 uint32_t Exception::Result() const { return (uint32_t)mResult
; }
291 uint32_t Exception::SourceId(JSContext
* aCx
) const {
293 return mLocation
->GetSourceId(aCx
);
299 uint32_t Exception::LineNumber(JSContext
* aCx
) const {
301 return mLocation
->GetLineNumber(aCx
);
307 uint32_t Exception::ColumnNumber() const { return 0; }
309 already_AddRefed
<nsIStackFrame
> Exception::GetLocation() const {
310 nsCOMPtr
<nsIStackFrame
> location
= mLocation
;
311 return location
.forget();
314 nsISupports
* Exception::GetData() const { return mData
; }
316 void Exception::GetStack(JSContext
* aCx
, nsAString
& aStack
) const {
318 mLocation
->GetFormattedStack(aCx
, aStack
);
322 void Exception::Stringify(JSContext
* aCx
, nsString
& retval
) {
325 CopyUTF8toUTF16(str
, retval
);
328 DOMException::DOMException(nsresult aRv
, const nsACString
& aMessage
,
329 const nsACString
& aName
, uint16_t aCode
,
330 nsIStackFrame
* aLocation
)
331 : Exception(aMessage
, aRv
, aName
, aLocation
, nullptr), mCode(aCode
) {}
333 void DOMException::ToString(JSContext
* aCx
, nsACString
& aReturn
) {
336 static const char defaultMsg
[] = "<no message>";
337 static const char defaultLocation
[] = "<unknown>";
338 static const char defaultName
[] = "<unknown>";
339 static const char format
[] =
340 "[Exception... \"%s\" code: \"%d\" nsresult: \"0x%" PRIx32
341 " (%s)\" location: \"%s\"]";
343 nsAutoCString location
;
345 if (location
.IsEmpty()) {
346 location
= defaultLocation
;
349 const char* msg
= !mMessage
.IsEmpty() ? mMessage
.get() : defaultMsg
;
350 const char* resultName
= !mName
.IsEmpty() ? mName
.get() : defaultName
;
352 aReturn
.AppendPrintf(format
, msg
, mCode
, static_cast<uint32_t>(mResult
),
353 resultName
, location
.get());
356 void DOMException::GetName(nsString
& retval
) { CopyUTF8toUTF16(mName
, retval
); }
358 already_AddRefed
<DOMException
> DOMException::Constructor(
359 GlobalObject
& /* unused */, const nsAString
& aMessage
,
360 const Optional
<nsAString
>& aName
) {
361 nsresult exceptionResult
= NS_OK
;
362 uint16_t exceptionCode
= 0;
363 nsCString
name("Error"_ns
);
365 if (aName
.WasPassed()) {
366 CopyUTF16toUTF8(aName
.Value(), name
);
367 for (uint32_t idx
= 0; idx
< ArrayLength(sDOMErrorMsgMap
); idx
++) {
368 if (name
.EqualsASCII(sDOMErrorMsgMap
[idx
].mName
)) {
369 exceptionResult
= sDOMErrorMsgMap
[idx
].mNSResult
;
370 exceptionCode
= sDOMErrorMsgMap
[idx
].mCode
;
376 RefPtr
<DOMException
> retval
= new DOMException(
377 exceptionResult
, NS_ConvertUTF16toUTF8(aMessage
), name
, exceptionCode
);
378 return retval
.forget();
381 JSObject
* DOMException::WrapObject(JSContext
* aCx
,
382 JS::Handle
<JSObject
*> aGivenProto
) {
383 return DOMException_Binding::Wrap(aCx
, this, aGivenProto
);
387 already_AddRefed
<DOMException
> DOMException::Create(nsresult aRv
) {
391 NSResultToNameAndMessage(aRv
, name
, message
, &code
);
392 RefPtr
<DOMException
> inst
= new DOMException(aRv
, message
, name
, code
);
393 return inst
.forget();
397 already_AddRefed
<DOMException
> DOMException::Create(
398 nsresult aRv
, const nsACString
& aMessage
) {
402 NSResultToNameAndMessage(aRv
, name
, message
, &code
);
403 RefPtr
<DOMException
> inst
= new DOMException(aRv
, aMessage
, name
, code
);
404 return inst
.forget();
407 } // namespace mozilla::dom