Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2023-04-10 07:27:58 +08:00
commit 20b787a4df
37 changed files with 523 additions and 153 deletions

View file

@ -824,6 +824,10 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
aVisitor.mCanHandle = true; aVisitor.mCanHandle = true;
aVisitor.mMayHaveListenerManager = HasListenerManager(); aVisitor.mMayHaveListenerManager = HasListenerManager();
if (IsInShadowTree()) {
aVisitor.mItemInShadowTree = true;
}
// Don't propagate mouseover and mouseout events when mouse is moving // Don't propagate mouseover and mouseout events when mouse is moving
// inside chrome access only content. // inside chrome access only content.
bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree(); bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree();

View file

@ -47,6 +47,7 @@
#include "mozilla/dom/HTMLTemplateElement.h" #include "mozilla/dom/HTMLTemplateElement.h"
#include "mozilla/dom/ipc/BlobChild.h" #include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/ipc/BlobParent.h" #include "mozilla/dom/ipc/BlobParent.h"
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/TabParent.h" #include "mozilla/dom/TabParent.h"
@ -9993,3 +9994,71 @@ nsContentUtils::GetClosestNonNativeAnonymousAncestor(Element* aElement)
} }
return e; return e;
} }
/* static */ nsresult
nsContentUtils::CreateJSValueFromSequenceOfObject(JSContext* aCx,
const Sequence<JSObject*>& aTransfer,
JS::MutableHandle<JS::Value> aValue)
{
if (aTransfer.IsEmpty()) {
return NS_OK;
}
JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aTransfer.Length()));
if (!array) {
return NS_ERROR_OUT_OF_MEMORY;
}
for (uint32_t i = 0; i < aTransfer.Length(); ++i) {
JS::Rooted<JSObject*> object(aCx, aTransfer[i]);
if (!object) {
continue;
}
if (NS_WARN_IF(!JS_DefineElement(aCx, array, i, object,
JSPROP_ENUMERATE))) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
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;
}

View file

@ -132,6 +132,7 @@ class nsIContentParent;
class TabChild; class TabChild;
class Selection; class Selection;
class TabParent; class TabParent;
struct StructuredSerializeOptions;
} // namespace dom } // namespace dom
namespace ipc { namespace ipc {
@ -2812,6 +2813,23 @@ public:
static bool static bool
IsCustomElementsEnabled() { return sIsCustomElementsEnabled; } IsCustomElementsEnabled() { return sIsCustomElementsEnabled; }
static nsresult
CreateJSValueFromSequenceOfObject(JSContext* aCx,
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: private:
static bool InitializeEventTable(); static bool InitializeEventTable();

View file

@ -909,7 +909,8 @@ nsPIDOMWindow<T>::nsPIDOMWindow(nsPIDOMWindowOuter *aOuterWindow)
mOuterWindow(aOuterWindow), mOuterWindow(aOuterWindow),
// Make sure no actual window ends up with mWindowID == 0 // Make sure no actual window ends up with mWindowID == 0
mWindowID(NextWindowID()), mHasNotifiedGlobalCreated(false), mWindowID(NextWindowID()), mHasNotifiedGlobalCreated(false),
mMarkedCCGeneration(0), mServiceWorkersTestingEnabled(false) mMarkedCCGeneration(0), mServiceWorkersTestingEnabled(false),
mEvent(nullptr)
{} {}
template<class T> template<class T>
@ -5245,6 +5246,16 @@ nsGlobalWindow::SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
SetOpenerWindow(outer, false); SetOpenerWindow(outer, false);
} }
void
nsGlobalWindow::GetEvent(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval)
{
if (mEvent) {
Unused << nsContentUtils::WrapNative(aCx, mEvent, aRetval);
} else {
aRetval.setUndefined();
}
}
void void
nsGlobalWindow::GetStatusOuter(nsAString& aStatus) nsGlobalWindow::GetStatusOuter(nsAString& aStatus)
{ {
@ -8886,30 +8897,33 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
} }
void void
nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, nsGlobalWindow::PostMessageMoz(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const nsAString& aTargetOrigin, const nsAString& aTargetOrigin,
const Optional<Sequence<JS::Value>>& aTransfer, const Sequence<JSObject*>& aTransfer,
nsIPrincipal& aSubjectPrincipal, nsIPrincipal& aSubjectPrincipal,
ErrorResult& aError) ErrorResult& aRv)
{ {
JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue()); JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
if (aTransfer.WasPassed()) { aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransfer,
const Sequence<JS::Value >& values = aTransfer.Value(); &transferArray);
if (NS_WARN_IF(aRv.Failed())) {
// The input sequence only comes from the generated bindings code, which return;
// ensures it is rooted.
JS::HandleValueArray elements =
JS::HandleValueArray::fromMarkedLocation(values.Length(), values.Elements());
transferArray = JS::ObjectOrNullValue(JS_NewArrayObject(aCx, elements));
if (transferArray.isNull()) {
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
} }
PostMessageMoz(aCx, aMessage, aTargetOrigin, transferArray, PostMessageMoz(aCx, aMessage, aTargetOrigin, transferArray,
aSubjectPrincipal, aError); aSubjectPrincipal, aRv);
}
void
nsGlobalWindow::PostMessageMoz(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const WindowPostMessageOptions& aOptions,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aRv)
{
PostMessageMoz(aCx, aMessage, aOptions.mTargetOrigin, aOptions.mTransfer,
aSubjectPrincipal, aRv);
} }
class nsCloseEvent : public Runnable { class nsCloseEvent : public Runnable {
@ -14641,6 +14655,17 @@ nsGlobalWindow::CreateImageBitmap(const ImageBitmapSource& aImage,
} }
} }
// https://html.spec.whatwg.org/#structured-cloning
void
nsGlobalWindow::StructuredClone(JSContext* aCx,
JS::Handle<JS::Value> aValue,
const StructuredSerializeOptions& aOptions,
JS::MutableHandle<JS::Value> aRv,
ErrorResult& aError)
{
nsContentUtils::StructuredClone(aCx, this, aValue, aOptions, aRv, aError);
}
// Helper called by methods that move/resize the window, // Helper called by methods that move/resize the window,
// to ensure the presContext (if any) is aware of resolution // to ensure the presContext (if any) is aware of resolution
// change that may happen in multi-monitor configuration. // change that may happen in multi-monitor configuration.

View file

@ -135,6 +135,7 @@ class TabGroup;
class Timeout; class Timeout;
class U2F; class U2F;
class WakeLock; class WakeLock;
struct WindowPostMessageOptions;
class Worklet; class Worklet;
namespace cache { namespace cache {
class CacheStorage; class CacheStorage;
@ -845,6 +846,7 @@ public:
already_AddRefed<nsPIDOMWindowOuter> GetOpener() override; already_AddRefed<nsPIDOMWindowOuter> GetOpener() override;
void SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener, void SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
mozilla::ErrorResult& aError); mozilla::ErrorResult& aError);
void GetEvent(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
already_AddRefed<nsPIDOMWindowOuter> GetParentOuter(); already_AddRefed<nsPIDOMWindowOuter> GetParentOuter();
already_AddRefed<nsPIDOMWindowOuter> GetParent(mozilla::ErrorResult& aError); already_AddRefed<nsPIDOMWindowOuter> GetParent(mozilla::ErrorResult& aError);
already_AddRefed<nsPIDOMWindowOuter> GetParent() override; already_AddRefed<nsPIDOMWindowOuter> GetParent() override;
@ -933,7 +935,12 @@ public:
void Print(mozilla::ErrorResult& aError); void Print(mozilla::ErrorResult& aError);
void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const nsAString& aTargetOrigin, const nsAString& aTargetOrigin,
const mozilla::dom::Optional<mozilla::dom::Sequence<JS::Value > >& aTransfer, const mozilla::dom::Sequence<JSObject*>& aTransfer,
nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& aRv);
void PostMessageMoz(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const mozilla::dom::WindowPostMessageOptions& aOptions,
nsIPrincipal& aSubjectPrincipal, nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& aError); mozilla::ErrorResult& aError);
int32_t SetTimeout(JSContext* aCx, mozilla::dom::Function& aFunction, int32_t SetTimeout(JSContext* aCx, mozilla::dom::Function& aFunction,
@ -1177,6 +1184,10 @@ public:
const mozilla::dom::Sequence<mozilla::dom::ChannelPixelLayout>& aLayout, const mozilla::dom::Sequence<mozilla::dom::ChannelPixelLayout>& aLayout,
mozilla::ErrorResult& aRv); mozilla::ErrorResult& aRv);
void StructuredClone(JSContext* aCx, JS::Handle<JS::Value> aValue,
const mozilla::dom::StructuredSerializeOptions& aOptions,
JS::MutableHandle<JS::Value> aRv,
mozilla::ErrorResult& aError);
// ChromeWindow bits. Do NOT call these unless your window is in // ChromeWindow bits. Do NOT call these unless your window is in
// fact an nsGlobalChromeWindow. // fact an nsGlobalChromeWindow.

View file

@ -194,6 +194,10 @@ protected:
// we have what it takes to do so. // we have what it takes to do so.
void MaybeCreateDoc(); void MaybeCreateDoc();
// The event dispatch code sets and unsets this while keeping
// the event object alive.
nsIDOMEvent* mEvent;
public: public:
inline bool IsLoadingOrRunningTimeout() const; inline bool IsLoadingOrRunningTimeout() const;
@ -789,6 +793,17 @@ public:
return mInnerObjectsFreed; return mInnerObjectsFreed;
} }
// Sets the event for window.event. Does NOT take ownership, so
// the caller is responsible for clearing the event before the
// event gets deallocated. Pass nullptr to set window.event to
// undefined. Returns the previous value.
nsIDOMEvent* SetEvent(nsIDOMEvent* aEvent)
{
nsIDOMEvent* old = mEvent;
mEvent = aEvent;
return old;
}
/** /**
* Check whether this window is a secure context. * Check whether this window is a secure context.
*/ */

View file

@ -264,6 +264,16 @@ public:
return mFlags.mRootOfClosedTree; return mFlags.mRootOfClosedTree;
} }
void SetItemInShadowTree(bool aSet)
{
mFlags.mItemInShadowTree = aSet;
}
bool IsItemInShadowTree()
{
return mFlags.mItemInShadowTree;
}
void SetIsSlotInClosedTree(bool aSet) void SetIsSlotInClosedTree(bool aSet)
{ {
mFlags.mIsSlotInClosedTree = aSet; mFlags.mIsSlotInClosedTree = aSet;
@ -351,7 +361,8 @@ public:
mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent, mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent,
&aVisitor.mDOMEvent, &aVisitor.mDOMEvent,
CurrentTarget(), CurrentTarget(),
&aVisitor.mEventStatus); &aVisitor.mEventStatus,
IsItemInShadowTree());
NS_ASSERTION(aVisitor.mEvent->mCurrentTarget == nullptr, NS_ASSERTION(aVisitor.mEvent->mCurrentTarget == nullptr,
"CurrentTarget should be null!"); "CurrentTarget should be null!");
} }
@ -384,6 +395,7 @@ private:
bool mWantsPreHandleEvent : 1; bool mWantsPreHandleEvent : 1;
bool mPreHandleEventOnly : 1; bool mPreHandleEventOnly : 1;
bool mRootOfClosedTree : 1; bool mRootOfClosedTree : 1;
bool mItemInShadowTree : 1;
bool mIsSlotInClosedTree : 1; bool mIsSlotInClosedTree : 1;
bool mIsChromeHandler : 1; bool mIsChromeHandler : 1;
private: private:
@ -433,6 +445,7 @@ EventTargetChainItem::GetEventTargetParent(EventChainPreVisitor& aVisitor)
SetWantsPreHandleEvent(aVisitor.mWantsPreHandleEvent); SetWantsPreHandleEvent(aVisitor.mWantsPreHandleEvent);
SetPreHandleEventOnly(aVisitor.mWantsPreHandleEvent && !aVisitor.mCanHandle); SetPreHandleEventOnly(aVisitor.mWantsPreHandleEvent && !aVisitor.mCanHandle);
SetRootOfClosedTree(aVisitor.mRootOfClosedTree); SetRootOfClosedTree(aVisitor.mRootOfClosedTree);
SetItemInShadowTree(aVisitor.mItemInShadowTree);
SetRetargetedRelatedTarget(aVisitor.mRetargetedRelatedTarget); SetRetargetedRelatedTarget(aVisitor.mRetargetedRelatedTarget);
mItemFlags = aVisitor.mItemFlags; mItemFlags = aVisitor.mItemFlags;
mItemData = aVisitor.mItemData; mItemData = aVisitor.mItemData;

View file

@ -125,6 +125,7 @@ public:
, mMayHaveListenerManager(true) , mMayHaveListenerManager(true)
, mWantsPreHandleEvent(false) , mWantsPreHandleEvent(false)
, mRootOfClosedTree(false) , mRootOfClosedTree(false)
, mItemInShadowTree(false)
, mParentIsSlotInClosedTree(false) , mParentIsSlotInClosedTree(false)
, mParentIsChromeHandler(false) , mParentIsChromeHandler(false)
, mRelatedTargetRetargetedInCurrentScope(false) , mRelatedTargetRetargetedInCurrentScope(false)
@ -147,6 +148,7 @@ public:
mMayHaveListenerManager = true; mMayHaveListenerManager = true;
mWantsPreHandleEvent = false; mWantsPreHandleEvent = false;
mRootOfClosedTree = false; mRootOfClosedTree = false;
mItemInShadowTree = false;
mParentIsSlotInClosedTree = false; mParentIsSlotInClosedTree = false;
mParentIsChromeHandler = false; mParentIsChromeHandler = false;
// Note, we don't clear mRelatedTargetRetargetedInCurrentScope explicitly, // Note, we don't clear mRelatedTargetRetargetedInCurrentScope explicitly,
@ -236,6 +238,12 @@ public:
*/ */
bool mRootOfClosedTree; bool mRootOfClosedTree;
/**
* If target is node and its root is a shadow root.
* https://dom.spec.whatwg.org/#event-path-item-in-shadow-tree
*/
bool mItemInShadowTree;
/** /**
* True if mParentTarget is HTMLSlotElement in a closed shadow tree and the * True if mParentTarget is HTMLSlotElement in a closed shadow tree and the
* current target is assigned to that slot. * current target is assigned to that slot.

View file

@ -1121,6 +1121,38 @@ EventListenerManager::GetLegacyEventMessage(EventMessage aEventMessage) const
} }
} }
already_AddRefed<nsPIDOMWindowInner>
EventListenerManager::WindowFromListener(Listener* aListener,
bool aItemInShadowTree)
{
nsCOMPtr<nsPIDOMWindowInner> innerWindow;
if (!aItemInShadowTree) {
if (aListener->mListener.HasWebIDLCallback()) {
CallbackObject* callback = aListener->mListener.GetWebIDLCallback();
nsGlobalWindow* win;
if (callback) {
// Find the real underlying callback.
JSObject* realCallback =
js::UncheckedUnwrap(callback->CallbackPreserveColor());
// Get the global for this callback.
win = mIsMainThreadELM ?
xpc::WindowGlobalOrNull(realCallback) :
nullptr;
}
if (win && win->IsInnerWindow()) {
innerWindow = win->AsInner(); // Can be nullptr
}
} else {
// Can't get the global from
// listener->mListener.GetXPCOMCallback().
// In most cases, it would be the same as for
// the target, so let's do that.
innerWindow = GetInnerWindowForTarget(); // Can be nullptr
}
}
return innerWindow.forget();
}
/** /**
* Causes a check for event listeners and processing by them if they exist. * Causes a check for event listeners and processing by them if they exist.
* @param an event listener * @param an event listener
@ -1131,7 +1163,8 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
WidgetEvent* aEvent, WidgetEvent* aEvent,
nsIDOMEvent** aDOMEvent, nsIDOMEvent** aDOMEvent,
EventTarget* aCurrentTarget, EventTarget* aCurrentTarget,
nsEventStatus* aEventStatus) nsEventStatus* aEventStatus,
bool aItemInShadowTree)
{ {
//Set the value of the internal PreventDefault flag properly based on aEventStatus //Set the value of the internal PreventDefault flag properly based on aEventStatus
if (!aEvent->DefaultPrevented() && if (!aEvent->DefaultPrevented() &&
@ -1223,9 +1256,18 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
listener = listenerHolder.ptr(); listener = listenerHolder.ptr();
hasRemovedListener = true; hasRemovedListener = true;
} }
nsCOMPtr<nsPIDOMWindowInner> innerWindow =
WindowFromListener(listener, aItemInShadowTree);
nsIDOMEvent* oldWindowEvent = nullptr;
if (innerWindow) {
oldWindowEvent = innerWindow->SetEvent(*aDOMEvent);
}
if (NS_FAILED(HandleEventSubType(listener, *aDOMEvent, aCurrentTarget))) { if (NS_FAILED(HandleEventSubType(listener, *aDOMEvent, aCurrentTarget))) {
aEvent->mFlags.mExceptionWasRaised = true; aEvent->mFlags.mExceptionWasRaised = true;
} }
if (innerWindow) {
Unused << innerWindow->SetEvent(oldWindowEvent);
}
aEvent->mFlags.mInPassiveListener = false; aEvent->mFlags.mInPassiveListener = false;
if (needsEndEventMarker) { if (needsEndEventMarker) {

View file

@ -350,7 +350,8 @@ public:
WidgetEvent* aEvent, WidgetEvent* aEvent,
nsIDOMEvent** aDOMEvent, nsIDOMEvent** aDOMEvent,
dom::EventTarget* aCurrentTarget, dom::EventTarget* aCurrentTarget,
nsEventStatus* aEventStatus) nsEventStatus* aEventStatus,
bool aItemInShadowTree)
{ {
if (mListeners.IsEmpty() || aEvent->PropagationStopped()) { if (mListeners.IsEmpty() || aEvent->PropagationStopped()) {
return; return;
@ -371,7 +372,7 @@ public:
return; return;
} }
HandleEventInternal(aPresContext, aEvent, aDOMEvent, aCurrentTarget, HandleEventInternal(aPresContext, aEvent, aDOMEvent, aCurrentTarget,
aEventStatus); aEventStatus, aItemInShadowTree);
} }
/** /**
@ -482,7 +483,8 @@ protected:
WidgetEvent* aEvent, WidgetEvent* aEvent,
nsIDOMEvent** aDOMEvent, nsIDOMEvent** aDOMEvent,
dom::EventTarget* aCurrentTarget, dom::EventTarget* aCurrentTarget,
nsEventStatus* aEventStatus); nsEventStatus* aEventStatus,
bool aItemInShadowTree);
nsresult HandleEventSubType(Listener* aListener, nsresult HandleEventSubType(Listener* aListener,
nsIDOMEvent* aDOMEvent, nsIDOMEvent* aDOMEvent,
@ -573,6 +575,10 @@ public:
return typedHandler ? typedHandler->OnBeforeUnloadEventHandler() : nullptr; return typedHandler ? typedHandler->OnBeforeUnloadEventHandler() : nullptr;
} }
private:
already_AddRefed<nsPIDOMWindowInner> WindowFromListener(Listener* aListener,
bool aItemInShadowTree);
protected: protected:
/** /**
* Helper method for implementing the various Get*EventHandler above. Will * Helper method for implementing the various Get*EventHandler above. Will

View file

@ -394,52 +394,39 @@ MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
} }
void void
MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, MessagePort::PostMessage(JSContext* aCx,
const Optional<Sequence<JS::Value>>& aTransferable, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) ErrorResult& aRv)
{ {
// We *must* clone the data here, or the JS::Value could be modified // We *must* clone the data here, or the JS::Value could be modified
// by script // by script
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue()); // Here we want to check if the transferable object list contains
if (aTransferable.WasPassed()) { // this port.
const Sequence<JS::Value>& realTransferable = aTransferable.Value(); for (uint32_t i = 0; i < aTransferable.Length(); ++i) {
JSObject* rawObject = aTransferable[i];
// Here we want to check if the transerable object list contains if (!rawObject) {
// this port. No other checks are done. continue;
for (const JS::Value& value : realTransferable) {
if (!value.isObject()) {
continue;
}
JS::Rooted<JSObject*> object(aCx, &value.toObject());
MessagePort* port = nullptr;
nsresult rv = UNWRAP_OBJECT(MessagePort, &object, port);
if (NS_FAILED(rv)) {
continue;
}
if (port == this) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}
} }
// The input sequence only comes from the generated bindings code, which JS::Rooted<JSObject*> object(aCx, rawObject);
// ensures it is rooted.
JS::HandleValueArray elements =
JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(),
realTransferable.Elements());
JSObject* array = MessagePort* port = nullptr;
JS_NewArrayObject(aCx, elements); nsresult rv = UNWRAP_OBJECT(MessagePort, &object, port);
if (!array) { if (NS_SUCCEEDED(rv) && port == this) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY); aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return; return;
} }
}
transferable.setObject(*array); JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx,
aTransferable,
&transferable);
if (NS_WARN_IF(aRv.Failed())) {
return;
} }
RefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage(); RefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage();
@ -508,6 +495,14 @@ MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
mActor->SendPostMessages(messages); mActor->SendPostMessages(messages);
} }
void
MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const StructuredSerializeOptions& aOptions,
ErrorResult& aRv)
{
PostMessage(aCx, aMessage, aOptions.mTransfer, aRv);
}
void void
MessagePort::Start() MessagePort::Start()
{ {

View file

@ -26,6 +26,7 @@ class MessagePortIdentifier;
class MessagePortMessage; class MessagePortMessage;
class PostMessageRunnable; class PostMessageRunnable;
class SharedMessagePortMessage; class SharedMessagePortMessage;
struct StructuredSerializeOptions;
namespace workers { namespace workers {
class WorkerHolder; class WorkerHolder;
@ -62,7 +63,12 @@ public:
void void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv);
void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const StructuredSerializeOptions& aOptions,
ErrorResult& aRv); ErrorResult& aRv);
void Start(); void Start();

View file

@ -383,13 +383,6 @@ var tests =
hasWrongReturnOriginBug: true hasWrongReturnOriginBug: true
}, },
// 55
{
args: ["NOT-RECEIVED", undefined],
source: "sameDomain",
name: "SyntaxError",
code: DOMException.SYNTAX_ERR
},
]; ];
function allTests(callback) function allTests(callback)

View file

@ -15,7 +15,9 @@ interface Client {
readonly attribute DOMString id; readonly attribute DOMString id;
[Throws] [Throws]
void postMessage(any message, optional sequence<Transferable> transfer); void postMessage(any message, sequence<object> transferable);
[Throws]
void postMessage(any message, optional StructuredSerializeOptions options);
}; };
[Exposed=ServiceWorker] [Exposed=ServiceWorker]

View file

@ -16,7 +16,9 @@
Exposed=DedicatedWorker] Exposed=DedicatedWorker]
interface DedicatedWorkerGlobalScope : WorkerGlobalScope { interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
[Throws] [Throws]
void postMessage(any message, optional sequence<any> transfer); void postMessage(any message, sequence<object> transfer);
[Throws]
void postMessage(any message, optional StructuredSerializeOptions options);
attribute EventHandler onmessage; attribute EventHandler onmessage;
}; };

View file

@ -10,7 +10,9 @@
[Exposed=(Window,Worker,System)] [Exposed=(Window,Worker,System)]
interface MessagePort : EventTarget { interface MessagePort : EventTarget {
[Throws] [Throws]
void postMessage(any message, optional sequence<Transferable> transferable); void postMessage(any message, sequence<object> transferable);
[Throws]
void postMessage(any message, optional StructuredSerializeOptions options);
void start(); void start();
void close(); void close();
@ -19,3 +21,8 @@ interface MessagePort : EventTarget {
attribute EventHandler onmessage; attribute EventHandler onmessage;
}; };
// MessagePort implements Transferable; // MessagePort implements Transferable;
// Used to declare which objects should be transferred.
dictionary StructuredSerializeOptions {
sequence<object> transfer = [];
};

View file

@ -19,9 +19,10 @@ interface ServiceWorker : EventTarget {
attribute EventHandler onstatechange; attribute EventHandler onstatechange;
// FIXME(catalinb): Should inherit this from Worker.
[Throws] [Throws]
void postMessage(any message, optional sequence<Transferable> transferable); void postMessage(any message, sequence<object> transferable);
[Throws]
void postMessage(any message, optional StructuredSerializeOptions options);
}; };
ServiceWorker implements AbstractWorker; ServiceWorker implements AbstractWorker;

View file

@ -22,7 +22,6 @@ interface IID;
interface nsIBrowserDOMWindow; interface nsIBrowserDOMWindow;
interface nsIMessageBroadcaster; interface nsIMessageBroadcaster;
interface nsIDOMCrypto; interface nsIDOMCrypto;
typedef any Transferable;
// http://www.whatwg.org/specs/web-apps/current-work/ // http://www.whatwg.org/specs/web-apps/current-work/
[PrimaryGlobal, LegacyUnenumerableNamedProperties, NeedResolve] [PrimaryGlobal, LegacyUnenumerableNamedProperties, NeedResolve]
@ -51,6 +50,7 @@ typedef any Transferable;
[Throws] void stop(); [Throws] void stop();
[Throws, CrossOriginCallable, UnsafeInPrerendering] void focus(); [Throws, CrossOriginCallable, UnsafeInPrerendering] void focus();
[Throws, CrossOriginCallable] void blur(); [Throws, CrossOriginCallable] void blur();
[Replaceable, Pref="dom.window.event.enabled"] readonly attribute any event;
// other browsing contexts // other browsing contexts
[Replaceable, Throws, CrossOriginReadable] readonly attribute WindowProxy frames; [Replaceable, Throws, CrossOriginReadable] readonly attribute WindowProxy frames;
@ -80,7 +80,9 @@ typedef any Transferable;
[Throws, UnsafeInPrerendering] void print(); [Throws, UnsafeInPrerendering] void print();
[Throws, CrossOriginCallable, NeedsSubjectPrincipal] [Throws, CrossOriginCallable, NeedsSubjectPrincipal]
void postMessage(any message, DOMString targetOrigin, optional sequence<Transferable> transfer); void postMessage(any message, DOMString targetOrigin, optional sequence<object> transfer = []);
[Throws, CrossOriginCallable, NeedsSubjectPrincipal]
void postMessage(any message, optional WindowPostMessageOptions options);
// also has obsolete members // also has obsolete members
}; };
@ -486,3 +488,7 @@ callback IdleRequestCallback = void (IdleDeadline deadline);
partial interface Window { partial interface Window {
[ChromeOnly] readonly attribute boolean isSecureContextIfOpenerIgnored; [ChromeOnly] readonly attribute boolean isSecureContextIfOpenerIgnored;
}; };
dictionary WindowPostMessageOptions : StructuredSerializeOptions {
USVString targetOrigin = "/";
};

View file

@ -44,6 +44,10 @@ interface WindowOrWorkerGlobalScope {
Promise<ImageBitmap> createImageBitmap(ImageBitmapSource aImage); Promise<ImageBitmap> createImageBitmap(ImageBitmapSource aImage);
[Throws] [Throws]
Promise<ImageBitmap> createImageBitmap(ImageBitmapSource aImage, long aSx, long aSy, long aSw, long aSh); Promise<ImageBitmap> createImageBitmap(ImageBitmapSource aImage, long aSx, long aSy, long aSw, long aSh);
// structured cloning
[Throws]
any structuredClone(any value, optional StructuredSerializeOptions options);
}; };
// https://fetch.spec.whatwg.org/#fetch-method // https://fetch.spec.whatwg.org/#fetch-method

View file

@ -19,7 +19,9 @@ interface Worker : EventTarget {
void terminate(); void terminate();
[Throws] [Throws]
void postMessage(any message, optional sequence<any> transfer); void postMessage(any message, sequence<object> transfer);
[Throws]
void postMessage(any message, optional StructuredSerializeOptions options);
attribute EventHandler onmessage; attribute EventHandler onmessage;
}; };

View file

@ -14,6 +14,7 @@
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h" #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
#ifdef XP_WIN #ifdef XP_WIN
@ -77,7 +78,7 @@ ServiceWorker::GetScriptURL(nsString& aURL) const
void void
ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) ErrorResult& aRv)
{ {
if (State() == ServiceWorkerState::Redundant) { if (State() == ServiceWorkerState::Redundant) {
@ -97,6 +98,15 @@ ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
aRv = workerPrivate->SendMessageEvent(aCx, aMessage, aTransferable, Move(clientInfo)); aRv = workerPrivate->SendMessageEvent(aCx, aMessage, aTransferable, Move(clientInfo));
} }
void
ServiceWorker::PostMessage(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const StructuredSerializeOptions& aOptions,
ErrorResult& aRv)
{
PostMessage(aCx, aMessage, aOptions.mTransfer, aRv);
}
} // namespace workers } // namespace workers
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla

View file

@ -15,6 +15,8 @@ class nsPIDOMWindowInner;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
struct StructuredSerializeOptions;
namespace workers { namespace workers {
class ServiceWorkerInfo; class ServiceWorkerInfo;
@ -63,7 +65,13 @@ public:
void void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv);
void
PostMessage(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const StructuredSerializeOptions& aOptions,
ErrorResult& aRv); ErrorResult& aRv);
private: private:

View file

@ -11,6 +11,7 @@
#include "mozilla/dom/Navigator.h" #include "mozilla/dom/Navigator.h"
#include "mozilla/dom/ServiceWorkerMessageEvent.h" #include "mozilla/dom/ServiceWorkerMessageEvent.h"
#include "mozilla/dom/ServiceWorkerMessageEventBinding.h" #include "mozilla/dom/ServiceWorkerMessageEventBinding.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "nsGlobalWindow.h" #include "nsGlobalWindow.h"
#include "nsIBrowserDOMWindow.h" #include "nsIBrowserDOMWindow.h"
#include "nsIDocument.h" #include "nsIDocument.h"
@ -190,7 +191,7 @@ private:
void void
ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) ErrorResult& aRv)
{ {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
@ -198,20 +199,11 @@ ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
workerPrivate->AssertIsOnWorkerThread(); workerPrivate->AssertIsOnWorkerThread();
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue()); JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
if (aTransferable.WasPassed()) { aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx,
const Sequence<JS::Value>& realTransferable = aTransferable.Value(); aTransferable,
&transferable);
JS::HandleValueArray elements = if (NS_WARN_IF(aRv.Failed())) {
JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), return;
realTransferable.Elements());
JSObject* array = JS_NewArrayObject(aCx, elements);
if (!array) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
transferable.setObject(*array);
} }
RefPtr<ServiceWorkerClientPostMessageRunnable> runnable = RefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
@ -229,3 +221,11 @@ ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
} }
} }
void
ServiceWorkerClient::PostMessage(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const StructuredSerializeOptions& aOptions,
ErrorResult& aRv)
{
PostMessage(aCx, aMessage, aOptions.mTransfer, aRv);
}

View file

@ -91,7 +91,13 @@ public:
void void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv);
void
PostMessage(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const StructuredSerializeOptions& aOptions,
ErrorResult& aRv); ErrorResult& aRv);
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;

View file

@ -141,7 +141,7 @@ NS_IMPL_ISUPPORTS0(MessageWaitUntilHandler)
nsresult nsresult
ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx, ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx,
JS::Handle<JS::Value> aMessage, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo) UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
{ {
ErrorResult rv(SpawnWorkerIfNeeded(MessageEvent, nullptr)); ErrorResult rv(SpawnWorkerIfNeeded(MessageEvent, nullptr));

View file

@ -74,7 +74,7 @@ public:
nsresult nsresult
SendMessageEvent(JSContext* aCx, JS::Handle<JS::Value> aMessage, SendMessageEvent(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo); UniquePtr<ServiceWorkerClientInfo>&& aClientInfo);
// This is used to validate the worker script and continue the installation // This is used to validate the worker script and continue the installation

View file

@ -22,6 +22,7 @@
using mozilla::dom::Optional; using mozilla::dom::Optional;
using mozilla::dom::Sequence; using mozilla::dom::Sequence;
using mozilla::dom::MessagePort; using mozilla::dom::MessagePort;
using mozilla::dom::StructuredSerializeOptions;
using namespace mozilla; using namespace mozilla;
USING_WORKERS_NAMESPACE USING_WORKERS_NAMESPACE
@ -142,7 +143,7 @@ SharedWorker::Close()
void void
SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) ErrorResult& aRv)
{ {
AssertIsOnMainThread(); AssertIsOnMainThread();
@ -152,6 +153,15 @@ SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
mMessagePort->PostMessage(aCx, aMessage, aTransferable, aRv); mMessagePort->PostMessage(aCx, aMessage, aTransferable, aRv);
} }
void
SharedWorker::PostMessage(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const StructuredSerializeOptions& aOptions,
ErrorResult& aRv)
{
PostMessage(aCx, aMessage, aOptions.mTransfer, aRv);
}
NS_IMPL_ADDREF_INHERITED(SharedWorker, DOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(SharedWorker, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(SharedWorker, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(SharedWorker, DOMEventTargetHelper)

View file

@ -94,8 +94,15 @@ private:
// Only called by MessagePort. // Only called by MessagePort.
void void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, PostMessage(JSContext* aCx,
const Optional<Sequence<JS::Value>>& aTransferable, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv);
void
PostMessage(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const StructuredSerializeOptions& aOptions,
ErrorResult& aRv); ErrorResult& aRv);
}; };

View file

@ -3006,13 +3006,12 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
template <class Derived> template <class Derived>
void void
WorkerPrivateParent<Derived>::PostMessageInternal( WorkerPrivateParent<Derived>::PostMessageInternal(JSContext* aCx,
JSContext* aCx, JS::Handle<JS::Value> aMessage,
JS::Handle<JS::Value> aMessage, const Sequence<JSObject*>& aTransferable,
const Optional<Sequence<JS::Value>>& aTransferable, UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo, PromiseNativeHandler* aHandler,
PromiseNativeHandler* aHandler, ErrorResult& aRv)
ErrorResult& aRv)
{ {
AssertIsOnParentThread(); AssertIsOnParentThread();
@ -3024,22 +3023,11 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
} }
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue()); JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
if (aTransferable.WasPassed()) { aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx,
const Sequence<JS::Value>& realTransferable = aTransferable.Value(); aTransferable,
&transferable);
// The input sequence only comes from the generated bindings code, which if (NS_WARN_IF(aRv.Failed())) {
// ensures it is rooted. return;
JS::HandleValueArray elements =
JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(),
realTransferable.Elements());
JSObject* array =
JS_NewArrayObject(aCx, elements);
if (!array) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
transferable.setObject(*array);
} }
RefPtr<MessageEventRunnable> runnable = RefPtr<MessageEventRunnable> runnable =
@ -3083,18 +3071,31 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
template <class Derived> template <class Derived>
void void
WorkerPrivateParent<Derived>::PostMessage( WorkerPrivateParent<Derived>::PostMessage(
JSContext* aCx, JS::Handle<JS::Value> aMessage, JSContext* aCx,
const Optional<Sequence<JS::Value>>& aTransferable, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) ErrorResult& aRv)
{ {
PostMessageInternal(aCx, aMessage, aTransferable, nullptr, nullptr, aRv); PostMessageInternal(aCx, aMessage, aTransferable, nullptr, nullptr, aRv);
} }
template <class Derived>
void
WorkerPrivateParent<Derived>::PostMessage(
JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const StructuredSerializeOptions& aOptions,
ErrorResult& aRv)
{
PostMessageInternal(aCx, aMessage, aOptions.mTransfer, nullptr, nullptr, aRv);
}
template <class Derived> template <class Derived>
void void
WorkerPrivateParent<Derived>::PostMessageToServiceWorker( WorkerPrivateParent<Derived>::PostMessageToServiceWorker(
JSContext* aCx, JS::Handle<JS::Value> aMessage, JSContext* aCx,
const Optional<Sequence<JS::Value>>& aTransferable, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo, UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
PromiseNativeHandler* aHandler, PromiseNativeHandler* aHandler,
ErrorResult& aRv) ErrorResult& aRv)
@ -5677,27 +5678,17 @@ void
WorkerPrivate::PostMessageToParentInternal( WorkerPrivate::PostMessageToParentInternal(
JSContext* aCx, JSContext* aCx,
JS::Handle<JS::Value> aMessage, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) ErrorResult& aRv)
{ {
AssertIsOnWorkerThread(); AssertIsOnWorkerThread();
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue()); JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
if (aTransferable.WasPassed()) { aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx,
const Sequence<JS::Value>& realTransferable = aTransferable.Value(); aTransferable,
&transferable);
// The input sequence only comes from the generated bindings code, which if (NS_WARN_IF(aRv.Failed())) {
// ensures it is rooted. return;
JS::HandleValueArray elements =
JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(),
realTransferable.Elements());
JSObject* array = JS_NewArrayObject(aCx, elements);
if (!array) {
aRv = NS_ERROR_OUT_OF_MEMORY;
return;
}
transferable.setObject(*array);
} }
RefPtr<MessageEventRunnable> runnable = RefPtr<MessageEventRunnable> runnable =

View file

@ -68,6 +68,7 @@ class PromiseNativeHandler;
class StructuredCloneHolder; class StructuredCloneHolder;
class WorkerDebuggerGlobalScope; class WorkerDebuggerGlobalScope;
class WorkerGlobalScope; class WorkerGlobalScope;
struct StructuredSerializeOptions;
} // namespace dom } // namespace dom
namespace ipc { namespace ipc {
class PrincipalInfo; class PrincipalInfo;
@ -287,7 +288,7 @@ private:
void void
PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage, PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo, UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
PromiseNativeHandler* aHandler, PromiseNativeHandler* aHandler,
ErrorResult& aRv); ErrorResult& aRv);
@ -400,12 +401,18 @@ public:
void void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv);
void
PostMessage(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const StructuredSerializeOptions& aOptions,
ErrorResult& aRv); ErrorResult& aRv);
void void
PostMessageToServiceWorker(JSContext* aCx, JS::Handle<JS::Value> aMessage, PostMessageToServiceWorker(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo, UniquePtr<ServiceWorkerClientInfo>&& aClientInfo,
PromiseNativeHandler* aHandler, PromiseNativeHandler* aHandler,
ErrorResult& aRv); ErrorResult& aRv);
@ -1161,18 +1168,17 @@ public:
void void
PostMessageToParent(JSContext* aCx, PostMessageToParent(JSContext* aCx,
JS::Handle<JS::Value> aMessage, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) ErrorResult& aRv)
{ {
PostMessageToParentInternal(aCx, aMessage, aTransferable, aRv); PostMessageToParentInternal(aCx, aMessage, aTransferable, aRv);
} }
void void
PostMessageToParentMessagePort( PostMessageToParentMessagePort(JSContext* aCx,
JSContext* aCx, JS::Handle<JS::Value> aMessage,
JS::Handle<JS::Value> aMessage, const Sequence<JSObject*>& aTransferable,
const Optional<Sequence<JS::Value>>& aTransferable, ErrorResult& aRv);
ErrorResult& aRv);
void void
EnterDebuggerEventLoop(); EnterDebuggerEventLoop();
@ -1471,7 +1477,7 @@ private:
void void
PostMessageToParentInternal(JSContext* aCx, PostMessageToParentInternal(JSContext* aCx,
JS::Handle<JS::Value> aMessage, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv); ErrorResult& aRv);
void void

View file

@ -7,6 +7,7 @@
#include "jsapi.h" #include "jsapi.h"
#include "mozilla/EventListenerManager.h" #include "mozilla/EventListenerManager.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/Console.h" #include "mozilla/dom/Console.h"
#include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h" #include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h"
@ -492,6 +493,15 @@ WorkerGlobalScope::CreateImageBitmap(const ImageBitmapSource& aImage,
} }
} }
// https://html.spec.whatwg.org/#structured-cloning
void WorkerGlobalScope::StructuredClone(JSContext* aCx,
JS::Handle<JS::Value> aValue,
const StructuredSerializeOptions& aOptions,
JS::MutableHandle<JS::Value> aRv,
ErrorResult& aError) {
nsContentUtils::StructuredClone(aCx, this, aValue, aOptions, aRv, aError);
}
DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate) DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
: WorkerGlobalScope(aWorkerPrivate) : WorkerGlobalScope(aWorkerPrivate)
{ {
@ -535,13 +545,22 @@ DedicatedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx,
void void
DedicatedWorkerGlobalScope::PostMessage(JSContext* aCx, DedicatedWorkerGlobalScope::PostMessage(JSContext* aCx,
JS::Handle<JS::Value> aMessage, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) ErrorResult& aRv)
{ {
mWorkerPrivate->AssertIsOnWorkerThread(); mWorkerPrivate->AssertIsOnWorkerThread();
mWorkerPrivate->PostMessageToParent(aCx, aMessage, aTransferable, aRv); mWorkerPrivate->PostMessageToParent(aCx, aMessage, aTransferable, aRv);
} }
void
DedicatedWorkerGlobalScope::PostMessage(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const StructuredSerializeOptions& aOptions,
ErrorResult& aRv)
{
PostMessage(aCx, aMessage, aOptions.mTransfer, aRv);
}
SharedWorkerGlobalScope::SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, SharedWorkerGlobalScope::SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
const nsCString& aName) const nsCString& aName)
: WorkerGlobalScope(aWorkerPrivate), mName(aName) : WorkerGlobalScope(aWorkerPrivate), mName(aName)

View file

@ -24,6 +24,7 @@ class Function;
class IDBFactory; class IDBFactory;
enum class ImageBitmapFormat : uint32_t; enum class ImageBitmapFormat : uint32_t;
class Performance; class Performance;
struct StructuredSerializeOptions;
class Promise; class Promise;
class RequestOrUSVString; class RequestOrUSVString;
class ServiceWorkerRegistration; class ServiceWorkerRegistration;
@ -182,6 +183,11 @@ public:
const mozilla::dom::Sequence<mozilla::dom::ChannelPixelLayout>& aLayout, const mozilla::dom::Sequence<mozilla::dom::ChannelPixelLayout>& aLayout,
mozilla::ErrorResult& aRv); mozilla::ErrorResult& aRv);
void StructuredClone(JSContext* aCx, JS::Handle<JS::Value> aValue,
const StructuredSerializeOptions& aOptions,
JS::MutableHandle<JS::Value> aRv,
ErrorResult& aError);
bool bool
WindowInteractionAllowed() const WindowInteractionAllowed() const
{ {
@ -215,7 +221,13 @@ public:
void void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable, const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv);
void
PostMessage(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const StructuredSerializeOptions& aOptions,
ErrorResult& aRv); ErrorResult& aRv);
IMPL_EVENT_HANDLER(message) IMPL_EVENT_HANDLER(message)

View file

@ -326,6 +326,43 @@ SandboxCreateFetch(JSContext* cx, HandleObject obj)
dom::HeadersBinding::GetConstructorObject(cx); 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;
}
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 static bool
SandboxIsProxy(JSContext* cx, unsigned argc, Value* vp) SandboxIsProxy(JSContext* cx, unsigned argc, Value* vp)
{ {
@ -931,6 +968,8 @@ xpc::GlobalProperties::Parse(JSContext* cx, JS::HandleObject obj)
#endif #endif
} else if (!strcmp(name.ptr(), "fetch")) { } else if (!strcmp(name.ptr(), "fetch")) {
fetch = true; fetch = true;
} else if (!strcmp(name.ptr(), "structuredClone")) {
structuredClone = true;
} else if (!strcmp(name.ptr(), "caches")) { } else if (!strcmp(name.ptr(), "caches")) {
caches = true; caches = true;
} else if (!strcmp(name.ptr(), "FileReader")) { } else if (!strcmp(name.ptr(), "FileReader")) {
@ -1006,6 +1045,9 @@ xpc::GlobalProperties::Define(JSContext* cx, JS::HandleObject obj)
if (fetch && !SandboxCreateFetch(cx, obj)) if (fetch && !SandboxCreateFetch(cx, obj))
return false; return false;
if (structuredClone && !SandboxCreateStructuredClone(cx, obj))
return false;
if (caches && !dom::cache::CacheStorage::DefineCaches(cx, obj)) if (caches && !dom::cache::CacheStorage::DefineCaches(cx, obj))
return false; return false;

View file

@ -2879,6 +2879,7 @@ struct GlobalProperties {
bool crypto : 1; bool crypto : 1;
bool rtcIdentityProvider : 1; bool rtcIdentityProvider : 1;
bool fetch : 1; bool fetch : 1;
bool structuredClone : 1;
bool caches : 1; bool caches : 1;
bool fileReader: 1; bool fileReader: 1;
private: private:

View 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);
}

View file

@ -114,6 +114,7 @@ skip-if = os == "android" # native test components aren't available on Android
[test_css.js] [test_css.js]
[test_rtcIdentityProvider.js] [test_rtcIdentityProvider.js]
[test_sandbox_atob.js] [test_sandbox_atob.js]
[test_structuredClone.js]
[test_isProxy.js] [test_isProxy.js]
[test_getObjectPrincipal.js] [test_getObjectPrincipal.js]
[test_sandbox_name.js] [test_sandbox_name.js]

View file

@ -5252,6 +5252,9 @@ pref("prompts.content_handling_dialog_modal.enabled", false);
// Whether module scripts (<script type="module">) are enabled for content. // Whether module scripts (<script type="module">) are enabled for content.
pref("dom.moduleScripts.enabled", true); pref("dom.moduleScripts.enabled", true);
// Whether read-only Window property event is enabled for content.
pref("dom.window.event.enabled", false);
// Report details when a media source error occurs? // Report details when a media source error occurs?
// Enabled by default in debug builds, otherwise should be explicitly enabled // Enabled by default in debug builds, otherwise should be explicitly enabled
// by the user to prevent XO leaking of the response status (CVE-2020-15666) // by the user to prevent XO leaking of the response status (CVE-2020-15666)