diff options
Diffstat (limited to '')
-rw-r--r-- | dom/bindings/nsScriptError.cpp | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/dom/bindings/nsScriptError.cpp b/dom/bindings/nsScriptError.cpp new file mode 100644 index 0000000000..0cc71e0bcc --- /dev/null +++ b/dom/bindings/nsScriptError.cpp @@ -0,0 +1,531 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * nsIScriptError implementation. + */ + +#include "nsScriptError.h" +#include "js/Printf.h" +#include "MainThreadUtils.h" +#include "mozilla/Assertions.h" +#include "nsContentUtils.h" +#include "nsGlobalWindow.h" +#include "nsNetUtil.h" +#include "nsPIDOMWindow.h" +#include "nsIMutableArray.h" +#include "nsIScriptError.h" +#include "mozilla/BasePrincipal.h" + +nsScriptErrorBase::nsScriptErrorBase() + : mMessage(), + mMessageName(), + mSourceName(), + mCssSelectors(), + mSourceId(0), + mLineNumber(0), + mSourceLine(), + mColumnNumber(0), + mFlags(0), + mCategory(), + mOuterWindowID(0), + mInnerWindowID(0), + mMicroSecondTimeStamp(0), + mInitializedOnMainThread(false), + mIsFromPrivateWindow(false), + mIsFromChromeContext(false), + mIsPromiseRejection(false), + mIsForwardedFromContentProcess(false) {} + +nsScriptErrorBase::~nsScriptErrorBase() = default; + +void nsScriptErrorBase::AddNote(nsIScriptErrorNote* note) { + mNotes.AppendObject(note); +} + +void nsScriptErrorBase::InitializeOnMainThread() { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mInitializedOnMainThread); + + if (mInnerWindowID) { + nsGlobalWindowInner* window = + nsGlobalWindowInner::GetInnerWindowWithId(mInnerWindowID); + if (window) { + nsPIDOMWindowOuter* outer = window->GetOuterWindow(); + if (outer) mOuterWindowID = outer->WindowID(); + mIsFromChromeContext = ComputeIsFromChromeContext(window); + mIsFromPrivateWindow = ComputeIsFromPrivateWindow(window); + } + } + + mInitializedOnMainThread = true; +} + +NS_IMETHODIMP +nsScriptErrorBase::InitSourceId(uint32_t value) { + mSourceId = value; + return NS_OK; +} + +// nsIConsoleMessage methods +NS_IMETHODIMP +nsScriptErrorBase::GetMessageMoz(nsAString& aMessage) { + nsAutoCString message; + nsresult rv = ToString(message); + if (NS_FAILED(rv)) { + return rv; + } + + CopyUTF8toUTF16(message, aMessage); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetLogLevel(uint32_t* aLogLevel) { + if (mFlags & (uint32_t)nsIScriptError::infoFlag) { + *aLogLevel = nsIConsoleMessage::info; + } else if (mFlags & (uint32_t)nsIScriptError::warningFlag) { + *aLogLevel = nsIConsoleMessage::warn; + } else { + *aLogLevel = nsIConsoleMessage::error; + } + return NS_OK; +} + +// nsIScriptError methods +NS_IMETHODIMP +nsScriptErrorBase::GetErrorMessage(nsAString& aResult) { + aResult.Assign(mMessage); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetSourceName(nsAString& aResult) { + aResult.Assign(mSourceName); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetCssSelectors(nsAString& aResult) { + aResult.Assign(mCssSelectors); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::SetCssSelectors(const nsAString& aCssSelectors) { + mCssSelectors = aCssSelectors; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetSourceId(uint32_t* result) { + *result = mSourceId; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetSourceLine(nsAString& aResult) { + aResult.Assign(mSourceLine); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetLineNumber(uint32_t* result) { + *result = mLineNumber; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetColumnNumber(uint32_t* result) { + *result = mColumnNumber; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetFlags(uint32_t* result) { + *result = mFlags; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetCategory(char** result) { + *result = ToNewCString(mCategory); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetHasException(bool* aHasException) { + *aHasException = false; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetException(JS::MutableHandle<JS::Value> aException) { + aException.setUndefined(); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::SetException(JS::Handle<JS::Value> aStack) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetStack(JS::MutableHandle<JS::Value> aStack) { + aStack.setUndefined(); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::SetStack(JS::Handle<JS::Value> aStack) { return NS_OK; } + +NS_IMETHODIMP +nsScriptErrorBase::GetStackGlobal(JS::MutableHandle<JS::Value> aStackGlobal) { + aStackGlobal.setUndefined(); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetErrorMessageName(nsAString& aErrorMessageName) { + aErrorMessageName = mMessageName; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::SetErrorMessageName(const nsAString& aErrorMessageName) { + mMessageName = aErrorMessageName; + return NS_OK; +} + +static void AssignSourceNameHelper(nsString& aSourceNameDest, + const nsAString& aSourceNameSrc) { + if (aSourceNameSrc.IsEmpty()) return; + + aSourceNameDest.Assign(aSourceNameSrc); + + nsCOMPtr<nsIURI> uri; + nsAutoCString pass; + if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), aSourceNameSrc)) && + NS_SUCCEEDED(uri->GetPassword(pass)) && !pass.IsEmpty()) { + NS_GetSanitizedURIStringFromURI(uri, aSourceNameDest); + } +} + +static void AssignSourceNameHelper(nsIURI* aSourceURI, + nsString& aSourceNameDest) { + if (!aSourceURI) return; + + if (NS_FAILED(NS_GetSanitizedURIStringFromURI(aSourceURI, aSourceNameDest))) { + aSourceNameDest.AssignLiteral("[nsIURI::GetSpec failed]"); + } +} + +NS_IMETHODIMP +nsScriptErrorBase::Init(const nsAString& message, const nsAString& sourceName, + const nsAString& sourceLine, uint32_t lineNumber, + uint32_t columnNumber, uint32_t flags, + const nsACString& category, bool fromPrivateWindow, + bool fromChromeContext) { + InitializationHelper(message, sourceLine, lineNumber, columnNumber, flags, + category, 0 /* inner Window ID */, fromChromeContext); + AssignSourceNameHelper(mSourceName, sourceName); + + mIsFromPrivateWindow = fromPrivateWindow; + mIsFromChromeContext = fromChromeContext; + return NS_OK; +} + +void nsScriptErrorBase::InitializationHelper( + const nsAString& message, const nsAString& sourceLine, uint32_t lineNumber, + uint32_t columnNumber, uint32_t flags, const nsACString& category, + uint64_t aInnerWindowID, bool aFromChromeContext) { + mMessage.Assign(message); + mLineNumber = lineNumber; + mSourceLine.Assign(sourceLine); + mColumnNumber = columnNumber; + mFlags = flags; + mCategory = category; + mMicroSecondTimeStamp = JS_Now(); + mInnerWindowID = aInnerWindowID; + mIsFromChromeContext = aFromChromeContext; +} + +NS_IMETHODIMP +nsScriptErrorBase::InitWithWindowID(const nsAString& message, + const nsAString& sourceName, + const nsAString& sourceLine, + uint32_t lineNumber, uint32_t columnNumber, + uint32_t flags, const nsACString& category, + uint64_t aInnerWindowID, + bool aFromChromeContext) { + InitializationHelper(message, sourceLine, lineNumber, columnNumber, flags, + category, aInnerWindowID, aFromChromeContext); + AssignSourceNameHelper(mSourceName, sourceName); + + if (aInnerWindowID && NS_IsMainThread()) InitializeOnMainThread(); + + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::InitWithSanitizedSource( + const nsAString& message, const nsAString& sourceName, + const nsAString& sourceLine, uint32_t lineNumber, uint32_t columnNumber, + uint32_t flags, const nsACString& category, uint64_t aInnerWindowID, + bool aFromChromeContext) { + InitializationHelper(message, sourceLine, lineNumber, columnNumber, flags, + category, aInnerWindowID, aFromChromeContext); + mSourceName = sourceName; + + if (aInnerWindowID && NS_IsMainThread()) InitializeOnMainThread(); + + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::InitWithSourceURI(const nsAString& message, + nsIURI* sourceURI, + const nsAString& sourceLine, + uint32_t lineNumber, uint32_t columnNumber, + uint32_t flags, const nsACString& category, + uint64_t aInnerWindowID, + bool aFromChromeContext) { + InitializationHelper(message, sourceLine, lineNumber, columnNumber, flags, + category, aInnerWindowID, aFromChromeContext); + AssignSourceNameHelper(sourceURI, mSourceName); + + if (aInnerWindowID && NS_IsMainThread()) InitializeOnMainThread(); + + return NS_OK; +} + +static nsresult ToStringHelper(const char* aSeverity, const nsString& aMessage, + const nsString& aSourceName, + const nsString* aSourceLine, + uint32_t aLineNumber, uint32_t aColumnNumber, + nsACString& /*UTF8*/ aResult) { + static const char format0[] = + "[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]"; + static const char format1[] = "[%s: \"%s\" {file: \"%s\" line: %d}]"; + static const char format2[] = "[%s: \"%s\"]"; + + JS::UniqueChars temp; + char* tempMessage = nullptr; + char* tempSourceName = nullptr; + char* tempSourceLine = nullptr; + + if (!aMessage.IsEmpty()) tempMessage = ToNewUTF8String(aMessage); + if (!aSourceName.IsEmpty()) + // Use at most 512 characters from mSourceName. + tempSourceName = ToNewUTF8String(StringHead(aSourceName, 512)); + if (aSourceLine && !aSourceLine->IsEmpty()) + // Use at most 512 characters from mSourceLine. + tempSourceLine = ToNewUTF8String(StringHead(*aSourceLine, 512)); + + if (nullptr != tempSourceName && nullptr != tempSourceLine) { + temp = JS_smprintf(format0, aSeverity, tempMessage, tempSourceName, + aLineNumber, aColumnNumber, tempSourceLine); + } else if (!aSourceName.IsEmpty()) { + temp = JS_smprintf(format1, aSeverity, tempMessage, tempSourceName, + aLineNumber); + } else { + temp = JS_smprintf(format2, aSeverity, tempMessage); + } + + if (nullptr != tempMessage) free(tempMessage); + if (nullptr != tempSourceName) free(tempSourceName); + if (nullptr != tempSourceLine) free(tempSourceLine); + + if (!temp) return NS_ERROR_OUT_OF_MEMORY; + + aResult.Assign(temp.get()); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult) { + static const char error[] = "JavaScript Error"; + static const char warning[] = "JavaScript Warning"; + + const char* severity = + !(mFlags & nsIScriptError::warningFlag) ? error : warning; + + return ToStringHelper(severity, mMessage, mSourceName, &mSourceLine, + mLineNumber, mColumnNumber, aResult); +} + +NS_IMETHODIMP +nsScriptErrorBase::GetOuterWindowID(uint64_t* aOuterWindowID) { + NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread, + "This can't be safely determined off the main thread, " + "returning an inaccurate value!"); + + if (!mInitializedOnMainThread && NS_IsMainThread()) { + InitializeOnMainThread(); + } + + *aOuterWindowID = mOuterWindowID; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetInnerWindowID(uint64_t* aInnerWindowID) { + *aInnerWindowID = mInnerWindowID; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetTimeStamp(int64_t* aTimeStamp) { + *aTimeStamp = mMicroSecondTimeStamp / 1000; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetMicroSecondTimeStamp(int64_t* aTimeStamp) { + *aTimeStamp = mMicroSecondTimeStamp; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow) { + NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread, + "This can't be safely determined off the main thread, " + "returning an inaccurate value!"); + + if (!mInitializedOnMainThread && NS_IsMainThread()) { + InitializeOnMainThread(); + } + + *aIsFromPrivateWindow = mIsFromPrivateWindow; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetIsFromChromeContext(bool* aIsFromChromeContext) { + NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread, + "This can't be safely determined off the main thread, " + "returning an inaccurate value!"); + if (!mInitializedOnMainThread && NS_IsMainThread()) { + InitializeOnMainThread(); + } + *aIsFromChromeContext = mIsFromChromeContext; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetIsPromiseRejection(bool* aIsPromiseRejection) { + *aIsPromiseRejection = mIsPromiseRejection; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::InitIsPromiseRejection(bool aIsPromiseRejection) { + mIsPromiseRejection = aIsPromiseRejection; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetIsForwardedFromContentProcess( + bool* aIsForwardedFromContentProcess) { + *aIsForwardedFromContentProcess = mIsForwardedFromContentProcess; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::SetIsForwardedFromContentProcess( + bool aIsForwardedFromContentProcess) { + mIsForwardedFromContentProcess = aIsForwardedFromContentProcess; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorBase::GetNotes(nsIArray** aNotes) { + nsresult rv = NS_OK; + nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t len = mNotes.Length(); + for (uint32_t i = 0; i < len; i++) array->AppendElement(mNotes[i]); + array.forget(aNotes); + + return NS_OK; +} + +/* static */ +bool nsScriptErrorBase::ComputeIsFromPrivateWindow( + nsGlobalWindowInner* aWindow) { + // Never mark exceptions from chrome windows as having come from private + // windows, since we always want them to be reported. + nsIPrincipal* winPrincipal = aWindow->GetPrincipal(); + return aWindow->IsPrivateBrowsing() && !winPrincipal->IsSystemPrincipal(); +} + +/* static */ +bool nsScriptErrorBase::ComputeIsFromChromeContext( + nsGlobalWindowInner* aWindow) { + nsIPrincipal* winPrincipal = aWindow->GetPrincipal(); + return winPrincipal->IsSystemPrincipal(); +} + +NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError) + +nsScriptErrorNote::nsScriptErrorNote() + : mMessage(), + mSourceName(), + mSourceId(0), + mLineNumber(0), + mColumnNumber(0) {} + +nsScriptErrorNote::~nsScriptErrorNote() = default; + +void nsScriptErrorNote::Init(const nsAString& message, + const nsAString& sourceName, uint32_t sourceId, + uint32_t lineNumber, uint32_t columnNumber) { + mMessage.Assign(message); + AssignSourceNameHelper(mSourceName, sourceName); + mSourceId = sourceId; + mLineNumber = lineNumber; + mColumnNumber = columnNumber; +} + +// nsIScriptErrorNote methods +NS_IMETHODIMP +nsScriptErrorNote::GetErrorMessage(nsAString& aResult) { + aResult.Assign(mMessage); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::GetSourceName(nsAString& aResult) { + aResult.Assign(mSourceName); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::GetSourceId(uint32_t* result) { + *result = mSourceId; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::GetLineNumber(uint32_t* result) { + *result = mLineNumber; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::GetColumnNumber(uint32_t* result) { + *result = mColumnNumber; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::ToString(nsACString& /*UTF8*/ aResult) { + return ToStringHelper("JavaScript Note", mMessage, mSourceName, nullptr, + mLineNumber, mColumnNumber, aResult); +} + +NS_IMPL_ISUPPORTS(nsScriptErrorNote, nsIScriptErrorNote) |