/* -*- 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/. */ #include "ConsoleUtils.h" #include "ConsoleCommon.h" #include "nsContentUtils.h" #include "nsIConsoleAPIStorage.h" #include "nsIXPConnect.h" #include "nsServiceManagerUtils.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/NullPrincipal.h" #include "mozilla/dom/ConsoleBinding.h" #include "mozilla/dom/ConsoleInstanceBinding.h" #include "mozilla/dom/RootedDictionary.h" #include "mozilla/dom/ScriptSettings.h" #include "js/PropertyAndElement.h" // JS_DefineProperty namespace mozilla::dom { namespace { StaticRefPtr gConsoleUtilsService; } /* static */ ConsoleUtils* ConsoleUtils::GetOrCreate() { if (!gConsoleUtilsService) { MOZ_ASSERT(NS_IsMainThread()); gConsoleUtilsService = new ConsoleUtils(); ClearOnShutdown(&gConsoleUtilsService); } return gConsoleUtilsService; } ConsoleUtils::ConsoleUtils() = default; ConsoleUtils::~ConsoleUtils() = default; /* static */ void ConsoleUtils::ReportForServiceWorkerScope(const nsAString& aScope, const nsAString& aMessage, const nsAString& aFilename, uint32_t aLineNumber, uint32_t aColumnNumber, Level aLevel) { MOZ_ASSERT(NS_IsMainThread()); RefPtr service = ConsoleUtils::GetOrCreate(); if (NS_WARN_IF(!service)) { return; } service->ReportForServiceWorkerScopeInternal( aScope, aMessage, aFilename, aLineNumber, aColumnNumber, aLevel); } void ConsoleUtils::ReportForServiceWorkerScopeInternal( const nsAString& aScope, const nsAString& aMessage, const nsAString& aFilename, uint32_t aLineNumber, uint32_t aColumnNumber, Level aLevel) { MOZ_ASSERT(NS_IsMainThread()); AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); ConsoleCommon::ClearException ce(cx); JS::Rooted global(cx, GetOrCreateSandbox(cx)); if (NS_WARN_IF(!global)) { return; } // The GetOrCreateSandbox call returns a proxy to the actual sandbox object. // We don't need a proxy here. global = js::UncheckedUnwrap(global); JSAutoRealm ar(cx, global); RootedDictionary event(cx); event.mID.Construct(); event.mID.Value().SetAsString() = aScope; event.mInnerID.Construct(); event.mInnerID.Value().SetAsString() = u"ServiceWorker"_ns; switch (aLevel) { case eLog: event.mLevel = u"log"_ns; break; case eWarning: event.mLevel = u"warn"_ns; break; case eError: event.mLevel = u"error"_ns; break; } event.mFilename = aFilename; event.mLineNumber = aLineNumber; event.mColumnNumber = aColumnNumber; event.mTimeStamp = JS_Now() / PR_USEC_PER_MSEC; event.mMicroSecondTimeStamp = JS_Now(); JS::Rooted messageValue(cx); if (!dom::ToJSValue(cx, aMessage, &messageValue)) { return; } event.mArguments.Construct(); if (!event.mArguments.Value().AppendElement(messageValue, fallible)) { return; } nsCOMPtr storage = do_GetService("@mozilla.org/consoleAPI-storage;1"); if (NS_WARN_IF(!storage)) { return; } JS::Rooted eventValue(cx); if (!ToJSValue(cx, event, &eventValue)) { return; } // This is a legacy property. JS::Rooted eventObj(cx, &eventValue.toObject()); if (NS_WARN_IF(!JS_DefineProperty(cx, eventObj, "wrappedJSObject", eventObj, JSPROP_ENUMERATE))) { return; } storage->RecordEvent(u"ServiceWorker"_ns, eventValue); } JSObject* ConsoleUtils::GetOrCreateSandbox(JSContext* aCx) { AssertIsOnMainThread(); if (!mSandbox) { nsIXPConnect* xpc = nsContentUtils::XPConnect(); MOZ_ASSERT(xpc, "This should never be null!"); RefPtr nullPrincipal = NullPrincipal::CreateWithoutOriginAttributes(); JS::Rooted sandbox(aCx); nsresult rv = xpc->CreateSandbox(aCx, nullPrincipal, sandbox.address()); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } mSandbox = new JSObjectHolder(aCx, sandbox); } return mSandbox->GetJSObject(); } } // namespace mozilla::dom