dom/base/DOMException.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:a3c103e46690
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/. */
5
6 #include "mozilla/dom/DOMException.h"
7
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"
23
24 #include "mozilla/dom/DOMExceptionBinding.h"
25
26 using namespace mozilla;
27
28 enum DOM4ErrorTypeCodeMap {
29 /* DOM4 errors from http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#domexception */
30 IndexSizeError = nsIDOMDOMException::INDEX_SIZE_ERR,
31 HierarchyRequestError = nsIDOMDOMException::HIERARCHY_REQUEST_ERR,
32 WrongDocumentError = nsIDOMDOMException::WRONG_DOCUMENT_ERR,
33 InvalidCharacterError = nsIDOMDOMException::INVALID_CHARACTER_ERR,
34 NoModificationAllowedError = nsIDOMDOMException::NO_MODIFICATION_ALLOWED_ERR,
35 NotFoundError = nsIDOMDOMException::NOT_FOUND_ERR,
36 NotSupportedError = nsIDOMDOMException::NOT_SUPPORTED_ERR,
37 // Can't remove until setNamedItem is removed
38 InUseAttributeError = nsIDOMDOMException::INUSE_ATTRIBUTE_ERR,
39 InvalidStateError = nsIDOMDOMException::INVALID_STATE_ERR,
40 SyntaxError = nsIDOMDOMException::SYNTAX_ERR,
41 InvalidModificationError = nsIDOMDOMException::INVALID_MODIFICATION_ERR,
42 NamespaceError = nsIDOMDOMException::NAMESPACE_ERR,
43 InvalidAccessError = nsIDOMDOMException::INVALID_ACCESS_ERR,
44 TypeMismatchError = nsIDOMDOMException::TYPE_MISMATCH_ERR,
45 SecurityError = nsIDOMDOMException::SECURITY_ERR,
46 NetworkError = nsIDOMDOMException::NETWORK_ERR,
47 AbortError = nsIDOMDOMException::ABORT_ERR,
48 URLMismatchError = nsIDOMDOMException::URL_MISMATCH_ERR,
49 QuotaExceededError = nsIDOMDOMException::QUOTA_EXCEEDED_ERR,
50 TimeoutError = nsIDOMDOMException::TIMEOUT_ERR,
51 InvalidNodeTypeError = nsIDOMDOMException::INVALID_NODE_TYPE_ERR,
52 DataCloneError = nsIDOMDOMException::DATA_CLONE_ERR,
53 InvalidPointerId = nsIDOMDOMException::INVALID_POINTER_ERR,
54 EncodingError = 0,
55
56 /* XXX Should be JavaScript native errors */
57 TypeError = 0,
58 RangeError = 0,
59
60 /* IndexedDB errors http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#exceptions */
61 UnknownError = 0,
62 ConstraintError = 0,
63 DataError = 0,
64 TransactionInactiveError = 0,
65 ReadOnlyError = 0,
66 VersionError = 0,
67
68 /* File API errors http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException */
69 NotReadableError = 0,
70
71 /* FileHandle API errors */
72 LockedFileInactiveError = 0,
73 };
74
75 #define DOM4_MSG_DEF(name, message, nsresult) {(nsresult), name, #name, message},
76 #define DOM_MSG_DEF(val, message) {(val), NS_ERROR_GET_CODE(val), #val, message},
77
78 static const struct ResultStruct
79 {
80 nsresult mNSResult;
81 uint16_t mCode;
82 const char* mName;
83 const char* mMessage;
84 } sDOMErrorMsgMap[] = {
85 #include "domerr.msg"
86 };
87
88 #undef DOM4_MSG_DEF
89 #undef DOM_MSG_DEF
90
91 static void
92 NSResultToNameAndMessage(nsresult aNSResult,
93 nsCString& aName,
94 nsCString& aMessage,
95 uint16_t* aCode)
96 {
97 aName.Truncate();
98 aMessage.Truncate();
99 *aCode = 0;
100 for (uint32_t idx = 0; idx < ArrayLength(sDOMErrorMsgMap); idx++) {
101 if (aNSResult == sDOMErrorMsgMap[idx].mNSResult) {
102 aName.Rebind(sDOMErrorMsgMap[idx].mName,
103 strlen(sDOMErrorMsgMap[idx].mName));
104 aMessage.Rebind(sDOMErrorMsgMap[idx].mMessage,
105 strlen(sDOMErrorMsgMap[idx].mMessage));
106 *aCode = sDOMErrorMsgMap[idx].mCode;
107 return;
108 }
109 }
110
111 NS_WARNING("Huh, someone is throwing non-DOM errors using the DOM module!");
112
113 return;
114 }
115
116 nsresult
117 NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, nsACString& aName,
118 nsACString& aMessage, uint16_t* aCode)
119 {
120 nsCString name;
121 nsCString message;
122 uint16_t code = 0;
123 NSResultToNameAndMessage(aNSResult, name, message, &code);
124
125 if (!name.IsEmpty() && !message.IsEmpty()) {
126 aName = name;
127 aMessage = message;
128 if (aCode) {
129 *aCode = code;
130 }
131 return NS_OK;
132 }
133
134 return NS_ERROR_NOT_AVAILABLE;
135 }
136
137 namespace mozilla {
138 namespace dom {
139
140 bool Exception::sEverMadeOneFromFactory = false;
141
142 NS_IMPL_CLASSINFO(Exception, nullptr, nsIClassInfo::DOM_OBJECT,
143 NS_XPCEXCEPTION_CID)
144 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Exception)
145 NS_INTERFACE_MAP_ENTRY(nsIException)
146 NS_INTERFACE_MAP_ENTRY(nsIXPCException)
147 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIException)
148 NS_IMPL_QUERY_CLASSINFO(Exception)
149 NS_INTERFACE_MAP_END
150
151 NS_IMPL_CYCLE_COLLECTING_ADDREF(Exception)
152 NS_IMPL_CYCLE_COLLECTING_RELEASE(Exception)
153
154 NS_IMPL_CYCLE_COLLECTION_CLASS(Exception)
155
156 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Exception)
157 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
158 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInner)
159 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
160 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
161
162 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception)
163 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
164 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mThrownJSVal);
165 NS_IMPL_CYCLE_COLLECTION_TRACE_END
166
167 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Exception)
168 NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
169 NS_IMPL_CYCLE_COLLECTION_UNLINK(mInner)
170 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
171 tmp->mThrownJSVal.setNull();
172 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
173
174 NS_IMPL_CI_INTERFACE_GETTER(Exception, nsIXPCException)
175
176 Exception::Exception(const nsACString& aMessage,
177 nsresult aResult,
178 const nsACString& aName,
179 nsIStackFrame *aLocation,
180 nsISupports *aData)
181 : mResult(NS_OK),
182 mLineNumber(0),
183 mInitialized(false),
184 mHoldingJSVal(false)
185 {
186 SetIsDOMBinding();
187
188 // A little hack... The nsIGenericModule nsIClassInfo scheme relies on there
189 // having been at least one instance made via the factory. Otherwise, the
190 // shared factory/classinsance object never gets created and our QI getter
191 // for our instance's pointer to our nsIClassInfo will always return null.
192 // This is bad because it means that wrapped exceptions will never have a
193 // shared prototype. So... We force one to be created via the factory
194 // *once* and then go about our business.
195 if (!sEverMadeOneFromFactory) {
196 nsCOMPtr<nsIXPCException> e =
197 do_CreateInstance(XPC_EXCEPTION_CONTRACTID);
198 sEverMadeOneFromFactory = true;
199 }
200
201 nsCOMPtr<nsIStackFrame> location;
202 if (aLocation) {
203 location = aLocation;
204 } else {
205 location = GetCurrentJSStack();
206 // it is legal for there to be no active JS stack, if C++ code
207 // is operating on a JS-implemented interface pointer without
208 // having been called in turn by JS. This happens in the JS
209 // component loader, and will become more common as additional
210 // components are implemented in JS.
211 }
212 // We want to trim off any leading native 'dataless' frames
213 if (location) {
214 while (1) {
215 uint32_t language;
216 int32_t lineNumber;
217 if (NS_FAILED(location->GetLanguage(&language)) ||
218 language == nsIProgrammingLanguage::JAVASCRIPT ||
219 NS_FAILED(location->GetLineNumber(&lineNumber)) ||
220 lineNumber) {
221 break;
222 }
223 nsCOMPtr<nsIStackFrame> caller;
224 if (NS_FAILED(location->GetCaller(getter_AddRefs(caller))) || !caller) {
225 break;
226 }
227 location = caller;
228 }
229 }
230
231 Initialize(aMessage, aResult, aName, location, aData, nullptr);
232 }
233
234 Exception::Exception()
235 : mResult(NS_OK),
236 mLineNumber(-1),
237 mInitialized(false),
238 mHoldingJSVal(false)
239 {
240 }
241
242 Exception::~Exception()
243 {
244 if (mHoldingJSVal) {
245 MOZ_ASSERT(NS_IsMainThread());
246
247 mozilla::DropJSObjects(this);
248 }
249 }
250
251 bool
252 Exception::StealJSVal(JS::Value* aVp)
253 {
254 MOZ_ASSERT(NS_IsMainThread());
255
256 if (mHoldingJSVal) {
257 *aVp = mThrownJSVal;
258 mThrownJSVal.setNull();
259
260 mozilla::DropJSObjects(this);
261 mHoldingJSVal = false;
262 return true;
263 }
264
265 return false;
266 }
267
268 void
269 Exception::StowJSVal(JS::Value& aVp)
270 {
271 MOZ_ASSERT(NS_IsMainThread());
272
273 mThrownJSVal = aVp;
274 if (!mHoldingJSVal) {
275 mozilla::HoldJSObjects(this);
276 mHoldingJSVal = true;
277 }
278 }
279
280 /* readonly attribute AUTF8String message; */
281 NS_IMETHODIMP
282 Exception::GetMessageMoz(nsACString& aMessage)
283 {
284 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
285
286 aMessage.Assign(mMessage);
287 return NS_OK;
288 }
289
290 /* readonly attribute nsresult result; */
291 NS_IMETHODIMP
292 Exception::GetResult(nsresult* aResult)
293 {
294 NS_ENSURE_ARG_POINTER(aResult);
295 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
296
297 *aResult = mResult;
298 return NS_OK;
299 }
300
301 /* readonly attribute AUTF8String name; */
302 NS_IMETHODIMP
303 Exception::GetName(nsACString& aName)
304 {
305 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
306
307 if (!mName.IsEmpty()) {
308 aName.Assign(mName);
309 } else {
310 aName.Truncate();
311
312 const char* name = nullptr;
313 nsXPCException::NameAndFormatForNSResult(mResult, &name, nullptr);
314
315 if (name) {
316 aName.Assign(name);
317 }
318 }
319
320 return NS_OK;
321 }
322
323 /* readonly attribute AString filename; */
324 NS_IMETHODIMP
325 Exception::GetFilename(nsAString& aFilename)
326 {
327 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
328
329 if (mLocation) {
330 return mLocation->GetFilename(aFilename);
331 }
332
333 aFilename.Assign(mFilename);
334 return NS_OK;
335 }
336
337 /* readonly attribute uint32_t lineNumber; */
338 NS_IMETHODIMP
339 Exception::GetLineNumber(uint32_t *aLineNumber)
340 {
341 NS_ENSURE_ARG_POINTER(aLineNumber);
342 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
343
344 if (mLocation) {
345 int32_t lineno;
346 nsresult rv = mLocation->GetLineNumber(&lineno);
347 *aLineNumber = lineno;
348 return rv;
349 }
350
351 *aLineNumber = mLineNumber;
352 return NS_OK;
353 }
354
355 /* readonly attribute uint32_t columnNumber; */
356 NS_IMETHODIMP
357 Exception::GetColumnNumber(uint32_t* aColumnNumber)
358 {
359 NS_ENSURE_ARG_POINTER(aColumnNumber);
360 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
361
362 *aColumnNumber = 0;
363 return NS_OK;
364 }
365
366 /* readonly attribute nsIStackFrame location; */
367 NS_IMETHODIMP
368 Exception::GetLocation(nsIStackFrame** aLocation)
369 {
370 NS_ENSURE_ARG_POINTER(aLocation);
371 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
372
373 nsCOMPtr<nsIStackFrame> location = mLocation;
374 location.forget(aLocation);
375 return NS_OK;
376 }
377
378 /* readonly attribute nsISupports data; */
379 NS_IMETHODIMP
380 Exception::GetData(nsISupports** aData)
381 {
382 NS_ENSURE_ARG_POINTER(aData);
383 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
384
385 nsCOMPtr<nsISupports> data = mData;
386 data.forget(aData);
387 return NS_OK;
388 }
389
390 /* readonly attribute nsIException inner; */
391 NS_IMETHODIMP
392 Exception::GetInner(nsIException** aException)
393 {
394 NS_ENSURE_ARG_POINTER(aException);
395 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
396
397 nsCOMPtr<nsIException> inner = mInner;
398 inner.forget(aException);
399 return NS_OK;
400 }
401
402 /* AUTF8String toString (); */
403 NS_IMETHODIMP
404 Exception::ToString(nsACString& _retval)
405 {
406 NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
407
408 static const char defaultMsg[] = "<no message>";
409 static const char defaultLocation[] = "<unknown>";
410 static const char format[] =
411 "[Exception... \"%s\" nsresult: \"0x%x (%s)\" location: \"%s\" data: %s]";
412
413 nsCString location;
414
415 if (mLocation) {
416 // we need to free this if it does not fail
417 nsresult rv = mLocation->ToString(location);
418 NS_ENSURE_SUCCESS(rv, rv);
419 }
420
421 if (location.IsEmpty()) {
422 location.Assign(defaultLocation);
423 }
424
425 const char* msg = mMessage.IsEmpty() ? nullptr : mMessage.get();
426
427 const char* resultName = mName.IsEmpty() ? nullptr: mName.get();
428 if (!resultName &&
429 !nsXPCException::NameAndFormatForNSResult(mResult, &resultName,
430 (!msg) ? &msg : nullptr)) {
431 if (!msg) {
432 msg = defaultMsg;
433 }
434 resultName = "<unknown>";
435 }
436 const char* data = mData ? "yes" : "no";
437
438 _retval.Truncate();
439 _retval.AppendPrintf(format, msg, mResult, resultName,
440 location.get(), data);
441 return NS_OK;
442 }
443
444 /* void initialize (in AUTF8String aMessage, in nsresult aResult,
445 * in AUTF8String aName, in nsIStackFrame aLocation,
446 * in nsISupports aData, in nsIException aInner); */
447 NS_IMETHODIMP
448 Exception::Initialize(const nsACString& aMessage, nsresult aResult,
449 const nsACString& aName, nsIStackFrame *aLocation,
450 nsISupports *aData, nsIException *aInner)
451 {
452 NS_ENSURE_FALSE(mInitialized, NS_ERROR_ALREADY_INITIALIZED);
453
454 mMessage = aMessage;
455 mName = aName;
456 mResult = aResult;
457
458 if (aLocation) {
459 mLocation = aLocation;
460 } else {
461 nsresult rv;
462 nsXPConnect* xpc = nsXPConnect::XPConnect();
463 rv = xpc->GetCurrentJSStack(getter_AddRefs(mLocation));
464 if (NS_FAILED(rv)) {
465 return rv;
466 }
467 }
468
469 mData = aData;
470 mInner = aInner;
471
472 mInitialized = true;
473 return NS_OK;
474 }
475
476 JSObject*
477 Exception::WrapObject(JSContext* cx)
478 {
479 return ExceptionBinding::Wrap(cx, this);
480 }
481
482 void
483 Exception::GetMessageMoz(nsString& retval)
484 {
485 nsCString str;
486 #ifdef DEBUG
487 DebugOnly<nsresult> rv =
488 #endif
489 GetMessageMoz(str);
490 MOZ_ASSERT(NS_SUCCEEDED(rv));
491 CopyUTF8toUTF16(str, retval);
492 }
493
494 uint32_t
495 Exception::Result() const
496 {
497 return (uint32_t)mResult;
498 }
499
500 void
501 Exception::GetName(nsString& retval)
502 {
503 nsCString str;
504 #ifdef DEBUG
505 DebugOnly<nsresult> rv =
506 #endif
507 GetName(str);
508 MOZ_ASSERT(NS_SUCCEEDED(rv));
509 CopyUTF8toUTF16(str, retval);
510 }
511
512 uint32_t
513 Exception::LineNumber() const
514 {
515 if (mLocation) {
516 int32_t lineno;
517 if (NS_SUCCEEDED(mLocation->GetLineNumber(&lineno))) {
518 return lineno;
519 }
520 return 0;
521 }
522
523 return mLineNumber;
524 }
525
526 uint32_t
527 Exception::ColumnNumber() const
528 {
529 return 0;
530 }
531
532 already_AddRefed<nsIStackFrame>
533 Exception::GetLocation() const
534 {
535 nsCOMPtr<nsIStackFrame> location = mLocation;
536 return location.forget();
537 }
538
539 already_AddRefed<nsISupports>
540 Exception::GetInner() const
541 {
542 nsCOMPtr<nsIException> inner = mInner;
543 return inner.forget();
544 }
545
546 already_AddRefed<nsISupports>
547 Exception::GetData() const
548 {
549 nsCOMPtr<nsISupports> data = mData;
550 return data.forget();
551 }
552
553 void
554 Exception::Stringify(nsString& retval)
555 {
556 nsCString str;
557 #ifdef DEBUG
558 DebugOnly<nsresult> rv =
559 #endif
560 ToString(str);
561 MOZ_ASSERT(NS_SUCCEEDED(rv));
562 CopyUTF8toUTF16(str, retval);
563 }
564
565 NS_IMPL_ADDREF_INHERITED(DOMException, Exception)
566 NS_IMPL_RELEASE_INHERITED(DOMException, Exception)
567 NS_INTERFACE_MAP_BEGIN(DOMException)
568 NS_INTERFACE_MAP_ENTRY(nsIDOMDOMException)
569 NS_INTERFACE_MAP_END_INHERITING(Exception)
570
571 DOMException::DOMException(nsresult aRv, const nsACString& aMessage,
572 const nsACString& aName, uint16_t aCode)
573 : Exception(EmptyCString(), aRv, EmptyCString(), nullptr, nullptr),
574 mName(aName),
575 mMessage(aMessage),
576 mCode(aCode)
577 {
578 SetIsDOMBinding();
579 }
580
581 NS_IMETHODIMP
582 DOMException::GetCode(uint16_t* aCode)
583 {
584 NS_ENSURE_ARG_POINTER(aCode);
585 *aCode = mCode;
586
587 // Warn only when the code was changed (other than DOM Core)
588 // or the code is useless (zero)
589 if (NS_ERROR_GET_MODULE(mResult) != NS_ERROR_MODULE_DOM || !mCode) {
590 nsCOMPtr<nsIDocument> doc = nsContentUtils::GetDocumentFromCaller();
591 if (doc) {
592 doc->WarnOnceAbout(nsIDocument::eDOMExceptionCode);
593 }
594 }
595
596 return NS_OK;
597 }
598
599 NS_IMETHODIMP
600 DOMException::ToString(nsACString& aReturn)
601 {
602 aReturn.Truncate();
603
604 static const char defaultMsg[] = "<no message>";
605 static const char defaultLocation[] = "<unknown>";
606 static const char defaultName[] = "<unknown>";
607 static const char format[] =
608 "[Exception... \"%s\" code: \"%d\" nsresult: \"0x%x (%s)\" location: \"%s\"]";
609
610 nsAutoCString location;
611
612 if (mInner) {
613 nsString filename;
614 mInner->GetFilename(filename);
615
616 if (!filename.IsEmpty()) {
617 uint32_t line_nr = 0;
618
619 mInner->GetLineNumber(&line_nr);
620
621 char *temp = PR_smprintf("%s Line: %d",
622 NS_ConvertUTF16toUTF8(filename).get(),
623 line_nr);
624 if (temp) {
625 location.Assign(temp);
626 PR_smprintf_free(temp);
627 }
628 }
629 }
630
631 if (location.IsEmpty()) {
632 location = defaultLocation;
633 }
634
635 const char* msg = !mMessage.IsEmpty() ? mMessage.get() : defaultMsg;
636 const char* resultName = !mName.IsEmpty() ? mName.get() : defaultName;
637
638 aReturn.AppendPrintf(format, msg, mCode, mResult, resultName,
639 location.get());
640
641 return NS_OK;
642 }
643
644 void
645 DOMException::GetName(nsString& retval)
646 {
647 CopyUTF8toUTF16(mName, retval);
648 }
649
650 void
651 DOMException::GetMessageMoz(nsString& retval)
652 {
653 CopyUTF8toUTF16(mMessage, retval);
654 }
655
656 JSObject*
657 DOMException::WrapObject(JSContext* aCx)
658 {
659 return DOMExceptionBinding::Wrap(aCx, this);
660 }
661
662 /* static */already_AddRefed<DOMException>
663 DOMException::Create(nsresult aRv)
664 {
665 nsCString name;
666 nsCString message;
667 uint16_t code;
668 NSResultToNameAndMessage(aRv, name, message, &code);
669 nsRefPtr<DOMException> inst =
670 new DOMException(aRv, message, name, code);
671 return inst.forget();
672 }
673
674 } // namespace dom
675 } // namespace mozilla

mercurial