Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/ChromeUtils.cpp
Line
Count
Source (jump to first uncovered line)
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 "ChromeUtils.h"
8
9
#include "js/CharacterEncoding.h"
10
#include "js/SavedFrameAPI.h"
11
#include "jsfriendapi.h"
12
#include "WrapperFactory.h"
13
14
#include "mozilla/Base64.h"
15
#include "mozilla/BasePrincipal.h"
16
#include "mozilla/CycleCollectedJSRuntime.h"
17
#include "mozilla/PerformanceMetricsCollector.h"
18
#include "mozilla/Preferences.h"
19
#include "mozilla/TimeStamp.h"
20
#include "mozilla/dom/BrowsingContext.h"
21
#include "mozilla/dom/ContentParent.h"
22
#include "mozilla/dom/IdleDeadline.h"
23
#include "mozilla/dom/UnionTypes.h"
24
#include "mozilla/dom/WindowBinding.h" // For IdleRequestCallback/Options
25
#include "IOActivityMonitor.h"
26
#include "nsThreadUtils.h"
27
#include "mozJSComponentLoader.h"
28
#include "GeckoProfiler.h"
29
30
namespace mozilla {
31
namespace dom {
32
33
/* static */ void
34
ChromeUtils::NondeterministicGetWeakMapKeys(GlobalObject& aGlobal,
35
                                            JS::Handle<JS::Value> aMap,
36
                                            JS::MutableHandle<JS::Value> aRetval,
37
                                            ErrorResult& aRv)
38
0
{
39
0
  if (!aMap.isObject()) {
40
0
    aRetval.setUndefined();
41
0
  } else {
42
0
    JSContext* cx = aGlobal.Context();
43
0
    JS::Rooted<JSObject*> objRet(cx);
44
0
    JS::Rooted<JSObject*> mapObj(cx, &aMap.toObject());
45
0
    if (!JS_NondeterministicGetWeakMapKeys(cx, mapObj, &objRet)) {
46
0
      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
47
0
    } else {
48
0
      aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
49
0
    }
50
0
  }
51
0
}
52
53
/* static */ void
54
ChromeUtils::NondeterministicGetWeakSetKeys(GlobalObject& aGlobal,
55
                                            JS::Handle<JS::Value> aSet,
56
                                            JS::MutableHandle<JS::Value> aRetval,
57
                                            ErrorResult& aRv)
58
0
{
59
0
  if (!aSet.isObject()) {
60
0
    aRetval.setUndefined();
61
0
  } else {
62
0
    JSContext* cx = aGlobal.Context();
63
0
    JS::Rooted<JSObject*> objRet(cx);
64
0
    JS::Rooted<JSObject*> setObj(cx, &aSet.toObject());
65
0
    if (!JS_NondeterministicGetWeakSetKeys(cx, setObj, &objRet)) {
66
0
      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
67
0
    } else {
68
0
      aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
69
0
    }
70
0
  }
71
0
}
72
73
/* static */ void
74
ChromeUtils::Base64URLEncode(GlobalObject& aGlobal,
75
                             const ArrayBufferViewOrArrayBuffer& aSource,
76
                             const Base64URLEncodeOptions& aOptions,
77
                             nsACString& aResult,
78
                             ErrorResult& aRv)
79
0
{
80
0
  size_t length = 0;
81
0
  uint8_t* data = nullptr;
82
0
  if (aSource.IsArrayBuffer()) {
83
0
    const ArrayBuffer& buffer = aSource.GetAsArrayBuffer();
84
0
    buffer.ComputeLengthAndData();
85
0
    length = buffer.Length();
86
0
    data = buffer.Data();
87
0
  } else if (aSource.IsArrayBufferView()) {
88
0
    const ArrayBufferView& view = aSource.GetAsArrayBufferView();
89
0
    view.ComputeLengthAndData();
90
0
    length = view.Length();
91
0
    data = view.Data();
92
0
  } else {
93
0
    MOZ_CRASH("Uninitialized union: expected buffer or view");
94
0
  }
95
0
96
0
  auto paddingPolicy = aOptions.mPad ? Base64URLEncodePaddingPolicy::Include :
97
0
                                       Base64URLEncodePaddingPolicy::Omit;
98
0
  nsresult rv = mozilla::Base64URLEncode(length, data, paddingPolicy, aResult);
99
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
100
0
    aResult.Truncate();
101
0
    aRv.Throw(rv);
102
0
  }
103
0
}
104
105
/* static */ void
106
ChromeUtils::Base64URLDecode(GlobalObject& aGlobal,
107
                             const nsACString& aString,
108
                             const Base64URLDecodeOptions& aOptions,
109
                             JS::MutableHandle<JSObject*> aRetval,
110
                             ErrorResult& aRv)
111
0
{
112
0
  Base64URLDecodePaddingPolicy paddingPolicy;
113
0
  switch (aOptions.mPadding) {
114
0
    case Base64URLDecodePadding::Require:
115
0
      paddingPolicy = Base64URLDecodePaddingPolicy::Require;
116
0
      break;
117
0
118
0
    case Base64URLDecodePadding::Ignore:
119
0
      paddingPolicy = Base64URLDecodePaddingPolicy::Ignore;
120
0
      break;
121
0
122
0
    case Base64URLDecodePadding::Reject:
123
0
      paddingPolicy = Base64URLDecodePaddingPolicy::Reject;
124
0
      break;
125
0
126
0
    default:
127
0
      aRv.Throw(NS_ERROR_INVALID_ARG);
128
0
      return;
129
0
  }
130
0
  FallibleTArray<uint8_t> data;
131
0
  nsresult rv = mozilla::Base64URLDecode(aString, paddingPolicy, data);
132
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
133
0
    aRv.Throw(rv);
134
0
    return;
135
0
  }
136
0
137
0
  JS::Rooted<JSObject*> buffer(aGlobal.Context(),
138
0
                               ArrayBuffer::Create(aGlobal.Context(),
139
0
                                                   data.Length(),
140
0
                                                   data.Elements()));
141
0
  if (NS_WARN_IF(!buffer)) {
142
0
    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
143
0
    return;
144
0
  }
145
0
  aRetval.set(buffer);
146
0
}
147
148
/* static */ void
149
ChromeUtils::WaiveXrays(GlobalObject& aGlobal,
150
                        JS::HandleValue aVal,
151
                        JS::MutableHandleValue aRetval,
152
                        ErrorResult& aRv)
153
0
{
154
0
  JS::RootedValue value(aGlobal.Context(), aVal);
155
0
  if (!xpc::WrapperFactory::WaiveXrayAndWrap(aGlobal.Context(), &value)) {
156
0
    aRv.NoteJSContextException(aGlobal.Context());
157
0
  } else {
158
0
    aRetval.set(value);
159
0
  }
160
0
}
161
162
/* static */ void
163
ChromeUtils::UnwaiveXrays(GlobalObject& aGlobal,
164
                          JS::HandleValue aVal,
165
                          JS::MutableHandleValue aRetval,
166
                          ErrorResult& aRv)
167
0
{
168
0
  if (!aVal.isObject()) {
169
0
      aRetval.set(aVal);
170
0
      return;
171
0
  }
172
0
173
0
  JS::RootedObject obj(aGlobal.Context(), js::UncheckedUnwrap(&aVal.toObject()));
174
0
  if (!JS_WrapObject(aGlobal.Context(), &obj)) {
175
0
    aRv.NoteJSContextException(aGlobal.Context());
176
0
  } else {
177
0
    aRetval.setObject(*obj);
178
0
  }
179
0
}
180
181
/* static */ void
182
ChromeUtils::GetClassName(GlobalObject& aGlobal,
183
                          JS::HandleObject aObj,
184
                          bool aUnwrap,
185
                          nsAString& aRetval)
186
0
{
187
0
  JS::RootedObject obj(aGlobal.Context(), aObj);
188
0
  if (aUnwrap) {
189
0
    obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
190
0
  }
191
0
192
0
  aRetval = NS_ConvertUTF8toUTF16(nsDependentCString(js::GetObjectClass(obj)->name));
193
0
}
194
195
/* static */ void
196
ChromeUtils::ShallowClone(GlobalObject& aGlobal,
197
                          JS::HandleObject aObj,
198
                          JS::HandleObject aTarget,
199
                          JS::MutableHandleObject aRetval,
200
                          ErrorResult& aRv)
201
0
{
202
0
  JSContext* cx = aGlobal.Context();
203
0
204
0
  auto cleanup = MakeScopeExit([&] () {
205
0
    aRv.NoteJSContextException(cx);
206
0
  });
207
0
208
0
  JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
209
0
  JS::AutoValueVector values(cx);
210
0
211
0
  {
212
0
    JS::RootedObject obj(cx, js::CheckedUnwrap(aObj));
213
0
    if (!obj) {
214
0
      js::ReportAccessDenied(cx);
215
0
      return;
216
0
    }
217
0
218
0
    if (js::IsScriptedProxy(obj)) {
219
0
      JS_ReportErrorASCII(cx, "Shallow cloning a proxy object is not allowed");
220
0
      return;
221
0
    }
222
0
223
0
    JSAutoRealm ar(cx, obj);
224
0
225
0
    if (!JS_Enumerate(cx, obj, &ids) ||
226
0
        !values.reserve(ids.length())) {
227
0
      return;
228
0
    }
229
0
230
0
    JS::Rooted<JS::PropertyDescriptor> desc(cx);
231
0
    JS::RootedId id(cx);
232
0
    for (jsid idVal : ids) {
233
0
      id = idVal;
234
0
      if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) {
235
0
        continue;
236
0
      }
237
0
      if (desc.setter() || desc.getter()) {
238
0
        continue;
239
0
      }
240
0
      values.infallibleAppend(desc.value());
241
0
    }
242
0
  }
243
0
244
0
  JS::RootedObject obj(cx);
245
0
  {
246
0
    Maybe<JSAutoRealm> ar;
247
0
    if (aTarget) {
248
0
      JS::RootedObject target(cx, js::CheckedUnwrap(aTarget));
249
0
      if (!target) {
250
0
        js::ReportAccessDenied(cx);
251
0
        return;
252
0
      }
253
0
      ar.emplace(cx, target);
254
0
    }
255
0
256
0
    obj = JS_NewPlainObject(cx);
257
0
    if (!obj) {
258
0
      return;
259
0
    }
260
0
261
0
    JS::RootedValue value(cx);
262
0
    JS::RootedId id(cx);
263
0
    for (uint32_t i = 0; i < ids.length(); i++) {
264
0
      id = ids[i];
265
0
      value = values[i];
266
0
267
0
      JS_MarkCrossZoneId(cx, id);
268
0
      if (!JS_WrapValue(cx, &value) ||
269
0
          !JS_SetPropertyById(cx, obj, id, value)) {
270
0
        return;
271
0
      }
272
0
    }
273
0
  }
274
0
275
0
  if (aTarget && !JS_WrapObject(cx, &obj)) {
276
0
    return;
277
0
  }
278
0
279
0
  cleanup.release();
280
0
  aRetval.set(obj);
281
0
}
282
283
namespace {
284
  class IdleDispatchRunnable final : public IdleRunnable
285
                                   , public nsITimerCallback
286
  {
287
  public:
288
    NS_DECL_ISUPPORTS_INHERITED
289
290
    IdleDispatchRunnable(nsIGlobalObject* aParent,
291
                         IdleRequestCallback& aCallback)
292
      : IdleRunnable("ChromeUtils::IdleDispatch")
293
      , mCallback(&aCallback)
294
      , mParent(aParent)
295
0
    {}
296
297
    NS_IMETHOD Run() override
298
0
    {
299
0
      if (mCallback) {
300
0
        CancelTimer();
301
0
302
0
        auto deadline = mDeadline - TimeStamp::ProcessCreation();
303
0
304
0
        ErrorResult rv;
305
0
        RefPtr<IdleDeadline> idleDeadline =
306
0
          new IdleDeadline(mParent, mTimedOut, deadline.ToMilliseconds());
307
0
308
0
        mCallback->Call(*idleDeadline, rv, "ChromeUtils::IdleDispatch handler");
309
0
        mCallback = nullptr;
310
0
        mParent = nullptr;
311
0
312
0
        rv.SuppressException();
313
0
        return rv.StealNSResult();
314
0
      }
315
0
      return NS_OK;
316
0
    }
317
318
    void SetDeadline(TimeStamp aDeadline) override
319
0
    {
320
0
      mDeadline = aDeadline;
321
0
    }
322
323
    NS_IMETHOD Notify(nsITimer* aTimer) override
324
0
    {
325
0
      mTimedOut = true;
326
0
      SetDeadline(TimeStamp::Now());
327
0
      return Run();
328
0
    }
329
330
    void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override
331
0
    {
332
0
      MOZ_ASSERT(aTarget);
333
0
      MOZ_ASSERT(!mTimer);
334
0
      NS_NewTimerWithCallback(getter_AddRefs(mTimer),
335
0
                              this, aDelay, nsITimer::TYPE_ONE_SHOT,
336
0
                              aTarget);
337
0
    }
338
339
  protected:
340
    virtual ~IdleDispatchRunnable()
341
0
    {
342
0
      CancelTimer();
343
0
    }
344
345
  private:
346
    void CancelTimer()
347
0
    {
348
0
      if (mTimer) {
349
0
        mTimer->Cancel();
350
0
        mTimer = nullptr;
351
0
      }
352
0
    }
353
354
    RefPtr<IdleRequestCallback> mCallback;
355
    nsCOMPtr<nsIGlobalObject> mParent;
356
357
    nsCOMPtr<nsITimer> mTimer;
358
359
    TimeStamp mDeadline{};
360
    bool mTimedOut = false;
361
  };
362
363
  NS_IMPL_ISUPPORTS_INHERITED(IdleDispatchRunnable, IdleRunnable, nsITimerCallback)
364
} // anonymous namespace
365
366
/* static */ void
367
ChromeUtils::IdleDispatch(const GlobalObject& aGlobal,
368
                          IdleRequestCallback& aCallback,
369
                          const IdleRequestOptions& aOptions,
370
                          ErrorResult& aRv)
371
0
{
372
0
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
373
0
  MOZ_ASSERT(global);
374
0
375
0
  auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback);
376
0
377
0
  if (aOptions.mTimeout.WasPassed()) {
378
0
    aRv = NS_IdleDispatchToCurrentThread(runnable.forget(), aOptions.mTimeout.Value());
379
0
  } else {
380
0
    aRv = NS_IdleDispatchToCurrentThread(runnable.forget());
381
0
  }
382
0
}
383
384
/* static */ void
385
ChromeUtils::Import(const GlobalObject& aGlobal,
386
                    const nsAString& aResourceURI,
387
                    const Optional<JS::Handle<JSObject*>>& aTargetObj,
388
                    JS::MutableHandle<JSObject*> aRetval,
389
                    ErrorResult& aRv)
390
8
{
391
8
392
8
  RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
393
8
  MOZ_ASSERT(moduleloader);
394
8
395
8
  NS_ConvertUTF16toUTF8 registryLocation(aResourceURI);
396
8
397
8
  AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
398
8
    "ChromeUtils::Import", OTHER, registryLocation);
399
8
400
8
  JSContext* cx = aGlobal.Context();
401
8
  JS::Rooted<JS::Value> targetObj(cx);
402
8
  uint8_t optionalArgc;
403
8
  if (aTargetObj.WasPassed()) {
404
0
    targetObj.setObjectOrNull(aTargetObj.Value());
405
0
    optionalArgc = 1;
406
8
  } else {
407
8
    targetObj.setUndefined();
408
8
    optionalArgc = 0;
409
8
  }
410
8
411
8
  JS::Rooted<JS::Value> retval(cx);
412
8
  nsresult rv = moduleloader->ImportInto(registryLocation, targetObj, cx,
413
8
                                         optionalArgc, &retval);
414
8
  if (NS_FAILED(rv)) {
415
0
    aRv.Throw(rv);
416
0
    return;
417
0
  }
418
8
419
8
  // Import() on the component loader can return NS_OK while leaving an
420
8
  // exception on the JSContext.  Check for that case.
421
8
  if (JS_IsExceptionPending(cx)) {
422
0
    aRv.NoteJSContextException(cx);
423
0
    return;
424
0
  }
425
8
426
8
  // Now we better have an object.
427
8
  MOZ_ASSERT(retval.isObject());
428
8
  aRetval.set(&retval.toObject());
429
8
}
430
431
namespace module_getter {
432
  static const size_t SLOT_ID = 0;
433
  static const size_t SLOT_URI = 1;
434
435
  static bool
436
  ExtractArgs(JSContext* aCx, JS::CallArgs& aArgs,
437
              JS::MutableHandle<JSObject*> aCallee,
438
              JS::MutableHandle<JSObject*> aThisObj,
439
              JS::MutableHandle<jsid> aId)
440
0
  {
441
0
    aCallee.set(&aArgs.callee());
442
0
443
0
    JS::Handle<JS::Value> thisv = aArgs.thisv();
444
0
    if (!thisv.isObject()) {
445
0
      JS_ReportErrorASCII(aCx, "Invalid target object");
446
0
      return false;
447
0
    }
448
0
449
0
    aThisObj.set(&thisv.toObject());
450
0
451
0
    JS::Rooted<JS::Value> id(aCx, js::GetFunctionNativeReserved(aCallee, SLOT_ID));
452
0
    MOZ_ALWAYS_TRUE(JS_ValueToId(aCx, id, aId));
453
0
    return true;
454
0
  }
455
456
  static bool
457
  ModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
458
0
  {
459
0
    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
460
0
461
0
    JS::Rooted<JSObject*> callee(aCx);
462
0
    JS::Rooted<JSObject*> thisObj(aCx);
463
0
    JS::Rooted<jsid> id(aCx);
464
0
    if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
465
0
      return false;
466
0
    }
467
0
468
0
    JS::Rooted<JSString*> moduleURI(
469
0
      aCx, js::GetFunctionNativeReserved(callee, SLOT_URI).toString());
470
0
    JS::UniqueChars bytes = JS_EncodeStringToUTF8(aCx, moduleURI);
471
0
    if (!bytes) {
472
0
      return false;
473
0
    }
474
0
    nsDependentCString uri(bytes.get());
475
0
476
0
    RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
477
0
    MOZ_ASSERT(moduleloader);
478
0
479
0
    JS::Rooted<JSObject*> moduleGlobal(aCx);
480
0
    JS::Rooted<JSObject*> moduleExports(aCx);
481
0
    nsresult rv = moduleloader->Import(aCx, uri, &moduleGlobal, &moduleExports);
482
0
    if (NS_FAILED(rv)) {
483
0
      Throw(aCx, rv);
484
0
      return false;
485
0
    }
486
0
487
0
    JS::RootedValue value(aCx);
488
0
    if (!JS_GetPropertyById(aCx, moduleExports, id, &value)) {
489
0
      return false;
490
0
    }
491
0
492
0
    if (!JS_DefinePropertyById(aCx, thisObj, id, value,
493
0
                               JSPROP_ENUMERATE)) {
494
0
      return false;
495
0
    }
496
0
497
0
    args.rval().set(value);
498
0
    return true;
499
0
  }
500
501
  static bool
502
  ModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
503
0
  {
504
0
    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
505
0
506
0
    JS::Rooted<JSObject*> callee(aCx);
507
0
    JS::Rooted<JSObject*> thisObj(aCx);
508
0
    JS::Rooted<jsid> id(aCx);
509
0
    if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
510
0
      return false;
511
0
    }
512
0
513
0
    return JS_DefinePropertyById(aCx, thisObj, id, args.get(0),
514
0
                                 JSPROP_ENUMERATE);
515
0
  }
516
517
  static bool
518
  DefineGetter(JSContext* aCx,
519
               JS::Handle<JSObject*> aTarget,
520
               const nsAString& aId,
521
               const nsAString& aResourceURI)
522
3
  {
523
3
    JS::RootedValue uri(aCx);
524
3
    JS::RootedValue idValue(aCx);
525
3
    JS::Rooted<jsid> id(aCx);
526
3
    if (!xpc::NonVoidStringToJsval(aCx, aResourceURI, &uri) ||
527
3
        !xpc::NonVoidStringToJsval(aCx, aId, &idValue) ||
528
3
        !JS_ValueToId(aCx, idValue, &id)) {
529
0
      return false;
530
0
    }
531
3
    idValue = js::IdToValue(id);
532
3
533
3
534
3
    JS::Rooted<JSObject*> getter(aCx, JS_GetFunctionObject(
535
3
      js::NewFunctionByIdWithReserved(aCx, ModuleGetter, 0, 0, id)));
536
3
537
3
    JS::Rooted<JSObject*> setter(aCx, JS_GetFunctionObject(
538
3
      js::NewFunctionByIdWithReserved(aCx, ModuleSetter, 0, 0, id)));
539
3
540
3
    if (!getter || !setter) {
541
0
      JS_ReportOutOfMemory(aCx);
542
0
      return false;
543
0
    }
544
3
545
3
    js::SetFunctionNativeReserved(getter, SLOT_ID, idValue);
546
3
    js::SetFunctionNativeReserved(setter, SLOT_ID, idValue);
547
3
548
3
    js::SetFunctionNativeReserved(getter, SLOT_URI, uri);
549
3
550
3
    return JS_DefinePropertyById(aCx, aTarget, id, getter, setter,
551
3
                                 JSPROP_GETTER | JSPROP_SETTER | JSPROP_ENUMERATE);
552
3
  }
553
} // namespace module_getter
554
555
/* static */ void
556
ChromeUtils::DefineModuleGetter(const GlobalObject& global,
557
                                JS::Handle<JSObject*> target,
558
                                const nsAString& id,
559
                                const nsAString& resourceURI,
560
                                ErrorResult& aRv)
561
3
{
562
3
  if (!module_getter::DefineGetter(global.Context(), target, id, resourceURI)) {
563
0
    aRv.NoteJSContextException(global.Context());
564
0
  }
565
3
}
566
567
/* static */ void
568
ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
569
                                      const dom::OriginAttributesDictionary& aAttrs,
570
                                      nsCString& aSuffix)
571
572
0
{
573
0
  OriginAttributes attrs(aAttrs);
574
0
  attrs.CreateSuffix(aSuffix);
575
0
}
576
577
/* static */ bool
578
ChromeUtils::OriginAttributesMatchPattern(dom::GlobalObject& aGlobal,
579
                                          const dom::OriginAttributesDictionary& aAttrs,
580
                                          const dom::OriginAttributesPatternDictionary& aPattern)
581
0
{
582
0
  OriginAttributes attrs(aAttrs);
583
0
  OriginAttributesPattern pattern(aPattern);
584
0
  return pattern.Matches(attrs);
585
0
}
586
587
/* static */ void
588
ChromeUtils::CreateOriginAttributesFromOrigin(dom::GlobalObject& aGlobal,
589
                                       const nsAString& aOrigin,
590
                                       dom::OriginAttributesDictionary& aAttrs,
591
                                       ErrorResult& aRv)
592
0
{
593
0
  OriginAttributes attrs;
594
0
  nsAutoCString suffix;
595
0
  if (!attrs.PopulateFromOrigin(NS_ConvertUTF16toUTF8(aOrigin), suffix)) {
596
0
    aRv.Throw(NS_ERROR_FAILURE);
597
0
    return;
598
0
  }
599
0
  aAttrs = attrs;
600
0
}
601
602
/* static */ void
603
ChromeUtils::FillNonDefaultOriginAttributes(dom::GlobalObject& aGlobal,
604
                                 const dom::OriginAttributesDictionary& aAttrs,
605
                                 dom::OriginAttributesDictionary& aNewAttrs)
606
0
{
607
0
  aNewAttrs = aAttrs;
608
0
}
609
610
611
/* static */ bool
612
ChromeUtils::IsOriginAttributesEqual(dom::GlobalObject& aGlobal,
613
                                     const dom::OriginAttributesDictionary& aA,
614
                                     const dom::OriginAttributesDictionary& aB)
615
0
{
616
0
  return IsOriginAttributesEqual(aA, aB);
617
0
}
618
619
/* static */ bool
620
ChromeUtils::IsOriginAttributesEqual(const dom::OriginAttributesDictionary& aA,
621
                                     const dom::OriginAttributesDictionary& aB)
622
0
{
623
0
  return aA.mAppId == aB.mAppId &&
624
0
         aA.mInIsolatedMozBrowser == aB.mInIsolatedMozBrowser &&
625
0
         aA.mUserContextId == aB.mUserContextId &&
626
0
         aA.mPrivateBrowsingId == aB.mPrivateBrowsingId;
627
0
}
628
629
#ifdef NIGHTLY_BUILD
630
/* static */ void
631
ChromeUtils::GetRecentJSDevError(GlobalObject& aGlobal,
632
                                JS::MutableHandleValue aRetval,
633
                                ErrorResult& aRv)
634
0
{
635
0
  aRetval.setUndefined();
636
0
  auto runtime = CycleCollectedJSRuntime::Get();
637
0
  MOZ_ASSERT(runtime);
638
0
639
0
  auto cx = aGlobal.Context();
640
0
  if (!runtime->GetRecentDevError(cx, aRetval)) {
641
0
    aRv.NoteJSContextException(cx);
642
0
    return;
643
0
  }
644
0
}
645
646
/* static */ void
647
ChromeUtils::ClearRecentJSDevError(GlobalObject&)
648
0
{
649
0
  auto runtime = CycleCollectedJSRuntime::Get();
650
0
  MOZ_ASSERT(runtime);
651
0
652
0
  runtime->ClearRecentDevError();
653
0
}
654
#endif // NIGHTLY_BUILD
655
656
/* static */
657
already_AddRefed<Promise>
658
ChromeUtils::RequestPerformanceMetrics(GlobalObject& aGlobal,
659
                                       ErrorResult& aRv)
660
0
{
661
0
  MOZ_ASSERT(XRE_IsParentProcess());
662
0
663
0
  // Creating a promise
664
0
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
665
0
  MOZ_ASSERT(global);
666
0
  RefPtr<Promise> domPromise = Promise::Create(global, aRv);
667
0
  if (NS_WARN_IF(aRv.Failed())) {
668
0
    return nullptr;
669
0
  }
670
0
  MOZ_ASSERT(domPromise);
671
0
672
0
  // requesting metrics, that will be returned into the promise
673
0
  PerformanceMetricsCollector::RequestMetrics(domPromise);
674
0
675
0
  // sending back the promise instance
676
0
  return domPromise.forget();
677
0
}
678
679
constexpr auto kSkipSelfHosted = JS::SavedFrameSelfHosted::Exclude;
680
681
/* static */ void
682
ChromeUtils::GetCallerLocation(const GlobalObject& aGlobal, nsIPrincipal* aPrincipal,
683
                               JS::MutableHandle<JSObject*> aRetval)
684
0
{
685
0
  JSContext* cx = aGlobal.Context();
686
0
687
0
  auto* principals = nsJSPrincipals::get(aPrincipal);
688
0
689
0
  JS::StackCapture captureMode(JS::FirstSubsumedFrame(cx, principals));
690
0
691
0
  JS::RootedObject frame(cx);
692
0
  if (!JS::CaptureCurrentStack(cx, &frame, std::move(captureMode))) {
693
0
    JS_ClearPendingException(cx);
694
0
    aRetval.set(nullptr);
695
0
    return;
696
0
  }
697
0
698
0
  // FirstSubsumedFrame gets us a stack which stops at the first principal which
699
0
  // is subsumed by the given principal. That means that we may have a lot of
700
0
  // privileged frames that we don't care about at the top of the stack, though.
701
0
  // We need to filter those out to get the frame we actually want.
702
0
  aRetval.set(js::GetFirstSubsumedSavedFrame(cx, principals, frame, kSkipSelfHosted));
703
0
}
704
705
/* static */ void
706
ChromeUtils::CreateError(const GlobalObject& aGlobal, const nsAString& aMessage,
707
                         JS::Handle<JSObject*> aStack,
708
                         JS::MutableHandle<JSObject*> aRetVal, ErrorResult& aRv)
709
0
{
710
0
  if (aStack && !JS::IsMaybeWrappedSavedFrame(aStack)) {
711
0
    aRv.Throw(NS_ERROR_INVALID_ARG);
712
0
    return;
713
0
  }
714
0
715
0
  JSContext* cx = aGlobal.Context();
716
0
717
0
  auto cleanup = MakeScopeExit([&]() {
718
0
    aRv.NoteJSContextException(cx);
719
0
  });
720
0
721
0
  JS::RootedObject retVal(cx);
722
0
  {
723
0
    JS::RootedString fileName(cx, JS_GetEmptyString(cx));
724
0
    uint32_t line = 0;
725
0
    uint32_t column = 0;
726
0
727
0
    Maybe<JSAutoRealm> ar;
728
0
    JS::RootedObject stack(cx);
729
0
    if (aStack) {
730
0
      stack = UncheckedUnwrap(aStack);
731
0
      ar.emplace(cx, stack);
732
0
733
0
      JSPrincipals* principals = JS::GetRealmPrincipals(js::GetContextRealm(cx));
734
0
      if (JS::GetSavedFrameLine(cx, principals, stack, &line) != JS::SavedFrameResult::Ok ||
735
0
          JS::GetSavedFrameColumn(cx, principals, stack, &column) != JS::SavedFrameResult::Ok ||
736
0
          JS::GetSavedFrameSource(cx, principals, stack, &fileName) != JS::SavedFrameResult::Ok) {
737
0
        return;
738
0
      }
739
0
    }
740
0
741
0
    JS::RootedString message(cx);
742
0
    {
743
0
      JS::RootedValue msgVal(cx);
744
0
      if (!xpc::NonVoidStringToJsval(cx, aMessage, &msgVal)) {
745
0
        return;
746
0
      }
747
0
      message = msgVal.toString();
748
0
    }
749
0
750
0
    JS::Rooted<JS::Value> err(cx);
751
0
    if (!JS::CreateError(cx, JSEXN_ERR, stack,
752
0
                         fileName, line, column,
753
0
                         nullptr, message, &err)) {
754
0
      return;
755
0
    }
756
0
757
0
    MOZ_ASSERT(err.isObject());
758
0
    retVal = &err.toObject();
759
0
  }
760
0
761
0
  if (aStack && !JS_WrapObject(cx, &retVal)) {
762
0
    return;
763
0
  }
764
0
765
0
  cleanup.release();
766
0
  aRetVal.set(retVal);
767
0
}
768
769
/* static */ already_AddRefed<Promise>
770
ChromeUtils::RequestIOActivity(GlobalObject& aGlobal, ErrorResult& aRv)
771
0
{
772
0
  MOZ_ASSERT(XRE_IsParentProcess());
773
0
  MOZ_ASSERT(Preferences::GetBool(IO_ACTIVITY_ENABLED_PREF, false));
774
0
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
775
0
  MOZ_ASSERT(global);
776
0
  RefPtr<Promise> domPromise = Promise::Create(global, aRv);
777
0
  if (NS_WARN_IF(aRv.Failed())) {
778
0
    return nullptr;
779
0
  }
780
0
  MOZ_ASSERT(domPromise);
781
0
  mozilla::net::IOActivityMonitor::RequestActivities(domPromise);
782
0
  return domPromise.forget();
783
0
}
784
785
/* static */ void
786
ChromeUtils::GetRootBrowsingContexts(GlobalObject& aGlobal,
787
                                     nsTArray<RefPtr<BrowsingContext>>& aBrowsingContexts)
788
0
{
789
0
  BrowsingContext::GetRootBrowsingContexts(aBrowsingContexts);
790
0
}
791
792
} // namespace dom
793
} // namespace mozilla