Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/DOMException.cpp
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#include "mozilla/dom/DOMException.h"
8
9
#include "mozilla/ArrayUtils.h"
10
#include "mozilla/HoldDropJSObjects.h"
11
#include "mozilla/dom/Exceptions.h"
12
#include "nsContentUtils.h"
13
#include "nsCOMPtr.h"
14
#include "nsIDocument.h"
15
#include "nsIException.h"
16
#include "nsMemory.h"
17
#include "xpcprivate.h"
18
19
#include "mozilla/dom/DOMExceptionBinding.h"
20
#include "mozilla/ErrorResult.h"
21
22
using namespace mozilla;
23
using namespace mozilla::dom;
24
25
enum DOM4ErrorTypeCodeMap {
26
  /* DOM4 errors from http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#domexception */
27
  IndexSizeError             = DOMException_Binding::INDEX_SIZE_ERR,
28
  HierarchyRequestError      = DOMException_Binding::HIERARCHY_REQUEST_ERR,
29
  WrongDocumentError         = DOMException_Binding::WRONG_DOCUMENT_ERR,
30
  InvalidCharacterError      = DOMException_Binding::INVALID_CHARACTER_ERR,
31
  NoModificationAllowedError = DOMException_Binding::NO_MODIFICATION_ALLOWED_ERR,
32
  NotFoundError              = DOMException_Binding::NOT_FOUND_ERR,
33
  NotSupportedError          = DOMException_Binding::NOT_SUPPORTED_ERR,
34
  // Can't remove until setNamedItem is removed
35
  InUseAttributeError        = DOMException_Binding::INUSE_ATTRIBUTE_ERR,
36
  InvalidStateError          = DOMException_Binding::INVALID_STATE_ERR,
37
  SyntaxError                = DOMException_Binding::SYNTAX_ERR,
38
  InvalidModificationError   = DOMException_Binding::INVALID_MODIFICATION_ERR,
39
  NamespaceError             = DOMException_Binding::NAMESPACE_ERR,
40
  InvalidAccessError         = DOMException_Binding::INVALID_ACCESS_ERR,
41
  TypeMismatchError          = DOMException_Binding::TYPE_MISMATCH_ERR,
42
  SecurityError              = DOMException_Binding::SECURITY_ERR,
43
  NetworkError               = DOMException_Binding::NETWORK_ERR,
44
  AbortError                 = DOMException_Binding::ABORT_ERR,
45
  URLMismatchError           = DOMException_Binding::URL_MISMATCH_ERR,
46
  QuotaExceededError         = DOMException_Binding::QUOTA_EXCEEDED_ERR,
47
  TimeoutError               = DOMException_Binding::TIMEOUT_ERR,
48
  InvalidNodeTypeError       = DOMException_Binding::INVALID_NODE_TYPE_ERR,
49
  DataCloneError             = DOMException_Binding::DATA_CLONE_ERR,
50
  InvalidPointerId           = 0,
51
  EncodingError              = 0,
52
53
  /* XXX Should be JavaScript native errors */
54
  TypeError                  = 0,
55
  RangeError                 = 0,
56
57
  /* IndexedDB errors http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#exceptions */
58
  UnknownError             = 0,
59
  ConstraintError          = 0,
60
  DataError                = 0,
61
  TransactionInactiveError = 0,
62
  ReadOnlyError            = 0,
63
  VersionError             = 0,
64
65
  /* File API errors http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException */
66
  NotReadableError         = 0,
67
68
  /* FileHandle API errors */
69
  FileHandleInactiveError = 0,
70
71
  /* WebCrypto errors https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#dfn-DataError */
72
  OperationError           = 0,
73
74
  /* Push API errors */
75
  NotAllowedError          = 0,
76
};
77
78
#define DOM4_MSG_DEF(name, message, nsresult) {(nsresult), name, #name, message},
79
#define DOM_MSG_DEF(val, message) {(val), NS_ERROR_GET_CODE(val), #val, message},
80
81
static constexpr struct ResultStruct
82
{
83
  nsresult mNSResult;
84
  uint16_t mCode;
85
  const char* mName;
86
  const char* mMessage;
87
} sDOMErrorMsgMap[] = {
88
#include "domerr.msg"
89
};
90
91
#undef DOM4_MSG_DEF
92
#undef DOM_MSG_DEF
93
94
static void
95
NSResultToNameAndMessage(nsresult aNSResult,
96
                         nsCString& aName,
97
                         nsCString& aMessage,
98
                         uint16_t* aCode)
99
0
{
100
0
  aName.Truncate();
101
0
  aMessage.Truncate();
102
0
  *aCode = 0;
103
0
  for (uint32_t idx = 0; idx < ArrayLength(sDOMErrorMsgMap); idx++) {
104
0
    if (aNSResult == sDOMErrorMsgMap[idx].mNSResult) {
105
0
      aName.Rebind(sDOMErrorMsgMap[idx].mName,
106
0
                   strlen(sDOMErrorMsgMap[idx].mName));
107
0
      aMessage.Rebind(sDOMErrorMsgMap[idx].mMessage,
108
0
                   strlen(sDOMErrorMsgMap[idx].mMessage));
109
0
      *aCode = sDOMErrorMsgMap[idx].mCode;
110
0
      return;
111
0
    }
112
0
  }
113
0
114
0
  NS_WARNING("Huh, someone is throwing non-DOM errors using the DOM module!");
115
0
}
116
117
nsresult
118
NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, nsACString& aName,
119
                                   nsACString& aMessage, uint16_t* aCode)
120
0
{
121
0
  nsCString name;
122
0
  nsCString message;
123
0
  uint16_t code = 0;
124
0
  NSResultToNameAndMessage(aNSResult, name, message, &code);
125
0
126
0
  if (!name.IsEmpty() && !message.IsEmpty()) {
127
0
    aName = name;
128
0
    aMessage = message;
129
0
    if (aCode) {
130
0
      *aCode = code;
131
0
    }
132
0
    return NS_OK;
133
0
  }
134
0
135
0
  return NS_ERROR_NOT_AVAILABLE;
136
0
}
137
138
namespace mozilla {
139
namespace dom {
140
141
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Exception)
142
0
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
143
0
  NS_INTERFACE_MAP_ENTRY(Exception)
144
0
  NS_INTERFACE_MAP_ENTRY(nsIException)
145
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
146
0
NS_INTERFACE_MAP_END
147
148
NS_IMPL_CYCLE_COLLECTING_ADDREF(Exception)
149
NS_IMPL_CYCLE_COLLECTING_RELEASE(Exception)
150
151
NS_IMPL_CYCLE_COLLECTION_CLASS(Exception)
152
153
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Exception)
154
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
155
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData)
156
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
157
158
0
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Exception)
159
0
  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
160
0
  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mThrownJSVal)
161
0
NS_IMPL_CYCLE_COLLECTION_TRACE_END
162
163
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Exception)
164
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
165
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mData)
166
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
167
0
  tmp->mThrownJSVal.setNull();
168
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
169
170
Exception::Exception(const nsACString& aMessage,
171
                     nsresult aResult,
172
                     const nsACString& aName,
173
                     nsIStackFrame *aLocation,
174
                     nsISupports *aData)
175
  : mMessage(aMessage)
176
  , mResult(aResult)
177
  , mName(aName)
178
  , mData(aData)
179
  , mHoldingJSVal(false)
180
0
{
181
0
  if (aLocation) {
182
0
    mLocation = aLocation;
183
0
  } else {
184
0
    mLocation = GetCurrentJSStack();
185
0
    // it is legal for there to be no active JS stack, if C++ code
186
0
    // is operating on a JS-implemented interface pointer without
187
0
    // having been called in turn by JS.  This happens in the JS
188
0
    // component loader.
189
0
  }
190
0
}
191
192
Exception::~Exception()
193
0
{
194
0
  if (mHoldingJSVal) {
195
0
    MOZ_ASSERT(NS_IsMainThread());
196
0
197
0
    mozilla::DropJSObjects(this);
198
0
  }
199
0
}
200
201
bool
202
Exception::StealJSVal(JS::Value* aVp)
203
0
{
204
0
  MOZ_ASSERT(NS_IsMainThread());
205
0
206
0
  if (mHoldingJSVal) {
207
0
    *aVp = mThrownJSVal;
208
0
    mThrownJSVal.setNull();
209
0
210
0
    mozilla::DropJSObjects(this);
211
0
    mHoldingJSVal = false;
212
0
    return true;
213
0
  }
214
0
215
0
  return false;
216
0
}
217
218
void
219
Exception::StowJSVal(JS::Value& aVp)
220
0
{
221
0
  MOZ_ASSERT(NS_IsMainThread());
222
0
223
0
  mThrownJSVal = aVp;
224
0
  if (!mHoldingJSVal) {
225
0
    mozilla::HoldJSObjects(this);
226
0
    mHoldingJSVal = true;
227
0
  }
228
0
}
229
230
void
231
Exception::GetName(nsAString& aName)
232
0
{
233
0
  if (!mName.IsEmpty()) {
234
0
    CopyUTF8toUTF16(mName, aName);
235
0
  } else {
236
0
    aName.Truncate();
237
0
238
0
    const char* name = nullptr;
239
0
    nsXPCException::NameAndFormatForNSResult(mResult, &name, nullptr);
240
0
241
0
    if (name) {
242
0
      CopyUTF8toUTF16(mozilla::MakeStringSpan(name), aName);
243
0
    }
244
0
  }
245
0
}
246
247
void
248
Exception::GetFilename(JSContext* aCx, nsAString& aFilename)
249
0
{
250
0
  if (mLocation) {
251
0
    mLocation->GetFilename(aCx, aFilename);
252
0
    return;
253
0
  }
254
0
255
0
  aFilename.Truncate();
256
0
}
257
258
void
259
Exception::ToString(JSContext* aCx, nsACString& _retval)
260
0
{
261
0
  static const char defaultMsg[] = "<no message>";
262
0
  static const char defaultLocation[] = "<unknown>";
263
0
  static const char format[] =
264
0
"[Exception... \"%s\"  nsresult: \"0x%" PRIx32 " (%s)\"  location: \"%s\"  data: %s]";
265
0
266
0
  nsCString location;
267
0
268
0
  if (mLocation) {
269
0
    // we need to free this if it does not fail
270
0
    mLocation->ToString(aCx, location);
271
0
  }
272
0
273
0
  if (location.IsEmpty()) {
274
0
    location.Assign(defaultLocation);
275
0
  }
276
0
277
0
  const char* msg = mMessage.IsEmpty() ? nullptr : mMessage.get();
278
0
279
0
  const char* resultName = mName.IsEmpty() ? nullptr: mName.get();
280
0
  if (!resultName &&
281
0
      !nsXPCException::NameAndFormatForNSResult(mResult, &resultName,
282
0
                                                (!msg) ? &msg : nullptr)) {
283
0
    if (!msg) {
284
0
      msg = defaultMsg;
285
0
    }
286
0
    resultName = "<unknown>";
287
0
  }
288
0
  const char* data = mData ? "yes" : "no";
289
0
290
0
  _retval.Truncate();
291
0
  _retval.AppendPrintf(format, msg, static_cast<uint32_t>(mResult), resultName,
292
0
                       location.get(), data);
293
0
}
294
295
JSObject*
296
Exception::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto)
297
0
{
298
0
  return Exception_Binding::Wrap(cx, this, aGivenProto);
299
0
}
300
301
void
302
Exception::GetMessageMoz(nsString& retval)
303
0
{
304
0
  CopyUTF8toUTF16(mMessage, retval);
305
0
}
306
307
uint32_t
308
Exception::Result() const
309
0
{
310
0
  return (uint32_t)mResult;
311
0
}
312
313
uint32_t
314
Exception::LineNumber(JSContext* aCx) const
315
0
{
316
0
  if (mLocation) {
317
0
    return mLocation->GetLineNumber(aCx);
318
0
  }
319
0
320
0
  return 0;
321
0
}
322
323
uint32_t
324
Exception::ColumnNumber() const
325
0
{
326
0
  return 0;
327
0
}
328
329
already_AddRefed<nsIStackFrame>
330
Exception::GetLocation() const
331
0
{
332
0
  nsCOMPtr<nsIStackFrame> location = mLocation;
333
0
  return location.forget();
334
0
}
335
336
nsISupports*
337
Exception::GetData() const
338
0
{
339
0
  return mData;
340
0
}
341
342
void
343
Exception::GetStack(JSContext* aCx, nsAString& aStack) const
344
0
{
345
0
  if (mLocation) {
346
0
    mLocation->GetFormattedStack(aCx, aStack);
347
0
  }
348
0
}
349
350
void
351
Exception::Stringify(JSContext* aCx, nsString& retval)
352
0
{
353
0
  nsCString str;
354
0
  ToString(aCx, str);
355
0
  CopyUTF8toUTF16(str, retval);
356
0
}
357
358
DOMException::DOMException(nsresult aRv, const nsACString& aMessage,
359
                           const nsACString& aName, uint16_t aCode)
360
  : Exception(aMessage, aRv, aName, nullptr, nullptr),
361
    mCode(aCode)
362
0
{
363
0
}
364
365
void
366
DOMException::ToString(JSContext* aCx, nsACString& aReturn)
367
0
{
368
0
  aReturn.Truncate();
369
0
370
0
  static const char defaultMsg[] = "<no message>";
371
0
  static const char defaultLocation[] = "<unknown>";
372
0
  static const char defaultName[] = "<unknown>";
373
0
  static const char format[] =
374
0
    "[Exception... \"%s\"  code: \"%d\" nsresult: \"0x%" PRIx32 " (%s)\"  location: \"%s\"]";
375
0
376
0
  nsAutoCString location;
377
0
378
0
  if (location.IsEmpty()) {
379
0
    location = defaultLocation;
380
0
  }
381
0
382
0
  const char* msg = !mMessage.IsEmpty() ? mMessage.get() : defaultMsg;
383
0
  const char* resultName = !mName.IsEmpty() ? mName.get() : defaultName;
384
0
385
0
  aReturn.AppendPrintf(format, msg, mCode, static_cast<uint32_t>(mResult), resultName,
386
0
                       location.get());
387
0
}
388
389
void
390
DOMException::GetName(nsString& retval)
391
0
{
392
0
  CopyUTF8toUTF16(mName, retval);
393
0
}
394
395
already_AddRefed<DOMException>
396
DOMException::Constructor(GlobalObject& /* unused */,
397
                          const nsAString& aMessage,
398
                          const Optional<nsAString>& aName,
399
                          ErrorResult& aError)
400
0
{
401
0
  nsresult exceptionResult = NS_OK;
402
0
  uint16_t exceptionCode = 0;
403
0
  nsCString name(NS_LITERAL_CSTRING("Error"));
404
0
405
0
  if (aName.WasPassed()) {
406
0
    CopyUTF16toUTF8(aName.Value(), name);
407
0
    for (uint32_t idx = 0; idx < ArrayLength(sDOMErrorMsgMap); idx++) {
408
0
      if (name.EqualsASCII(sDOMErrorMsgMap[idx].mName)) {
409
0
        exceptionResult = sDOMErrorMsgMap[idx].mNSResult;
410
0
        exceptionCode = sDOMErrorMsgMap[idx].mCode;
411
0
        break;
412
0
      }
413
0
    }
414
0
  }
415
0
416
0
  RefPtr<DOMException> retval =
417
0
    new DOMException(exceptionResult,
418
0
                     NS_ConvertUTF16toUTF8(aMessage),
419
0
                     name,
420
0
                     exceptionCode);
421
0
  return retval.forget();
422
0
}
423
424
JSObject*
425
DOMException::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
426
0
{
427
0
  return DOMException_Binding::Wrap(aCx, this, aGivenProto);
428
0
}
429
430
/* static */already_AddRefed<DOMException>
431
DOMException::Create(nsresult aRv)
432
0
{
433
0
  nsCString name;
434
0
  nsCString message;
435
0
  uint16_t code;
436
0
  NSResultToNameAndMessage(aRv, name, message, &code);
437
0
  RefPtr<DOMException> inst =
438
0
    new DOMException(aRv, message, name, code);
439
0
  return inst.forget();
440
0
}
441
442
/* static */already_AddRefed<DOMException>
443
DOMException::Create(nsresult aRv, const nsACString& aMessage)
444
0
{
445
0
  nsCString name;
446
0
  nsCString message;
447
0
  uint16_t code;
448
0
  NSResultToNameAndMessage(aRv, name, message, &code);
449
0
  RefPtr<DOMException> inst =
450
0
    new DOMException(aRv, aMessage, name, code);
451
0
  return inst.forget();
452
0
}
453
454
} // namespace dom
455
} // namespace mozilla