2017-10-26 22:08:41 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2015-06-17 18:12:23 +00:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#include "ChromeUtils.h"
|
|
|
|
|
2017-08-18 18:10:10 +00:00
|
|
|
#include "jsfriendapi.h"
|
|
|
|
#include "WrapperFactory.h"
|
|
|
|
|
2016-03-22 19:09:04 +00:00
|
|
|
#include "mozilla/Base64.h"
|
2015-06-17 18:12:23 +00:00
|
|
|
#include "mozilla/BasePrincipal.h"
|
2017-11-16 09:48:45 +00:00
|
|
|
#include "mozilla/CycleCollectedJSRuntime.h"
|
2017-09-24 05:12:32 +00:00
|
|
|
#include "mozilla/TimeStamp.h"
|
2018-03-20 19:07:41 +00:00
|
|
|
#include "mozilla/dom/ContentParent.h"
|
2017-09-24 05:12:32 +00:00
|
|
|
#include "mozilla/dom/IdleDeadline.h"
|
2017-10-12 12:50:23 +00:00
|
|
|
#include "mozilla/dom/UnionTypes.h"
|
2017-09-24 05:12:32 +00:00
|
|
|
#include "mozilla/dom/WindowBinding.h" // For IdleRequestCallback/Options
|
|
|
|
#include "nsThreadUtils.h"
|
2017-12-16 05:30:25 +00:00
|
|
|
#include "mozJSComponentLoader.h"
|
|
|
|
#include "GeckoProfiler.h"
|
2015-06-17 18:12:23 +00:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
|
|
|
|
2015-06-24 20:34:54 +00:00
|
|
|
/* static */ void
|
2017-11-08 05:25:33 +00:00
|
|
|
ChromeUtils::NondeterministicGetWeakMapKeys(GlobalObject& aGlobal,
|
|
|
|
JS::Handle<JS::Value> aMap,
|
|
|
|
JS::MutableHandle<JS::Value> aRetval,
|
|
|
|
ErrorResult& aRv)
|
2015-11-11 11:55:00 +00:00
|
|
|
{
|
|
|
|
if (!aMap.isObject()) {
|
|
|
|
aRetval.setUndefined();
|
|
|
|
} else {
|
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
JS::Rooted<JSObject*> objRet(cx);
|
|
|
|
JS::Rooted<JSObject*> mapObj(cx, &aMap.toObject());
|
|
|
|
if (!JS_NondeterministicGetWeakMapKeys(cx, mapObj, &objRet)) {
|
|
|
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
} else {
|
|
|
|
aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-16 14:50:00 +00:00
|
|
|
/* static */ void
|
2017-11-08 05:25:33 +00:00
|
|
|
ChromeUtils::NondeterministicGetWeakSetKeys(GlobalObject& aGlobal,
|
|
|
|
JS::Handle<JS::Value> aSet,
|
|
|
|
JS::MutableHandle<JS::Value> aRetval,
|
|
|
|
ErrorResult& aRv)
|
2015-11-16 14:50:00 +00:00
|
|
|
{
|
|
|
|
if (!aSet.isObject()) {
|
|
|
|
aRetval.setUndefined();
|
|
|
|
} else {
|
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
JS::Rooted<JSObject*> objRet(cx);
|
|
|
|
JS::Rooted<JSObject*> setObj(cx, &aSet.toObject());
|
|
|
|
if (!JS_NondeterministicGetWeakSetKeys(cx, setObj, &objRet)) {
|
|
|
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
} else {
|
|
|
|
aRetval.set(objRet ? JS::ObjectValue(*objRet) : JS::UndefinedValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-22 19:09:04 +00:00
|
|
|
/* static */ void
|
2017-11-08 05:25:33 +00:00
|
|
|
ChromeUtils::Base64URLEncode(GlobalObject& aGlobal,
|
|
|
|
const ArrayBufferViewOrArrayBuffer& aSource,
|
|
|
|
const Base64URLEncodeOptions& aOptions,
|
|
|
|
nsACString& aResult,
|
|
|
|
ErrorResult& aRv)
|
2016-03-22 19:09:04 +00:00
|
|
|
{
|
|
|
|
size_t length = 0;
|
|
|
|
uint8_t* data = nullptr;
|
|
|
|
if (aSource.IsArrayBuffer()) {
|
|
|
|
const ArrayBuffer& buffer = aSource.GetAsArrayBuffer();
|
|
|
|
buffer.ComputeLengthAndData();
|
|
|
|
length = buffer.Length();
|
|
|
|
data = buffer.Data();
|
|
|
|
} else if (aSource.IsArrayBufferView()) {
|
|
|
|
const ArrayBufferView& view = aSource.GetAsArrayBufferView();
|
|
|
|
view.ComputeLengthAndData();
|
|
|
|
length = view.Length();
|
|
|
|
data = view.Data();
|
|
|
|
} else {
|
|
|
|
MOZ_CRASH("Uninitialized union: expected buffer or view");
|
|
|
|
}
|
|
|
|
|
2016-04-22 14:41:58 +00:00
|
|
|
auto paddingPolicy = aOptions.mPad ? Base64URLEncodePaddingPolicy::Include :
|
|
|
|
Base64URLEncodePaddingPolicy::Omit;
|
|
|
|
nsresult rv = mozilla::Base64URLEncode(length, data, paddingPolicy, aResult);
|
2016-03-22 19:09:04 +00:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
aResult.Truncate();
|
|
|
|
aRv.Throw(rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ void
|
2017-11-08 05:25:33 +00:00
|
|
|
ChromeUtils::Base64URLDecode(GlobalObject& aGlobal,
|
|
|
|
const nsACString& aString,
|
|
|
|
const Base64URLDecodeOptions& aOptions,
|
|
|
|
JS::MutableHandle<JSObject*> aRetval,
|
|
|
|
ErrorResult& aRv)
|
2016-03-22 19:09:04 +00:00
|
|
|
{
|
2016-04-22 14:41:58 +00:00
|
|
|
Base64URLDecodePaddingPolicy paddingPolicy;
|
|
|
|
switch (aOptions.mPadding) {
|
|
|
|
case Base64URLDecodePadding::Require:
|
|
|
|
paddingPolicy = Base64URLDecodePaddingPolicy::Require;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Base64URLDecodePadding::Ignore:
|
|
|
|
paddingPolicy = Base64URLDecodePaddingPolicy::Ignore;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Base64URLDecodePadding::Reject:
|
|
|
|
paddingPolicy = Base64URLDecodePaddingPolicy::Reject;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
|
|
return;
|
|
|
|
}
|
2016-03-22 19:09:04 +00:00
|
|
|
FallibleTArray<uint8_t> data;
|
2016-04-22 14:41:58 +00:00
|
|
|
nsresult rv = mozilla::Base64URLDecode(aString, paddingPolicy, data);
|
2016-03-22 19:09:04 +00:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> buffer(aGlobal.Context(),
|
|
|
|
ArrayBuffer::Create(aGlobal.Context(),
|
|
|
|
data.Length(),
|
|
|
|
data.Elements()));
|
|
|
|
if (NS_WARN_IF(!buffer)) {
|
|
|
|
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
aRetval.set(buffer);
|
|
|
|
}
|
|
|
|
|
2017-08-18 18:10:10 +00:00
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::WaiveXrays(GlobalObject& aGlobal,
|
|
|
|
JS::HandleValue aVal,
|
|
|
|
JS::MutableHandleValue aRetval,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
JS::RootedValue value(aGlobal.Context(), aVal);
|
|
|
|
if (!xpc::WrapperFactory::WaiveXrayAndWrap(aGlobal.Context(), &value)) {
|
|
|
|
aRv.NoteJSContextException(aGlobal.Context());
|
|
|
|
} else {
|
|
|
|
aRetval.set(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::UnwaiveXrays(GlobalObject& aGlobal,
|
|
|
|
JS::HandleValue aVal,
|
|
|
|
JS::MutableHandleValue aRetval,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
if (!aVal.isObject()) {
|
|
|
|
aRetval.set(aVal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::RootedObject obj(aGlobal.Context(), js::UncheckedUnwrap(&aVal.toObject()));
|
|
|
|
if (!JS_WrapObject(aGlobal.Context(), &obj)) {
|
|
|
|
aRv.NoteJSContextException(aGlobal.Context());
|
|
|
|
} else {
|
|
|
|
aRetval.setObject(*obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::GetClassName(GlobalObject& aGlobal,
|
|
|
|
JS::HandleObject aObj,
|
|
|
|
bool aUnwrap,
|
|
|
|
nsAString& aRetval)
|
|
|
|
{
|
|
|
|
JS::RootedObject obj(aGlobal.Context(), aObj);
|
|
|
|
if (aUnwrap) {
|
|
|
|
obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
|
|
|
|
}
|
|
|
|
|
|
|
|
aRetval = NS_ConvertUTF8toUTF16(nsDependentCString(js::GetObjectClass(obj)->name));
|
|
|
|
}
|
|
|
|
|
2017-08-24 20:33:40 +00:00
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::ShallowClone(GlobalObject& aGlobal,
|
|
|
|
JS::HandleObject aObj,
|
|
|
|
JS::HandleObject aTarget,
|
|
|
|
JS::MutableHandleObject aRetval,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
|
|
|
|
auto cleanup = MakeScopeExit([&] () {
|
|
|
|
aRv.NoteJSContextException(cx);
|
|
|
|
});
|
|
|
|
|
|
|
|
JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
|
|
|
|
JS::AutoValueVector values(cx);
|
|
|
|
|
|
|
|
{
|
|
|
|
JS::RootedObject obj(cx, js::CheckedUnwrap(aObj));
|
|
|
|
if (!obj) {
|
|
|
|
js::ReportAccessDenied(cx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (js::IsScriptedProxy(obj)) {
|
|
|
|
JS_ReportErrorASCII(cx, "Shallow cloning a proxy object is not allowed");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSAutoCompartment ac(cx, obj);
|
|
|
|
|
|
|
|
if (!JS_Enumerate(cx, obj, &ids) ||
|
|
|
|
!values.reserve(ids.length())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<JS::PropertyDescriptor> desc(cx);
|
|
|
|
JS::RootedId id(cx);
|
|
|
|
for (jsid idVal : ids) {
|
|
|
|
id = idVal;
|
|
|
|
if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (desc.setter() || desc.getter()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
values.infallibleAppend(desc.value());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::RootedObject obj(cx);
|
|
|
|
{
|
|
|
|
Maybe<JSAutoCompartment> ac;
|
|
|
|
if (aTarget) {
|
|
|
|
JS::RootedObject target(cx, js::CheckedUnwrap(aTarget));
|
|
|
|
if (!target) {
|
|
|
|
js::ReportAccessDenied(cx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ac.emplace(cx, target);
|
|
|
|
}
|
|
|
|
|
|
|
|
obj = JS_NewPlainObject(cx);
|
|
|
|
if (!obj) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::RootedValue value(cx);
|
|
|
|
JS::RootedId id(cx);
|
|
|
|
for (uint32_t i = 0; i < ids.length(); i++) {
|
|
|
|
id = ids[i];
|
|
|
|
value = values[i];
|
|
|
|
|
|
|
|
JS_MarkCrossZoneId(cx, id);
|
|
|
|
if (!JS_WrapValue(cx, &value) ||
|
|
|
|
!JS_SetPropertyById(cx, obj, id, value)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aTarget && !JS_WrapObject(cx, &obj)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup.release();
|
|
|
|
aRetval.set(obj);
|
|
|
|
}
|
|
|
|
|
2017-09-24 05:12:32 +00:00
|
|
|
namespace {
|
|
|
|
class IdleDispatchRunnable final : public IdleRunnable
|
|
|
|
, public nsITimerCallback
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS_INHERITED
|
|
|
|
|
|
|
|
IdleDispatchRunnable(nsIGlobalObject* aParent,
|
|
|
|
IdleRequestCallback& aCallback)
|
|
|
|
: IdleRunnable("ChromeUtils::IdleDispatch")
|
|
|
|
, mCallback(&aCallback)
|
|
|
|
, mParent(aParent)
|
|
|
|
{}
|
|
|
|
|
|
|
|
NS_IMETHOD Run() override
|
|
|
|
{
|
|
|
|
if (mCallback) {
|
|
|
|
CancelTimer();
|
|
|
|
|
|
|
|
auto deadline = mDeadline - TimeStamp::ProcessCreation();
|
|
|
|
|
|
|
|
ErrorResult rv;
|
|
|
|
RefPtr<IdleDeadline> idleDeadline =
|
|
|
|
new IdleDeadline(mParent, mTimedOut, deadline.ToMilliseconds());
|
|
|
|
|
|
|
|
mCallback->Call(*idleDeadline, rv, "ChromeUtils::IdleDispatch handler");
|
|
|
|
mCallback = nullptr;
|
|
|
|
mParent = nullptr;
|
|
|
|
|
|
|
|
rv.SuppressException();
|
|
|
|
return rv.StealNSResult();
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetDeadline(TimeStamp aDeadline) override
|
|
|
|
{
|
|
|
|
mDeadline = aDeadline;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD Notify(nsITimer* aTimer) override
|
|
|
|
{
|
|
|
|
mTimedOut = true;
|
|
|
|
SetDeadline(TimeStamp::Now());
|
|
|
|
return Run();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aTarget);
|
|
|
|
MOZ_ASSERT(!mTimer);
|
2017-10-16 06:15:40 +00:00
|
|
|
NS_NewTimerWithCallback(getter_AddRefs(mTimer),
|
|
|
|
this, aDelay, nsITimer::TYPE_ONE_SHOT,
|
|
|
|
aTarget);
|
2017-09-24 05:12:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual ~IdleDispatchRunnable()
|
|
|
|
{
|
|
|
|
CancelTimer();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void CancelTimer()
|
|
|
|
{
|
|
|
|
if (mTimer) {
|
|
|
|
mTimer->Cancel();
|
|
|
|
mTimer = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<IdleRequestCallback> mCallback;
|
|
|
|
nsCOMPtr<nsIGlobalObject> mParent;
|
|
|
|
|
|
|
|
nsCOMPtr<nsITimer> mTimer;
|
|
|
|
|
|
|
|
TimeStamp mDeadline{};
|
|
|
|
bool mTimedOut = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED(IdleDispatchRunnable, IdleRunnable, nsITimerCallback)
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::IdleDispatch(const GlobalObject& aGlobal,
|
|
|
|
IdleRequestCallback& aCallback,
|
|
|
|
const IdleRequestOptions& aOptions,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
|
|
|
MOZ_ASSERT(global);
|
|
|
|
|
|
|
|
auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback);
|
|
|
|
|
|
|
|
if (aOptions.mTimeout.WasPassed()) {
|
|
|
|
aRv = NS_IdleDispatchToCurrentThread(runnable.forget(), aOptions.mTimeout.Value());
|
|
|
|
} else {
|
|
|
|
aRv = NS_IdleDispatchToCurrentThread(runnable.forget());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-16 05:30:25 +00:00
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::Import(const GlobalObject& aGlobal,
|
|
|
|
const nsAString& aResourceURI,
|
|
|
|
const Optional<JS::Handle<JSObject*>>& aTargetObj,
|
|
|
|
JS::MutableHandle<JSObject*> aRetval,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
|
|
|
|
RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
|
|
|
|
MOZ_ASSERT(moduleloader);
|
|
|
|
|
|
|
|
NS_ConvertUTF16toUTF8 registryLocation(aResourceURI);
|
|
|
|
|
|
|
|
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
|
|
|
|
"ChromeUtils::Import", OTHER, registryLocation);
|
|
|
|
|
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
JS::Rooted<JS::Value> targetObj(cx);
|
|
|
|
uint8_t optionalArgc;
|
|
|
|
if (aTargetObj.WasPassed()) {
|
|
|
|
targetObj.setObjectOrNull(aTargetObj.Value());
|
|
|
|
optionalArgc = 1;
|
|
|
|
} else {
|
|
|
|
targetObj.setUndefined();
|
|
|
|
optionalArgc = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<JS::Value> retval(cx);
|
2018-01-18 22:12:04 +00:00
|
|
|
nsresult rv = moduleloader->ImportInto(registryLocation, targetObj, cx,
|
|
|
|
optionalArgc, &retval);
|
2017-12-16 05:30:25 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Import() on the component loader can return NS_OK while leaving an
|
|
|
|
// exception on the JSContext. Check for that case.
|
|
|
|
if (JS_IsExceptionPending(cx)) {
|
|
|
|
aRv.NoteJSContextException(cx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now we better have an object.
|
|
|
|
MOZ_ASSERT(retval.isObject());
|
|
|
|
aRetval.set(&retval.toObject());
|
|
|
|
}
|
|
|
|
|
2018-01-18 03:20:16 +00:00
|
|
|
namespace module_getter {
|
|
|
|
static const size_t SLOT_ID = 0;
|
|
|
|
static const size_t SLOT_URI = 1;
|
|
|
|
|
|
|
|
static bool
|
|
|
|
ExtractArgs(JSContext* aCx, JS::CallArgs& aArgs,
|
|
|
|
JS::MutableHandle<JSObject*> aCallee,
|
|
|
|
JS::MutableHandle<JSObject*> aThisObj,
|
|
|
|
JS::MutableHandle<jsid> aId)
|
|
|
|
{
|
|
|
|
aCallee.set(&aArgs.callee());
|
|
|
|
|
|
|
|
JS::Handle<JS::Value> thisv = aArgs.thisv();
|
|
|
|
if (!thisv.isObject()) {
|
|
|
|
JS_ReportErrorASCII(aCx, "Invalid target object");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
aThisObj.set(&thisv.toObject());
|
|
|
|
|
|
|
|
JS::Rooted<JS::Value> id(aCx, js::GetFunctionNativeReserved(aCallee, SLOT_ID));
|
|
|
|
MOZ_ALWAYS_TRUE(JS_ValueToId(aCx, id, aId));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
ModuleGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
|
|
|
|
{
|
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> callee(aCx);
|
|
|
|
JS::Rooted<JSObject*> thisObj(aCx);
|
|
|
|
JS::Rooted<jsid> id(aCx);
|
|
|
|
if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<JSString*> moduleURI(
|
|
|
|
aCx, js::GetFunctionNativeReserved(callee, SLOT_URI).toString());
|
|
|
|
JSAutoByteString bytes;
|
|
|
|
if (!bytes.encodeUtf8(aCx, moduleURI)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsDependentCString uri(bytes.ptr());
|
|
|
|
|
|
|
|
RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
|
|
|
|
MOZ_ASSERT(moduleloader);
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> moduleGlobal(aCx);
|
|
|
|
JS::Rooted<JSObject*> moduleExports(aCx);
|
|
|
|
nsresult rv = moduleloader->Import(aCx, uri, &moduleGlobal, &moduleExports);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
Throw(aCx, rv);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::RootedValue value(aCx);
|
|
|
|
{
|
|
|
|
JSAutoCompartment ac(aCx, moduleExports);
|
|
|
|
|
|
|
|
if (!JS_GetPropertyById(aCx, moduleExports, id, &value)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!JS_WrapValue(aCx, &value) ||
|
|
|
|
!JS_DefinePropertyById(aCx, thisObj, id, value,
|
|
|
|
JSPROP_ENUMERATE)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
args.rval().set(value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
ModuleSetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
|
|
|
|
{
|
|
|
|
JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> callee(aCx);
|
|
|
|
JS::Rooted<JSObject*> thisObj(aCx);
|
|
|
|
JS::Rooted<jsid> id(aCx);
|
|
|
|
if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_DefinePropertyById(aCx, thisObj, id, args.get(0),
|
|
|
|
JSPROP_ENUMERATE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
DefineGetter(JSContext* aCx,
|
|
|
|
JS::Handle<JSObject*> aTarget,
|
|
|
|
const nsAString& aId,
|
|
|
|
const nsAString& aResourceURI)
|
|
|
|
{
|
|
|
|
JS::RootedValue uri(aCx);
|
|
|
|
JS::RootedValue idValue(aCx);
|
|
|
|
JS::Rooted<jsid> id(aCx);
|
|
|
|
if (!xpc::NonVoidStringToJsval(aCx, aResourceURI, &uri) ||
|
|
|
|
!xpc::NonVoidStringToJsval(aCx, aId, &idValue) ||
|
|
|
|
!JS_ValueToId(aCx, idValue, &id)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
idValue = js::IdToValue(id);
|
|
|
|
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> getter(aCx, JS_GetFunctionObject(
|
|
|
|
js::NewFunctionByIdWithReserved(aCx, ModuleGetter, 0, 0, id)));
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> setter(aCx, JS_GetFunctionObject(
|
|
|
|
js::NewFunctionByIdWithReserved(aCx, ModuleSetter, 0, 0, id)));
|
|
|
|
|
|
|
|
if (!getter || !setter) {
|
|
|
|
JS_ReportOutOfMemory(aCx);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
js::SetFunctionNativeReserved(getter, SLOT_ID, idValue);
|
|
|
|
js::SetFunctionNativeReserved(setter, SLOT_ID, idValue);
|
|
|
|
|
|
|
|
js::SetFunctionNativeReserved(getter, SLOT_URI, uri);
|
|
|
|
|
|
|
|
return JS_DefinePropertyById(aCx, aTarget, id,
|
|
|
|
JS_DATA_TO_FUNC_PTR(JSNative, getter.get()),
|
|
|
|
JS_DATA_TO_FUNC_PTR(JSNative, setter.get()),
|
|
|
|
JSPROP_GETTER | JSPROP_SETTER | JSPROP_ENUMERATE);
|
|
|
|
}
|
|
|
|
} // namespace module_getter
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::DefineModuleGetter(const GlobalObject& global,
|
|
|
|
JS::Handle<JSObject*> target,
|
|
|
|
const nsAString& id,
|
|
|
|
const nsAString& resourceURI,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
if (!module_getter::DefineGetter(global.Context(), target, id, resourceURI)) {
|
|
|
|
aRv.NoteJSContextException(global.Context());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-29 11:26:00 +00:00
|
|
|
/* static */ void
|
2015-06-24 20:34:54 +00:00
|
|
|
ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
|
|
|
|
const dom::OriginAttributesDictionary& aAttrs,
|
|
|
|
nsCString& aSuffix)
|
|
|
|
|
|
|
|
{
|
2017-01-12 16:38:48 +00:00
|
|
|
OriginAttributes attrs(aAttrs);
|
2015-06-24 20:34:54 +00:00
|
|
|
attrs.CreateSuffix(aSuffix);
|
|
|
|
}
|
2015-07-13 15:25:42 +00:00
|
|
|
|
2015-07-09 18:36:35 +00:00
|
|
|
/* static */ bool
|
|
|
|
ChromeUtils::OriginAttributesMatchPattern(dom::GlobalObject& aGlobal,
|
|
|
|
const dom::OriginAttributesDictionary& aAttrs,
|
|
|
|
const dom::OriginAttributesPatternDictionary& aPattern)
|
|
|
|
{
|
2017-01-12 16:38:48 +00:00
|
|
|
OriginAttributes attrs(aAttrs);
|
2015-07-09 18:36:35 +00:00
|
|
|
OriginAttributesPattern pattern(aPattern);
|
|
|
|
return pattern.Matches(attrs);
|
|
|
|
}
|
|
|
|
|
2016-02-29 11:26:00 +00:00
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::CreateOriginAttributesFromOrigin(dom::GlobalObject& aGlobal,
|
|
|
|
const nsAString& aOrigin,
|
|
|
|
dom::OriginAttributesDictionary& aAttrs,
|
|
|
|
ErrorResult& aRv)
|
2016-01-06 10:08:30 +00:00
|
|
|
{
|
2017-01-12 16:38:48 +00:00
|
|
|
OriginAttributes attrs;
|
2016-01-06 10:08:30 +00:00
|
|
|
nsAutoCString suffix;
|
|
|
|
if (!attrs.PopulateFromOrigin(NS_ConvertUTF16toUTF8(aOrigin), suffix)) {
|
|
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
|
|
return;
|
|
|
|
}
|
2016-02-19 14:55:25 +00:00
|
|
|
aAttrs = attrs;
|
2016-02-18 12:42:00 +00:00
|
|
|
}
|
|
|
|
|
2016-02-29 11:26:00 +00:00
|
|
|
/* static */ void
|
2016-04-04 10:20:00 +00:00
|
|
|
ChromeUtils::FillNonDefaultOriginAttributes(dom::GlobalObject& aGlobal,
|
2016-02-29 11:26:00 +00:00
|
|
|
const dom::OriginAttributesDictionary& aAttrs,
|
|
|
|
dom::OriginAttributesDictionary& aNewAttrs)
|
|
|
|
{
|
|
|
|
aNewAttrs = aAttrs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-25 15:41:13 +00:00
|
|
|
/* static */ bool
|
|
|
|
ChromeUtils::IsOriginAttributesEqual(dom::GlobalObject& aGlobal,
|
|
|
|
const dom::OriginAttributesDictionary& aA,
|
|
|
|
const dom::OriginAttributesDictionary& aB)
|
2016-11-17 13:52:16 +00:00
|
|
|
{
|
|
|
|
return IsOriginAttributesEqual(aA, aB);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool
|
|
|
|
ChromeUtils::IsOriginAttributesEqual(const dom::OriginAttributesDictionary& aA,
|
|
|
|
const dom::OriginAttributesDictionary& aB)
|
2016-02-25 15:41:13 +00:00
|
|
|
{
|
2016-11-09 01:11:32 +00:00
|
|
|
return aA.mAppId == aB.mAppId &&
|
2016-02-05 01:42:44 +00:00
|
|
|
aA.mInIsolatedMozBrowser == aB.mInIsolatedMozBrowser &&
|
2016-06-02 21:02:29 +00:00
|
|
|
aA.mUserContextId == aB.mUserContextId &&
|
|
|
|
aA.mPrivateBrowsingId == aB.mPrivateBrowsingId;
|
2016-02-25 15:41:13 +00:00
|
|
|
}
|
|
|
|
|
2017-11-16 09:48:45 +00:00
|
|
|
#ifdef NIGHTLY_BUILD
|
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::GetRecentJSDevError(GlobalObject& aGlobal,
|
|
|
|
JS::MutableHandleValue aRetval,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
aRetval.setUndefined();
|
|
|
|
auto runtime = CycleCollectedJSRuntime::Get();
|
|
|
|
MOZ_ASSERT(runtime);
|
|
|
|
|
|
|
|
auto cx = aGlobal.Context();
|
|
|
|
if (!runtime->GetRecentDevError(cx, aRetval)) {
|
|
|
|
aRv.NoteJSContextException(cx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::ClearRecentJSDevError(GlobalObject&)
|
|
|
|
{
|
|
|
|
auto runtime = CycleCollectedJSRuntime::Get();
|
|
|
|
MOZ_ASSERT(runtime);
|
|
|
|
|
|
|
|
runtime->ClearRecentDevError();
|
|
|
|
}
|
|
|
|
#endif // NIGHTLY_BUILD
|
|
|
|
|
2018-03-20 19:07:41 +00:00
|
|
|
#ifndef RELEASE_OR_BETA
|
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::RequestPerformanceMetrics(GlobalObject&)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
|
|
nsTArray<ContentParent*> children;
|
|
|
|
ContentParent::GetAll(children);
|
|
|
|
for (uint32_t i = 0; i < children.Length(); i++) {
|
|
|
|
mozilla::Unused << children[i]->SendRequestPerformanceMetrics();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
Bug 1441333: Part 1 - Add helper to retrieve closest stack frame with a given principal. r=bz
Most WebExtension APIs are async, and have fairly complicated error reporting
semantics. As a result, when we report an error, the current JS stack has very
little to do with the JS caller that triggered the error, which makes it
difficult to diagnose.
In order to improve the situation, we need to store the location of the caller
at the start of an async operation, so we can tie the error to some marginally
useful location. We don't have a reasonable way to do that now other than
proactively creating an error object when the API is called, or creating a
promise with a full async stack, both of which are too expensive.
This helper instead returns a single SavedStack frame with a given principal,
which should be considerably cheaper, and likely good enough to give a
starting point for debugging cryptic errors.
MozReview-Commit-ID: BTxhpZK9Fdz
--HG--
extra : rebase_source : 7f2c66b1dc18d4ce4c47bef2e3b9d5d3ade929aa
2017-11-12 01:39:16 +00:00
|
|
|
constexpr auto kSkipSelfHosted = JS::SavedFrameSelfHosted::Exclude;
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::GetCallerLocation(const GlobalObject& aGlobal, nsIPrincipal* aPrincipal,
|
|
|
|
JS::MutableHandle<JSObject*> aRetval)
|
|
|
|
{
|
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
|
|
|
|
auto* principals = nsJSPrincipals::get(aPrincipal);
|
|
|
|
|
|
|
|
JS::StackCapture captureMode(JS::FirstSubsumedFrame(cx, principals));
|
|
|
|
|
|
|
|
JS::RootedObject frame(cx);
|
|
|
|
if (!JS::CaptureCurrentStack(cx, &frame, mozilla::Move(captureMode))) {
|
|
|
|
JS_ClearPendingException(cx);
|
|
|
|
aRetval.set(nullptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FirstSubsumedFrame gets us a stack which stops at the first principal which
|
|
|
|
// is subsumed by the given principal. That means that we may have a lot of
|
|
|
|
// privileged frames that we don't care about at the top of the stack, though.
|
|
|
|
// We need to filter those out to get the frame we actually want.
|
|
|
|
aRetval.set(js::GetFirstSubsumedSavedFrame(cx, principals, frame, kSkipSelfHosted));
|
|
|
|
}
|
|
|
|
|
2018-03-01 22:00:00 +00:00
|
|
|
/* static */ void
|
|
|
|
ChromeUtils::CreateError(const GlobalObject& aGlobal, const nsAString& aMessage,
|
|
|
|
JS::Handle<JSObject*> aStack,
|
|
|
|
JS::MutableHandle<JSObject*> aRetVal, ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
if (aStack && !JS::IsSavedFrame(aStack)) {
|
|
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSContext* cx = aGlobal.Context();
|
|
|
|
|
|
|
|
auto cleanup = MakeScopeExit([&]() {
|
|
|
|
aRv.NoteJSContextException(cx);
|
|
|
|
});
|
|
|
|
|
|
|
|
JS::RootedObject retVal(cx);
|
|
|
|
{
|
|
|
|
JS::RootedString fileName(cx, JS_GetEmptyString(cx));
|
|
|
|
uint32_t line = 0;
|
|
|
|
uint32_t column = 0;
|
|
|
|
|
|
|
|
Maybe<JSAutoCompartment> ac;
|
|
|
|
JS::RootedObject stack(cx);
|
|
|
|
if (aStack) {
|
|
|
|
stack = UncheckedUnwrap(aStack);
|
|
|
|
ac.emplace(cx, stack);
|
|
|
|
|
|
|
|
if (JS::GetSavedFrameLine(cx, stack, &line) != JS::SavedFrameResult::Ok ||
|
|
|
|
JS::GetSavedFrameColumn(cx, stack, &column) != JS::SavedFrameResult::Ok ||
|
|
|
|
JS::GetSavedFrameSource(cx, stack, &fileName) != JS::SavedFrameResult::Ok) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::RootedString message(cx);
|
|
|
|
{
|
|
|
|
JS::RootedValue msgVal(cx);
|
|
|
|
if (!xpc::NonVoidStringToJsval(cx, aMessage, &msgVal)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
message = msgVal.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Rooted<JS::Value> err(cx);
|
|
|
|
if (!JS::CreateError(cx, JSEXN_ERR, stack,
|
|
|
|
fileName, line, column,
|
|
|
|
nullptr, message, &err)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(err.isObject());
|
|
|
|
retVal = &err.toObject();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aStack && !JS_WrapObject(cx, &retVal)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup.release();
|
|
|
|
aRetVal.set(retVal);
|
|
|
|
}
|
|
|
|
|
2015-06-17 18:12:23 +00:00
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|