Bug 1890277: part 2) Add `require-trusted-types-for` directive to CSP parser, guarded...
[gecko.git] / dom / base / ChromeUtils.cpp
blob407f33e0449677a9d431ab25bbbc5d6d1e11125e
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/. */
7 #include "ChromeUtils.h"
9 #include "JSOracleParent.h"
10 #include "js/CallAndConstruct.h" // JS::Call
11 #include "js/ColumnNumber.h" // JS::TaggedColumnNumberOneOrigin, JS::ColumnNumberOneOrigin
12 #include "js/CharacterEncoding.h"
13 #include "js/Date.h" // JS::IsISOStyleDate
14 #include "js/Object.h" // JS::GetClass
15 #include "js/PropertyAndElement.h" // JS_DefineProperty, JS_DefinePropertyById, JS_Enumerate, JS_GetProperty, JS_GetPropertyById, JS_SetProperty, JS_SetPropertyById, JS::IdVector
16 #include "js/PropertyDescriptor.h" // JS::PropertyDescriptor, JS_GetOwnPropertyDescriptorById
17 #include "js/SavedFrameAPI.h"
18 #include "js/Value.h" // JS::Value, JS::StringValue
19 #include "jsfriendapi.h"
20 #include "WrapperFactory.h"
22 #include "mozilla/Base64.h"
23 #include "mozilla/CycleCollectedJSRuntime.h"
24 #include "mozilla/ErrorNames.h"
25 #include "mozilla/EventStateManager.h"
26 #include "mozilla/FormAutofillNative.h"
27 #include "mozilla/IntentionalCrash.h"
28 #include "mozilla/PerfStats.h"
29 #include "mozilla/Preferences.h"
30 #include "mozilla/ProcInfo.h"
31 #include "mozilla/ResultExtensions.h"
32 #include "mozilla/ScopeExit.h"
33 #include "mozilla/ScrollingMetrics.h"
34 #include "mozilla/SharedStyleSheetCache.h"
35 #include "mozilla/SpinEventLoopUntil.h"
36 #include "mozilla/TimeStamp.h"
37 #include "mozilla/dom/ContentParent.h"
38 #include "mozilla/dom/IdleDeadline.h"
39 #include "mozilla/dom/InProcessParent.h"
40 #include "mozilla/dom/JSActorService.h"
41 #include "mozilla/dom/MediaSessionBinding.h"
42 #include "mozilla/dom/PBrowserParent.h"
43 #include "mozilla/dom/Performance.h"
44 #include "mozilla/dom/PopupBlocker.h"
45 #include "mozilla/dom/Promise.h"
46 #include "mozilla/dom/Record.h"
47 #include "mozilla/dom/ReportingHeader.h"
48 #include "mozilla/dom/UnionTypes.h"
49 #include "mozilla/dom/WindowBinding.h" // For IdleRequestCallback/Options
50 #include "mozilla/dom/WindowGlobalParent.h"
51 #include "mozilla/dom/WorkerScope.h"
52 #include "mozilla/ipc/GeckoChildProcessHost.h"
53 #include "mozilla/ipc/UtilityProcessSandboxing.h"
54 #include "mozilla/ipc/UtilityProcessManager.h"
55 #include "mozilla/ipc/UtilityProcessHost.h"
56 #include "mozilla/net/UrlClassifierFeatureFactory.h"
57 #include "mozilla/RemoteDecoderManagerChild.h"
58 #include "mozilla/KeySystemConfig.h"
59 #include "mozilla/WheelHandlingHelper.h"
60 #include "IOActivityMonitor.h"
61 #include "nsNativeTheme.h"
62 #include "nsThreadUtils.h"
63 #include "mozJSModuleLoader.h"
64 #include "mozilla/ProfilerLabels.h"
65 #include "mozilla/ProfilerMarkers.h"
66 #include "nsDocShell.h"
67 #include "nsIException.h"
68 #include "VsyncSource.h"
70 #ifdef XP_UNIX
71 # include <errno.h>
72 # include <unistd.h>
73 # include <fcntl.h>
74 # include <poll.h>
75 # include <sys/wait.h>
77 # ifdef XP_LINUX
78 # include <sys/prctl.h>
79 # endif
80 #endif
82 #ifdef MOZ_WMF_CDM
83 # include "mozilla/MFCDMParent.h"
84 #endif
86 namespace mozilla::dom {
88 /* static */
89 void ChromeUtils::NondeterministicGetWeakMapKeys(
90 GlobalObject& aGlobal, JS::Handle<JS::Value> aMap,
91 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
92 if (!aMap.isObject()) {
93 aRetval.setUndefined();
94 } else {
95 JSContext* cx = aGlobal.Context();
96 JS::Rooted<JSObject*> objRet(cx);
97 JS::Rooted<JSObject*> mapObj(cx, &aMap.toObject());
98 if (!JS_NondeterministicGetWeakMapKeys(cx, mapObj, &objRet)) {
99 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
100 } else {
101 aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
106 /* static */
107 void ChromeUtils::NondeterministicGetWeakSetKeys(
108 GlobalObject& aGlobal, JS::Handle<JS::Value> aSet,
109 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
110 if (!aSet.isObject()) {
111 aRetval.setUndefined();
112 } else {
113 JSContext* cx = aGlobal.Context();
114 JS::Rooted<JSObject*> objRet(cx);
115 JS::Rooted<JSObject*> setObj(cx, &aSet.toObject());
116 if (!JS_NondeterministicGetWeakSetKeys(cx, setObj, &objRet)) {
117 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
118 } else {
119 aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
124 /* static */
125 void ChromeUtils::Base64URLEncode(GlobalObject& aGlobal,
126 const ArrayBufferViewOrArrayBuffer& aSource,
127 const Base64URLEncodeOptions& aOptions,
128 nsACString& aResult, ErrorResult& aRv) {
129 auto paddingPolicy = aOptions.mPad ? Base64URLEncodePaddingPolicy::Include
130 : Base64URLEncodePaddingPolicy::Omit;
131 ProcessTypedArrays(
132 aSource, [&](const Span<uint8_t>& aData, JS::AutoCheckCannotGC&&) {
133 nsresult rv = mozilla::Base64URLEncode(aData.Length(), aData.Elements(),
134 paddingPolicy, aResult);
135 if (NS_WARN_IF(NS_FAILED(rv))) {
136 aResult.Truncate();
137 aRv.Throw(rv);
142 /* static */
143 void ChromeUtils::Base64URLDecode(GlobalObject& aGlobal,
144 const nsACString& aString,
145 const Base64URLDecodeOptions& aOptions,
146 JS::MutableHandle<JSObject*> aRetval,
147 ErrorResult& aRv) {
148 Base64URLDecodePaddingPolicy paddingPolicy;
149 switch (aOptions.mPadding) {
150 case Base64URLDecodePadding::Require:
151 paddingPolicy = Base64URLDecodePaddingPolicy::Require;
152 break;
154 case Base64URLDecodePadding::Ignore:
155 paddingPolicy = Base64URLDecodePaddingPolicy::Ignore;
156 break;
158 case Base64URLDecodePadding::Reject:
159 paddingPolicy = Base64URLDecodePaddingPolicy::Reject;
160 break;
162 default:
163 aRv.Throw(NS_ERROR_INVALID_ARG);
164 return;
166 FallibleTArray<uint8_t> data;
167 nsresult rv = mozilla::Base64URLDecode(aString, paddingPolicy, data);
168 if (NS_WARN_IF(NS_FAILED(rv))) {
169 aRv.Throw(rv);
170 return;
173 JS::Rooted<JSObject*> buffer(
174 aGlobal.Context(), ArrayBuffer::Create(aGlobal.Context(), data, aRv));
175 if (aRv.Failed()) {
176 return;
178 aRetval.set(buffer);
181 /* static */
182 void ChromeUtils::ReleaseAssert(GlobalObject& aGlobal, bool aCondition,
183 const nsAString& aMessage) {
184 // If the condition didn't fail, which is the likely case, immediately return.
185 if (MOZ_LIKELY(aCondition)) {
186 return;
189 // Extract the current stack from the JS runtime to embed in the crash reason.
190 nsAutoString filename;
191 uint32_t lineNo = 0;
193 if (nsCOMPtr<nsIStackFrame> location = GetCurrentJSStack(1)) {
194 location->GetFilename(aGlobal.Context(), filename);
195 lineNo = location->GetLineNumber(aGlobal.Context());
196 } else {
197 filename.Assign(u"<unknown>"_ns);
200 // Convert to utf-8 for adding as the MozCrashReason.
201 NS_ConvertUTF16toUTF8 filenameUtf8(filename);
202 NS_ConvertUTF16toUTF8 messageUtf8(aMessage);
204 // Actually crash.
205 MOZ_CRASH_UNSAFE_PRINTF("Failed ChromeUtils.releaseAssert(\"%s\") @ %s:%u",
206 messageUtf8.get(), filenameUtf8.get(), lineNo);
209 /* static */
210 void ChromeUtils::AddProfilerMarker(
211 GlobalObject& aGlobal, const nsACString& aName,
212 const ProfilerMarkerOptionsOrDouble& aOptions,
213 const Optional<nsACString>& aText) {
214 if (!profiler_thread_is_being_profiled_for_markers()) {
215 return;
218 MarkerOptions options;
220 MarkerCategory category = ::geckoprofiler::category::JS;
222 DOMHighResTimeStamp startTime = 0;
223 uint64_t innerWindowId = 0;
224 if (aOptions.IsDouble()) {
225 startTime = aOptions.GetAsDouble();
226 } else {
227 const ProfilerMarkerOptions& opt = aOptions.GetAsProfilerMarkerOptions();
228 startTime = opt.mStartTime;
229 innerWindowId = opt.mInnerWindowId;
231 if (opt.mCaptureStack) {
232 // If we will be capturing a stack, change the category of the
233 // ChromeUtils.addProfilerMarker label automatically added by the webidl
234 // binding from DOM to PROFILER so that this function doesn't appear in
235 // the marker stack.
236 JSContext* cx = aGlobal.Context();
237 ProfilingStack* stack = js::GetContextProfilingStackIfEnabled(cx);
238 if (MOZ_LIKELY(stack)) {
239 uint32_t sp = stack->stackPointer;
240 if (MOZ_LIKELY(sp > 0)) {
241 js::ProfilingStackFrame& frame = stack->frames[sp - 1];
242 if (frame.isLabelFrame() && "ChromeUtils"_ns.Equals(frame.label()) &&
243 "addProfilerMarker"_ns.Equals(frame.dynamicString())) {
244 frame.setLabelCategory(JS::ProfilingCategoryPair::PROFILER);
249 options.Set(MarkerStack::Capture());
251 #define BEGIN_CATEGORY(name, labelAsString, color) \
252 if (opt.mCategory.Equals(labelAsString)) { \
253 category = ::geckoprofiler::category::name; \
254 } else
255 #define SUBCATEGORY(supercategory, name, labelAsString)
256 #define END_CATEGORY
257 MOZ_PROFILING_CATEGORY_LIST(BEGIN_CATEGORY, SUBCATEGORY, END_CATEGORY)
258 #undef BEGIN_CATEGORY
259 #undef SUBCATEGORY
260 #undef END_CATEGORY
262 category = ::geckoprofiler::category::OTHER;
265 if (startTime) {
266 RefPtr<Performance> performance;
268 if (NS_IsMainThread()) {
269 nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
270 do_QueryInterface(aGlobal.GetAsSupports());
271 if (ownerWindow) {
272 performance = ownerWindow->GetPerformance();
274 } else {
275 JSContext* cx = aGlobal.Context();
276 WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
277 if (workerPrivate) {
278 performance = workerPrivate->GlobalScope()->GetPerformance();
282 if (performance) {
283 options.Set(MarkerTiming::IntervalUntilNowFrom(
284 performance->CreationTimeStamp() +
285 TimeDuration::FromMilliseconds(startTime)));
286 } else {
287 options.Set(MarkerTiming::IntervalUntilNowFrom(
288 TimeStamp::ProcessCreation() +
289 TimeDuration::FromMilliseconds(startTime)));
293 if (innerWindowId) {
294 options.Set(MarkerInnerWindowId(innerWindowId));
295 } else {
296 options.Set(MarkerInnerWindowIdFromJSContext(aGlobal.Context()));
300 AUTO_PROFILER_STATS(ChromeUtils_AddProfilerMarker);
301 if (aText.WasPassed()) {
302 profiler_add_marker(aName, category, std::move(options),
303 ::geckoprofiler::markers::TextMarker{},
304 aText.Value());
305 } else {
306 profiler_add_marker(aName, category, std::move(options));
311 /* static */
312 void ChromeUtils::GetXPCOMErrorName(GlobalObject& aGlobal, uint32_t aErrorCode,
313 nsACString& aRetval) {
314 GetErrorName((nsresult)aErrorCode, aRetval);
317 /* static */
318 void ChromeUtils::WaiveXrays(GlobalObject& aGlobal, JS::Handle<JS::Value> aVal,
319 JS::MutableHandle<JS::Value> aRetval,
320 ErrorResult& aRv) {
321 JS::Rooted<JS::Value> value(aGlobal.Context(), aVal);
322 if (!xpc::WrapperFactory::WaiveXrayAndWrap(aGlobal.Context(), &value)) {
323 aRv.NoteJSContextException(aGlobal.Context());
324 } else {
325 aRetval.set(value);
329 /* static */
330 void ChromeUtils::UnwaiveXrays(GlobalObject& aGlobal,
331 JS::Handle<JS::Value> aVal,
332 JS::MutableHandle<JS::Value> aRetval,
333 ErrorResult& aRv) {
334 if (!aVal.isObject()) {
335 aRetval.set(aVal);
336 return;
339 JS::Rooted<JSObject*> obj(aGlobal.Context(),
340 js::UncheckedUnwrap(&aVal.toObject()));
341 if (!JS_WrapObject(aGlobal.Context(), &obj)) {
342 aRv.NoteJSContextException(aGlobal.Context());
343 } else {
344 aRetval.setObject(*obj);
348 /* static */
349 void ChromeUtils::GetClassName(GlobalObject& aGlobal,
350 JS::Handle<JSObject*> aObj, bool aUnwrap,
351 nsAString& aRetval) {
352 JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
353 if (aUnwrap) {
354 obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
357 aRetval = NS_ConvertUTF8toUTF16(nsDependentCString(JS::GetClass(obj)->name));
360 /* static */
361 bool ChromeUtils::IsDOMObject(GlobalObject& aGlobal, JS::Handle<JSObject*> aObj,
362 bool aUnwrap) {
363 JS::Rooted<JSObject*> obj(aGlobal.Context(), aObj);
364 if (aUnwrap) {
365 obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
368 return mozilla::dom::IsDOMObject(obj);
371 /* static */
372 bool ChromeUtils::IsISOStyleDate(GlobalObject& aGlobal,
373 const nsACString& aStr) {
374 // aStr is a UTF-8 string, however we can cast to JS::Latin1Chars
375 // because JS::IsISOStyleDate handles ASCII only
376 return JS::IsISOStyleDate(aGlobal.Context(),
377 JS::Latin1Chars(aStr.Data(), aStr.Length()));
380 /* static */
381 void ChromeUtils::ShallowClone(GlobalObject& aGlobal,
382 JS::Handle<JSObject*> aObj,
383 JS::Handle<JSObject*> aTarget,
384 JS::MutableHandle<JSObject*> aRetval,
385 ErrorResult& aRv) {
386 JSContext* cx = aGlobal.Context();
388 auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
390 JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
391 JS::RootedVector<JS::Value> values(cx);
392 JS::RootedVector<jsid> valuesIds(cx);
395 // cx represents our current Realm, so it makes sense to use it for the
396 // CheckedUnwrapDynamic call. We do want CheckedUnwrapDynamic, in case
397 // someone is shallow-cloning a Window.
398 JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapDynamic(aObj, cx));
399 if (!obj) {
400 js::ReportAccessDenied(cx);
401 return;
404 if (js::IsScriptedProxy(obj)) {
405 JS_ReportErrorASCII(cx, "Shallow cloning a proxy object is not allowed");
406 return;
409 JSAutoRealm ar(cx, obj);
411 if (!JS_Enumerate(cx, obj, &ids) || !values.reserve(ids.length()) ||
412 !valuesIds.reserve(ids.length())) {
413 return;
416 JS::Rooted<Maybe<JS::PropertyDescriptor>> desc(cx);
417 JS::Rooted<JS::PropertyKey> id(cx);
418 for (jsid idVal : ids) {
419 id = idVal;
420 if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) {
421 continue;
423 if (desc.isNothing() || desc->isAccessorDescriptor()) {
424 continue;
426 valuesIds.infallibleAppend(id);
427 values.infallibleAppend(desc->value());
431 JS::Rooted<JSObject*> obj(cx);
433 Maybe<JSAutoRealm> ar;
434 if (aTarget) {
435 // Our target could be anything, so we want CheckedUnwrapDynamic here.
436 // "cx" represents the current Realm when we were called from bindings, so
437 // we can just use that.
438 JS::Rooted<JSObject*> target(cx, js::CheckedUnwrapDynamic(aTarget, cx));
439 if (!target) {
440 js::ReportAccessDenied(cx);
441 return;
443 ar.emplace(cx, target);
446 obj = JS_NewPlainObject(cx);
447 if (!obj) {
448 return;
451 JS::Rooted<JS::Value> value(cx);
452 JS::Rooted<JS::PropertyKey> id(cx);
453 for (uint32_t i = 0; i < valuesIds.length(); i++) {
454 id = valuesIds[i];
455 value = values[i];
457 JS_MarkCrossZoneId(cx, id);
458 if (!JS_WrapValue(cx, &value) ||
459 !JS_SetPropertyById(cx, obj, id, value)) {
460 return;
465 if (aTarget && !JS_WrapObject(cx, &obj)) {
466 return;
469 cleanup.release();
470 aRetval.set(obj);
473 namespace {
474 class IdleDispatchRunnable final : public IdleRunnable,
475 public nsITimerCallback {
476 public:
477 NS_DECL_ISUPPORTS_INHERITED
479 IdleDispatchRunnable(nsIGlobalObject* aParent, IdleRequestCallback& aCallback)
480 : IdleRunnable("ChromeUtils::IdleDispatch"),
481 mCallback(&aCallback),
482 mParent(aParent) {}
484 // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT.
485 // See bug 1535398.
486 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
487 if (mCallback) {
488 CancelTimer();
490 auto deadline = mDeadline - TimeStamp::ProcessCreation();
492 ErrorResult rv;
493 RefPtr<IdleDeadline> idleDeadline =
494 new IdleDeadline(mParent, mTimedOut, deadline.ToMilliseconds());
496 RefPtr<IdleRequestCallback> callback(std::move(mCallback));
497 MOZ_ASSERT(!mCallback);
498 callback->Call(*idleDeadline, "ChromeUtils::IdleDispatch handler");
499 mParent = nullptr;
501 return NS_OK;
504 void SetDeadline(TimeStamp aDeadline) override { mDeadline = aDeadline; }
506 NS_IMETHOD Notify(nsITimer* aTimer) override {
507 mTimedOut = true;
508 SetDeadline(TimeStamp::Now());
509 return Run();
512 void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override {
513 MOZ_ASSERT(aTarget);
514 MOZ_ASSERT(!mTimer);
515 NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, aDelay,
516 nsITimer::TYPE_ONE_SHOT, aTarget);
519 protected:
520 virtual ~IdleDispatchRunnable() { CancelTimer(); }
522 private:
523 void CancelTimer() {
524 if (mTimer) {
525 mTimer->Cancel();
526 mTimer = nullptr;
530 RefPtr<IdleRequestCallback> mCallback;
531 nsCOMPtr<nsIGlobalObject> mParent;
533 nsCOMPtr<nsITimer> mTimer;
535 TimeStamp mDeadline{};
536 bool mTimedOut = false;
539 NS_IMPL_ISUPPORTS_INHERITED(IdleDispatchRunnable, IdleRunnable,
540 nsITimerCallback)
541 } // anonymous namespace
543 /* static */
544 void ChromeUtils::IdleDispatch(const GlobalObject& aGlobal,
545 IdleRequestCallback& aCallback,
546 const IdleRequestOptions& aOptions,
547 ErrorResult& aRv) {
548 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
549 MOZ_ASSERT(global);
551 auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback);
553 if (aOptions.mTimeout.WasPassed()) {
554 aRv = NS_DispatchToCurrentThreadQueue(
555 runnable.forget(), aOptions.mTimeout.Value(), EventQueuePriority::Idle);
556 } else {
557 aRv = NS_DispatchToCurrentThreadQueue(runnable.forget(),
558 EventQueuePriority::Idle);
562 /* static */
563 void ChromeUtils::Import(const GlobalObject& aGlobal,
564 const nsACString& aResourceURI,
565 const Optional<JS::Handle<JSObject*>>& aTargetObj,
566 JS::MutableHandle<JSObject*> aRetval,
567 ErrorResult& aRv) {
568 RefPtr moduleloader = mozJSModuleLoader::Get();
569 MOZ_ASSERT(moduleloader);
571 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE("ChromeUtils::Import",
572 OTHER, aResourceURI);
574 JSContext* cx = aGlobal.Context();
576 JS::Rooted<JSObject*> global(cx);
577 JS::Rooted<JSObject*> exports(cx);
578 nsresult rv = moduleloader->Import(cx, aResourceURI, &global, &exports);
579 if (NS_FAILED(rv)) {
580 aRv.Throw(rv);
581 return;
584 // Import() on the component loader can return NS_OK while leaving an
585 // exception on the JSContext. Check for that case.
586 if (JS_IsExceptionPending(cx)) {
587 aRv.NoteJSContextException(cx);
588 return;
591 if (aTargetObj.WasPassed()) {
592 if (!JS_AssignObject(cx, aTargetObj.Value(), exports)) {
593 aRv.Throw(NS_ERROR_FAILURE);
594 return;
598 if (!JS_WrapObject(cx, &exports)) {
599 aRv.Throw(NS_ERROR_FAILURE);
600 return;
602 aRetval.set(exports);
605 static mozJSModuleLoader* GetModuleLoaderForCurrentGlobal(
606 JSContext* aCx, const GlobalObject& aGlobal,
607 Maybe<loader::NonSharedGlobalSyncModuleLoaderScope>&
608 aMaybeSyncLoaderScope) {
609 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
611 if (mozJSModuleLoader::IsSharedSystemGlobal(global)) {
612 return mozJSModuleLoader::Get();
614 if (mozJSModuleLoader::IsDevToolsLoaderGlobal(global)) {
615 return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
618 if (loader::NonSharedGlobalSyncModuleLoaderScope::IsActive()) {
619 mozJSModuleLoader* moduleloader =
620 loader::NonSharedGlobalSyncModuleLoaderScope::ActiveLoader();
622 if (!moduleloader->IsLoaderGlobal(global->GetGlobalJSObject())) {
623 JS_ReportErrorASCII(aCx,
624 "global: \"current\" option cannot be used for "
625 "different global while other importESModule "
626 "with global: \"current\" is on the stack");
627 return nullptr;
630 return moduleloader;
633 RefPtr targetModuleLoader = global->GetModuleLoader(aCx);
634 if (!targetModuleLoader) {
635 // Sandbox without associated window returns nullptr for GetModuleLoader.
636 JS_ReportErrorASCII(aCx, "No ModuleLoader found for the current context");
637 return nullptr;
640 if (targetModuleLoader->HasFetchingModules()) {
641 if (!NS_IsMainThread()) {
642 JS_ReportErrorASCII(aCx,
643 "ChromeUtils.importESModule cannot be used in worker "
644 "when there is ongoing dynamic import");
645 return nullptr;
648 if (!mozilla::SpinEventLoopUntil(
649 "importESModule for current global"_ns, [&]() -> bool {
650 return !targetModuleLoader->HasFetchingModules();
651 })) {
652 JS_ReportErrorASCII(aCx, "Failed to wait for ongoing module requests");
653 return nullptr;
657 aMaybeSyncLoaderScope.emplace(aCx, global);
658 return aMaybeSyncLoaderScope->ActiveLoader();
661 static mozJSModuleLoader* GetModuleLoaderForOptions(
662 JSContext* aCx, const GlobalObject& aGlobal,
663 const ImportESModuleOptionsDictionary& aOptions,
664 Maybe<loader::NonSharedGlobalSyncModuleLoaderScope>&
665 aMaybeSyncLoaderScope) {
666 if (!aOptions.mGlobal.WasPassed()) {
667 return mozJSModuleLoader::Get();
670 switch (aOptions.mGlobal.Value()) {
671 case ImportESModuleTargetGlobal::Shared:
672 return mozJSModuleLoader::Get();
674 case ImportESModuleTargetGlobal::Devtools:
675 return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
677 case ImportESModuleTargetGlobal::Contextual: {
678 if (!NS_IsMainThread()) {
679 return GetModuleLoaderForCurrentGlobal(aCx, aGlobal,
680 aMaybeSyncLoaderScope);
683 RefPtr devToolsModuleloader = mozJSModuleLoader::GetDevToolsLoader();
684 if (devToolsModuleloader &&
685 devToolsModuleloader->IsLoaderGlobal(aGlobal.Get())) {
686 return mozJSModuleLoader::GetOrCreateDevToolsLoader(aCx);
688 return mozJSModuleLoader::Get();
691 case ImportESModuleTargetGlobal::Current:
692 return GetModuleLoaderForCurrentGlobal(aCx, aGlobal,
693 aMaybeSyncLoaderScope);
695 default:
696 MOZ_CRASH("Unknown ImportESModuleTargetGlobal");
700 static bool ValidateImportOptions(
701 JSContext* aCx, const GlobalObject& aGlobal,
702 const ImportESModuleOptionsDictionary& aOptions) {
703 if (!NS_IsMainThread() &&
704 (!aOptions.mGlobal.WasPassed() ||
705 (aOptions.mGlobal.Value() != ImportESModuleTargetGlobal::Current &&
706 aOptions.mGlobal.Value() != ImportESModuleTargetGlobal::Contextual))) {
707 JS_ReportErrorASCII(aCx,
708 "ChromeUtils.importESModule: Only { global: "
709 "\"current\" } and { global: \"contextual\" } options "
710 "are supported on worker");
711 return false;
714 if (NS_IsMainThread()) {
715 nsCOMPtr<nsIGlobalObject> global =
716 do_QueryInterface(aGlobal.GetAsSupports());
718 if (mozJSModuleLoader::IsDevToolsLoaderGlobal(global) &&
719 !aOptions.mGlobal.WasPassed()) {
720 JS_ReportErrorASCII(aCx,
721 "ChromeUtils.importESModule: global option is "
722 "required in DevTools distinct global");
723 return false;
727 return true;
730 /* static */
731 void ChromeUtils::ImportESModule(
732 const GlobalObject& aGlobal, const nsAString& aResourceURI,
733 const ImportESModuleOptionsDictionary& aOptions,
734 JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) {
735 JSContext* cx = aGlobal.Context();
737 if (!ValidateImportOptions(cx, aGlobal, aOptions)) {
738 aRv.Throw(NS_ERROR_FAILURE);
739 return;
742 Maybe<loader::NonSharedGlobalSyncModuleLoaderScope> maybeSyncLoaderScope;
743 RefPtr<mozJSModuleLoader> moduleloader =
744 GetModuleLoaderForOptions(cx, aGlobal, aOptions, maybeSyncLoaderScope);
745 if (!moduleloader) {
746 aRv.Throw(NS_ERROR_FAILURE);
747 return;
750 NS_ConvertUTF16toUTF8 registryLocation(aResourceURI);
752 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE(
753 "ChromeUtils::ImportESModule", OTHER, registryLocation);
755 JS::Rooted<JSObject*> moduleNamespace(cx);
756 nsresult rv =
757 moduleloader->ImportESModule(cx, registryLocation, &moduleNamespace);
758 if (NS_FAILED(rv)) {
759 aRv.Throw(rv);
760 return;
763 MOZ_ASSERT(!JS_IsExceptionPending(cx));
765 if (!JS_WrapObject(cx, &moduleNamespace)) {
766 aRv.Throw(NS_ERROR_FAILURE);
767 return;
769 aRetval.set(moduleNamespace);
771 if (maybeSyncLoaderScope) {
772 maybeSyncLoaderScope->Finish();
776 // An integer encoding for ImportESModuleOptionsDictionary, to pass the value
777 // to the lazy getters.
778 class EncodedOptions {
779 public:
780 explicit EncodedOptions(const ImportESModuleOptionsDictionary& aOptions) {
781 if (aOptions.mGlobal.WasPassed()) {
782 mValue = uint32_t(aOptions.mGlobal.Value()) + 1;
783 } else {
784 mValue = 0;
788 explicit EncodedOptions(uint32_t aValue) : mValue(aValue) {}
790 int32_t toInt32() const { return int32_t(mValue); }
792 void DecodeInto(ImportESModuleOptionsDictionary& aOptions) {
793 if (mValue == 0) {
794 aOptions.mGlobal.Reset();
795 } else {
796 aOptions.mGlobal.Construct(ImportESModuleTargetGlobal(mValue - 1));
800 private:
801 uint32_t mValue = 0;
804 namespace lazy_getter {
806 // The property id of the getter.
807 // Used by all lazy getters.
808 static const size_t SLOT_ID = 0;
810 // The URI of the module to import.
811 // Used by ChromeUtils.defineModuleGetter and ChromeUtils.defineESModuleGetters.
812 static const size_t SLOT_URI = 1;
814 // An array object that contians values for PARAM_INDEX_TARGET and
815 // PARAM_INDEX_LAMBDA.
816 // Used by ChromeUtils.defineLazyGetter.
817 static const size_t SLOT_PARAMS = 1;
819 // The EncodedOptions value.
820 // Used by ChromeUtils.defineESModuleGetters.
821 static const size_t SLOT_OPTIONS = 2;
823 static const size_t PARAM_INDEX_TARGET = 0;
824 static const size_t PARAM_INDEX_LAMBDA = 1;
825 static const size_t PARAMS_COUNT = 2;
827 static bool ExtractArgs(JSContext* aCx, JS::CallArgs& aArgs,
828 JS::MutableHandle<JSObject*> aCallee,
829 JS::MutableHandle<JSObject*> aThisObj,
830 JS::MutableHandle<jsid> aId) {
831 aCallee.set(&aArgs.callee());
833 JS::Handle<JS::Value> thisv = aArgs.thisv();
834 if (!thisv.isObject()) {
835 JS_ReportErrorASCII(aCx, "Invalid target object");
836 return false;
839 aThisObj.set(&thisv.toObject());
841 JS::Rooted<JS::Value> id(aCx,
842 js::GetFunctionNativeReserved(aCallee, SLOT_ID));
843 MOZ_ALWAYS_TRUE(JS_ValueToId(aCx, id, aId));
844 return true;
847 static bool JSLazyGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
848 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
850 JS::Rooted<JSObject*> callee(aCx);
851 JS::Rooted<JSObject*> unused(aCx);
852 JS::Rooted<jsid> id(aCx);
853 if (!ExtractArgs(aCx, args, &callee, &unused, &id)) {
854 return false;
857 JS::Rooted<JS::Value> paramsVal(
858 aCx, js::GetFunctionNativeReserved(callee, SLOT_PARAMS));
859 if (paramsVal.isUndefined()) {
860 args.rval().setUndefined();
861 return true;
863 // Avoid calling the lambda multiple times, in case of:
864 // * the getter function is retrieved from property descriptor and called
865 // * the lambda gets the property again
866 // * the getter function throws and accessed again
867 js::SetFunctionNativeReserved(callee, SLOT_PARAMS, JS::UndefinedHandleValue);
869 JS::Rooted<JSObject*> paramsObj(aCx, &paramsVal.toObject());
871 JS::Rooted<JS::Value> targetVal(aCx);
872 JS::Rooted<JS::Value> lambdaVal(aCx);
873 if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_TARGET, &targetVal)) {
874 return false;
876 if (!JS_GetElement(aCx, paramsObj, PARAM_INDEX_LAMBDA, &lambdaVal)) {
877 return false;
880 JS::Rooted<JSObject*> targetObj(aCx, &targetVal.toObject());
882 JS::Rooted<JS::Value> value(aCx);
883 if (!JS::Call(aCx, targetObj, lambdaVal, JS::HandleValueArray::empty(),
884 &value)) {
885 return false;
888 if (!JS_DefinePropertyById(aCx, targetObj, id, value, JSPROP_ENUMERATE)) {
889 return false;
892 args.rval().set(value);
893 return true;
896 static bool DefineLazyGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
897 JS::Handle<JS::Value> aName,
898 JS::Handle<JSObject*> aLambda) {
899 JS::Rooted<jsid> id(aCx);
900 if (!JS_ValueToId(aCx, aName, &id)) {
901 return false;
904 JS::Rooted<JSObject*> getter(
905 aCx, JS_GetFunctionObject(
906 js::NewFunctionByIdWithReserved(aCx, JSLazyGetter, 0, 0, id)));
907 if (!getter) {
908 JS_ReportOutOfMemory(aCx);
909 return false;
912 JS::RootedVector<JS::Value> params(aCx);
913 if (!params.resize(PARAMS_COUNT)) {
914 return false;
916 params[PARAM_INDEX_TARGET].setObject(*aTarget);
917 params[PARAM_INDEX_LAMBDA].setObject(*aLambda);
918 JS::Rooted<JSObject*> paramsObj(aCx, JS::NewArrayObject(aCx, params));
919 if (!paramsObj) {
920 return false;
923 js::SetFunctionNativeReserved(getter, SLOT_ID, aName);
924 js::SetFunctionNativeReserved(getter, SLOT_PARAMS,
925 JS::ObjectValue(*paramsObj));
927 return JS_DefinePropertyById(aCx, aTarget, id, getter, nullptr,
928 JSPROP_ENUMERATE);
931 enum class ModuleType { JSM, ESM };
933 static bool ModuleGetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
934 ModuleType aType) {
935 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
937 JS::Rooted<JSObject*> callee(aCx);
938 JS::Rooted<JSObject*> thisObj(aCx);
939 JS::Rooted<jsid> id(aCx);
940 if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
941 return false;
944 JS::Rooted<JSString*> moduleURI(
945 aCx, js::GetFunctionNativeReserved(callee, SLOT_URI).toString());
946 JS::UniqueChars bytes = JS_EncodeStringToUTF8(aCx, moduleURI);
947 if (!bytes) {
948 return false;
950 nsDependentCString uri(bytes.get());
952 JS::Rooted<JS::Value> value(aCx);
953 if (aType == ModuleType::JSM) {
954 RefPtr moduleloader = mozJSModuleLoader::Get();
955 MOZ_ASSERT(moduleloader);
957 JS::Rooted<JSObject*> moduleGlobal(aCx);
958 JS::Rooted<JSObject*> moduleExports(aCx);
959 nsresult rv = moduleloader->Import(aCx, uri, &moduleGlobal, &moduleExports);
960 if (NS_FAILED(rv)) {
961 Throw(aCx, rv);
962 return false;
965 // JSM's exports is from the same realm.
966 if (!JS_GetPropertyById(aCx, moduleExports, id, &value)) {
967 return false;
969 } else {
970 EncodedOptions encodedOptions(
971 js::GetFunctionNativeReserved(callee, SLOT_OPTIONS).toInt32());
973 ImportESModuleOptionsDictionary options;
974 encodedOptions.DecodeInto(options);
976 GlobalObject global(aCx, callee);
978 Maybe<loader::NonSharedGlobalSyncModuleLoaderScope> maybeSyncLoaderScope;
979 RefPtr<mozJSModuleLoader> moduleloader =
980 GetModuleLoaderForOptions(aCx, global, options, maybeSyncLoaderScope);
981 if (!moduleloader) {
982 return false;
985 JS::Rooted<JSObject*> moduleNamespace(aCx);
986 nsresult rv = moduleloader->ImportESModule(aCx, uri, &moduleNamespace);
987 if (NS_FAILED(rv)) {
988 Throw(aCx, rv);
989 return false;
992 // ESM's namespace is from the module's realm.
994 JSAutoRealm ar(aCx, moduleNamespace);
995 if (!JS_GetPropertyById(aCx, moduleNamespace, id, &value)) {
996 return false;
999 if (!JS_WrapValue(aCx, &value)) {
1000 return false;
1003 if (maybeSyncLoaderScope) {
1004 maybeSyncLoaderScope->Finish();
1008 if (!JS_DefinePropertyById(aCx, thisObj, id, value, JSPROP_ENUMERATE)) {
1009 return false;
1012 args.rval().set(value);
1013 return true;
1016 static bool JSModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
1017 return ModuleGetterImpl(aCx, aArgc, aVp, ModuleType::JSM);
1020 static bool ESModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
1021 return ModuleGetterImpl(aCx, aArgc, aVp, ModuleType::ESM);
1024 static bool ModuleSetterImpl(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
1025 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
1027 JS::Rooted<JSObject*> callee(aCx);
1028 JS::Rooted<JSObject*> thisObj(aCx);
1029 JS::Rooted<jsid> id(aCx);
1030 if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
1031 return false;
1034 return JS_DefinePropertyById(aCx, thisObj, id, args.get(0), JSPROP_ENUMERATE);
1037 static bool JSModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
1038 return ModuleSetterImpl(aCx, aArgc, aVp);
1041 static bool ESModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
1042 return ModuleSetterImpl(aCx, aArgc, aVp);
1045 static bool DefineJSModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
1046 const nsAString& aId,
1047 const nsAString& aResourceURI) {
1048 JS::Rooted<JS::Value> uri(aCx);
1049 JS::Rooted<JS::Value> idValue(aCx);
1050 JS::Rooted<jsid> id(aCx);
1051 if (!xpc::NonVoidStringToJsval(aCx, aResourceURI, &uri) ||
1052 !xpc::NonVoidStringToJsval(aCx, aId, &idValue) ||
1053 !JS_ValueToId(aCx, idValue, &id)) {
1054 return false;
1056 idValue = js::IdToValue(id);
1058 JS::Rooted<JSObject*> getter(
1059 aCx, JS_GetFunctionObject(
1060 js::NewFunctionByIdWithReserved(aCx, JSModuleGetter, 0, 0, id)));
1062 JS::Rooted<JSObject*> setter(
1063 aCx, JS_GetFunctionObject(
1064 js::NewFunctionByIdWithReserved(aCx, JSModuleSetter, 0, 0, id)));
1066 if (!getter || !setter) {
1067 JS_ReportOutOfMemory(aCx);
1068 return false;
1071 js::SetFunctionNativeReserved(getter, SLOT_ID, idValue);
1072 js::SetFunctionNativeReserved(setter, SLOT_ID, idValue);
1074 js::SetFunctionNativeReserved(getter, SLOT_URI, uri);
1076 return JS_DefinePropertyById(aCx, aTarget, id, getter, setter,
1077 JSPROP_ENUMERATE);
1080 static bool DefineESModuleGetter(JSContext* aCx, JS::Handle<JSObject*> aTarget,
1081 JS::Handle<JS::PropertyKey> aId,
1082 JS::Handle<JS::Value> aResourceURI,
1083 const EncodedOptions& encodedOptions) {
1084 JS::Rooted<JS::Value> idVal(aCx, JS::StringValue(aId.toString()));
1086 JS::Rooted<JS::Value> optionsVal(aCx,
1087 JS::Int32Value(encodedOptions.toInt32()));
1089 JS::Rooted<JSObject*> getter(
1090 aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
1091 aCx, ESModuleGetter, 0, 0, aId)));
1093 JS::Rooted<JSObject*> setter(
1094 aCx, JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
1095 aCx, ESModuleSetter, 0, 0, aId)));
1097 if (!getter || !setter) {
1098 JS_ReportOutOfMemory(aCx);
1099 return false;
1102 js::SetFunctionNativeReserved(getter, SLOT_ID, idVal);
1103 js::SetFunctionNativeReserved(setter, SLOT_ID, idVal);
1105 js::SetFunctionNativeReserved(getter, SLOT_URI, aResourceURI);
1107 js::SetFunctionNativeReserved(getter, SLOT_OPTIONS, optionsVal);
1109 return JS_DefinePropertyById(aCx, aTarget, aId, getter, setter,
1110 JSPROP_ENUMERATE);
1113 } // namespace lazy_getter
1115 /* static */
1116 void ChromeUtils::DefineLazyGetter(const GlobalObject& aGlobal,
1117 JS::Handle<JSObject*> aTarget,
1118 JS::Handle<JS::Value> aName,
1119 JS::Handle<JSObject*> aLambda,
1120 ErrorResult& aRv) {
1121 JSContext* cx = aGlobal.Context();
1122 if (!lazy_getter::DefineLazyGetter(cx, aTarget, aName, aLambda)) {
1123 aRv.NoteJSContextException(cx);
1124 return;
1128 /* static */
1129 void ChromeUtils::DefineModuleGetter(const GlobalObject& global,
1130 JS::Handle<JSObject*> target,
1131 const nsAString& id,
1132 const nsAString& resourceURI,
1133 ErrorResult& aRv) {
1134 if (!lazy_getter::DefineJSModuleGetter(global.Context(), target, id,
1135 resourceURI)) {
1136 aRv.NoteJSContextException(global.Context());
1140 /* static */
1141 void ChromeUtils::DefineESModuleGetters(
1142 const GlobalObject& global, JS::Handle<JSObject*> target,
1143 JS::Handle<JSObject*> modules,
1144 const ImportESModuleOptionsDictionary& aOptions, ErrorResult& aRv) {
1145 JSContext* cx = global.Context();
1147 JS::Rooted<JS::IdVector> props(cx, JS::IdVector(cx));
1148 if (!JS_Enumerate(cx, modules, &props)) {
1149 aRv.NoteJSContextException(cx);
1150 return;
1153 if (!ValidateImportOptions(cx, global, aOptions)) {
1154 aRv.Throw(NS_ERROR_FAILURE);
1155 return;
1158 EncodedOptions encodedOptions(aOptions);
1160 JS::Rooted<JS::PropertyKey> prop(cx);
1161 JS::Rooted<JS::Value> resourceURIVal(cx);
1162 for (JS::PropertyKey tmp : props) {
1163 prop = tmp;
1165 if (!prop.isString()) {
1166 aRv.Throw(NS_ERROR_FAILURE);
1167 return;
1170 if (!JS_GetPropertyById(cx, modules, prop, &resourceURIVal)) {
1171 aRv.NoteJSContextException(cx);
1172 return;
1175 if (!lazy_getter::DefineESModuleGetter(cx, target, prop, resourceURIVal,
1176 encodedOptions)) {
1177 aRv.NoteJSContextException(cx);
1178 return;
1183 #ifdef XP_UNIX
1184 /* static */
1185 void ChromeUtils::GetLibcConstants(const GlobalObject&,
1186 LibcConstants& aConsts) {
1187 aConsts.mEINTR.Construct(EINTR);
1188 aConsts.mEACCES.Construct(EACCES);
1189 aConsts.mEAGAIN.Construct(EAGAIN);
1190 aConsts.mEINVAL.Construct(EINVAL);
1191 aConsts.mENOSYS.Construct(ENOSYS);
1193 aConsts.mF_SETFD.Construct(F_SETFD);
1194 aConsts.mF_SETFL.Construct(F_SETFL);
1196 aConsts.mFD_CLOEXEC.Construct(FD_CLOEXEC);
1198 aConsts.mAT_EACCESS.Construct(AT_EACCESS);
1200 aConsts.mO_CREAT.Construct(O_CREAT);
1201 aConsts.mO_NONBLOCK.Construct(O_NONBLOCK);
1202 aConsts.mO_WRONLY.Construct(O_WRONLY);
1204 aConsts.mPOLLERR.Construct(POLLERR);
1205 aConsts.mPOLLHUP.Construct(POLLHUP);
1206 aConsts.mPOLLIN.Construct(POLLIN);
1207 aConsts.mPOLLNVAL.Construct(POLLNVAL);
1208 aConsts.mPOLLOUT.Construct(POLLOUT);
1210 aConsts.mWNOHANG.Construct(WNOHANG);
1212 # ifdef XP_LINUX
1213 aConsts.mPR_CAPBSET_READ.Construct(PR_CAPBSET_READ);
1214 # endif
1216 #endif
1218 /* static */
1219 void ChromeUtils::OriginAttributesToSuffix(
1220 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1221 nsCString& aSuffix)
1224 OriginAttributes attrs(aAttrs);
1225 attrs.CreateSuffix(aSuffix);
1228 /* static */
1229 bool ChromeUtils::OriginAttributesMatchPattern(
1230 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1231 const dom::OriginAttributesPatternDictionary& aPattern) {
1232 OriginAttributes attrs(aAttrs);
1233 OriginAttributesPattern pattern(aPattern);
1234 return pattern.Matches(attrs);
1237 /* static */
1238 void ChromeUtils::CreateOriginAttributesFromOrigin(
1239 dom::GlobalObject& aGlobal, const nsAString& aOrigin,
1240 dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
1241 OriginAttributes attrs;
1242 nsAutoCString suffix;
1243 if (!attrs.PopulateFromOrigin(NS_ConvertUTF16toUTF8(aOrigin), suffix)) {
1244 aRv.Throw(NS_ERROR_FAILURE);
1245 return;
1247 aAttrs = attrs;
1250 /* static */
1251 void ChromeUtils::CreateOriginAttributesFromOriginSuffix(
1252 dom::GlobalObject& aGlobal, const nsAString& aSuffix,
1253 dom::OriginAttributesDictionary& aAttrs, ErrorResult& aRv) {
1254 OriginAttributes attrs;
1255 nsAutoCString suffix;
1256 if (!attrs.PopulateFromSuffix(NS_ConvertUTF16toUTF8(aSuffix))) {
1257 aRv.Throw(NS_ERROR_FAILURE);
1258 return;
1260 aAttrs = attrs;
1263 /* static */
1264 void ChromeUtils::FillNonDefaultOriginAttributes(
1265 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aAttrs,
1266 dom::OriginAttributesDictionary& aNewAttrs) {
1267 aNewAttrs = aAttrs;
1270 /* static */
1271 bool ChromeUtils::IsOriginAttributesEqual(
1272 dom::GlobalObject& aGlobal, const dom::OriginAttributesDictionary& aA,
1273 const dom::OriginAttributesDictionary& aB) {
1274 return IsOriginAttributesEqual(aA, aB);
1277 /* static */
1278 bool ChromeUtils::IsOriginAttributesEqual(
1279 const dom::OriginAttributesDictionary& aA,
1280 const dom::OriginAttributesDictionary& aB) {
1281 return aA == aB;
1284 /* static */
1285 void ChromeUtils::GetBaseDomainFromPartitionKey(dom::GlobalObject& aGlobal,
1286 const nsAString& aPartitionKey,
1287 nsAString& aBaseDomain,
1288 ErrorResult& aRv) {
1289 nsString scheme;
1290 nsString pkBaseDomain;
1291 int32_t port;
1292 bool ancestor;
1294 if (!mozilla::OriginAttributes::ParsePartitionKey(
1295 aPartitionKey, scheme, pkBaseDomain, port, ancestor)) {
1296 aRv.Throw(NS_ERROR_FAILURE);
1297 return;
1300 aBaseDomain = pkBaseDomain;
1303 /* static */
1304 void ChromeUtils::GetPartitionKeyFromURL(dom::GlobalObject& aGlobal,
1305 const nsAString& aURL,
1306 nsAString& aPartitionKey,
1307 ErrorResult& aRv) {
1308 nsCOMPtr<nsIURI> uri;
1309 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL);
1310 if (NS_SUCCEEDED(rv) && uri->SchemeIs("chrome")) {
1311 rv = NS_ERROR_FAILURE;
1314 if (NS_WARN_IF(NS_FAILED(rv))) {
1315 aPartitionKey.Truncate();
1316 aRv.Throw(rv);
1317 return;
1320 mozilla::OriginAttributes attrs;
1321 // For now, uses assume the partition key is cross-site.
1322 // We will need to not make this assumption to allow access
1323 // to same-site partitioned cookies in the cookie extension API.
1324 attrs.SetPartitionKey(uri, false);
1326 aPartitionKey = attrs.mPartitionKey;
1329 #ifdef NIGHTLY_BUILD
1330 /* static */
1331 void ChromeUtils::GetRecentJSDevError(GlobalObject& aGlobal,
1332 JS::MutableHandle<JS::Value> aRetval,
1333 ErrorResult& aRv) {
1334 aRetval.setUndefined();
1335 auto runtime = CycleCollectedJSRuntime::Get();
1336 MOZ_ASSERT(runtime);
1338 auto cx = aGlobal.Context();
1339 if (!runtime->GetRecentDevError(cx, aRetval)) {
1340 aRv.NoteJSContextException(cx);
1341 return;
1345 /* static */
1346 void ChromeUtils::ClearRecentJSDevError(GlobalObject&) {
1347 auto runtime = CycleCollectedJSRuntime::Get();
1348 MOZ_ASSERT(runtime);
1350 runtime->ClearRecentDevError();
1352 #endif // NIGHTLY_BUILD
1354 void ChromeUtils::ClearStyleSheetCacheByPrincipal(GlobalObject&,
1355 nsIPrincipal* aForPrincipal) {
1356 SharedStyleSheetCache::Clear(aForPrincipal);
1359 void ChromeUtils::ClearStyleSheetCacheByBaseDomain(
1360 GlobalObject&, const nsACString& aBaseDomain) {
1361 SharedStyleSheetCache::Clear(nullptr, &aBaseDomain);
1364 void ChromeUtils::ClearStyleSheetCache(GlobalObject&) {
1365 SharedStyleSheetCache::Clear();
1368 #define PROCTYPE_TO_WEBIDL_CASE(_procType, _webidl) \
1369 case mozilla::ProcType::_procType: \
1370 return WebIDLProcType::_webidl
1372 static WebIDLProcType ProcTypeToWebIDL(mozilla::ProcType aType) {
1373 // Max is the value of the last enum, not the length, so add one.
1374 static_assert(
1375 static_cast<size_t>(MaxContiguousEnumValue<WebIDLProcType>::value) ==
1376 static_cast<size_t>(ProcType::Max),
1377 "In order for this static cast to be okay, "
1378 "WebIDLProcType must match ProcType exactly");
1380 // These must match the similar ones in E10SUtils.sys.mjs, RemoteTypes.h,
1381 // ProcInfo.h and ChromeUtils.webidl
1382 switch (aType) {
1383 PROCTYPE_TO_WEBIDL_CASE(Web, Web);
1384 PROCTYPE_TO_WEBIDL_CASE(WebIsolated, WebIsolated);
1385 PROCTYPE_TO_WEBIDL_CASE(File, File);
1386 PROCTYPE_TO_WEBIDL_CASE(Extension, Extension);
1387 PROCTYPE_TO_WEBIDL_CASE(PrivilegedAbout, Privilegedabout);
1388 PROCTYPE_TO_WEBIDL_CASE(PrivilegedMozilla, Privilegedmozilla);
1389 PROCTYPE_TO_WEBIDL_CASE(WebCOOPCOEP, WithCoopCoep);
1390 PROCTYPE_TO_WEBIDL_CASE(WebServiceWorker, WebServiceWorker);
1392 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1393 process_bin_type, procinfo_typename, \
1394 webidl_typename, allcaps_name) \
1395 PROCTYPE_TO_WEBIDL_CASE(procinfo_typename, webidl_typename);
1396 #define SKIP_PROCESS_TYPE_CONTENT
1397 #ifndef MOZ_ENABLE_FORKSERVER
1398 # define SKIP_PROCESS_TYPE_FORKSERVER
1399 #endif // MOZ_ENABLE_FORKSERVER
1400 #include "mozilla/GeckoProcessTypes.h"
1401 #undef SKIP_PROCESS_TYPE_CONTENT
1402 #ifndef MOZ_ENABLE_FORKSERVER
1403 # undef SKIP_PROCESS_TYPE_FORKSERVER
1404 #endif // MOZ_ENABLE_FORKSERVER
1405 #undef GECKO_PROCESS_TYPE
1407 PROCTYPE_TO_WEBIDL_CASE(Preallocated, Preallocated);
1408 PROCTYPE_TO_WEBIDL_CASE(Unknown, Unknown);
1411 MOZ_ASSERT(false, "Unhandled case in ProcTypeToWebIDL");
1412 return WebIDLProcType::Unknown;
1415 #undef PROCTYPE_TO_WEBIDL_CASE
1417 /* static */
1418 already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
1419 ErrorResult& aRv) {
1420 // This function will use IPDL to enable threads info on macOS
1421 // see https://bugzilla.mozilla.org/show_bug.cgi?id=1529023
1422 if (!XRE_IsParentProcess()) {
1423 aRv.Throw(NS_ERROR_FAILURE);
1424 return nullptr;
1426 // Prepare the JS promise that will hold our response.
1427 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1428 MOZ_ASSERT(global);
1429 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
1430 if (NS_WARN_IF(aRv.Failed())) {
1431 return nullptr;
1433 MOZ_ASSERT(domPromise);
1435 // Get a list of processes to examine and pre-fill them with available info.
1436 // Note that this is subject to race conditions: just because we have a
1437 // process in the list doesn't mean that the process will still be alive when
1438 // we attempt to get its information. Followup code MUST be able to fail
1439 // gracefully on some processes and still return whichever information is
1440 // available.
1442 // Get all the content parents.
1443 // Note that this array includes even the long dead content parents, so we
1444 // might have some garbage, especially with Fission.
1445 // SAFETY NOTE: `contentParents` is only valid if used synchronously.
1446 // Anything else and you may end up dealing with dangling pointers.
1447 nsTArray<ContentParent*> contentParents;
1448 ContentParent::GetAll(contentParents);
1450 // Prepare our background request.
1451 // We reserve one more slot for the browser process itself.
1452 nsTArray<ProcInfoRequest> requests(contentParents.Length() + 1);
1453 // Requesting process info for the browser process itself.
1454 requests.EmplaceBack(
1455 /* aPid = */ base::GetCurrentProcId(),
1456 /* aProcessType = */ ProcType::Browser,
1457 /* aOrigin = */ ""_ns,
1458 /* aWindowInfo = */ nsTArray<WindowInfo>(),
1459 /* aUtilityInfo = */ nsTArray<UtilityInfo>());
1461 // First handle non-ContentParent processes.
1462 mozilla::ipc::GeckoChildProcessHost::GetAll(
1463 [&requests](mozilla::ipc::GeckoChildProcessHost* aGeckoProcess) {
1464 base::ProcessId childPid = aGeckoProcess->GetChildProcessId();
1465 if (childPid == 0) {
1466 // Something went wrong with this process, it may be dead already,
1467 // fail gracefully.
1468 return;
1470 mozilla::ProcType type = mozilla::ProcType::Unknown;
1472 switch (aGeckoProcess->GetProcessType()) {
1473 case GeckoProcessType::GeckoProcessType_Content: {
1474 // These processes are handled separately.
1475 return;
1478 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
1479 process_bin_type, procinfo_typename, \
1480 webidl_typename, allcaps_name) \
1481 case GeckoProcessType::GeckoProcessType_##enum_name: { \
1482 type = mozilla::ProcType::procinfo_typename; \
1483 break; \
1485 #define SKIP_PROCESS_TYPE_CONTENT
1486 #ifndef MOZ_ENABLE_FORKSERVER
1487 # define SKIP_PROCESS_TYPE_FORKSERVER
1488 #endif // MOZ_ENABLE_FORKSERVER
1489 #include "mozilla/GeckoProcessTypes.h"
1490 #ifndef MOZ_ENABLE_FORKSERVER
1491 # undef SKIP_PROCESS_TYPE_FORKSERVER
1492 #endif // MOZ_ENABLE_FORKSERVER
1493 #undef SKIP_PROCESS_TYPE_CONTENT
1494 #undef GECKO_PROCESS_TYPE
1495 default:
1496 // Leave the default Unknown value in |type|.
1497 break;
1500 // Attach utility actor information to the process.
1501 nsTArray<UtilityInfo> utilityActors;
1502 if (aGeckoProcess->GetProcessType() ==
1503 GeckoProcessType::GeckoProcessType_Utility) {
1504 RefPtr<mozilla::ipc::UtilityProcessManager> upm =
1505 mozilla::ipc::UtilityProcessManager::GetSingleton();
1506 if (!utilityActors.AppendElements(upm->GetActors(aGeckoProcess),
1507 fallible)) {
1508 NS_WARNING("Error adding actors");
1509 return;
1513 requests.EmplaceBack(
1514 /* aPid = */ childPid,
1515 /* aProcessType = */ type,
1516 /* aOrigin = */ ""_ns,
1517 /* aWindowInfo = */ nsTArray<WindowInfo>(), // Without a
1518 // ContentProcess, no
1519 // DOM windows.
1520 /* aUtilityInfo = */ std::move(utilityActors),
1521 /* aChild = */ 0 // Without a ContentProcess, no ChildId.
1522 #ifdef XP_DARWIN
1524 /* aChildTask = */ aGeckoProcess->GetChildTask()
1525 #endif // XP_DARWIN
1529 // Now handle ContentParents.
1530 for (const auto* contentParent : contentParents) {
1531 if (!contentParent || !contentParent->Process()) {
1532 // Presumably, the process is dead or dying.
1533 continue;
1535 base::ProcessId pid = contentParent->Process()->GetChildProcessId();
1536 if (pid == 0) {
1537 // Presumably, the process is dead or dying.
1538 continue;
1540 if (contentParent->Process()->GetProcessType() !=
1541 GeckoProcessType::GeckoProcessType_Content) {
1542 // We're probably racing against a process changing type.
1543 // We'll get it in the next call, skip it for the moment.
1544 continue;
1547 // Since this code is executed synchronously on the main thread,
1548 // processes cannot die while we're in this loop.
1549 mozilla::ProcType type = mozilla::ProcType::Unknown;
1551 // Convert the remoteType into a ProcType.
1552 // Ideally, the remoteType should be strongly typed
1553 // upstream, this would make the conversion less brittle.
1554 const nsAutoCString remoteType(contentParent->GetRemoteType());
1555 if (StringBeginsWith(remoteType, FISSION_WEB_REMOTE_TYPE)) {
1556 // WARNING: Do not change the order, as
1557 // `DEFAULT_REMOTE_TYPE` is a prefix of
1558 // `FISSION_WEB_REMOTE_TYPE`.
1559 type = mozilla::ProcType::WebIsolated;
1560 } else if (StringBeginsWith(remoteType, SERVICEWORKER_REMOTE_TYPE)) {
1561 type = mozilla::ProcType::WebServiceWorker;
1562 } else if (StringBeginsWith(remoteType,
1563 WITH_COOP_COEP_REMOTE_TYPE_PREFIX)) {
1564 type = mozilla::ProcType::WebCOOPCOEP;
1565 } else if (remoteType == FILE_REMOTE_TYPE) {
1566 type = mozilla::ProcType::File;
1567 } else if (remoteType == EXTENSION_REMOTE_TYPE) {
1568 type = mozilla::ProcType::Extension;
1569 } else if (remoteType == PRIVILEGEDABOUT_REMOTE_TYPE) {
1570 type = mozilla::ProcType::PrivilegedAbout;
1571 } else if (remoteType == PRIVILEGEDMOZILLA_REMOTE_TYPE) {
1572 type = mozilla::ProcType::PrivilegedMozilla;
1573 } else if (remoteType == PREALLOC_REMOTE_TYPE) {
1574 type = mozilla::ProcType::Preallocated;
1575 } else if (StringBeginsWith(remoteType, DEFAULT_REMOTE_TYPE)) {
1576 type = mozilla::ProcType::Web;
1577 } else {
1578 MOZ_CRASH_UNSAFE_PRINTF("Unknown remoteType '%s'", remoteType.get());
1581 // By convention, everything after '=' is the origin.
1582 nsAutoCString origin;
1583 nsACString::const_iterator cursor;
1584 nsACString::const_iterator end;
1585 remoteType.BeginReading(cursor);
1586 remoteType.EndReading(end);
1587 if (FindCharInReadable('=', cursor, end)) {
1588 origin = Substring(++cursor, end);
1591 // Attach DOM window information to the process.
1592 nsTArray<WindowInfo> windows;
1593 for (const auto& browserParentWrapperKey :
1594 contentParent->ManagedPBrowserParent()) {
1595 for (const auto& windowGlobalParentWrapperKey :
1596 browserParentWrapperKey->ManagedPWindowGlobalParent()) {
1597 // WindowGlobalParent is the only immediate subclass of
1598 // PWindowGlobalParent.
1599 auto* windowGlobalParent =
1600 static_cast<WindowGlobalParent*>(windowGlobalParentWrapperKey);
1602 nsString documentTitle;
1603 windowGlobalParent->GetDocumentTitle(documentTitle);
1604 WindowInfo* window = windows.EmplaceBack(
1605 fallible,
1606 /* aOuterWindowId = */ windowGlobalParent->OuterWindowId(),
1607 /* aDocumentURI = */ windowGlobalParent->GetDocumentURI(),
1608 /* aDocumentTitle = */ std::move(documentTitle),
1609 /* aIsProcessRoot = */ windowGlobalParent->IsProcessRoot(),
1610 /* aIsInProcess = */ windowGlobalParent->IsInProcess());
1611 if (!window) {
1612 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
1613 return nullptr;
1617 requests.EmplaceBack(
1618 /* aPid = */ pid,
1619 /* aProcessType = */ type,
1620 /* aOrigin = */ origin,
1621 /* aWindowInfo = */ std::move(windows),
1622 /* aUtilityInfo = */ nsTArray<UtilityInfo>(),
1623 /* aChild = */ contentParent->ChildID()
1624 #ifdef XP_DARWIN
1626 /* aChildTask = */ contentParent->Process()->GetChildTask()
1627 #endif // XP_DARWIN
1631 // Now place background request.
1632 RefPtr<nsISerialEventTarget> target = global->SerialEventTarget();
1633 mozilla::GetProcInfo(std::move(requests))
1634 ->Then(
1635 target, __func__,
1636 [target,
1637 domPromise](const HashMap<base::ProcessId, ProcInfo>& aSysProcInfo) {
1638 ParentProcInfoDictionary parentInfo;
1639 if (aSysProcInfo.count() == 0) {
1640 // For some reason, we couldn't get *any* info.
1641 // Maybe a sandboxing issue?
1642 domPromise->MaybeReject(NS_ERROR_UNEXPECTED);
1643 return;
1645 nsTArray<ChildProcInfoDictionary> childrenInfo(
1646 aSysProcInfo.count() - 1);
1647 for (auto iter = aSysProcInfo.iter(); !iter.done(); iter.next()) {
1648 const auto& sysProcInfo = iter.get().value();
1649 nsresult rv;
1650 if (sysProcInfo.type == ProcType::Browser) {
1651 rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, &parentInfo);
1652 if (NS_FAILED(rv)) {
1653 // Failing to copy? That's probably not something from we can
1654 // (or should) try to recover gracefully.
1655 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1656 return;
1658 MOZ_ASSERT(sysProcInfo.childId == 0);
1659 MOZ_ASSERT(sysProcInfo.origin.IsEmpty());
1660 } else {
1661 mozilla::dom::ChildProcInfoDictionary* childInfo =
1662 childrenInfo.AppendElement(fallible);
1663 if (!childInfo) {
1664 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1665 return;
1667 rv = mozilla::CopySysProcInfoToDOM(sysProcInfo, childInfo);
1668 if (NS_FAILED(rv)) {
1669 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1670 return;
1672 // Copy Firefox info.
1673 childInfo->mChildID = sysProcInfo.childId;
1674 childInfo->mOrigin = sysProcInfo.origin;
1675 childInfo->mType = ProcTypeToWebIDL(sysProcInfo.type);
1677 for (const auto& source : sysProcInfo.windows) {
1678 auto* dest = childInfo->mWindows.AppendElement(fallible);
1679 if (!dest) {
1680 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1681 return;
1683 dest->mOuterWindowId = source.outerWindowId;
1684 dest->mDocumentURI = source.documentURI;
1685 dest->mDocumentTitle = source.documentTitle;
1686 dest->mIsProcessRoot = source.isProcessRoot;
1687 dest->mIsInProcess = source.isInProcess;
1690 if (sysProcInfo.type == ProcType::Utility) {
1691 for (const auto& source : sysProcInfo.utilityActors) {
1692 auto* dest =
1693 childInfo->mUtilityActors.AppendElement(fallible);
1694 if (!dest) {
1695 domPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
1696 return;
1699 dest->mActorName = source.actorName;
1705 // Attach the children to the parent.
1706 mozilla::dom::Sequence<mozilla::dom::ChildProcInfoDictionary>
1707 children(std::move(childrenInfo));
1708 parentInfo.mChildren = std::move(children);
1709 domPromise->MaybeResolve(parentInfo);
1711 [domPromise](nsresult aRv) { domPromise->MaybeReject(aRv); });
1712 MOZ_ASSERT(domPromise);
1714 // sending back the promise instance
1715 return domPromise.forget();
1718 /* static */
1719 bool ChromeUtils::VsyncEnabled(GlobalObject& aGlobal) {
1720 return mozilla::gfx::VsyncSource::GetFastestVsyncRate().isSome();
1723 void ChromeUtils::SetPerfStatsCollectionMask(GlobalObject& aGlobal,
1724 uint64_t aMask) {
1725 PerfStats::SetCollectionMask(static_cast<PerfStats::MetricMask>(aMask));
1728 already_AddRefed<Promise> ChromeUtils::CollectPerfStats(GlobalObject& aGlobal,
1729 ErrorResult& aRv) {
1730 // Creating a JS promise
1731 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1732 MOZ_ASSERT(global);
1734 RefPtr<Promise> promise = Promise::Create(global, aRv);
1735 if (aRv.Failed()) {
1736 return nullptr;
1739 RefPtr<PerfStats::PerfStatsPromise> extPromise =
1740 PerfStats::CollectPerfStatsJSON();
1742 extPromise->Then(
1743 GetCurrentSerialEventTarget(), __func__,
1744 [promise](const nsCString& aResult) {
1745 promise->MaybeResolve(NS_ConvertUTF8toUTF16(aResult));
1747 [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
1749 return promise.forget();
1752 constexpr auto kSkipSelfHosted = JS::SavedFrameSelfHosted::Exclude;
1754 /* static */
1755 void ChromeUtils::GetCallerLocation(const GlobalObject& aGlobal,
1756 nsIPrincipal* aPrincipal,
1757 JS::MutableHandle<JSObject*> aRetval) {
1758 JSContext* cx = aGlobal.Context();
1760 auto* principals = nsJSPrincipals::get(aPrincipal);
1762 JS::StackCapture captureMode(JS::FirstSubsumedFrame(cx, principals));
1764 JS::Rooted<JSObject*> frame(cx);
1765 if (!JS::CaptureCurrentStack(cx, &frame, std::move(captureMode))) {
1766 JS_ClearPendingException(cx);
1767 aRetval.set(nullptr);
1768 return;
1771 // FirstSubsumedFrame gets us a stack which stops at the first principal which
1772 // is subsumed by the given principal. That means that we may have a lot of
1773 // privileged frames that we don't care about at the top of the stack, though.
1774 // We need to filter those out to get the frame we actually want.
1775 aRetval.set(
1776 js::GetFirstSubsumedSavedFrame(cx, principals, frame, kSkipSelfHosted));
1779 /* static */
1780 void ChromeUtils::CreateError(const GlobalObject& aGlobal,
1781 const nsAString& aMessage,
1782 JS::Handle<JSObject*> aStack,
1783 JS::MutableHandle<JSObject*> aRetVal,
1784 ErrorResult& aRv) {
1785 if (aStack && !JS::IsMaybeWrappedSavedFrame(aStack)) {
1786 aRv.Throw(NS_ERROR_INVALID_ARG);
1787 return;
1790 JSContext* cx = aGlobal.Context();
1792 auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
1794 JS::Rooted<JSObject*> retVal(cx);
1796 JS::Rooted<JSString*> fileName(cx, JS_GetEmptyString(cx));
1797 uint32_t line = 0;
1798 JS::TaggedColumnNumberOneOrigin column;
1800 Maybe<JSAutoRealm> ar;
1801 JS::Rooted<JSObject*> stack(cx);
1802 if (aStack) {
1803 stack = UncheckedUnwrap(aStack);
1804 ar.emplace(cx, stack);
1806 JSPrincipals* principals =
1807 JS::GetRealmPrincipals(js::GetContextRealm(cx));
1808 if (JS::GetSavedFrameLine(cx, principals, stack, &line) !=
1809 JS::SavedFrameResult::Ok ||
1810 JS::GetSavedFrameColumn(cx, principals, stack, &column) !=
1811 JS::SavedFrameResult::Ok ||
1812 JS::GetSavedFrameSource(cx, principals, stack, &fileName) !=
1813 JS::SavedFrameResult::Ok) {
1814 return;
1818 JS::Rooted<JSString*> message(cx);
1820 JS::Rooted<JS::Value> msgVal(cx);
1821 if (!xpc::NonVoidStringToJsval(cx, aMessage, &msgVal)) {
1822 return;
1824 message = msgVal.toString();
1827 JS::Rooted<JS::Value> err(cx);
1828 if (!JS::CreateError(cx, JSEXN_ERR, stack, fileName, line,
1829 JS::ColumnNumberOneOrigin(column.oneOriginValue()),
1830 nullptr, message, JS::NothingHandleValue, &err)) {
1831 return;
1834 MOZ_ASSERT(err.isObject());
1835 retVal = &err.toObject();
1838 if (aStack && !JS_WrapObject(cx, &retVal)) {
1839 return;
1842 cleanup.release();
1843 aRetVal.set(retVal);
1846 /* static */
1847 already_AddRefed<Promise> ChromeUtils::RequestIOActivity(GlobalObject& aGlobal,
1848 ErrorResult& aRv) {
1849 MOZ_ASSERT(XRE_IsParentProcess());
1850 MOZ_ASSERT(Preferences::GetBool(IO_ACTIVITY_ENABLED_PREF, false));
1851 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
1852 MOZ_ASSERT(global);
1853 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
1854 if (NS_WARN_IF(aRv.Failed())) {
1855 return nullptr;
1857 MOZ_ASSERT(domPromise);
1858 mozilla::net::IOActivityMonitor::RequestActivities(domPromise);
1859 return domPromise.forget();
1862 /* static */
1863 bool ChromeUtils::HasReportingHeaderForOrigin(GlobalObject& global,
1864 const nsAString& aOrigin,
1865 ErrorResult& aRv) {
1866 if (!XRE_IsParentProcess()) {
1867 aRv.Throw(NS_ERROR_FAILURE);
1868 return false;
1871 return ReportingHeader::HasReportingHeaderForOrigin(
1872 NS_ConvertUTF16toUTF8(aOrigin));
1875 /* static */
1876 PopupBlockerState ChromeUtils::GetPopupControlState(GlobalObject& aGlobal) {
1877 switch (PopupBlocker::GetPopupControlState()) {
1878 case PopupBlocker::PopupControlState::openAllowed:
1879 return PopupBlockerState::OpenAllowed;
1881 case PopupBlocker::PopupControlState::openControlled:
1882 return PopupBlockerState::OpenControlled;
1884 case PopupBlocker::PopupControlState::openBlocked:
1885 return PopupBlockerState::OpenBlocked;
1887 case PopupBlocker::PopupControlState::openAbused:
1888 return PopupBlockerState::OpenAbused;
1890 case PopupBlocker::PopupControlState::openOverridden:
1891 return PopupBlockerState::OpenOverridden;
1893 default:
1894 MOZ_CRASH(
1895 "PopupBlocker::PopupControlState and PopupBlockerState are out of "
1896 "sync");
1900 /* static */
1901 double ChromeUtils::LastExternalProtocolIframeAllowed(GlobalObject& aGlobal) {
1902 TimeStamp when = PopupBlocker::WhenLastExternalProtocolIframeAllowed();
1903 if (when.IsNull()) {
1904 return 0;
1907 TimeDuration duration = TimeStamp::Now() - when;
1908 return duration.ToMilliseconds();
1911 /* static */
1912 void ChromeUtils::ResetLastExternalProtocolIframeAllowed(
1913 GlobalObject& aGlobal) {
1914 PopupBlocker::ResetLastExternalProtocolIframeAllowed();
1917 /* static */
1918 void ChromeUtils::EndWheelTransaction(GlobalObject& aGlobal) {
1919 // This allows us to end the current wheel transaction from the browser
1920 // chrome. We do not need to perform any checks before calling
1921 // EndTransaction(), as it should do nothing in the case that there is
1922 // no current wheel transaction.
1923 WheelTransaction::EndTransaction();
1926 /* static */
1927 void ChromeUtils::RegisterWindowActor(const GlobalObject& aGlobal,
1928 const nsACString& aName,
1929 const WindowActorOptions& aOptions,
1930 ErrorResult& aRv) {
1931 MOZ_ASSERT(XRE_IsParentProcess());
1933 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1934 service->RegisterWindowActor(aName, aOptions, aRv);
1937 /* static */
1938 void ChromeUtils::UnregisterWindowActor(const GlobalObject& aGlobal,
1939 const nsACString& aName) {
1940 MOZ_ASSERT(XRE_IsParentProcess());
1942 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1943 service->UnregisterWindowActor(aName);
1946 /* static */
1947 void ChromeUtils::RegisterProcessActor(const GlobalObject& aGlobal,
1948 const nsACString& aName,
1949 const ProcessActorOptions& aOptions,
1950 ErrorResult& aRv) {
1951 MOZ_ASSERT(XRE_IsParentProcess());
1953 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1954 service->RegisterProcessActor(aName, aOptions, aRv);
1957 /* static */
1958 void ChromeUtils::UnregisterProcessActor(const GlobalObject& aGlobal,
1959 const nsACString& aName) {
1960 MOZ_ASSERT(XRE_IsParentProcess());
1962 RefPtr<JSActorService> service = JSActorService::GetSingleton();
1963 service->UnregisterProcessActor(aName);
1966 /* static */
1967 bool ChromeUtils::IsClassifierBlockingErrorCode(GlobalObject& aGlobal,
1968 uint32_t aError) {
1969 return net::UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(
1970 static_cast<nsresult>(aError));
1973 /* static */
1974 void ChromeUtils::PrivateNoteIntentionalCrash(const GlobalObject& aGlobal,
1975 ErrorResult& aError) {
1976 if (XRE_IsContentProcess()) {
1977 NoteIntentionalCrash("tab");
1978 return;
1980 aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
1983 /* static */
1984 nsIDOMProcessChild* ChromeUtils::GetDomProcessChild(const GlobalObject&) {
1985 return nsIDOMProcessChild::GetSingleton();
1988 /* static */
1989 void ChromeUtils::GetAllDOMProcesses(
1990 GlobalObject& aGlobal, nsTArray<RefPtr<nsIDOMProcessParent>>& aParents,
1991 ErrorResult& aRv) {
1992 if (!XRE_IsParentProcess()) {
1993 aRv.ThrowNotAllowedError(
1994 "getAllDOMProcesses() may only be called in the parent process");
1995 return;
1997 aParents.Clear();
1998 // Always add the parent process nsIDOMProcessParent first
1999 aParents.AppendElement(InProcessParent::Singleton());
2001 // Before adding nsIDOMProcessParent for all the content processes
2002 for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
2003 aParents.AppendElement(cp);
2007 /* static */
2008 void ChromeUtils::ConsumeInteractionData(
2009 GlobalObject& aGlobal, Record<nsString, InteractionData>& aInteractions,
2010 ErrorResult& aRv) {
2011 if (!XRE_IsParentProcess()) {
2012 aRv.ThrowNotAllowedError(
2013 "consumeInteractionData() may only be called in the parent "
2014 "process");
2015 return;
2017 EventStateManager::ConsumeInteractionData(aInteractions);
2020 already_AddRefed<Promise> ChromeUtils::CollectScrollingData(
2021 GlobalObject& aGlobal, ErrorResult& aRv) {
2022 // Creating a JS promise
2023 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
2024 MOZ_ASSERT(global);
2026 RefPtr<Promise> promise = Promise::Create(global, aRv);
2027 if (aRv.Failed()) {
2028 return nullptr;
2031 RefPtr<ScrollingMetrics::ScrollingMetricsPromise> extPromise =
2032 ScrollingMetrics::CollectScrollingMetrics();
2034 extPromise->Then(
2035 GetCurrentSerialEventTarget(), __func__,
2036 [promise](const std::tuple<uint32_t, uint32_t>& aResult) {
2037 InteractionData out = {};
2038 out.mInteractionTimeInMilliseconds = std::get<0>(aResult);
2039 out.mScrollingDistanceInPixels = std::get<1>(aResult);
2040 promise->MaybeResolve(out);
2042 [promise](bool aValue) { promise->MaybeReject(NS_ERROR_FAILURE); });
2044 return promise.forget();
2047 /* static */
2048 void ChromeUtils::GetFormAutofillConfidences(
2049 GlobalObject& aGlobal, const Sequence<OwningNonNull<Element>>& aElements,
2050 nsTArray<FormAutofillConfidences>& aResults, ErrorResult& aRv) {
2051 FormAutofillNative::GetFormAutofillConfidences(aGlobal, aElements, aResults,
2052 aRv);
2055 bool ChromeUtils::IsDarkBackground(GlobalObject&, Element& aElement) {
2056 nsIFrame* f = aElement.GetPrimaryFrame(FlushType::Frames);
2057 if (!f) {
2058 return false;
2060 return nsNativeTheme::IsDarkBackground(f);
2063 double ChromeUtils::DateNow(GlobalObject&) { return JS_Now() / 1000.0; }
2065 /* static */
2066 void ChromeUtils::EnsureJSOracleStarted(GlobalObject&) {
2067 if (StaticPrefs::browser_opaqueResponseBlocking_javascriptValidator()) {
2068 JSOracleParent::WithJSOracle([](JSOracleParent* aParent) {});
2072 /* static */
2073 unsigned ChromeUtils::AliveUtilityProcesses(const GlobalObject&) {
2074 const auto& utilityProcessManager =
2075 mozilla::ipc::UtilityProcessManager::GetIfExists();
2076 return utilityProcessManager ? utilityProcessManager->AliveProcesses() : 0;
2079 /* static */
2080 void ChromeUtils::GetAllPossibleUtilityActorNames(GlobalObject& aGlobal,
2081 nsTArray<nsCString>& aNames) {
2082 aNames.Clear();
2083 for (UtilityActorName idlName :
2084 MakeWebIDLEnumeratedRange<WebIDLUtilityActorName>()) {
2085 aNames.AppendElement(GetEnumString(idlName));
2089 /* static */
2090 bool ChromeUtils::ShouldResistFingerprinting(
2091 GlobalObject& aGlobal, JSRFPTarget aTarget,
2092 const Nullable<uint64_t>& aOverriddenFingerprintingSettings) {
2093 RFPTarget target;
2094 switch (aTarget) {
2095 case JSRFPTarget::RoundWindowSize:
2096 target = RFPTarget::RoundWindowSize;
2097 break;
2098 case JSRFPTarget::SiteSpecificZoom:
2099 target = RFPTarget::SiteSpecificZoom;
2100 break;
2101 default:
2102 MOZ_CRASH("Unhandled JSRFPTarget enum value");
2105 bool isPBM = false;
2106 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
2107 if (global) {
2108 nsPIDOMWindowInner* win = global->GetAsInnerWindow();
2109 if (win) {
2110 nsIDocShell* docshell = win->GetDocShell();
2111 if (docshell) {
2112 nsDocShell::Cast(docshell)->GetUsePrivateBrowsing(&isPBM);
2117 Maybe<RFPTarget> overriddenFingerprintingSettings;
2118 if (!aOverriddenFingerprintingSettings.IsNull()) {
2119 overriddenFingerprintingSettings.emplace(
2120 RFPTarget(aOverriddenFingerprintingSettings.Value()));
2123 // This global object appears to be the global window, not for individual
2124 // sites so to exempt individual sites (instead of just PBM/Not-PBM windows)
2125 // more work would be needed to get the correct context.
2126 return nsRFPService::IsRFPEnabledFor(isPBM, target,
2127 overriddenFingerprintingSettings);
2130 std::atomic<uint32_t> ChromeUtils::sDevToolsOpenedCount = 0;
2132 /* static */
2133 bool ChromeUtils::IsDevToolsOpened() {
2134 return ChromeUtils::sDevToolsOpenedCount > 0;
2137 /* static */
2138 bool ChromeUtils::IsDevToolsOpened(GlobalObject& aGlobal) {
2139 return ChromeUtils::IsDevToolsOpened();
2142 /* static */
2143 void ChromeUtils::NotifyDevToolsOpened(GlobalObject& aGlobal) {
2144 ChromeUtils::sDevToolsOpenedCount++;
2147 /* static */
2148 void ChromeUtils::NotifyDevToolsClosed(GlobalObject& aGlobal) {
2149 MOZ_ASSERT(ChromeUtils::sDevToolsOpenedCount >= 1);
2150 ChromeUtils::sDevToolsOpenedCount--;
2153 #ifdef MOZ_WMF_CDM
2154 /* static */
2155 already_AddRefed<Promise> ChromeUtils::GetWMFContentDecryptionModuleInformation(
2156 GlobalObject& aGlobal, ErrorResult& aRv) {
2157 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
2158 MOZ_ASSERT(global);
2159 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
2160 if (NS_WARN_IF(aRv.Failed())) {
2161 return nullptr;
2163 MOZ_ASSERT(domPromise);
2164 MFCDMService::GetAllKeySystemsCapabilities(domPromise);
2165 return domPromise.forget();
2167 #endif
2169 already_AddRefed<Promise> ChromeUtils::GetGMPContentDecryptionModuleInformation(
2170 GlobalObject& aGlobal, ErrorResult& aRv) {
2171 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
2172 MOZ_ASSERT(global);
2173 RefPtr<Promise> domPromise = Promise::Create(global, aRv);
2174 if (NS_WARN_IF(aRv.Failed())) {
2175 return nullptr;
2177 MOZ_ASSERT(domPromise);
2178 KeySystemConfig::GetGMPKeySystemConfigs(domPromise);
2179 return domPromise.forget();
2182 } // namespace mozilla::dom