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 #include "ScriptErrorHelper.h"
8
9 #include "MainThreadUtils.h"
10 #include "nsCOMPtr.h"
11 #include "nsContentUtils.h"
12 #include "nsIConsoleService.h"
13 #include "nsIScriptError.h"
14 #include "nsString.h"
15 #include "nsThreadUtils.h"
16
17 #include "mozilla/SchedulerGroup.h"
18
19 namespace {
20
21 class ScriptErrorRunnable final : public mozilla::Runnable {
22 nsString mMessage;
23 nsCString mMessageName;
24 nsString mFilename;
25 uint32_t mLineNumber;
26 uint32_t mColumnNumber;
27 uint32_t mSeverityFlag;
28 uint64_t mInnerWindowID;
29 bool mIsChrome;
30
31 public:
ScriptErrorRunnable(const nsAString & aMessage,const nsAString & aFilename,uint32_t aLineNumber,uint32_t aColumnNumber,uint32_t aSeverityFlag,bool aIsChrome,uint64_t aInnerWindowID)32 ScriptErrorRunnable(const nsAString& aMessage, const nsAString& aFilename,
33 uint32_t aLineNumber, uint32_t aColumnNumber,
34 uint32_t aSeverityFlag, bool aIsChrome,
35 uint64_t aInnerWindowID)
36 : mozilla::Runnable("ScriptErrorRunnable"),
37 mMessage(aMessage),
38 mFilename(aFilename),
39 mLineNumber(aLineNumber),
40 mColumnNumber(aColumnNumber),
41 mSeverityFlag(aSeverityFlag),
42 mInnerWindowID(aInnerWindowID),
43 mIsChrome(aIsChrome) {
44 MOZ_ASSERT(!NS_IsMainThread());
45 mMessageName.SetIsVoid(true);
46 }
47
ScriptErrorRunnable(const nsACString & aMessageName,const nsAString & aFilename,uint32_t aLineNumber,uint32_t aColumnNumber,uint32_t aSeverityFlag,bool aIsChrome,uint64_t aInnerWindowID)48 ScriptErrorRunnable(const nsACString& aMessageName,
49 const nsAString& aFilename, uint32_t aLineNumber,
50 uint32_t aColumnNumber, uint32_t aSeverityFlag,
51 bool aIsChrome, uint64_t aInnerWindowID)
52 : mozilla::Runnable("ScriptErrorRunnable"),
53 mMessageName(aMessageName),
54 mFilename(aFilename),
55 mLineNumber(aLineNumber),
56 mColumnNumber(aColumnNumber),
57 mSeverityFlag(aSeverityFlag),
58 mInnerWindowID(aInnerWindowID),
59 mIsChrome(aIsChrome) {
60 MOZ_ASSERT(!NS_IsMainThread());
61 mMessage.SetIsVoid(true);
62 }
63
DumpLocalizedMessage(const nsACString & aMessageName,const nsAString & aFilename,uint32_t aLineNumber,uint32_t aColumnNumber,uint32_t aSeverityFlag,bool aIsChrome,uint64_t aInnerWindowID)64 static void DumpLocalizedMessage(const nsACString& aMessageName,
65 const nsAString& aFilename,
66 uint32_t aLineNumber, uint32_t aColumnNumber,
67 uint32_t aSeverityFlag, bool aIsChrome,
68 uint64_t aInnerWindowID) {
69 MOZ_ASSERT(NS_IsMainThread());
70 MOZ_ASSERT(!aMessageName.IsEmpty());
71
72 nsAutoString localizedMessage;
73 if (NS_WARN_IF(NS_FAILED(nsContentUtils::GetLocalizedString(
74 nsContentUtils::eDOM_PROPERTIES, aMessageName.BeginReading(),
75 localizedMessage)))) {
76 return;
77 }
78
79 Dump(localizedMessage, aFilename, aLineNumber, aColumnNumber, aSeverityFlag,
80 aIsChrome, aInnerWindowID);
81 }
82
Dump(const nsAString & aMessage,const nsAString & aFilename,uint32_t aLineNumber,uint32_t aColumnNumber,uint32_t aSeverityFlag,bool aIsChrome,uint64_t aInnerWindowID)83 static void Dump(const nsAString& aMessage, const nsAString& aFilename,
84 uint32_t aLineNumber, uint32_t aColumnNumber,
85 uint32_t aSeverityFlag, bool aIsChrome,
86 uint64_t aInnerWindowID) {
87 MOZ_ASSERT(NS_IsMainThread());
88
89 nsAutoCString category;
90 if (aIsChrome) {
91 category.AssignLiteral("chrome ");
92 } else {
93 category.AssignLiteral("content ");
94 }
95 category.AppendLiteral("javascript");
96
97 nsCOMPtr<nsIConsoleService> consoleService =
98 do_GetService(NS_CONSOLESERVICE_CONTRACTID);
99
100 nsCOMPtr<nsIScriptError> scriptError =
101 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
102 // We may not be able to create the script error object when we're shutting
103 // down.
104 if (!scriptError) {
105 return;
106 }
107
108 if (aInnerWindowID) {
109 MOZ_ALWAYS_SUCCEEDS(scriptError->InitWithWindowID(
110 aMessage, aFilename,
111 /* aSourceLine */ EmptyString(), aLineNumber, aColumnNumber,
112 aSeverityFlag, category, aInnerWindowID));
113 } else {
114 MOZ_ALWAYS_SUCCEEDS(scriptError->Init(
115 aMessage, aFilename,
116 /* aSourceLine */ EmptyString(), aLineNumber, aColumnNumber,
117 aSeverityFlag, category.get(),
118 /* IDB doesn't run on Private browsing mode */ false,
119 /* from chrome context */ aIsChrome));
120 }
121
122 // We may not be able to obtain the console service when we're shutting
123 // down.
124 if (consoleService) {
125 MOZ_ALWAYS_SUCCEEDS(consoleService->LogMessage(scriptError));
126 }
127 }
128
129 NS_IMETHOD
Run()130 Run() override {
131 MOZ_ASSERT(NS_IsMainThread());
132 MOZ_ASSERT(mMessage.IsVoid() != mMessageName.IsVoid());
133
134 if (!mMessage.IsVoid()) {
135 Dump(mMessage, mFilename, mLineNumber, mColumnNumber, mSeverityFlag,
136 mIsChrome, mInnerWindowID);
137 return NS_OK;
138 }
139
140 DumpLocalizedMessage(mMessageName, mFilename, mLineNumber, mColumnNumber,
141 mSeverityFlag, mIsChrome, mInnerWindowID);
142
143 return NS_OK;
144 }
145
146 private:
147 virtual ~ScriptErrorRunnable() = default;
148 };
149
150 } // namespace
151
152 namespace mozilla {
153 namespace dom {
154 namespace indexedDB {
155
156 /*static*/
Dump(const nsAString & aMessage,const nsAString & aFilename,uint32_t aLineNumber,uint32_t aColumnNumber,uint32_t aSeverityFlag,bool aIsChrome,uint64_t aInnerWindowID)157 void ScriptErrorHelper::Dump(const nsAString& aMessage,
158 const nsAString& aFilename, uint32_t aLineNumber,
159 uint32_t aColumnNumber, uint32_t aSeverityFlag,
160 bool aIsChrome, uint64_t aInnerWindowID) {
161 if (NS_IsMainThread()) {
162 ScriptErrorRunnable::Dump(aMessage, aFilename, aLineNumber, aColumnNumber,
163 aSeverityFlag, aIsChrome, aInnerWindowID);
164 } else {
165 RefPtr<ScriptErrorRunnable> runnable =
166 new ScriptErrorRunnable(aMessage, aFilename, aLineNumber, aColumnNumber,
167 aSeverityFlag, aIsChrome, aInnerWindowID);
168 MOZ_ALWAYS_SUCCEEDS(
169 SchedulerGroup::Dispatch(TaskCategory::Other, runnable.forget()));
170 }
171 }
172
173 /*static*/
DumpLocalizedMessage(const nsACString & aMessageName,const nsAString & aFilename,uint32_t aLineNumber,uint32_t aColumnNumber,uint32_t aSeverityFlag,bool aIsChrome,uint64_t aInnerWindowID)174 void ScriptErrorHelper::DumpLocalizedMessage(
175 const nsACString& aMessageName, const nsAString& aFilename,
176 uint32_t aLineNumber, uint32_t aColumnNumber, uint32_t aSeverityFlag,
177 bool aIsChrome, uint64_t aInnerWindowID) {
178 if (NS_IsMainThread()) {
179 ScriptErrorRunnable::DumpLocalizedMessage(
180 aMessageName, aFilename, aLineNumber, aColumnNumber, aSeverityFlag,
181 aIsChrome, aInnerWindowID);
182 } else {
183 RefPtr<ScriptErrorRunnable> runnable = new ScriptErrorRunnable(
184 aMessageName, aFilename, aLineNumber, aColumnNumber, aSeverityFlag,
185 aIsChrome, aInnerWindowID);
186 MOZ_ALWAYS_SUCCEEDS(
187 SchedulerGroup::Dispatch(TaskCategory::Other, runnable.forget()));
188 }
189 }
190
191 } // namespace indexedDB
192 } // namespace dom
193 } // namespace mozilla
194