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