Bumping manifests a=b2g-bump
[gecko.git] / dom / base / DOMException.cpp
blob5693d9c05d87d099cb32db6befbaf243dcd4c719
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"
8 #include "jsprf.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"
14 #include "nsCOMPtr.h"
15 #include "nsIClassInfoImpl.h"
16 #include "nsIDocument.h"
17 #include "nsIDOMDOMException.h"
18 #include "nsIException.h"
19 #include "nsIProgrammingLanguage.h"
20 #include "nsMemory.h"
21 #include "prprf.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,
55 EncodingError = 0,
57 /* XXX Should be JavaScript native errors */
58 TypeError = 0,
59 RangeError = 0,
61 /* IndexedDB errors http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#exceptions */
62 UnknownError = 0,
63 ConstraintError = 0,
64 DataError = 0,
65 TransactionInactiveError = 0,
66 ReadOnlyError = 0,
67 VersionError = 0,
69 /* File API errors http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException */
70 NotReadableError = 0,
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 */
76 OperationError = 0,
78 /* Bluetooth API errors */
79 BtFailError = 0,
80 BtNotReadyError = 0,
81 BtNoMemError = 0,
82 BtBusyError = 0,
83 BtDoneError = 0,
84 BtUnsupportedError = 0,
85 BtParmInvalidError = 0,
86 BtUnhandledError = 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
97 nsresult mNSResult;
98 uint16_t mCode;
99 const char* mName;
100 const char* mMessage;
101 } sDOMErrorMsgMap[] = {
102 #include "domerr.msg"
105 #undef DOM4_MSG_DEF
106 #undef DOM_MSG_DEF
108 static void
109 NSResultToNameAndMessage(nsresult aNSResult,
110 nsCString& aName,
111 nsCString& aMessage,
112 uint16_t* aCode)
114 aName.Truncate();
115 aMessage.Truncate();
116 *aCode = 0;
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;
124 return;
128 NS_WARNING("Huh, someone is throwing non-DOM errors using the DOM module!");
130 return;
133 nsresult
134 NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, nsACString& aName,
135 nsACString& aMessage, uint16_t* aCode)
137 nsCString name;
138 nsCString message;
139 uint16_t code = 0;
140 NSResultToNameAndMessage(aNSResult, name, message, &code);
142 if (!name.IsEmpty() && !message.IsEmpty()) {
143 aName = name;
144 aMessage = message;
145 if (aCode) {
146 *aCode = code;
148 return NS_OK;
151 return NS_ERROR_NOT_AVAILABLE;
154 namespace mozilla {
155 namespace dom {
157 bool Exception::sEverMadeOneFromFactory = false;
159 NS_IMPL_CLASSINFO(Exception, nullptr, nsIClassInfo::DOM_OBJECT,
160 NS_XPCEXCEPTION_CID)
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)
166 NS_INTERFACE_MAP_END
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,
194 nsresult aResult,
195 const nsACString& aName,
196 nsIStackFrame *aLocation,
197 nsISupports *aData)
198 : mResult(NS_OK),
199 mLineNumber(0),
200 mInitialized(false),
201 mHoldingJSVal(false)
203 SetIsDOMBinding();
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;
219 if (aLocation) {
220 location = aLocation;
221 } else {
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
230 if (location) {
231 while (1) {
232 uint32_t language;
233 int32_t lineNumber;
234 if (NS_FAILED(location->GetLanguage(&language)) ||
235 language == nsIProgrammingLanguage::JAVASCRIPT ||
236 NS_FAILED(location->GetLineNumber(&lineNumber)) ||
237 lineNumber) {
238 break;
240 nsCOMPtr<nsIStackFrame> caller;
241 if (NS_FAILED(location->GetCaller(getter_AddRefs(caller))) || !caller) {
242 break;
244 location = caller;
248 Initialize(aMessage, aResult, aName, location, aData, nullptr);
251 Exception::Exception()
252 : mResult(NS_OK),
253 mLineNumber(-1),
254 mInitialized(false),
255 mHoldingJSVal(false)
259 Exception::~Exception()
261 if (mHoldingJSVal) {
262 MOZ_ASSERT(NS_IsMainThread());
264 mozilla::DropJSObjects(this);
268 bool
269 Exception::StealJSVal(JS::Value* aVp)
271 MOZ_ASSERT(NS_IsMainThread());
273 if (mHoldingJSVal) {
274 *aVp = mThrownJSVal;
275 mThrownJSVal.setNull();
277 mozilla::DropJSObjects(this);
278 mHoldingJSVal = false;
279 return true;
282 return false;
285 void
286 Exception::StowJSVal(JS::Value& aVp)
288 MOZ_ASSERT(NS_IsMainThread());
290 mThrownJSVal = aVp;
291 if (!mHoldingJSVal) {
292 mozilla::HoldJSObjects(this);
293 mHoldingJSVal = true;
297 /* readonly attribute AUTF8String message; */
298 NS_IMETHODIMP
299 Exception::GetMessageMoz(nsACString& aMessage)
301 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
303 aMessage.Assign(mMessage);
304 return NS_OK;
307 /* readonly attribute nsresult result; */
308 NS_IMETHODIMP
309 Exception::GetResult(nsresult* aResult)
311 NS_ENSURE_ARG_POINTER(aResult);
312 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
314 *aResult = mResult;
315 return NS_OK;
318 /* readonly attribute AUTF8String name; */
319 NS_IMETHODIMP
320 Exception::GetName(nsACString& aName)
322 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
324 if (!mName.IsEmpty()) {
325 aName.Assign(mName);
326 } else {
327 aName.Truncate();
329 const char* name = nullptr;
330 nsXPCException::NameAndFormatForNSResult(mResult, &name, nullptr);
332 if (name) {
333 aName.Assign(name);
337 return NS_OK;
340 /* readonly attribute AString filename; */
341 NS_IMETHODIMP
342 Exception::GetFilename(nsAString& aFilename)
344 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
346 if (mLocation) {
347 return mLocation->GetFilename(aFilename);
350 aFilename.Assign(mFilename);
351 return NS_OK;
354 /* readonly attribute uint32_t lineNumber; */
355 NS_IMETHODIMP
356 Exception::GetLineNumber(uint32_t *aLineNumber)
358 NS_ENSURE_ARG_POINTER(aLineNumber);
359 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
361 if (mLocation) {
362 int32_t lineno;
363 nsresult rv = mLocation->GetLineNumber(&lineno);
364 *aLineNumber = lineno;
365 return rv;
368 *aLineNumber = mLineNumber;
369 return NS_OK;
372 /* readonly attribute uint32_t columnNumber; */
373 NS_IMETHODIMP
374 Exception::GetColumnNumber(uint32_t* aColumnNumber)
376 NS_ENSURE_ARG_POINTER(aColumnNumber);
377 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
379 *aColumnNumber = 0;
380 return NS_OK;
383 /* readonly attribute nsIStackFrame location; */
384 NS_IMETHODIMP
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);
392 return NS_OK;
395 /* readonly attribute nsISupports data; */
396 NS_IMETHODIMP
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;
403 data.forget(aData);
404 return NS_OK;
407 /* readonly attribute nsIException inner; */
408 NS_IMETHODIMP
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);
416 return NS_OK;
419 /* AUTF8String toString (); */
420 NS_IMETHODIMP
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]";
430 nsCString location;
432 if (mLocation) {
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();
445 if (!resultName &&
446 !nsXPCException::NameAndFormatForNSResult(mResult, &resultName,
447 (!msg) ? &msg : nullptr)) {
448 if (!msg) {
449 msg = defaultMsg;
451 resultName = "<unknown>";
453 const char* data = mData ? "yes" : "no";
455 _retval.Truncate();
456 _retval.AppendPrintf(format, msg, mResult, resultName,
457 location.get(), data);
458 return NS_OK;
461 /* void initialize (in AUTF8String aMessage, in nsresult aResult,
462 * in AUTF8String aName, in nsIStackFrame aLocation,
463 * in nsISupports aData, in nsIException aInner); */
464 NS_IMETHODIMP
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);
471 mMessage = aMessage;
472 mName = aName;
473 mResult = aResult;
475 if (aLocation) {
476 mLocation = aLocation;
477 } else {
478 nsresult rv;
479 nsXPConnect* xpc = nsXPConnect::XPConnect();
480 rv = xpc->GetCurrentJSStack(getter_AddRefs(mLocation));
481 if (NS_FAILED(rv)) {
482 return rv;
486 mData = aData;
487 mInner = aInner;
489 mInitialized = true;
490 return NS_OK;
493 JSObject*
494 Exception::WrapObject(JSContext* cx)
496 return ExceptionBinding::Wrap(cx, this);
499 void
500 Exception::GetMessageMoz(nsString& retval)
502 nsCString str;
503 #ifdef DEBUG
504 DebugOnly<nsresult> rv =
505 #endif
506 GetMessageMoz(str);
507 MOZ_ASSERT(NS_SUCCEEDED(rv));
508 CopyUTF8toUTF16(str, retval);
511 uint32_t
512 Exception::Result() const
514 return (uint32_t)mResult;
517 void
518 Exception::GetName(nsString& retval)
520 nsCString str;
521 #ifdef DEBUG
522 DebugOnly<nsresult> rv =
523 #endif
524 GetName(str);
525 MOZ_ASSERT(NS_SUCCEEDED(rv));
526 CopyUTF8toUTF16(str, retval);
529 uint32_t
530 Exception::LineNumber() const
532 if (mLocation) {
533 int32_t lineno;
534 if (NS_SUCCEEDED(mLocation->GetLineNumber(&lineno))) {
535 return lineno;
537 return 0;
540 return mLineNumber;
543 uint32_t
544 Exception::ColumnNumber() const
546 return 0;
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();
570 void
571 Exception::GetStack(nsAString& aStack, ErrorResult& aRv) const
573 if (mLocation) {
574 aRv = mLocation->GetFormattedStack(aStack);
578 void
579 Exception::Stringify(nsString& retval)
581 nsCString str;
582 #ifdef DEBUG
583 DebugOnly<nsresult> rv =
584 #endif
585 ToString(str);
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),
599 mName(aName),
600 mMessage(aMessage),
601 mCode(aCode)
603 SetIsDOMBinding();
606 NS_IMETHODIMP
607 DOMException::GetCode(uint16_t* aCode)
609 NS_ENSURE_ARG_POINTER(aCode);
610 *aCode = mCode;
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();
616 if (doc) {
617 doc->WarnOnceAbout(nsIDocument::eDOMExceptionCode);
621 return NS_OK;
624 NS_IMETHODIMP
625 DOMException::ToString(nsACString& aReturn)
627 aReturn.Truncate();
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;
637 if (mInner) {
638 nsString filename;
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(),
648 line_nr);
649 if (temp) {
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,
664 location.get());
666 return NS_OK;
669 void
670 DOMException::GetName(nsString& retval)
672 CopyUTF8toUTF16(mName, retval);
675 void
676 DOMException::GetMessageMoz(nsString& retval)
678 CopyUTF8toUTF16(mMessage, retval);
681 JSObject*
682 DOMException::WrapObject(JSContext* aCx)
684 return DOMExceptionBinding::Wrap(aCx, this);
687 /* static */already_AddRefed<DOMException>
688 DOMException::Create(nsresult aRv)
690 nsCString name;
691 nsCString message;
692 uint16_t code;
693 NSResultToNameAndMessage(aRv, name, message, &code);
694 nsRefPtr<DOMException> inst =
695 new DOMException(aRv, message, name, code);
696 return inst.forget();
699 } // namespace dom
700 } // namespace mozilla