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/. */
8 * nsIScriptError implementation.
11 #include "nsScriptError.h"
12 #include "js/Printf.h"
13 #include "MainThreadUtils.h"
14 #include "mozilla/Assertions.h"
15 #include "nsContentUtils.h"
16 #include "nsGlobalWindowInner.h"
17 #include "nsNetUtil.h"
18 #include "nsPIDOMWindow.h"
19 #include "nsIMutableArray.h"
20 #include "nsIScriptError.h"
21 #include "mozilla/BasePrincipal.h"
23 nsScriptErrorBase::nsScriptErrorBase()
30 mMicroSecondTimeStamp(0),
31 mInitializedOnMainThread(false),
32 mIsFromPrivateWindow(false),
33 mIsFromChromeContext(false),
34 mIsPromiseRejection(false),
35 mIsForwardedFromContentProcess(false) {}
37 nsScriptErrorBase::~nsScriptErrorBase() = default;
39 void nsScriptErrorBase::AddNote(nsIScriptErrorNote
* note
) {
40 mNotes
.AppendObject(note
);
43 void nsScriptErrorBase::InitializeOnMainThread() {
44 MOZ_ASSERT(NS_IsMainThread());
45 MOZ_ASSERT(!mInitializedOnMainThread
);
48 nsGlobalWindowInner
* window
=
49 nsGlobalWindowInner::GetInnerWindowWithId(mInnerWindowID
);
51 nsPIDOMWindowOuter
* outer
= window
->GetOuterWindow();
52 if (outer
) mOuterWindowID
= outer
->WindowID();
53 mIsFromChromeContext
= ComputeIsFromChromeContext(window
);
54 mIsFromPrivateWindow
= ComputeIsFromPrivateWindow(window
);
58 mInitializedOnMainThread
= true;
62 nsScriptErrorBase::InitSourceId(uint32_t value
) {
67 // nsIConsoleMessage methods
69 nsScriptErrorBase::GetMessageMoz(nsAString
& aMessage
) {
70 nsAutoCString message
;
71 nsresult rv
= ToString(message
);
76 CopyUTF8toUTF16(message
, aMessage
);
81 nsScriptErrorBase::GetLogLevel(uint32_t* aLogLevel
) {
82 if (mFlags
& (uint32_t)nsIScriptError::infoFlag
) {
83 *aLogLevel
= nsIConsoleMessage::info
;
84 } else if (mFlags
& (uint32_t)nsIScriptError::warningFlag
) {
85 *aLogLevel
= nsIConsoleMessage::warn
;
87 *aLogLevel
= nsIConsoleMessage::error
;
92 // nsIScriptError methods
94 nsScriptErrorBase::GetErrorMessage(nsAString
& aResult
) {
95 aResult
.Assign(mMessage
);
100 nsScriptErrorBase::GetSourceName(nsAString
& aResult
) {
101 aResult
.Assign(mSourceName
);
106 nsScriptErrorBase::GetCssSelectors(nsAString
& aResult
) {
107 aResult
.Assign(mCssSelectors
);
112 nsScriptErrorBase::SetCssSelectors(const nsAString
& aCssSelectors
) {
113 mCssSelectors
= aCssSelectors
;
118 nsScriptErrorBase::GetSourceId(uint32_t* result
) {
124 nsScriptErrorBase::GetSourceLine(nsAString
& aResult
) {
125 aResult
.Assign(mSourceLine
);
130 nsScriptErrorBase::GetLineNumber(uint32_t* result
) {
131 *result
= mLineNumber
;
136 nsScriptErrorBase::GetColumnNumber(uint32_t* result
) {
137 *result
= mColumnNumber
;
142 nsScriptErrorBase::GetFlags(uint32_t* result
) {
148 nsScriptErrorBase::GetCategory(char** result
) {
149 *result
= ToNewCString(mCategory
);
154 nsScriptErrorBase::GetHasException(bool* aHasException
) {
155 *aHasException
= false;
160 nsScriptErrorBase::GetException(JS::MutableHandle
<JS::Value
> aException
) {
161 aException
.setUndefined();
166 nsScriptErrorBase::SetException(JS::Handle
<JS::Value
> aStack
) {
167 return NS_ERROR_NOT_IMPLEMENTED
;
171 nsScriptErrorBase::GetStack(JS::MutableHandle
<JS::Value
> aStack
) {
172 aStack
.setUndefined();
177 nsScriptErrorBase::SetStack(JS::Handle
<JS::Value
> aStack
) { return NS_OK
; }
180 nsScriptErrorBase::GetStackGlobal(JS::MutableHandle
<JS::Value
> aStackGlobal
) {
181 aStackGlobal
.setUndefined();
186 nsScriptErrorBase::GetErrorMessageName(nsAString
& aErrorMessageName
) {
187 aErrorMessageName
= mMessageName
;
192 nsScriptErrorBase::SetErrorMessageName(const nsAString
& aErrorMessageName
) {
193 mMessageName
= aErrorMessageName
;
197 static void AssignSourceNameHelper(nsString
& aSourceNameDest
,
198 const nsAString
& aSourceNameSrc
) {
199 if (aSourceNameSrc
.IsEmpty()) return;
201 aSourceNameDest
.Assign(aSourceNameSrc
);
203 nsCOMPtr
<nsIURI
> uri
;
205 if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri
), aSourceNameSrc
)) &&
206 NS_SUCCEEDED(uri
->GetPassword(pass
)) && !pass
.IsEmpty()) {
207 NS_GetSanitizedURIStringFromURI(uri
, aSourceNameDest
);
211 static void AssignSourceNameHelper(nsIURI
* aSourceURI
,
212 nsString
& aSourceNameDest
) {
213 if (!aSourceURI
) return;
215 if (NS_FAILED(NS_GetSanitizedURIStringFromURI(aSourceURI
, aSourceNameDest
))) {
216 aSourceNameDest
.AssignLiteral("[nsIURI::GetSpec failed]");
221 nsScriptErrorBase::Init(const nsAString
& message
, const nsAString
& sourceName
,
222 const nsAString
& sourceLine
, uint32_t lineNumber
,
223 uint32_t columnNumber
, uint32_t flags
,
224 const nsACString
& category
, bool fromPrivateWindow
,
225 bool fromChromeContext
) {
226 InitializationHelper(message
, sourceLine
, lineNumber
, columnNumber
, flags
,
227 category
, 0 /* inner Window ID */, fromChromeContext
);
228 AssignSourceNameHelper(mSourceName
, sourceName
);
230 mIsFromPrivateWindow
= fromPrivateWindow
;
231 mIsFromChromeContext
= fromChromeContext
;
235 void nsScriptErrorBase::InitializationHelper(
236 const nsAString
& message
, const nsAString
& sourceLine
, uint32_t lineNumber
,
237 uint32_t columnNumber
, uint32_t flags
, const nsACString
& category
,
238 uint64_t aInnerWindowID
, bool aFromChromeContext
) {
239 mMessage
.Assign(message
);
240 mLineNumber
= lineNumber
;
241 mSourceLine
.Assign(sourceLine
);
242 mColumnNumber
= columnNumber
;
244 mCategory
= category
;
245 mMicroSecondTimeStamp
= JS_Now();
246 mInnerWindowID
= aInnerWindowID
;
247 mIsFromChromeContext
= aFromChromeContext
;
251 nsScriptErrorBase::InitWithWindowID(const nsAString
& message
,
252 const nsAString
& sourceName
,
253 const nsAString
& sourceLine
,
254 uint32_t lineNumber
, uint32_t columnNumber
,
255 uint32_t flags
, const nsACString
& category
,
256 uint64_t aInnerWindowID
,
257 bool aFromChromeContext
) {
258 InitializationHelper(message
, sourceLine
, lineNumber
, columnNumber
, flags
,
259 category
, aInnerWindowID
, aFromChromeContext
);
260 AssignSourceNameHelper(mSourceName
, sourceName
);
262 if (aInnerWindowID
&& NS_IsMainThread()) InitializeOnMainThread();
268 nsScriptErrorBase::InitWithSanitizedSource(
269 const nsAString
& message
, const nsAString
& sourceName
,
270 const nsAString
& sourceLine
, uint32_t lineNumber
, uint32_t columnNumber
,
271 uint32_t flags
, const nsACString
& category
, uint64_t aInnerWindowID
,
272 bool aFromChromeContext
) {
273 InitializationHelper(message
, sourceLine
, lineNumber
, columnNumber
, flags
,
274 category
, aInnerWindowID
, aFromChromeContext
);
275 mSourceName
= sourceName
;
277 if (aInnerWindowID
&& NS_IsMainThread()) InitializeOnMainThread();
283 nsScriptErrorBase::InitWithSourceURI(const nsAString
& message
,
285 const nsAString
& sourceLine
,
286 uint32_t lineNumber
, uint32_t columnNumber
,
287 uint32_t flags
, const nsACString
& category
,
288 uint64_t aInnerWindowID
,
289 bool aFromChromeContext
) {
290 InitializationHelper(message
, sourceLine
, lineNumber
, columnNumber
, flags
,
291 category
, aInnerWindowID
, aFromChromeContext
);
292 AssignSourceNameHelper(sourceURI
, mSourceName
);
294 if (aInnerWindowID
&& NS_IsMainThread()) InitializeOnMainThread();
299 static nsresult
ToStringHelper(const char* aSeverity
, const nsString
& aMessage
,
300 const nsString
& aSourceName
,
301 const nsString
* aSourceLine
,
302 uint32_t aLineNumber
, uint32_t aColumnNumber
,
303 nsACString
& /*UTF8*/ aResult
) {
304 static const char format0
[] =
305 "[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]";
306 static const char format1
[] = "[%s: \"%s\" {file: \"%s\" line: %d}]";
307 static const char format2
[] = "[%s: \"%s\"]";
309 JS::UniqueChars temp
;
310 char* tempMessage
= nullptr;
311 char* tempSourceName
= nullptr;
312 char* tempSourceLine
= nullptr;
314 if (!aMessage
.IsEmpty()) tempMessage
= ToNewUTF8String(aMessage
);
315 if (!aSourceName
.IsEmpty())
316 // Use at most 512 characters from mSourceName.
317 tempSourceName
= ToNewUTF8String(StringHead(aSourceName
, 512));
318 if (aSourceLine
&& !aSourceLine
->IsEmpty())
319 // Use at most 512 characters from mSourceLine.
320 tempSourceLine
= ToNewUTF8String(StringHead(*aSourceLine
, 512));
322 if (nullptr != tempSourceName
&& nullptr != tempSourceLine
) {
323 temp
= JS_smprintf(format0
, aSeverity
, tempMessage
, tempSourceName
,
324 aLineNumber
, aColumnNumber
, tempSourceLine
);
325 } else if (!aSourceName
.IsEmpty()) {
326 temp
= JS_smprintf(format1
, aSeverity
, tempMessage
, tempSourceName
,
329 temp
= JS_smprintf(format2
, aSeverity
, tempMessage
);
332 if (nullptr != tempMessage
) free(tempMessage
);
333 if (nullptr != tempSourceName
) free(tempSourceName
);
334 if (nullptr != tempSourceLine
) free(tempSourceLine
);
336 if (!temp
) return NS_ERROR_OUT_OF_MEMORY
;
338 aResult
.Assign(temp
.get());
343 nsScriptErrorBase::ToString(nsACString
& /*UTF8*/ aResult
) {
344 static const char error
[] = "JavaScript Error";
345 static const char warning
[] = "JavaScript Warning";
347 const char* severity
=
348 !(mFlags
& nsIScriptError::warningFlag
) ? error
: warning
;
350 return ToStringHelper(severity
, mMessage
, mSourceName
, &mSourceLine
,
351 mLineNumber
, mColumnNumber
, aResult
);
355 nsScriptErrorBase::GetOuterWindowID(uint64_t* aOuterWindowID
) {
356 NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread
,
357 "This can't be safely determined off the main thread, "
358 "returning an inaccurate value!");
360 if (!mInitializedOnMainThread
&& NS_IsMainThread()) {
361 InitializeOnMainThread();
364 *aOuterWindowID
= mOuterWindowID
;
369 nsScriptErrorBase::GetInnerWindowID(uint64_t* aInnerWindowID
) {
370 *aInnerWindowID
= mInnerWindowID
;
375 nsScriptErrorBase::GetTimeStamp(int64_t* aTimeStamp
) {
376 *aTimeStamp
= mMicroSecondTimeStamp
/ 1000;
381 nsScriptErrorBase::GetMicroSecondTimeStamp(int64_t* aTimeStamp
) {
382 *aTimeStamp
= mMicroSecondTimeStamp
;
387 nsScriptErrorBase::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow
) {
388 NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread
,
389 "This can't be safely determined off the main thread, "
390 "returning an inaccurate value!");
392 if (!mInitializedOnMainThread
&& NS_IsMainThread()) {
393 InitializeOnMainThread();
396 *aIsFromPrivateWindow
= mIsFromPrivateWindow
;
401 nsScriptErrorBase::GetIsFromChromeContext(bool* aIsFromChromeContext
) {
402 NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread
,
403 "This can't be safely determined off the main thread, "
404 "returning an inaccurate value!");
405 if (!mInitializedOnMainThread
&& NS_IsMainThread()) {
406 InitializeOnMainThread();
408 *aIsFromChromeContext
= mIsFromChromeContext
;
413 nsScriptErrorBase::GetIsPromiseRejection(bool* aIsPromiseRejection
) {
414 *aIsPromiseRejection
= mIsPromiseRejection
;
419 nsScriptErrorBase::InitIsPromiseRejection(bool aIsPromiseRejection
) {
420 mIsPromiseRejection
= aIsPromiseRejection
;
425 nsScriptErrorBase::GetIsForwardedFromContentProcess(
426 bool* aIsForwardedFromContentProcess
) {
427 *aIsForwardedFromContentProcess
= mIsForwardedFromContentProcess
;
432 nsScriptErrorBase::SetIsForwardedFromContentProcess(
433 bool aIsForwardedFromContentProcess
) {
434 mIsForwardedFromContentProcess
= aIsForwardedFromContentProcess
;
439 nsScriptErrorBase::GetNotes(nsIArray
** aNotes
) {
441 nsCOMPtr
<nsIMutableArray
> array
= do_CreateInstance(NS_ARRAY_CONTRACTID
, &rv
);
442 NS_ENSURE_SUCCESS(rv
, rv
);
444 uint32_t len
= mNotes
.Length();
445 for (uint32_t i
= 0; i
< len
; i
++) array
->AppendElement(mNotes
[i
]);
446 array
.forget(aNotes
);
452 bool nsScriptErrorBase::ComputeIsFromPrivateWindow(
453 nsGlobalWindowInner
* aWindow
) {
454 // Never mark exceptions from chrome windows as having come from private
455 // windows, since we always want them to be reported.
456 nsIPrincipal
* winPrincipal
= aWindow
->GetPrincipal();
457 return aWindow
->IsPrivateBrowsing() && !winPrincipal
->IsSystemPrincipal();
461 bool nsScriptErrorBase::ComputeIsFromChromeContext(
462 nsGlobalWindowInner
* aWindow
) {
463 nsIPrincipal
* winPrincipal
= aWindow
->GetPrincipal();
464 return winPrincipal
->IsSystemPrincipal();
467 NS_IMPL_ISUPPORTS(nsScriptError
, nsIConsoleMessage
, nsIScriptError
)
469 nsScriptErrorNote::nsScriptErrorNote()
470 : mSourceId(0), mLineNumber(0), mColumnNumber(0) {}
472 nsScriptErrorNote::~nsScriptErrorNote() = default;
474 void nsScriptErrorNote::Init(const nsAString
& message
,
475 const nsAString
& sourceName
, uint32_t sourceId
,
476 uint32_t lineNumber
, uint32_t columnNumber
) {
477 mMessage
.Assign(message
);
478 AssignSourceNameHelper(mSourceName
, sourceName
);
479 mSourceId
= sourceId
;
480 mLineNumber
= lineNumber
;
481 mColumnNumber
= columnNumber
;
484 // nsIScriptErrorNote methods
486 nsScriptErrorNote::GetErrorMessage(nsAString
& aResult
) {
487 aResult
.Assign(mMessage
);
492 nsScriptErrorNote::GetSourceName(nsAString
& aResult
) {
493 aResult
.Assign(mSourceName
);
498 nsScriptErrorNote::GetSourceId(uint32_t* result
) {
504 nsScriptErrorNote::GetLineNumber(uint32_t* result
) {
505 *result
= mLineNumber
;
510 nsScriptErrorNote::GetColumnNumber(uint32_t* result
) {
511 *result
= mColumnNumber
;
516 nsScriptErrorNote::ToString(nsACString
& /*UTF8*/ aResult
) {
517 return ToStringHelper("JavaScript Note", mMessage
, mSourceName
, nullptr,
518 mLineNumber
, mColumnNumber
, aResult
);
521 NS_IMPL_ISUPPORTS(nsScriptErrorNote
, nsIScriptErrorNote
)