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 "ConsoleUtils.h"
8 #include "ConsoleCommon.h"
9 #include "nsContentUtils.h"
10 #include "nsIConsoleAPIStorage.h"
11 #include "nsIXPConnect.h"
12 #include "nsServiceManagerUtils.h"
13
14 #include "mozilla/ClearOnShutdown.h"
15 #include "mozilla/NullPrincipal.h"
16 #include "mozilla/dom/ConsoleBinding.h"
17 #include "mozilla/dom/RootedDictionary.h"
18 #include "mozilla/dom/ScriptSettings.h"
19
20 namespace mozilla::dom {
21
22 namespace {
23
24 StaticRefPtr<ConsoleUtils> gConsoleUtilsService;
25
26 }
27
28 /* static */
GetOrCreate()29 ConsoleUtils* ConsoleUtils::GetOrCreate() {
30 if (!gConsoleUtilsService) {
31 MOZ_ASSERT(NS_IsMainThread());
32
33 gConsoleUtilsService = new ConsoleUtils();
34 ClearOnShutdown(&gConsoleUtilsService);
35 }
36
37 return gConsoleUtilsService;
38 }
39
40 ConsoleUtils::ConsoleUtils() = default;
41 ConsoleUtils::~ConsoleUtils() = default;
42
43 /* static */
ReportForServiceWorkerScope(const nsAString & aScope,const nsAString & aMessage,const nsAString & aFilename,uint32_t aLineNumber,uint32_t aColumnNumber,Level aLevel)44 void ConsoleUtils::ReportForServiceWorkerScope(const nsAString& aScope,
45 const nsAString& aMessage,
46 const nsAString& aFilename,
47 uint32_t aLineNumber,
48 uint32_t aColumnNumber,
49 Level aLevel) {
50 MOZ_ASSERT(NS_IsMainThread());
51
52 RefPtr<ConsoleUtils> service = ConsoleUtils::GetOrCreate();
53 if (NS_WARN_IF(!service)) {
54 return;
55 }
56
57 service->ReportForServiceWorkerScopeInternal(
58 aScope, aMessage, aFilename, aLineNumber, aColumnNumber, aLevel);
59 }
60
ReportForServiceWorkerScopeInternal(const nsAString & aScope,const nsAString & aMessage,const nsAString & aFilename,uint32_t aLineNumber,uint32_t aColumnNumber,Level aLevel)61 void ConsoleUtils::ReportForServiceWorkerScopeInternal(
62 const nsAString& aScope, const nsAString& aMessage,
63 const nsAString& aFilename, uint32_t aLineNumber, uint32_t aColumnNumber,
64 Level aLevel) {
65 MOZ_ASSERT(NS_IsMainThread());
66
67 AutoJSAPI jsapi;
68 jsapi.Init();
69
70 JSContext* cx = jsapi.cx();
71
72 ConsoleCommon::ClearException ce(cx);
73 JS::Rooted<JSObject*> global(cx, GetOrCreateSandbox(cx));
74 if (NS_WARN_IF(!global)) {
75 return;
76 }
77
78 // The GetOrCreateSandbox call returns a proxy to the actual sandbox object.
79 // We don't need a proxy here.
80 global = js::UncheckedUnwrap(global);
81
82 JSAutoRealm ar(cx, global);
83
84 RootedDictionary<ConsoleEvent> event(cx);
85
86 event.mID.Construct();
87 event.mID.Value().SetAsString() = aScope;
88
89 event.mInnerID.Construct();
90 event.mInnerID.Value().SetAsString() = u"ServiceWorker"_ns;
91
92 switch (aLevel) {
93 case eLog:
94 event.mLevel = u"log"_ns;
95 break;
96
97 case eWarning:
98 event.mLevel = u"warn"_ns;
99 break;
100
101 case eError:
102 event.mLevel = u"error"_ns;
103 break;
104 }
105
106 event.mFilename = aFilename;
107 event.mLineNumber = aLineNumber;
108 event.mColumnNumber = aColumnNumber;
109 event.mTimeStamp = JS_Now() / PR_USEC_PER_MSEC;
110
111 JS::Rooted<JS::Value> messageValue(cx);
112 if (!dom::ToJSValue(cx, aMessage, &messageValue)) {
113 return;
114 }
115
116 event.mArguments.Construct();
117 if (!event.mArguments.Value().AppendElement(messageValue, fallible)) {
118 return;
119 }
120
121 nsCOMPtr<nsIConsoleAPIStorage> storage =
122 do_GetService("@mozilla.org/consoleAPI-storage;1");
123
124 if (NS_WARN_IF(!storage)) {
125 return;
126 }
127
128 JS::Rooted<JS::Value> eventValue(cx);
129 if (!ToJSValue(cx, event, &eventValue)) {
130 return;
131 }
132
133 // This is a legacy property.
134 JS::Rooted<JSObject*> eventObj(cx, &eventValue.toObject());
135 if (NS_WARN_IF(!JS_DefineProperty(cx, eventObj, "wrappedJSObject", eventObj,
136 JSPROP_ENUMERATE))) {
137 return;
138 }
139
140 storage->RecordEvent(u"ServiceWorker"_ns, aScope, eventValue);
141 }
142
GetOrCreateSandbox(JSContext * aCx)143 JSObject* ConsoleUtils::GetOrCreateSandbox(JSContext* aCx) {
144 AssertIsOnMainThread();
145
146 if (!mSandbox) {
147 nsIXPConnect* xpc = nsContentUtils::XPConnect();
148 MOZ_ASSERT(xpc, "This should never be null!");
149
150 RefPtr<NullPrincipal> nullPrincipal =
151 NullPrincipal::CreateWithoutOriginAttributes();
152
153 JS::Rooted<JSObject*> sandbox(aCx);
154 nsresult rv = xpc->CreateSandbox(aCx, nullPrincipal, sandbox.address());
155 if (NS_WARN_IF(NS_FAILED(rv))) {
156 return nullptr;
157 }
158
159 mSandbox = new JSObjectHolder(aCx, sandbox);
160 }
161
162 return mSandbox->GetJSObject();
163 }
164
165 } // namespace mozilla::dom
166