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
;
143 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Exception
)
144 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
145 NS_INTERFACE_MAP_ENTRY(Exception
)
146 NS_INTERFACE_MAP_ENTRY(nsIException
)
147 NS_INTERFACE_MAP_ENTRY(nsISupports
)
150 NS_IMPL_CYCLE_COLLECTING_ADDREF(Exception
)
151 NS_IMPL_CYCLE_COLLECTING_RELEASE(Exception
)
153 NS_IMPL_CYCLE_COLLECTION_CLASS(Exception
)
155 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Exception
)
156 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation
)
157 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData
)
158 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
160 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception
)
161 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
162 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mThrownJSVal
)
163 NS_IMPL_CYCLE_COLLECTION_TRACE_END
165 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Exception
)
166 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation
)
167 NS_IMPL_CYCLE_COLLECTION_UNLINK(mData
)
168 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
169 tmp
->mThrownJSVal
.setNull();
170 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
172 Exception::Exception(const nsACString
& aMessage
, nsresult aResult
,
173 const nsACString
& aName
, nsIStackFrame
* aLocation
,
175 : mMessage(aMessage
),
179 mHoldingJSVal(false) {
181 mLocation
= aLocation
;
183 mLocation
= GetCurrentJSStack();
184 // it is legal for there to be no active JS stack, if C++ code
185 // is operating on a JS-implemented interface pointer without
186 // having been called in turn by JS. This happens in the JS
191 Exception::~Exception() {
193 MOZ_ASSERT(NS_IsMainThread());
195 mozilla::DropJSObjects(this);
199 bool Exception::StealJSVal(JS::Value
* aVp
) {
200 MOZ_ASSERT(NS_IsMainThread());
204 mThrownJSVal
.setNull();
206 mozilla::DropJSObjects(this);
207 mHoldingJSVal
= false;
214 void Exception::StowJSVal(JS::Value
& aVp
) {
215 MOZ_ASSERT(NS_IsMainThread());
218 if (!mHoldingJSVal
) {
219 mozilla::HoldJSObjects(this);
220 mHoldingJSVal
= true;
224 void Exception::GetName(nsAString
& aName
) {
225 if (!mName
.IsEmpty()) {
226 CopyUTF8toUTF16(mName
, aName
);
230 const char* name
= nullptr;
231 nsXPCException::NameAndFormatForNSResult(mResult
, &name
, nullptr);
234 CopyUTF8toUTF16(mozilla::MakeStringSpan(name
), aName
);
239 void Exception::GetFilename(JSContext
* aCx
, nsAString
& aFilename
) {
241 mLocation
->GetFilename(aCx
, aFilename
);
245 aFilename
.Truncate();
248 void Exception::ToString(JSContext
* aCx
, nsACString
& _retval
) {
249 static const char defaultMsg
[] = "<no message>";
250 static const char defaultLocation
[] = "<unknown>";
251 static const char format
[] = "[Exception... \"%s\" nsresult: \"0x%" PRIx32
252 " (%s)\" location: \"%s\" data: %s]";
257 // we need to free this if it does not fail
258 mLocation
->ToString(aCx
, location
);
261 if (location
.IsEmpty()) {
262 location
.Assign(defaultLocation
);
265 const char* msg
= mMessage
.IsEmpty() ? nullptr : mMessage
.get();
267 const char* resultName
= mName
.IsEmpty() ? nullptr : mName
.get();
268 if (!resultName
&& !nsXPCException::NameAndFormatForNSResult(
269 mResult
, &resultName
, (!msg
) ? &msg
: nullptr)) {
273 resultName
= "<unknown>";
275 const char* data
= mData
? "yes" : "no";
278 _retval
.AppendPrintf(format
, msg
, static_cast<uint32_t>(mResult
), resultName
,
279 location
.get(), data
);
282 JSObject
* Exception::WrapObject(JSContext
* cx
,
283 JS::Handle
<JSObject
*> aGivenProto
) {
284 return Exception_Binding::Wrap(cx
, this, aGivenProto
);
287 void Exception::GetMessageMoz(nsString
& retval
) {
288 CopyUTF8toUTF16(mMessage
, retval
);
291 uint32_t Exception::Result() const { return (uint32_t)mResult
; }
293 uint32_t Exception::SourceId(JSContext
* aCx
) const {
295 return mLocation
->GetSourceId(aCx
);
301 uint32_t Exception::LineNumber(JSContext
* aCx
) const {
303 return mLocation
->GetLineNumber(aCx
);
309 uint32_t Exception::ColumnNumber() const { return 0; }
311 already_AddRefed
<nsIStackFrame
> Exception::GetLocation() const {
312 nsCOMPtr
<nsIStackFrame
> location
= mLocation
;
313 return location
.forget();
316 nsISupports
* Exception::GetData() const { return mData
; }
318 void Exception::GetStack(JSContext
* aCx
, nsAString
& aStack
) const {
320 mLocation
->GetFormattedStack(aCx
, aStack
);
324 void Exception::Stringify(JSContext
* aCx
, nsString
& retval
) {
327 CopyUTF8toUTF16(str
, retval
);
330 DOMException::DOMException(nsresult aRv
, const nsACString
& aMessage
,
331 const nsACString
& aName
, uint16_t aCode
,
332 nsIStackFrame
* aLocation
)
333 : Exception(aMessage
, aRv
, aName
, aLocation
, nullptr), mCode(aCode
) {}
335 void DOMException::ToString(JSContext
* aCx
, nsACString
& aReturn
) {
338 static const char defaultMsg
[] = "<no message>";
339 static const char defaultLocation
[] = "<unknown>";
340 static const char defaultName
[] = "<unknown>";
341 static const char format
[] =
342 "[Exception... \"%s\" code: \"%d\" nsresult: \"0x%" PRIx32
343 " (%s)\" location: \"%s\"]";
345 nsAutoCString location
;
347 if (location
.IsEmpty()) {
348 location
= defaultLocation
;
351 const char* msg
= !mMessage
.IsEmpty() ? mMessage
.get() : defaultMsg
;
352 const char* resultName
= !mName
.IsEmpty() ? mName
.get() : defaultName
;
354 aReturn
.AppendPrintf(format
, msg
, mCode
, static_cast<uint32_t>(mResult
),
355 resultName
, location
.get());
358 void DOMException::GetName(nsString
& retval
) { CopyUTF8toUTF16(mName
, retval
); }
360 already_AddRefed
<DOMException
> DOMException::Constructor(
361 GlobalObject
& /* unused */, const nsAString
& aMessage
,
362 const Optional
<nsAString
>& aName
) {
363 nsresult exceptionResult
= NS_OK
;
364 uint16_t exceptionCode
= 0;
365 nsCString
name("Error"_ns
);
367 if (aName
.WasPassed()) {
368 CopyUTF16toUTF8(aName
.Value(), name
);
369 for (uint32_t idx
= 0; idx
< ArrayLength(sDOMErrorMsgMap
); idx
++) {
370 if (name
.EqualsASCII(sDOMErrorMsgMap
[idx
].mName
)) {
371 exceptionResult
= sDOMErrorMsgMap
[idx
].mNSResult
;
372 exceptionCode
= sDOMErrorMsgMap
[idx
].mCode
;
378 RefPtr
<DOMException
> retval
= new DOMException(
379 exceptionResult
, NS_ConvertUTF16toUTF8(aMessage
), name
, exceptionCode
);
380 return retval
.forget();
383 JSObject
* DOMException::WrapObject(JSContext
* aCx
,
384 JS::Handle
<JSObject
*> aGivenProto
) {
385 return DOMException_Binding::Wrap(aCx
, this, aGivenProto
);
389 already_AddRefed
<DOMException
> DOMException::Create(nsresult aRv
) {
393 NSResultToNameAndMessage(aRv
, name
, message
, &code
);
394 RefPtr
<DOMException
> inst
= new DOMException(aRv
, message
, name
, code
);
395 return inst
.forget();
399 already_AddRefed
<DOMException
> DOMException::Create(
400 nsresult aRv
, const nsACString
& aMessage
) {
404 NSResultToNameAndMessage(aRv
, name
, message
, &code
);
405 RefPtr
<DOMException
> inst
= new DOMException(aRv
, aMessage
, name
, code
);
406 return inst
.forget();
410 } // namespace mozilla