mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-04 14:58:37 +09:00
Issue #2197 - Part 4: Expose structuredClone in Sandbox
Partially based on https://bugzilla.mozilla.org/show_bug.cgi?id=1734320
This commit is contained in:
parent
ef6b8db1d5
commit
bbcfb62753
10 changed files with 129 additions and 67 deletions
|
|
@ -47,6 +47,7 @@
|
|||
#include "mozilla/dom/HTMLTemplateElement.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
|
|
@ -10023,3 +10024,41 @@ nsContentUtils::CreateJSValueFromSequenceOfObject(JSContext* aCx,
|
|||
aValue.setObject(*array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void nsContentUtils::StructuredClone(JSContext* aCx,
|
||||
nsIGlobalObject* aGlobal,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
const StructuredSerializeOptions& aOptions,
|
||||
JS::MutableHandle<JS::Value> aRv,
|
||||
ErrorResult& aError) {
|
||||
JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
|
||||
aError = nsContentUtils::CreateJSValueFromSequenceOfObject(
|
||||
aCx, aOptions.mTransfer, &transferArray);
|
||||
if (NS_WARN_IF(aError.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
JS::CloneDataPolicy clonePolicy;
|
||||
// FIXME: Uncomment once bug 1609990 and bug 1611855 lands.
|
||||
//clonePolicy.allowIntraClusterClonableSharedObjects();
|
||||
//clonePolicy.allowSharedMemoryObjects();
|
||||
|
||||
StructuredCloneHolder holder(StructuredCloneHolder::CloningSupported,
|
||||
StructuredCloneHolder::TransferringSupported,
|
||||
JS::StructuredCloneScope::SameProcessDifferentThread);
|
||||
holder.Write(aCx, aValue, transferArray, clonePolicy, aError);
|
||||
if (NS_WARN_IF(aError.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Pass clonePolicy.
|
||||
//holder.Read(this, aCx, aRv, clonePolicy, aError);
|
||||
holder.Read(aGlobal, aCx, aRv, aError);
|
||||
if (NS_WARN_IF(aError.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<MessagePort>> ports = holder.TakeTransferredPorts();
|
||||
Unused << ports;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ class nsIContentParent;
|
|||
class TabChild;
|
||||
class Selection;
|
||||
class TabParent;
|
||||
struct StructuredSerializeOptions;
|
||||
} // namespace dom
|
||||
|
||||
namespace ipc {
|
||||
|
|
@ -2817,6 +2818,18 @@ public:
|
|||
const mozilla::dom::Sequence<JSObject*>& aTransfer,
|
||||
JS::MutableHandle<JS::Value> aValue);
|
||||
|
||||
/**
|
||||
* This implements the structured cloning algorithm as described by
|
||||
* https://html.spec.whatwg.org/#structured-cloning.
|
||||
*/
|
||||
static void
|
||||
StructuredClone(JSContext* aCx,
|
||||
nsIGlobalObject* aGlobal,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
const mozilla::dom::StructuredSerializeOptions& aOptions,
|
||||
JS::MutableHandle<JS::Value> aRv,
|
||||
mozilla::ErrorResult& aError);
|
||||
|
||||
private:
|
||||
static bool InitializeEventTable();
|
||||
|
||||
|
|
|
|||
|
|
@ -192,7 +192,6 @@
|
|||
#include "mozilla/dom/IDBFactory.h"
|
||||
#include "mozilla/dom/MessageChannel.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
|
||||
#ifdef MOZ_GAMEPAD
|
||||
#include "mozilla/dom/Gamepad.h"
|
||||
|
|
@ -14650,40 +14649,10 @@ void
|
|||
nsGlobalWindow::StructuredClone(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
const StructuredSerializeOptions& aOptions,
|
||||
JS::MutableHandle<JS::Value> aRetval,
|
||||
JS::MutableHandle<JS::Value> aRv,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
|
||||
aError = nsContentUtils::CreateJSValueFromSequenceOfObject(
|
||||
aCx, aOptions.mTransfer, &transferArray);
|
||||
if (NS_WARN_IF(aError.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Uncomment once bug 1609990 and bug 1611855 lands.
|
||||
//JS::CloneDataPolicy clonePolicy;
|
||||
//clonePolicy.allowIntraClusterClonableSharedObjects();
|
||||
//clonePolicy.allowSharedMemoryObjects();
|
||||
|
||||
StructuredCloneHolder holder(StructuredCloneHolder::CloningSupported,
|
||||
StructuredCloneHolder::TransferringSupported,
|
||||
JS::StructuredCloneScope::SameProcessDifferentThread);
|
||||
holder.Write(aCx, aValue, transferArray, clonePolicy, aError);
|
||||
if (NS_WARN_IF(aError.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Stop casting to nsISupports once bug 1585284 lands.
|
||||
nsISupports* windowAsSupports = static_cast<nsIGlobalObject*>(this);
|
||||
// TODO: Pass clonePolicy.
|
||||
//holder.Read(this, aCx, aRetval, clonePolicy, aError);
|
||||
holder.Read(windowAsSupports, aCx, aRetval, aError);
|
||||
if (NS_WARN_IF(aError.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<MessagePort>> ports = holder.TakeTransferredPorts();
|
||||
Unused << ports;
|
||||
nsContentUtils::StructuredClone(aCx, this, aValue, aOptions, aRv, aError);
|
||||
}
|
||||
|
||||
// Helper called by methods that move/resize the window,
|
||||
|
|
|
|||
|
|
@ -1185,7 +1185,7 @@ public:
|
|||
|
||||
void StructuredClone(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||
const mozilla::dom::StructuredSerializeOptions& aOptions,
|
||||
JS::MutableHandle<JS::Value> aRetval,
|
||||
JS::MutableHandle<JS::Value> aRv,
|
||||
mozilla::ErrorResult& aError);
|
||||
|
||||
// ChromeWindow bits. Do NOT call these unless your window is in
|
||||
|
|
|
|||
|
|
@ -497,39 +497,9 @@ WorkerGlobalScope::CreateImageBitmap(const ImageBitmapSource& aImage,
|
|||
void WorkerGlobalScope::StructuredClone(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
const StructuredSerializeOptions& aOptions,
|
||||
JS::MutableHandle<JS::Value> aRetval,
|
||||
JS::MutableHandle<JS::Value> aRv,
|
||||
ErrorResult& aError) {
|
||||
JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
|
||||
aError = nsContentUtils::CreateJSValueFromSequenceOfObject(
|
||||
aCx, aOptions.mTransfer, &transferArray);
|
||||
if (NS_WARN_IF(aError.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Uncomment once bug 1609990 and bug 1611855 lands.
|
||||
//JS::CloneDataPolicy clonePolicy;
|
||||
//clonePolicy.allowIntraClusterClonableSharedObjects();
|
||||
//clonePolicy.allowSharedMemoryObjects();
|
||||
|
||||
StructuredCloneHolder holder(StructuredCloneHolder::CloningSupported,
|
||||
StructuredCloneHolder::TransferringSupported,
|
||||
JS::StructuredCloneScope::SameProcessDifferentThread);
|
||||
holder.Write(aCx, aValue, transferArray, clonePolicy, aError);
|
||||
if (NS_WARN_IF(aError.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Stop casting to nsISupports once bug 1585284 lands.
|
||||
nsISupports* workerAsSupports = static_cast<nsIGlobalObject*>(this);
|
||||
// TODO: Pass clonePolicy.
|
||||
//holder.Read(this, aCx, aRetval, clonePolicy, aError);
|
||||
holder.Read(workerAsSupports, aCx, aRetval, aError);
|
||||
if (NS_WARN_IF(aError.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<MessagePort>> ports = holder.TakeTransferredPorts();
|
||||
Unused << ports;
|
||||
nsContentUtils::StructuredClone(aCx, this, aValue, aOptions, aRv, aError);
|
||||
}
|
||||
|
||||
DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ public:
|
|||
|
||||
void StructuredClone(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||
const StructuredSerializeOptions& aOptions,
|
||||
JS::MutableHandle<JS::Value> aRetval,
|
||||
JS::MutableHandle<JS::Value> aRv,
|
||||
ErrorResult& aError);
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -326,6 +326,45 @@ SandboxCreateFetch(JSContext* cx, HandleObject obj)
|
|||
dom::HeadersBinding::GetConstructorObject(cx);
|
||||
}
|
||||
|
||||
static bool SandboxStructuredClone(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (!args.requireAtLeast(cx, "structuredClone", 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedDictionary<dom::StructuredSerializeOptions> options(cx);
|
||||
if (!options.Init(cx, args.hasDefined(1) ? args[1] : JS::NullHandleValue,
|
||||
"Argument 2", false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(cx));
|
||||
if (!global) {
|
||||
JS_ReportErrorASCII(cx, "structuredClone: Missing global");
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
ErrorResult rv;
|
||||
nsContentUtils::StructuredClone(cx, global, args[0], options, &result, rv);
|
||||
if (rv.MaybeSetPendingException(cx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(result.isGCThing(),
|
||||
!JS::GCThingIsMarkedGray(result.toGCCellPtr()));
|
||||
args.rval().set(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SandboxCreateStructuredClone(JSContext* cx, HandleObject obj) {
|
||||
MOZ_ASSERT(JS_IsGlobalObject(obj));
|
||||
|
||||
return JS_DefineFunction(cx, obj, "structuredClone", SandboxStructuredClone,
|
||||
1, 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
SandboxIsProxy(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
|
@ -931,6 +970,8 @@ xpc::GlobalProperties::Parse(JSContext* cx, JS::HandleObject obj)
|
|||
#endif
|
||||
} else if (!strcmp(name.ptr(), "fetch")) {
|
||||
fetch = true;
|
||||
} else if (!strcmp(name.ptr(), "structuredClone")) {
|
||||
structuredClone = true;
|
||||
} else if (!strcmp(name.ptr(), "caches")) {
|
||||
caches = true;
|
||||
} else if (!strcmp(name.ptr(), "FileReader")) {
|
||||
|
|
@ -1006,6 +1047,9 @@ xpc::GlobalProperties::Define(JSContext* cx, JS::HandleObject obj)
|
|||
if (fetch && !SandboxCreateFetch(cx, obj))
|
||||
return false;
|
||||
|
||||
if (structuredClone && !SandboxCreateStructuredClone(cx, obj))
|
||||
return false;
|
||||
|
||||
if (caches && !dom::cache::CacheStorage::DefineCaches(cx, obj))
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -2879,6 +2879,7 @@ struct GlobalProperties {
|
|||
bool crypto : 1;
|
||||
bool rtcIdentityProvider : 1;
|
||||
bool fetch : 1;
|
||||
bool structuredClone : 1;
|
||||
bool caches : 1;
|
||||
bool fileReader: 1;
|
||||
private:
|
||||
|
|
|
|||
25
js/xpconnect/tests/unit/test_structuredClone.js
Normal file
25
js/xpconnect/tests/unit/test_structuredClone.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
function run_test() {
|
||||
var sb = new Cu.Sandbox('http://www.example.com',
|
||||
{ wantGlobalProperties: ["structuredClone"] });
|
||||
|
||||
sb.equal = equal;
|
||||
|
||||
sb.testing = Components.utils.cloneInto({xyz: 123}, sb);
|
||||
Cu.evalInSandbox(`
|
||||
equal(structuredClone("abc"), "abc");
|
||||
|
||||
var obj = {a: 1};
|
||||
obj.self = obj;
|
||||
var clone = structuredClone(obj);
|
||||
equal(clone.a, 1);
|
||||
equal(clone.self, clone);
|
||||
|
||||
var ab = new ArrayBuffer(1);
|
||||
clone = structuredClone(ab, {transfer: [ab]});
|
||||
equal(clone.byteLength, 1);
|
||||
equal(ab.byteLength, 0);
|
||||
|
||||
clone = structuredClone(testing);
|
||||
equal(clone.xyz, 123);
|
||||
`, sb);
|
||||
}
|
||||
|
|
@ -114,6 +114,7 @@ skip-if = os == "android" # native test components aren't available on Android
|
|||
[test_css.js]
|
||||
[test_rtcIdentityProvider.js]
|
||||
[test_sandbox_atob.js]
|
||||
[test_structuredClone.js]
|
||||
[test_isProxy.js]
|
||||
[test_getObjectPrincipal.js]
|
||||
[test_sandbox_name.js]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue