Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
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 : #include "jsprf.h"
13 : #include "MainThreadUtils.h"
14 : #include "mozilla/Assertions.h"
15 : #include "nsGlobalWindow.h"
16 : #include "nsNetUtil.h"
17 : #include "nsPIDOMWindow.h"
18 : #include "nsILoadContext.h"
19 : #include "nsIDocShell.h"
20 : #include "nsIMutableArray.h"
21 : #include "nsIScriptError.h"
22 : #include "nsISensitiveInfoHiddenURI.h"
23 :
24 : static_assert(nsIScriptError::errorFlag == JSREPORT_ERROR &&
25 : nsIScriptError::warningFlag == JSREPORT_WARNING &&
26 : nsIScriptError::exceptionFlag == JSREPORT_EXCEPTION &&
27 : nsIScriptError::strictFlag == JSREPORT_STRICT &&
28 : nsIScriptError::infoFlag == JSREPORT_USER_1,
29 : "flags should be consistent");
30 :
31 2 : nsScriptErrorBase::nsScriptErrorBase()
32 : : mMessage(),
33 : mMessageName(),
34 : mSourceName(),
35 : mLineNumber(0),
36 : mSourceLine(),
37 : mColumnNumber(0),
38 : mFlags(0),
39 : mCategory(),
40 : mOuterWindowID(0),
41 : mInnerWindowID(0),
42 : mTimeStamp(0),
43 : mInitializedOnMainThread(false),
44 2 : mIsFromPrivateWindow(false)
45 : {
46 2 : }
47 :
48 0 : nsScriptErrorBase::~nsScriptErrorBase() {}
49 :
50 : void
51 0 : nsScriptErrorBase::AddNote(nsIScriptErrorNote* note)
52 : {
53 0 : mNotes.AppendObject(note);
54 0 : }
55 :
56 : void
57 0 : nsScriptErrorBase::InitializeOnMainThread()
58 : {
59 0 : MOZ_ASSERT(NS_IsMainThread());
60 0 : MOZ_ASSERT(!mInitializedOnMainThread);
61 :
62 0 : if (mInnerWindowID) {
63 : nsGlobalWindow* window =
64 0 : nsGlobalWindow::GetInnerWindowWithId(mInnerWindowID);
65 0 : if (window) {
66 0 : nsPIDOMWindowOuter* outer = window->GetOuterWindow();
67 0 : if (outer)
68 0 : mOuterWindowID = outer->WindowID();
69 :
70 0 : nsIDocShell* docShell = window->GetDocShell();
71 0 : nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
72 :
73 0 : if (loadContext) {
74 : // Never mark exceptions from chrome windows as having come from
75 : // private windows, since we always want them to be reported.
76 0 : nsIPrincipal* winPrincipal = window->GetPrincipal();
77 0 : mIsFromPrivateWindow = loadContext->UsePrivateBrowsing() &&
78 0 : !nsContentUtils::IsSystemPrincipal(winPrincipal);
79 : }
80 : }
81 : }
82 :
83 0 : mInitializedOnMainThread = true;
84 0 : }
85 :
86 : // nsIConsoleMessage methods
87 : NS_IMETHODIMP
88 0 : nsScriptErrorBase::GetMessageMoz(char16_t** result) {
89 : nsresult rv;
90 :
91 0 : nsAutoCString message;
92 0 : rv = ToString(message);
93 0 : if (NS_FAILED(rv))
94 0 : return rv;
95 :
96 0 : *result = UTF8ToNewUnicode(message);
97 0 : if (!*result)
98 0 : return NS_ERROR_OUT_OF_MEMORY;
99 :
100 0 : return NS_OK;
101 : }
102 :
103 :
104 : NS_IMETHODIMP
105 0 : nsScriptErrorBase::GetLogLevel(uint32_t* aLogLevel)
106 : {
107 0 : if (mFlags & (uint32_t)nsIScriptError::infoFlag) {
108 0 : *aLogLevel = nsIConsoleMessage::info;
109 0 : } else if (mFlags & (uint32_t)nsIScriptError::warningFlag) {
110 0 : *aLogLevel = nsIConsoleMessage::warn;
111 : } else {
112 0 : *aLogLevel = nsIConsoleMessage::error;
113 : }
114 0 : return NS_OK;
115 : }
116 :
117 : // nsIScriptError methods
118 : NS_IMETHODIMP
119 0 : nsScriptErrorBase::GetErrorMessage(nsAString& aResult) {
120 0 : aResult.Assign(mMessage);
121 0 : return NS_OK;
122 : }
123 :
124 : NS_IMETHODIMP
125 0 : nsScriptErrorBase::GetSourceName(nsAString& aResult) {
126 0 : aResult.Assign(mSourceName);
127 0 : return NS_OK;
128 : }
129 :
130 : NS_IMETHODIMP
131 0 : nsScriptErrorBase::GetSourceLine(nsAString& aResult) {
132 0 : aResult.Assign(mSourceLine);
133 0 : return NS_OK;
134 : }
135 :
136 : NS_IMETHODIMP
137 0 : nsScriptErrorBase::GetLineNumber(uint32_t* result) {
138 0 : *result = mLineNumber;
139 0 : return NS_OK;
140 : }
141 :
142 : NS_IMETHODIMP
143 0 : nsScriptErrorBase::GetColumnNumber(uint32_t* result) {
144 0 : *result = mColumnNumber;
145 0 : return NS_OK;
146 : }
147 :
148 : NS_IMETHODIMP
149 0 : nsScriptErrorBase::GetFlags(uint32_t* result) {
150 0 : *result = mFlags;
151 0 : return NS_OK;
152 : }
153 :
154 : NS_IMETHODIMP
155 0 : nsScriptErrorBase::GetCategory(char** result) {
156 0 : *result = ToNewCString(mCategory);
157 0 : return NS_OK;
158 : }
159 :
160 : NS_IMETHODIMP
161 0 : nsScriptErrorBase::GetStack(JS::MutableHandleValue aStack) {
162 0 : aStack.setUndefined();
163 0 : return NS_OK;
164 : }
165 :
166 : NS_IMETHODIMP
167 0 : nsScriptErrorBase::SetStack(JS::HandleValue aStack) {
168 0 : return NS_OK;
169 : }
170 :
171 : NS_IMETHODIMP
172 0 : nsScriptErrorBase::GetErrorMessageName(nsAString& aErrorMessageName) {
173 0 : aErrorMessageName = mMessageName;
174 0 : return NS_OK;
175 : }
176 :
177 : NS_IMETHODIMP
178 0 : nsScriptErrorBase::SetErrorMessageName(const nsAString& aErrorMessageName) {
179 0 : mMessageName = aErrorMessageName;
180 0 : return NS_OK;
181 : }
182 :
183 : NS_IMETHODIMP
184 2 : nsScriptErrorBase::Init(const nsAString& message,
185 : const nsAString& sourceName,
186 : const nsAString& sourceLine,
187 : uint32_t lineNumber,
188 : uint32_t columnNumber,
189 : uint32_t flags,
190 : const char* category)
191 : {
192 : return InitWithWindowID(message, sourceName, sourceLine, lineNumber,
193 : columnNumber, flags,
194 6 : category ? nsDependentCString(category)
195 0 : : EmptyCString(),
196 6 : 0);
197 : }
198 :
199 : static void
200 2 : AssignSourceNameHelper(nsString& aSourceNameDest, const nsAString& aSourceNameSrc)
201 : {
202 2 : if (aSourceNameSrc.IsEmpty())
203 0 : return;
204 :
205 2 : aSourceNameDest.Assign(aSourceNameSrc);
206 :
207 4 : nsCOMPtr<nsIURI> uri;
208 4 : nsAutoCString pass;
209 8 : if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), aSourceNameSrc)) &&
210 8 : NS_SUCCEEDED(uri->GetPassword(pass)) &&
211 2 : !pass.IsEmpty())
212 : {
213 0 : nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri = do_QueryInterface(uri);
214 :
215 0 : nsAutoCString loc;
216 0 : if (safeUri && NS_SUCCEEDED(safeUri->GetSensitiveInfoHiddenSpec(loc)))
217 0 : aSourceNameDest.Assign(NS_ConvertUTF8toUTF16(loc));
218 : }
219 : }
220 :
221 : NS_IMETHODIMP
222 2 : nsScriptErrorBase::InitWithWindowID(const nsAString& message,
223 : const nsAString& sourceName,
224 : const nsAString& sourceLine,
225 : uint32_t lineNumber,
226 : uint32_t columnNumber,
227 : uint32_t flags,
228 : const nsACString& category,
229 : uint64_t aInnerWindowID)
230 : {
231 2 : mMessage.Assign(message);
232 2 : AssignSourceNameHelper(mSourceName, sourceName);
233 2 : mLineNumber = lineNumber;
234 2 : mSourceLine.Assign(sourceLine);
235 2 : mColumnNumber = columnNumber;
236 2 : mFlags = flags;
237 2 : mCategory = category;
238 2 : mTimeStamp = JS_Now() / 1000;
239 2 : mInnerWindowID = aInnerWindowID;
240 :
241 2 : if (aInnerWindowID && NS_IsMainThread())
242 0 : InitializeOnMainThread();
243 :
244 2 : return NS_OK;
245 : }
246 :
247 : static nsresult
248 0 : ToStringHelper(const char* aSeverity, const nsString& aMessage,
249 : const nsString& aSourceName, const nsString* aSourceLine,
250 : uint32_t aLineNumber, uint32_t aColumnNumber,
251 : nsACString& /*UTF8*/ aResult)
252 : {
253 : static const char format0[] =
254 : "[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]";
255 : static const char format1[] =
256 : "[%s: \"%s\" {file: \"%s\" line: %d}]";
257 : static const char format2[] =
258 : "[%s: \"%s\"]";
259 :
260 0 : UniqueChars temp;
261 0 : char* tempMessage = nullptr;
262 0 : char* tempSourceName = nullptr;
263 0 : char* tempSourceLine = nullptr;
264 :
265 0 : if (!aMessage.IsEmpty())
266 0 : tempMessage = ToNewUTF8String(aMessage);
267 0 : if (!aSourceName.IsEmpty())
268 : // Use at most 512 characters from mSourceName.
269 0 : tempSourceName = ToNewUTF8String(StringHead(aSourceName, 512));
270 0 : if (aSourceLine && !aSourceLine->IsEmpty())
271 : // Use at most 512 characters from mSourceLine.
272 0 : tempSourceLine = ToNewUTF8String(StringHead(*aSourceLine, 512));
273 :
274 0 : if (nullptr != tempSourceName && nullptr != tempSourceLine) {
275 0 : temp = JS_smprintf(format0,
276 : aSeverity,
277 : tempMessage,
278 : tempSourceName,
279 : aLineNumber,
280 : aColumnNumber,
281 0 : tempSourceLine);
282 0 : } else if (!aSourceName.IsEmpty()) {
283 0 : temp = JS_smprintf(format1,
284 : aSeverity,
285 : tempMessage,
286 : tempSourceName,
287 0 : aLineNumber);
288 : } else {
289 0 : temp = JS_smprintf(format2,
290 : aSeverity,
291 0 : tempMessage);
292 : }
293 :
294 0 : if (nullptr != tempMessage)
295 0 : free(tempMessage);
296 0 : if (nullptr != tempSourceName)
297 0 : free(tempSourceName);
298 0 : if (nullptr != tempSourceLine)
299 0 : free(tempSourceLine);
300 :
301 0 : if (!temp)
302 0 : return NS_ERROR_OUT_OF_MEMORY;
303 :
304 0 : aResult.Assign(temp.get());
305 0 : return NS_OK;
306 : }
307 :
308 : NS_IMETHODIMP
309 0 : nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult)
310 : {
311 : static const char error[] = "JavaScript Error";
312 : static const char warning[] = "JavaScript Warning";
313 :
314 0 : const char* severity = !(mFlags & JSREPORT_WARNING) ? error : warning;
315 :
316 0 : return ToStringHelper(severity, mMessage, mSourceName, &mSourceLine,
317 0 : mLineNumber, mColumnNumber, aResult);
318 : }
319 :
320 : NS_IMETHODIMP
321 0 : nsScriptErrorBase::GetOuterWindowID(uint64_t* aOuterWindowID)
322 : {
323 0 : NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread,
324 : "This can't be safely determined off the main thread, "
325 : "returning an inaccurate value!");
326 :
327 0 : if (!mInitializedOnMainThread && NS_IsMainThread()) {
328 0 : InitializeOnMainThread();
329 : }
330 :
331 0 : *aOuterWindowID = mOuterWindowID;
332 0 : return NS_OK;
333 : }
334 :
335 : NS_IMETHODIMP
336 1 : nsScriptErrorBase::GetInnerWindowID(uint64_t* aInnerWindowID)
337 : {
338 1 : *aInnerWindowID = mInnerWindowID;
339 1 : return NS_OK;
340 : }
341 :
342 : NS_IMETHODIMP
343 0 : nsScriptErrorBase::GetTimeStamp(int64_t* aTimeStamp)
344 : {
345 0 : *aTimeStamp = mTimeStamp;
346 0 : return NS_OK;
347 : }
348 :
349 : NS_IMETHODIMP
350 0 : nsScriptErrorBase::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow)
351 : {
352 0 : NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread,
353 : "This can't be safely determined off the main thread, "
354 : "returning an inaccurate value!");
355 :
356 0 : if (!mInitializedOnMainThread && NS_IsMainThread()) {
357 0 : InitializeOnMainThread();
358 : }
359 :
360 0 : *aIsFromPrivateWindow = mIsFromPrivateWindow;
361 0 : return NS_OK;
362 : }
363 :
364 : NS_IMETHODIMP
365 0 : nsScriptErrorBase::GetNotes(nsIArray** aNotes)
366 : {
367 0 : nsresult rv = NS_OK;
368 : nsCOMPtr<nsIMutableArray> array =
369 0 : do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
370 0 : NS_ENSURE_SUCCESS(rv, rv);
371 :
372 0 : uint32_t len = mNotes.Length();
373 0 : for (uint32_t i = 0; i < len; i++)
374 0 : array->AppendElement(mNotes[i], false);
375 0 : array.forget(aNotes);
376 :
377 0 : return NS_OK;
378 : }
379 :
380 27 : NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError)
381 :
382 0 : nsScriptErrorNote::nsScriptErrorNote()
383 : : mMessage(),
384 : mSourceName(),
385 : mLineNumber(0),
386 0 : mColumnNumber(0)
387 : {
388 0 : }
389 :
390 0 : nsScriptErrorNote::~nsScriptErrorNote() {}
391 :
392 : void
393 0 : nsScriptErrorNote::Init(const nsAString& message,
394 : const nsAString& sourceName,
395 : uint32_t lineNumber,
396 : uint32_t columnNumber)
397 : {
398 0 : mMessage.Assign(message);
399 0 : AssignSourceNameHelper(mSourceName, sourceName);
400 0 : mLineNumber = lineNumber;
401 0 : mColumnNumber = columnNumber;
402 0 : }
403 :
404 : // nsIScriptErrorNote methods
405 : NS_IMETHODIMP
406 0 : nsScriptErrorNote::GetErrorMessage(nsAString& aResult) {
407 0 : aResult.Assign(mMessage);
408 0 : return NS_OK;
409 : }
410 :
411 : NS_IMETHODIMP
412 0 : nsScriptErrorNote::GetSourceName(nsAString& aResult) {
413 0 : aResult.Assign(mSourceName);
414 0 : return NS_OK;
415 : }
416 :
417 : NS_IMETHODIMP
418 0 : nsScriptErrorNote::GetLineNumber(uint32_t* result) {
419 0 : *result = mLineNumber;
420 0 : return NS_OK;
421 : }
422 :
423 : NS_IMETHODIMP
424 0 : nsScriptErrorNote::GetColumnNumber(uint32_t* result) {
425 0 : *result = mColumnNumber;
426 0 : return NS_OK;
427 : }
428 :
429 : NS_IMETHODIMP
430 0 : nsScriptErrorNote::ToString(nsACString& /*UTF8*/ aResult)
431 : {
432 0 : return ToStringHelper("JavaScript Note", mMessage, mSourceName, nullptr,
433 0 : mLineNumber, mColumnNumber, aResult);
434 : }
435 :
436 0 : NS_IMPL_ISUPPORTS(nsScriptErrorNote, nsIScriptErrorNote)
|