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());
203 mThrownJSVal
.setNull();
205 mozilla::DropJSObjects(this);
206 mHoldingJSVal
= false;
213 void Exception::StowJSVal(JS::Value
& aVp
) {
214 MOZ_ASSERT(NS_IsMainThread());
217 if (!mHoldingJSVal
) {
218 mozilla::HoldJSObjects(this);
219 mHoldingJSVal
= true;
223 void Exception::GetName(nsAString
& aName
) {
224 if (!mName
.IsEmpty()) {
225 CopyUTF8toUTF16(mName
, aName
);
229 const char* name
= nullptr;
230 nsXPCException::NameAndFormatForNSResult(mResult
, &name
, nullptr);
233 CopyUTF8toUTF16(mozilla::MakeStringSpan(name
), aName
);
238 void Exception::GetFilename(JSContext
* aCx
, nsAString
& aFilename
) {
240 mLocation
->GetFilename(aCx
, aFilename
);
244 aFilename
.Truncate();
247 void Exception::ToString(JSContext
* aCx
, nsACString
& _retval
) {
248 static const char defaultMsg
[] = "<no message>";
249 static const char defaultLocation
[] = "<unknown>";
250 static const char format
[] = "[Exception... \"%s\" nsresult: \"0x%" PRIx32
251 " (%s)\" location: \"%s\" data: %s]";
256 // we need to free this if it does not fail
257 mLocation
->ToString(aCx
, location
);
260 if (location
.IsEmpty()) {
261 location
.Assign(defaultLocation
);
264 const char* msg
= mMessage
.IsEmpty() ? nullptr : mMessage
.get();
266 const char* resultName
= mName
.IsEmpty() ? nullptr : mName
.get();
267 if (!resultName
&& !nsXPCException::NameAndFormatForNSResult(
268 mResult
, &resultName
, (!msg
) ? &msg
: nullptr)) {
272 resultName
= "<unknown>";
274 const char* data
= mData
? "yes" : "no";
277 _retval
.AppendPrintf(format
, msg
, static_cast<uint32_t>(mResult
), resultName
,
278 location
.get(), data
);
281 JSObject
* Exception::WrapObject(JSContext
* cx
,
282 JS::Handle
<JSObject
*> aGivenProto
) {
283 return Exception_Binding::Wrap(cx
, this, aGivenProto
);
286 void Exception::GetMessageMoz(nsString
& retval
) {
287 CopyUTF8toUTF16(mMessage
, retval
);
290 uint32_t Exception::Result() const { return (uint32_t)mResult
; }
292 uint32_t Exception::SourceId(JSContext
* aCx
) const {
294 return mLocation
->GetSourceId(aCx
);
300 uint32_t Exception::LineNumber(JSContext
* aCx
) const {
302 return mLocation
->GetLineNumber(aCx
);
308 uint32_t Exception::ColumnNumber() const { return 0; }
310 already_AddRefed
<nsIStackFrame
> Exception::GetLocation() const {
311 nsCOMPtr
<nsIStackFrame
> location
= mLocation
;
312 return location
.forget();
315 nsISupports
* Exception::GetData() const { return mData
; }
317 void Exception::GetStack(JSContext
* aCx
, nsAString
& aStack
) const {
319 mLocation
->GetFormattedStack(aCx
, aStack
);
323 void Exception::Stringify(JSContext
* aCx
, nsString
& retval
) {
326 CopyUTF8toUTF16(str
, retval
);
329 DOMException::DOMException(nsresult aRv
, const nsACString
& aMessage
,
330 const nsACString
& aName
, uint16_t aCode
,
331 nsIStackFrame
* aLocation
)
332 : Exception(aMessage
, aRv
, aName
, aLocation
, nullptr), mCode(aCode
) {}
334 void DOMException::ToString(JSContext
* aCx
, nsACString
& aReturn
) {
337 static const char defaultMsg
[] = "<no message>";
338 static const char defaultLocation
[] = "<unknown>";
339 static const char defaultName
[] = "<unknown>";
340 static const char format
[] =
341 "[Exception... \"%s\" code: \"%d\" nsresult: \"0x%" PRIx32
342 " (%s)\" location: \"%s\"]";
344 nsAutoCString location
;
346 if (location
.IsEmpty()) {
347 location
= defaultLocation
;
350 const char* msg
= !mMessage
.IsEmpty() ? mMessage
.get() : defaultMsg
;
351 const char* resultName
= !mName
.IsEmpty() ? mName
.get() : defaultName
;
353 aReturn
.AppendPrintf(format
, msg
, mCode
, static_cast<uint32_t>(mResult
),
354 resultName
, location
.get());
357 void DOMException::GetName(nsString
& retval
) { CopyUTF8toUTF16(mName
, retval
); }
359 already_AddRefed
<DOMException
> DOMException::Constructor(
360 GlobalObject
& /* unused */, const nsAString
& aMessage
,
361 const Optional
<nsAString
>& aName
) {
362 nsresult exceptionResult
= NS_OK
;
363 uint16_t exceptionCode
= 0;
364 nsCString
name("Error"_ns
);
366 if (aName
.WasPassed()) {
367 CopyUTF16toUTF8(aName
.Value(), name
);
368 for (uint32_t idx
= 0; idx
< ArrayLength(sDOMErrorMsgMap
); idx
++) {
369 if (name
.EqualsASCII(sDOMErrorMsgMap
[idx
].mName
)) {
370 exceptionResult
= sDOMErrorMsgMap
[idx
].mNSResult
;
371 exceptionCode
= sDOMErrorMsgMap
[idx
].mCode
;
377 RefPtr
<DOMException
> retval
= new DOMException(
378 exceptionResult
, NS_ConvertUTF16toUTF8(aMessage
), name
, exceptionCode
);
379 return retval
.forget();
382 JSObject
* DOMException::WrapObject(JSContext
* aCx
,
383 JS::Handle
<JSObject
*> aGivenProto
) {
384 return DOMException_Binding::Wrap(aCx
, this, aGivenProto
);
388 already_AddRefed
<DOMException
> DOMException::Create(nsresult aRv
) {
392 NSResultToNameAndMessage(aRv
, name
, message
, &code
);
393 RefPtr
<DOMException
> inst
= new DOMException(aRv
, message
, name
, code
);
394 return inst
.forget();
398 already_AddRefed
<DOMException
> DOMException::Create(
399 nsresult aRv
, const nsACString
& aMessage
) {
403 NSResultToNameAndMessage(aRv
, name
, message
, &code
);
404 RefPtr
<DOMException
> inst
= new DOMException(aRv
, aMessage
, name
, code
);
405 return inst
.forget();
408 } // namespace mozilla::dom