Bug 1885602 - Part 5: Implement navigating to the SUMO help topic from the menu heade...
[gecko.git] / dom / bindings / nsScriptError.cpp
blobc44ccaf39f254a0e46552de5afbef108804d5c45
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/. */
7 /*
8 * nsIScriptError implementation.
9 */
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()
24 : mSourceId(0),
25 mLineNumber(0),
26 mColumnNumber(0),
27 mFlags(0),
28 mOuterWindowID(0),
29 mInnerWindowID(0),
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);
47 if (mInnerWindowID) {
48 nsGlobalWindowInner* window =
49 nsGlobalWindowInner::GetInnerWindowWithId(mInnerWindowID);
50 if (window) {
51 nsPIDOMWindowOuter* outer = window->GetOuterWindow();
52 if (outer) mOuterWindowID = outer->WindowID();
53 mIsFromChromeContext = ComputeIsFromChromeContext(window);
54 mIsFromPrivateWindow = ComputeIsFromPrivateWindow(window);
58 mInitializedOnMainThread = true;
61 NS_IMETHODIMP
62 nsScriptErrorBase::InitSourceId(uint32_t value) {
63 mSourceId = value;
64 return NS_OK;
67 // nsIConsoleMessage methods
68 NS_IMETHODIMP
69 nsScriptErrorBase::GetMessageMoz(nsAString& aMessage) {
70 nsAutoCString message;
71 nsresult rv = ToString(message);
72 if (NS_FAILED(rv)) {
73 return rv;
76 CopyUTF8toUTF16(message, aMessage);
77 return NS_OK;
80 NS_IMETHODIMP
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;
86 } else {
87 *aLogLevel = nsIConsoleMessage::error;
89 return NS_OK;
92 // nsIScriptError methods
93 NS_IMETHODIMP
94 nsScriptErrorBase::GetErrorMessage(nsAString& aResult) {
95 aResult.Assign(mMessage);
96 return NS_OK;
99 NS_IMETHODIMP
100 nsScriptErrorBase::GetSourceName(nsAString& aResult) {
101 aResult.Assign(mSourceName);
102 return NS_OK;
105 NS_IMETHODIMP
106 nsScriptErrorBase::GetCssSelectors(nsAString& aResult) {
107 aResult.Assign(mCssSelectors);
108 return NS_OK;
111 NS_IMETHODIMP
112 nsScriptErrorBase::SetCssSelectors(const nsAString& aCssSelectors) {
113 mCssSelectors = aCssSelectors;
114 return NS_OK;
117 NS_IMETHODIMP
118 nsScriptErrorBase::GetSourceId(uint32_t* result) {
119 *result = mSourceId;
120 return NS_OK;
123 NS_IMETHODIMP
124 nsScriptErrorBase::GetSourceLine(nsAString& aResult) {
125 aResult.Assign(mSourceLine);
126 return NS_OK;
129 NS_IMETHODIMP
130 nsScriptErrorBase::GetLineNumber(uint32_t* result) {
131 *result = mLineNumber;
132 return NS_OK;
135 NS_IMETHODIMP
136 nsScriptErrorBase::GetColumnNumber(uint32_t* result) {
137 *result = mColumnNumber;
138 return NS_OK;
141 NS_IMETHODIMP
142 nsScriptErrorBase::GetFlags(uint32_t* result) {
143 *result = mFlags;
144 return NS_OK;
147 NS_IMETHODIMP
148 nsScriptErrorBase::GetCategory(char** result) {
149 *result = ToNewCString(mCategory);
150 return NS_OK;
153 NS_IMETHODIMP
154 nsScriptErrorBase::GetHasException(bool* aHasException) {
155 *aHasException = false;
156 return NS_OK;
159 NS_IMETHODIMP
160 nsScriptErrorBase::GetException(JS::MutableHandle<JS::Value> aException) {
161 aException.setUndefined();
162 return NS_OK;
165 NS_IMETHODIMP
166 nsScriptErrorBase::SetException(JS::Handle<JS::Value> aStack) {
167 return NS_ERROR_NOT_IMPLEMENTED;
170 NS_IMETHODIMP
171 nsScriptErrorBase::GetStack(JS::MutableHandle<JS::Value> aStack) {
172 aStack.setUndefined();
173 return NS_OK;
176 NS_IMETHODIMP
177 nsScriptErrorBase::SetStack(JS::Handle<JS::Value> aStack) { return NS_OK; }
179 NS_IMETHODIMP
180 nsScriptErrorBase::GetStackGlobal(JS::MutableHandle<JS::Value> aStackGlobal) {
181 aStackGlobal.setUndefined();
182 return NS_OK;
185 NS_IMETHODIMP
186 nsScriptErrorBase::GetErrorMessageName(nsAString& aErrorMessageName) {
187 aErrorMessageName = mMessageName;
188 return NS_OK;
191 NS_IMETHODIMP
192 nsScriptErrorBase::SetErrorMessageName(const nsAString& aErrorMessageName) {
193 mMessageName = aErrorMessageName;
194 return NS_OK;
197 static void AssignSourceNameHelper(nsString& aSourceNameDest,
198 const nsAString& aSourceNameSrc) {
199 if (aSourceNameSrc.IsEmpty()) return;
201 aSourceNameDest.Assign(aSourceNameSrc);
203 nsCOMPtr<nsIURI> uri;
204 nsAutoCString pass;
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]");
220 NS_IMETHODIMP
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;
232 return NS_OK;
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;
243 mFlags = flags;
244 mCategory = category;
245 mMicroSecondTimeStamp = JS_Now();
246 mInnerWindowID = aInnerWindowID;
247 mIsFromChromeContext = aFromChromeContext;
250 NS_IMETHODIMP
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();
264 return NS_OK;
267 NS_IMETHODIMP
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();
279 return NS_OK;
282 NS_IMETHODIMP
283 nsScriptErrorBase::InitWithSourceURI(const nsAString& message,
284 nsIURI* sourceURI,
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();
296 return NS_OK;
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,
327 aLineNumber);
328 } else {
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());
339 return NS_OK;
342 NS_IMETHODIMP
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);
354 NS_IMETHODIMP
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;
365 return NS_OK;
368 NS_IMETHODIMP
369 nsScriptErrorBase::GetInnerWindowID(uint64_t* aInnerWindowID) {
370 *aInnerWindowID = mInnerWindowID;
371 return NS_OK;
374 NS_IMETHODIMP
375 nsScriptErrorBase::GetTimeStamp(int64_t* aTimeStamp) {
376 *aTimeStamp = mMicroSecondTimeStamp / 1000;
377 return NS_OK;
380 NS_IMETHODIMP
381 nsScriptErrorBase::GetMicroSecondTimeStamp(int64_t* aTimeStamp) {
382 *aTimeStamp = mMicroSecondTimeStamp;
383 return NS_OK;
386 NS_IMETHODIMP
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;
397 return NS_OK;
400 NS_IMETHODIMP
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;
409 return NS_OK;
412 NS_IMETHODIMP
413 nsScriptErrorBase::GetIsPromiseRejection(bool* aIsPromiseRejection) {
414 *aIsPromiseRejection = mIsPromiseRejection;
415 return NS_OK;
418 NS_IMETHODIMP
419 nsScriptErrorBase::InitIsPromiseRejection(bool aIsPromiseRejection) {
420 mIsPromiseRejection = aIsPromiseRejection;
421 return NS_OK;
424 NS_IMETHODIMP
425 nsScriptErrorBase::GetIsForwardedFromContentProcess(
426 bool* aIsForwardedFromContentProcess) {
427 *aIsForwardedFromContentProcess = mIsForwardedFromContentProcess;
428 return NS_OK;
431 NS_IMETHODIMP
432 nsScriptErrorBase::SetIsForwardedFromContentProcess(
433 bool aIsForwardedFromContentProcess) {
434 mIsForwardedFromContentProcess = aIsForwardedFromContentProcess;
435 return NS_OK;
438 NS_IMETHODIMP
439 nsScriptErrorBase::GetNotes(nsIArray** aNotes) {
440 nsresult rv = NS_OK;
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);
448 return NS_OK;
451 /* static */
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();
460 /* static */
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
485 NS_IMETHODIMP
486 nsScriptErrorNote::GetErrorMessage(nsAString& aResult) {
487 aResult.Assign(mMessage);
488 return NS_OK;
491 NS_IMETHODIMP
492 nsScriptErrorNote::GetSourceName(nsAString& aResult) {
493 aResult.Assign(mSourceName);
494 return NS_OK;
497 NS_IMETHODIMP
498 nsScriptErrorNote::GetSourceId(uint32_t* result) {
499 *result = mSourceId;
500 return NS_OK;
503 NS_IMETHODIMP
504 nsScriptErrorNote::GetLineNumber(uint32_t* result) {
505 *result = mLineNumber;
506 return NS_OK;
509 NS_IMETHODIMP
510 nsScriptErrorNote::GetColumnNumber(uint32_t* result) {
511 *result = mColumnNumber;
512 return NS_OK;
515 NS_IMETHODIMP
516 nsScriptErrorNote::ToString(nsACString& /*UTF8*/ aResult) {
517 return ToStringHelper("JavaScript Note", mMessage, mSourceName, nullptr,
518 mLineNumber, mColumnNumber, aResult);
521 NS_IMPL_ISUPPORTS(nsScriptErrorNote, nsIScriptErrorNote)