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()
36 mMicroSecondTimeStamp(0),
37 mInitializedOnMainThread(false),
38 mIsFromPrivateWindow(false),
39 mIsFromChromeContext(false),
40 mIsPromiseRejection(false),
41 mIsForwardedFromContentProcess(false) {}
43 nsScriptErrorBase::~nsScriptErrorBase() = default;
45 void nsScriptErrorBase::AddNote(nsIScriptErrorNote
* note
) {
46 mNotes
.AppendObject(note
);
49 void nsScriptErrorBase::InitializeOnMainThread() {
50 MOZ_ASSERT(NS_IsMainThread());
51 MOZ_ASSERT(!mInitializedOnMainThread
);
54 nsGlobalWindowInner
* window
=
55 nsGlobalWindowInner::GetInnerWindowWithId(mInnerWindowID
);
57 nsPIDOMWindowOuter
* outer
= window
->GetOuterWindow();
58 if (outer
) mOuterWindowID
= outer
->WindowID();
59 mIsFromChromeContext
= ComputeIsFromChromeContext(window
);
60 mIsFromPrivateWindow
= ComputeIsFromPrivateWindow(window
);
64 mInitializedOnMainThread
= true;
68 nsScriptErrorBase::InitSourceId(uint32_t value
) {
73 // nsIConsoleMessage methods
75 nsScriptErrorBase::GetMessageMoz(nsAString
& aMessage
) {
76 nsAutoCString message
;
77 nsresult rv
= ToString(message
);
82 CopyUTF8toUTF16(message
, aMessage
);
87 nsScriptErrorBase::GetLogLevel(uint32_t* aLogLevel
) {
88 if (mFlags
& (uint32_t)nsIScriptError::infoFlag
) {
89 *aLogLevel
= nsIConsoleMessage::info
;
90 } else if (mFlags
& (uint32_t)nsIScriptError::warningFlag
) {
91 *aLogLevel
= nsIConsoleMessage::warn
;
93 *aLogLevel
= nsIConsoleMessage::error
;
98 // nsIScriptError methods
100 nsScriptErrorBase::GetErrorMessage(nsAString
& aResult
) {
101 aResult
.Assign(mMessage
);
106 nsScriptErrorBase::GetSourceName(nsAString
& aResult
) {
107 aResult
.Assign(mSourceName
);
112 nsScriptErrorBase::GetCssSelectors(nsAString
& aResult
) {
113 aResult
.Assign(mCssSelectors
);
118 nsScriptErrorBase::SetCssSelectors(const nsAString
& aCssSelectors
) {
119 mCssSelectors
= aCssSelectors
;
124 nsScriptErrorBase::GetSourceId(uint32_t* result
) {
130 nsScriptErrorBase::GetSourceLine(nsAString
& aResult
) {
131 aResult
.Assign(mSourceLine
);
136 nsScriptErrorBase::GetLineNumber(uint32_t* result
) {
137 *result
= mLineNumber
;
142 nsScriptErrorBase::GetColumnNumber(uint32_t* result
) {
143 *result
= mColumnNumber
;
148 nsScriptErrorBase::GetFlags(uint32_t* result
) {
154 nsScriptErrorBase::GetCategory(char** result
) {
155 *result
= ToNewCString(mCategory
);
160 nsScriptErrorBase::GetHasException(bool* aHasException
) {
161 *aHasException
= false;
166 nsScriptErrorBase::GetException(JS::MutableHandle
<JS::Value
> aException
) {
167 aException
.setUndefined();
172 nsScriptErrorBase::SetException(JS::Handle
<JS::Value
> aStack
) {
173 return NS_ERROR_NOT_IMPLEMENTED
;
177 nsScriptErrorBase::GetStack(JS::MutableHandle
<JS::Value
> aStack
) {
178 aStack
.setUndefined();
183 nsScriptErrorBase::SetStack(JS::Handle
<JS::Value
> aStack
) { return NS_OK
; }
186 nsScriptErrorBase::GetStackGlobal(JS::MutableHandle
<JS::Value
> aStackGlobal
) {
187 aStackGlobal
.setUndefined();
192 nsScriptErrorBase::GetErrorMessageName(nsAString
& aErrorMessageName
) {
193 aErrorMessageName
= mMessageName
;
198 nsScriptErrorBase::SetErrorMessageName(const nsAString
& aErrorMessageName
) {
199 mMessageName
= aErrorMessageName
;
203 static void AssignSourceNameHelper(nsString
& aSourceNameDest
,
204 const nsAString
& aSourceNameSrc
) {
205 if (aSourceNameSrc
.IsEmpty()) return;
207 aSourceNameDest
.Assign(aSourceNameSrc
);
209 nsCOMPtr
<nsIURI
> uri
;
211 if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri
), aSourceNameSrc
)) &&
212 NS_SUCCEEDED(uri
->GetPassword(pass
)) && !pass
.IsEmpty()) {
213 NS_GetSanitizedURIStringFromURI(uri
, aSourceNameDest
);
217 static void AssignSourceNameHelper(nsIURI
* aSourceURI
,
218 nsString
& aSourceNameDest
) {
219 if (!aSourceURI
) return;
221 if (NS_FAILED(NS_GetSanitizedURIStringFromURI(aSourceURI
, aSourceNameDest
))) {
222 aSourceNameDest
.AssignLiteral("[nsIURI::GetSpec failed]");
227 nsScriptErrorBase::Init(const nsAString
& message
, const nsAString
& sourceName
,
228 const nsAString
& sourceLine
, uint32_t lineNumber
,
229 uint32_t columnNumber
, uint32_t flags
,
230 const nsACString
& category
, bool fromPrivateWindow
,
231 bool fromChromeContext
) {
232 InitializationHelper(message
, sourceLine
, lineNumber
, columnNumber
, flags
,
233 category
, 0 /* inner Window ID */, fromChromeContext
);
234 AssignSourceNameHelper(mSourceName
, sourceName
);
236 mIsFromPrivateWindow
= fromPrivateWindow
;
237 mIsFromChromeContext
= fromChromeContext
;
241 void nsScriptErrorBase::InitializationHelper(
242 const nsAString
& message
, const nsAString
& sourceLine
, uint32_t lineNumber
,
243 uint32_t columnNumber
, uint32_t flags
, const nsACString
& category
,
244 uint64_t aInnerWindowID
, bool aFromChromeContext
) {
245 mMessage
.Assign(message
);
246 mLineNumber
= lineNumber
;
247 mSourceLine
.Assign(sourceLine
);
248 mColumnNumber
= columnNumber
;
250 mCategory
= category
;
251 mMicroSecondTimeStamp
= JS_Now();
252 mInnerWindowID
= aInnerWindowID
;
253 mIsFromChromeContext
= aFromChromeContext
;
257 nsScriptErrorBase::InitWithWindowID(const nsAString
& message
,
258 const nsAString
& sourceName
,
259 const nsAString
& sourceLine
,
260 uint32_t lineNumber
, uint32_t columnNumber
,
261 uint32_t flags
, const nsACString
& category
,
262 uint64_t aInnerWindowID
,
263 bool aFromChromeContext
) {
264 InitializationHelper(message
, sourceLine
, lineNumber
, columnNumber
, flags
,
265 category
, aInnerWindowID
, aFromChromeContext
);
266 AssignSourceNameHelper(mSourceName
, sourceName
);
268 if (aInnerWindowID
&& NS_IsMainThread()) InitializeOnMainThread();
274 nsScriptErrorBase::InitWithSanitizedSource(
275 const nsAString
& message
, const nsAString
& sourceName
,
276 const nsAString
& sourceLine
, uint32_t lineNumber
, uint32_t columnNumber
,
277 uint32_t flags
, const nsACString
& category
, uint64_t aInnerWindowID
,
278 bool aFromChromeContext
) {
279 InitializationHelper(message
, sourceLine
, lineNumber
, columnNumber
, flags
,
280 category
, aInnerWindowID
, aFromChromeContext
);
281 mSourceName
= sourceName
;
283 if (aInnerWindowID
&& NS_IsMainThread()) InitializeOnMainThread();
289 nsScriptErrorBase::InitWithSourceURI(const nsAString
& message
,
291 const nsAString
& sourceLine
,
292 uint32_t lineNumber
, uint32_t columnNumber
,
293 uint32_t flags
, const nsACString
& category
,
294 uint64_t aInnerWindowID
,
295 bool aFromChromeContext
) {
296 InitializationHelper(message
, sourceLine
, lineNumber
, columnNumber
, flags
,
297 category
, aInnerWindowID
, aFromChromeContext
);
298 AssignSourceNameHelper(sourceURI
, mSourceName
);
300 if (aInnerWindowID
&& NS_IsMainThread()) InitializeOnMainThread();
305 static nsresult
ToStringHelper(const char* aSeverity
, const nsString
& aMessage
,
306 const nsString
& aSourceName
,
307 const nsString
* aSourceLine
,
308 uint32_t aLineNumber
, uint32_t aColumnNumber
,
309 nsACString
& /*UTF8*/ aResult
) {
310 static const char format0
[] =
311 "[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]";
312 static const char format1
[] = "[%s: \"%s\" {file: \"%s\" line: %d}]";
313 static const char format2
[] = "[%s: \"%s\"]";
315 JS::UniqueChars temp
;
316 char* tempMessage
= nullptr;
317 char* tempSourceName
= nullptr;
318 char* tempSourceLine
= nullptr;
320 if (!aMessage
.IsEmpty()) tempMessage
= ToNewUTF8String(aMessage
);
321 if (!aSourceName
.IsEmpty())
322 // Use at most 512 characters from mSourceName.
323 tempSourceName
= ToNewUTF8String(StringHead(aSourceName
, 512));
324 if (aSourceLine
&& !aSourceLine
->IsEmpty())
325 // Use at most 512 characters from mSourceLine.
326 tempSourceLine
= ToNewUTF8String(StringHead(*aSourceLine
, 512));
328 if (nullptr != tempSourceName
&& nullptr != tempSourceLine
) {
329 temp
= JS_smprintf(format0
, aSeverity
, tempMessage
, tempSourceName
,
330 aLineNumber
, aColumnNumber
, tempSourceLine
);
331 } else if (!aSourceName
.IsEmpty()) {
332 temp
= JS_smprintf(format1
, aSeverity
, tempMessage
, tempSourceName
,
335 temp
= JS_smprintf(format2
, aSeverity
, tempMessage
);
338 if (nullptr != tempMessage
) free(tempMessage
);
339 if (nullptr != tempSourceName
) free(tempSourceName
);
340 if (nullptr != tempSourceLine
) free(tempSourceLine
);
342 if (!temp
) return NS_ERROR_OUT_OF_MEMORY
;
344 aResult
.Assign(temp
.get());
349 nsScriptErrorBase::ToString(nsACString
& /*UTF8*/ aResult
) {
350 static const char error
[] = "JavaScript Error";
351 static const char warning
[] = "JavaScript Warning";
353 const char* severity
=
354 !(mFlags
& nsIScriptError::warningFlag
) ? error
: warning
;
356 return ToStringHelper(severity
, mMessage
, mSourceName
, &mSourceLine
,
357 mLineNumber
, mColumnNumber
, aResult
);
361 nsScriptErrorBase::GetOuterWindowID(uint64_t* aOuterWindowID
) {
362 NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread
,
363 "This can't be safely determined off the main thread, "
364 "returning an inaccurate value!");
366 if (!mInitializedOnMainThread
&& NS_IsMainThread()) {
367 InitializeOnMainThread();
370 *aOuterWindowID
= mOuterWindowID
;
375 nsScriptErrorBase::GetInnerWindowID(uint64_t* aInnerWindowID
) {
376 *aInnerWindowID
= mInnerWindowID
;
381 nsScriptErrorBase::GetTimeStamp(int64_t* aTimeStamp
) {
382 *aTimeStamp
= mMicroSecondTimeStamp
/ 1000;
387 nsScriptErrorBase::GetMicroSecondTimeStamp(int64_t* aTimeStamp
) {
388 *aTimeStamp
= mMicroSecondTimeStamp
;
393 nsScriptErrorBase::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow
) {
394 NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread
,
395 "This can't be safely determined off the main thread, "
396 "returning an inaccurate value!");
398 if (!mInitializedOnMainThread
&& NS_IsMainThread()) {
399 InitializeOnMainThread();
402 *aIsFromPrivateWindow
= mIsFromPrivateWindow
;
407 nsScriptErrorBase::GetIsFromChromeContext(bool* aIsFromChromeContext
) {
408 NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread
,
409 "This can't be safely determined off the main thread, "
410 "returning an inaccurate value!");
411 if (!mInitializedOnMainThread
&& NS_IsMainThread()) {
412 InitializeOnMainThread();
414 *aIsFromChromeContext
= mIsFromChromeContext
;
419 nsScriptErrorBase::GetIsPromiseRejection(bool* aIsPromiseRejection
) {
420 *aIsPromiseRejection
= mIsPromiseRejection
;
425 nsScriptErrorBase::InitIsPromiseRejection(bool aIsPromiseRejection
) {
426 mIsPromiseRejection
= aIsPromiseRejection
;
431 nsScriptErrorBase::GetIsForwardedFromContentProcess(
432 bool* aIsForwardedFromContentProcess
) {
433 *aIsForwardedFromContentProcess
= mIsForwardedFromContentProcess
;
438 nsScriptErrorBase::SetIsForwardedFromContentProcess(
439 bool aIsForwardedFromContentProcess
) {
440 mIsForwardedFromContentProcess
= aIsForwardedFromContentProcess
;
445 nsScriptErrorBase::GetNotes(nsIArray
** aNotes
) {
447 nsCOMPtr
<nsIMutableArray
> array
= do_CreateInstance(NS_ARRAY_CONTRACTID
, &rv
);
448 NS_ENSURE_SUCCESS(rv
, rv
);
450 uint32_t len
= mNotes
.Length();
451 for (uint32_t i
= 0; i
< len
; i
++) array
->AppendElement(mNotes
[i
]);
452 array
.forget(aNotes
);
458 bool nsScriptErrorBase::ComputeIsFromPrivateWindow(
459 nsGlobalWindowInner
* aWindow
) {
460 // Never mark exceptions from chrome windows as having come from private
461 // windows, since we always want them to be reported.
462 nsIPrincipal
* winPrincipal
= aWindow
->GetPrincipal();
463 return aWindow
->IsPrivateBrowsing() && !winPrincipal
->IsSystemPrincipal();
467 bool nsScriptErrorBase::ComputeIsFromChromeContext(
468 nsGlobalWindowInner
* aWindow
) {
469 nsIPrincipal
* winPrincipal
= aWindow
->GetPrincipal();
470 return winPrincipal
->IsSystemPrincipal();
473 NS_IMPL_ISUPPORTS(nsScriptError
, nsIConsoleMessage
, nsIScriptError
)
475 nsScriptErrorNote::nsScriptErrorNote()
482 nsScriptErrorNote::~nsScriptErrorNote() = default;
484 void nsScriptErrorNote::Init(const nsAString
& message
,
485 const nsAString
& sourceName
, uint32_t sourceId
,
486 uint32_t lineNumber
, uint32_t columnNumber
) {
487 mMessage
.Assign(message
);
488 AssignSourceNameHelper(mSourceName
, sourceName
);
489 mSourceId
= sourceId
;
490 mLineNumber
= lineNumber
;
491 mColumnNumber
= columnNumber
;
494 // nsIScriptErrorNote methods
496 nsScriptErrorNote::GetErrorMessage(nsAString
& aResult
) {
497 aResult
.Assign(mMessage
);
502 nsScriptErrorNote::GetSourceName(nsAString
& aResult
) {
503 aResult
.Assign(mSourceName
);
508 nsScriptErrorNote::GetSourceId(uint32_t* result
) {
514 nsScriptErrorNote::GetLineNumber(uint32_t* result
) {
515 *result
= mLineNumber
;
520 nsScriptErrorNote::GetColumnNumber(uint32_t* result
) {
521 *result
= mColumnNumber
;
526 nsScriptErrorNote::ToString(nsACString
& /*UTF8*/ aResult
) {
527 return ToStringHelper("JavaScript Note", mMessage
, mSourceName
, nullptr,
528 mLineNumber
, mColumnNumber
, aResult
);
531 NS_IMPL_ISUPPORTS(nsScriptErrorNote
, nsIScriptErrorNote
)