nsScriptError.cpp (15031B)
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 /* 8 * nsIScriptError implementation. 9 */ 10 11 #include "nsScriptError.h" 12 13 #include "MainThreadUtils.h" 14 #include "js/Printf.h" 15 #include "mozilla/Assertions.h" 16 #include "mozilla/BasePrincipal.h" 17 #include "nsContentUtils.h" 18 #include "nsGlobalWindowInner.h" 19 #include "nsIMutableArray.h" 20 #include "nsIScriptError.h" 21 #include "nsNetUtil.h" 22 #include "nsPIDOMWindow.h" 23 24 nsScriptErrorBase::nsScriptErrorBase() 25 : mSourceId(0), 26 mLineNumber(0), 27 mColumnNumber(0), 28 mFlags(0), 29 mOuterWindowID(0), 30 mInnerWindowID(0), 31 mMicroSecondTimeStamp(0), 32 mInitializedOnMainThread(false), 33 mIsFromPrivateWindow(false), 34 mIsFromChromeContext(false), 35 mIsPromiseRejection(false), 36 mIsForwardedFromContentProcess(false) {} 37 38 nsScriptErrorBase::~nsScriptErrorBase() = default; 39 40 void nsScriptErrorBase::AddNote(nsIScriptErrorNote* note) { 41 mNotes.AppendObject(note); 42 } 43 44 void nsScriptErrorBase::InitializeOnMainThread() { 45 MOZ_ASSERT(NS_IsMainThread()); 46 MOZ_ASSERT(!mInitializedOnMainThread); 47 48 if (mInnerWindowID) { 49 nsGlobalWindowInner* window = 50 nsGlobalWindowInner::GetInnerWindowWithId(mInnerWindowID); 51 if (window) { 52 nsPIDOMWindowOuter* outer = window->GetOuterWindow(); 53 if (outer) mOuterWindowID = outer->WindowID(); 54 mIsFromChromeContext = ComputeIsFromChromeContext(window); 55 mIsFromPrivateWindow = ComputeIsFromPrivateWindow(window); 56 } 57 } 58 59 mInitializedOnMainThread = true; 60 } 61 62 NS_IMETHODIMP 63 nsScriptErrorBase::InitSourceId(uint32_t value) { 64 mSourceId = value; 65 return NS_OK; 66 } 67 68 // nsIConsoleMessage methods 69 NS_IMETHODIMP 70 nsScriptErrorBase::GetMessageMoz(nsAString& aMessage) { 71 nsAutoCString message; 72 nsresult rv = ToString(message); 73 if (NS_FAILED(rv)) { 74 return rv; 75 } 76 77 CopyUTF8toUTF16(message, aMessage); 78 return NS_OK; 79 } 80 81 NS_IMETHODIMP 82 nsScriptErrorBase::GetLogLevel(uint32_t* aLogLevel) { 83 if (mFlags & (uint32_t)nsIScriptError::infoFlag) { 84 *aLogLevel = nsIConsoleMessage::info; 85 } else if (mFlags & (uint32_t)nsIScriptError::warningFlag) { 86 *aLogLevel = nsIConsoleMessage::warn; 87 } else { 88 *aLogLevel = nsIConsoleMessage::error; 89 } 90 return NS_OK; 91 } 92 93 // nsIScriptError methods 94 NS_IMETHODIMP 95 nsScriptErrorBase::GetErrorMessage(nsAString& aResult) { 96 aResult.Assign(mMessage); 97 return NS_OK; 98 } 99 100 NS_IMETHODIMP 101 nsScriptErrorBase::GetSourceName(nsACString& aResult) { 102 aResult.Assign(mSourceName); 103 return NS_OK; 104 } 105 106 NS_IMETHODIMP 107 nsScriptErrorBase::GetCssSelectors(nsAString& aResult) { 108 aResult.Assign(mCssSelectors); 109 return NS_OK; 110 } 111 112 NS_IMETHODIMP 113 nsScriptErrorBase::SetCssSelectors(const nsAString& aCssSelectors) { 114 mCssSelectors = aCssSelectors; 115 return NS_OK; 116 } 117 118 NS_IMETHODIMP 119 nsScriptErrorBase::GetSourceId(uint32_t* result) { 120 *result = mSourceId; 121 return NS_OK; 122 } 123 124 NS_IMETHODIMP 125 nsScriptErrorBase::GetLineNumber(uint32_t* result) { 126 *result = mLineNumber; 127 return NS_OK; 128 } 129 130 NS_IMETHODIMP 131 nsScriptErrorBase::GetColumnNumber(uint32_t* result) { 132 *result = mColumnNumber; 133 return NS_OK; 134 } 135 136 NS_IMETHODIMP 137 nsScriptErrorBase::GetFlags(uint32_t* result) { 138 *result = mFlags; 139 return NS_OK; 140 } 141 142 NS_IMETHODIMP 143 nsScriptErrorBase::GetCategory(char** result) { 144 *result = ToNewCString(mCategory); 145 return NS_OK; 146 } 147 148 NS_IMETHODIMP 149 nsScriptErrorBase::GetHasException(bool* aHasException) { 150 *aHasException = false; 151 return NS_OK; 152 } 153 154 NS_IMETHODIMP 155 nsScriptErrorBase::GetException(JS::MutableHandle<JS::Value> aException) { 156 aException.setUndefined(); 157 return NS_OK; 158 } 159 160 NS_IMETHODIMP 161 nsScriptErrorBase::SetException(JS::Handle<JS::Value> aStack) { 162 return NS_ERROR_NOT_IMPLEMENTED; 163 } 164 165 NS_IMETHODIMP 166 nsScriptErrorBase::GetStack(JS::MutableHandle<JS::Value> aStack) { 167 aStack.setUndefined(); 168 return NS_OK; 169 } 170 171 NS_IMETHODIMP 172 nsScriptErrorBase::SetStack(JS::Handle<JS::Value> aStack) { return NS_OK; } 173 174 NS_IMETHODIMP 175 nsScriptErrorBase::GetStackGlobal(JS::MutableHandle<JS::Value> aStackGlobal) { 176 aStackGlobal.setUndefined(); 177 return NS_OK; 178 } 179 180 NS_IMETHODIMP 181 nsScriptErrorBase::GetErrorMessageName(nsAString& aErrorMessageName) { 182 aErrorMessageName = mMessageName; 183 return NS_OK; 184 } 185 186 NS_IMETHODIMP 187 nsScriptErrorBase::SetErrorMessageName(const nsAString& aErrorMessageName) { 188 mMessageName = aErrorMessageName; 189 return NS_OK; 190 } 191 192 static void AssignSourceNameHelper(nsCString& aSourceNameDest, 193 const nsACString& aSourceNameSrc) { 194 if (aSourceNameSrc.IsEmpty()) { 195 return; 196 } 197 198 aSourceNameDest.Assign(aSourceNameSrc); 199 200 nsCOMPtr<nsIURI> uri; 201 nsAutoCString pass; 202 if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), aSourceNameSrc)) && 203 NS_SUCCEEDED(uri->GetPassword(pass)) && !pass.IsEmpty()) { 204 NS_GetSanitizedURIStringFromURI(uri, aSourceNameDest); 205 } 206 } 207 208 static void AssignSourceNameHelper(nsIURI* aSourceURI, 209 nsCString& aSourceNameDest) { 210 if (!aSourceURI) return; 211 212 if (NS_FAILED(NS_GetSanitizedURIStringFromURI(aSourceURI, aSourceNameDest))) { 213 aSourceNameDest.AssignLiteral("[nsIURI::GetSpec failed]"); 214 } 215 } 216 217 NS_IMETHODIMP 218 nsScriptErrorBase::Init(const nsAString& message, const nsACString& sourceName, 219 uint32_t lineNumber, uint32_t columnNumber, 220 uint32_t flags, const nsACString& category, 221 bool fromPrivateWindow, bool fromChromeContext) { 222 InitializationHelper(message, lineNumber, columnNumber, flags, category, 223 0 /* inner Window ID */, fromChromeContext); 224 AssignSourceNameHelper(mSourceName, sourceName); 225 226 mIsFromPrivateWindow = fromPrivateWindow; 227 mIsFromChromeContext = fromChromeContext; 228 return NS_OK; 229 } 230 231 void nsScriptErrorBase::InitializationHelper( 232 const nsAString& message, uint32_t lineNumber, uint32_t columnNumber, 233 uint32_t flags, const nsACString& category, uint64_t aInnerWindowID, 234 bool aFromChromeContext) { 235 mMessage.Assign(message); 236 mLineNumber = lineNumber; 237 mColumnNumber = columnNumber; 238 mFlags = flags; 239 mCategory = category; 240 mMicroSecondTimeStamp = JS_Now(); 241 mInnerWindowID = aInnerWindowID; 242 mIsFromChromeContext = aFromChromeContext; 243 } 244 245 NS_IMETHODIMP 246 nsScriptErrorBase::InitWithWindowID(const nsAString& message, 247 const nsACString& sourceName, 248 uint32_t lineNumber, uint32_t columnNumber, 249 uint32_t flags, const nsACString& category, 250 uint64_t aInnerWindowID, 251 bool aFromChromeContext) { 252 InitializationHelper(message, lineNumber, columnNumber, flags, category, 253 aInnerWindowID, aFromChromeContext); 254 AssignSourceNameHelper(mSourceName, sourceName); 255 256 if (aInnerWindowID && NS_IsMainThread()) InitializeOnMainThread(); 257 258 return NS_OK; 259 } 260 261 NS_IMETHODIMP 262 nsScriptErrorBase::InitWithSanitizedSource( 263 const nsAString& message, const nsACString& sourceName, uint32_t lineNumber, 264 uint32_t columnNumber, uint32_t flags, const nsACString& category, 265 uint64_t aInnerWindowID, bool aFromChromeContext) { 266 InitializationHelper(message, lineNumber, columnNumber, flags, category, 267 aInnerWindowID, aFromChromeContext); 268 mSourceName = sourceName; 269 270 if (aInnerWindowID && NS_IsMainThread()) InitializeOnMainThread(); 271 272 return NS_OK; 273 } 274 275 NS_IMETHODIMP 276 nsScriptErrorBase::InitWithSourceURI(const nsAString& message, 277 nsIURI* sourceURI, uint32_t lineNumber, 278 uint32_t columnNumber, uint32_t flags, 279 const nsACString& category, 280 uint64_t aInnerWindowID, 281 bool aFromChromeContext) { 282 InitializationHelper(message, lineNumber, columnNumber, flags, category, 283 aInnerWindowID, aFromChromeContext); 284 AssignSourceNameHelper(sourceURI, mSourceName); 285 286 if (aInnerWindowID && NS_IsMainThread()) InitializeOnMainThread(); 287 288 return NS_OK; 289 } 290 291 static nsresult ToStringHelper(const char* aSeverity, const nsString& aMessage, 292 const nsCString& aSourceName, 293 uint32_t aLineNumber, uint32_t aColumnNumber, 294 nsACString& /*UTF8*/ aResult) { 295 static const char format0[] = 296 "[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]"; 297 static const char format1[] = "[%s: \"%s\" {file: \"%s\" line: %d}]"; 298 static const char format2[] = "[%s: \"%s\"]"; 299 300 JS::UniqueChars temp; 301 char* tempMessage = nullptr; 302 char* tempSourceName = nullptr; 303 char* tempSourceLine = nullptr; 304 305 if (!aMessage.IsEmpty()) { 306 tempMessage = ToNewUTF8String(aMessage); 307 } 308 if (!aSourceName.IsEmpty()) { 309 // Use at most 512 characters from mSourceName. 310 tempSourceName = ToNewCString(StringHead(aSourceName, 512)); 311 } 312 313 if (tempSourceName && tempSourceLine) { 314 temp = JS_smprintf(format0, aSeverity, tempMessage, tempSourceName, 315 aLineNumber, aColumnNumber, tempSourceLine); 316 } else if (!aSourceName.IsEmpty()) { 317 temp = JS_smprintf(format1, aSeverity, tempMessage, tempSourceName, 318 aLineNumber); 319 } else { 320 temp = JS_smprintf(format2, aSeverity, tempMessage); 321 } 322 323 if (tempMessage) free(tempMessage); 324 if (tempSourceName) free(tempSourceName); 325 if (tempSourceLine) free(tempSourceLine); 326 327 if (!temp) return NS_ERROR_OUT_OF_MEMORY; 328 329 aResult.Assign(temp.get()); 330 return NS_OK; 331 } 332 333 NS_IMETHODIMP 334 nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult) { 335 static const char error[] = "JavaScript Error"; 336 static const char warning[] = "JavaScript Warning"; 337 338 const char* severity = 339 !(mFlags & nsIScriptError::warningFlag) ? error : warning; 340 341 return ToStringHelper(severity, mMessage, mSourceName, mLineNumber, 342 mColumnNumber, aResult); 343 } 344 345 NS_IMETHODIMP 346 nsScriptErrorBase::GetOuterWindowID(uint64_t* aOuterWindowID) { 347 NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread, 348 "This can't be safely determined off the main thread, " 349 "returning an inaccurate value!"); 350 351 if (!mInitializedOnMainThread && NS_IsMainThread()) { 352 InitializeOnMainThread(); 353 } 354 355 *aOuterWindowID = mOuterWindowID; 356 return NS_OK; 357 } 358 359 NS_IMETHODIMP 360 nsScriptErrorBase::GetInnerWindowID(uint64_t* aInnerWindowID) { 361 *aInnerWindowID = mInnerWindowID; 362 return NS_OK; 363 } 364 365 NS_IMETHODIMP 366 nsScriptErrorBase::GetTimeStamp(int64_t* aTimeStamp) { 367 *aTimeStamp = mMicroSecondTimeStamp / 1000; 368 return NS_OK; 369 } 370 371 NS_IMETHODIMP 372 nsScriptErrorBase::GetMicroSecondTimeStamp(int64_t* aTimeStamp) { 373 *aTimeStamp = mMicroSecondTimeStamp; 374 return NS_OK; 375 } 376 377 NS_IMETHODIMP 378 nsScriptErrorBase::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow) { 379 NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread, 380 "This can't be safely determined off the main thread, " 381 "returning an inaccurate value!"); 382 383 if (!mInitializedOnMainThread && NS_IsMainThread()) { 384 InitializeOnMainThread(); 385 } 386 387 *aIsFromPrivateWindow = mIsFromPrivateWindow; 388 return NS_OK; 389 } 390 391 NS_IMETHODIMP 392 nsScriptErrorBase::GetIsFromChromeContext(bool* aIsFromChromeContext) { 393 NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread, 394 "This can't be safely determined off the main thread, " 395 "returning an inaccurate value!"); 396 if (!mInitializedOnMainThread && NS_IsMainThread()) { 397 InitializeOnMainThread(); 398 } 399 *aIsFromChromeContext = mIsFromChromeContext; 400 return NS_OK; 401 } 402 403 NS_IMETHODIMP 404 nsScriptErrorBase::GetIsPromiseRejection(bool* aIsPromiseRejection) { 405 *aIsPromiseRejection = mIsPromiseRejection; 406 return NS_OK; 407 } 408 409 NS_IMETHODIMP 410 nsScriptErrorBase::InitIsPromiseRejection(bool aIsPromiseRejection) { 411 mIsPromiseRejection = aIsPromiseRejection; 412 return NS_OK; 413 } 414 415 NS_IMETHODIMP 416 nsScriptErrorBase::GetIsForwardedFromContentProcess( 417 bool* aIsForwardedFromContentProcess) { 418 *aIsForwardedFromContentProcess = mIsForwardedFromContentProcess; 419 return NS_OK; 420 } 421 422 NS_IMETHODIMP 423 nsScriptErrorBase::SetIsForwardedFromContentProcess( 424 bool aIsForwardedFromContentProcess) { 425 mIsForwardedFromContentProcess = aIsForwardedFromContentProcess; 426 return NS_OK; 427 } 428 429 NS_IMETHODIMP 430 nsScriptErrorBase::GetNotes(nsIArray** aNotes) { 431 nsresult rv = NS_OK; 432 nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); 433 NS_ENSURE_SUCCESS(rv, rv); 434 435 uint32_t len = mNotes.Length(); 436 for (uint32_t i = 0; i < len; i++) array->AppendElement(mNotes[i]); 437 array.forget(aNotes); 438 439 return NS_OK; 440 } 441 442 /* static */ 443 bool nsScriptErrorBase::ComputeIsFromPrivateWindow( 444 nsGlobalWindowInner* aWindow) { 445 // Never mark exceptions from chrome windows as having come from private 446 // windows, since we always want them to be reported. 447 nsIPrincipal* winPrincipal = aWindow->GetPrincipal(); 448 return aWindow->IsPrivateBrowsing() && !winPrincipal->IsSystemPrincipal(); 449 } 450 451 /* static */ 452 bool nsScriptErrorBase::ComputeIsFromChromeContext( 453 nsGlobalWindowInner* aWindow) { 454 nsIPrincipal* winPrincipal = aWindow->GetPrincipal(); 455 return winPrincipal->IsSystemPrincipal(); 456 } 457 458 NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError) 459 460 nsScriptErrorNote::nsScriptErrorNote() 461 : mSourceId(0), mLineNumber(0), mColumnNumber(0) {} 462 463 nsScriptErrorNote::~nsScriptErrorNote() = default; 464 465 void nsScriptErrorNote::Init(const nsAString& message, 466 const nsACString& sourceName, uint32_t sourceId, 467 uint32_t lineNumber, uint32_t columnNumber) { 468 mMessage.Assign(message); 469 AssignSourceNameHelper(mSourceName, sourceName); 470 mSourceId = sourceId; 471 mLineNumber = lineNumber; 472 mColumnNumber = columnNumber; 473 } 474 475 // nsIScriptErrorNote methods 476 NS_IMETHODIMP 477 nsScriptErrorNote::GetErrorMessage(nsAString& aResult) { 478 aResult.Assign(mMessage); 479 return NS_OK; 480 } 481 482 NS_IMETHODIMP 483 nsScriptErrorNote::GetSourceName(nsACString& aResult) { 484 aResult.Assign(mSourceName); 485 return NS_OK; 486 } 487 488 NS_IMETHODIMP 489 nsScriptErrorNote::GetSourceId(uint32_t* result) { 490 *result = mSourceId; 491 return NS_OK; 492 } 493 494 NS_IMETHODIMP 495 nsScriptErrorNote::GetLineNumber(uint32_t* result) { 496 *result = mLineNumber; 497 return NS_OK; 498 } 499 500 NS_IMETHODIMP 501 nsScriptErrorNote::GetColumnNumber(uint32_t* result) { 502 *result = mColumnNumber; 503 return NS_OK; 504 } 505 506 NS_IMETHODIMP 507 nsScriptErrorNote::ToString(nsACString& /*UTF8*/ aResult) { 508 return ToStringHelper("JavaScript Note", mMessage, mSourceName, mLineNumber, 509 mColumnNumber, aResult); 510 } 511 512 NS_IMPL_ISUPPORTS(nsScriptErrorNote, nsIScriptErrorNote)