author | Ryan VanderMeulen <ryanvm@gmail.com> |
Thu, 23 Jul 2015 13:04:14 -0400 | |
changeset 286001 | 6793c7bd6ea4d792583f83fddacac0a2b831a13a |
parent 286000 | 79637e9bcdaa0657cd79732b095936b377e262b4 |
child 286002 | 4c6858eaf1b29c59bdc027b648affbca67c4edc1 |
push id | unknown |
push user | unknown |
push date | unknown |
bugs | 1184557 |
milestone | 42.0a1 |
backs out | 69542d63fcc858f402992155e870ceec0e350ba4 6326eaf87f8662124a5ad2f7dfce191d925f1b0e |
--- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -202,18 +202,16 @@ public: , mConsole(aConsole) { MOZ_ASSERT(mWorkerPrivate); } virtual ~ConsoleRunnable() { - // Shutdown the StructuredCloneHelperInternal class. - Shutdown(); } bool Dispatch() { mWorkerPrivate->AssertIsOnWorkerThread(); JSContext* cx = mWorkerPrivate->GetJSContext();
--- a/dom/base/PostMessageEvent.cpp +++ b/dom/base/PostMessageEvent.cpp @@ -18,16 +18,256 @@ #include "nsGlobalWindow.h" #include "nsIPresShell.h" #include "nsIPrincipal.h" #include "nsPresContext.h" namespace mozilla { namespace dom { +namespace { + +struct StructuredCloneInfo +{ + PostMessageEvent* event; + nsPIDOMWindow* window; + + // This hashtable contains the transferred ports - used to avoid duplicates. + nsTArray<nsRefPtr<MessagePortBase>> transferredPorts; + + // This array is populated when the ports are cloned. + nsTArray<nsRefPtr<MessagePortBase>> clonedPorts; +}; + +} // namespace + +const JSStructuredCloneCallbacks PostMessageEvent::sPostMessageCallbacks = { + PostMessageEvent::ReadStructuredClone, + PostMessageEvent::WriteStructuredClone, + nullptr, + PostMessageEvent::ReadTransferStructuredClone, + PostMessageEvent::TransferStructuredClone, + PostMessageEvent::FreeTransferStructuredClone +}; + +/* static */ JSObject* +PostMessageEvent::ReadStructuredClone(JSContext* cx, + JSStructuredCloneReader* reader, + uint32_t tag, + uint32_t data, + void* closure) +{ + StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + if (tag == SCTAG_DOM_BLOB) { + NS_ASSERTION(!data, "Data should be empty"); + + // What we get back from the reader is a BlobImpl. + // From that we create a new File. + BlobImpl* blobImpl; + if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) { + MOZ_ASSERT(blobImpl); + + // nsRefPtr<File> needs to go out of scope before toObjectOrNull() is + // called because the static analysis thinks dereferencing XPCOM objects + // can GC (because in some cases it can!), and a return statement with a + // JSObject* type means that JSObject* is on the stack as a raw pointer + // while destructors are running. + JS::Rooted<JS::Value> val(cx); + { + nsRefPtr<Blob> blob = Blob::Create(scInfo->window, blobImpl); + if (!ToJSValue(cx, blob, &val)) { + return nullptr; + } + } + + return &val.toObject(); + } + } + + if (tag == SCTAG_DOM_FILELIST) { + NS_ASSERTION(!data, "Data should be empty"); + + // What we get back from the reader is a FileListClonedData. + // From that we create a new FileList. + FileListClonedData* fileListClonedData; + if (JS_ReadBytes(reader, &fileListClonedData, sizeof(fileListClonedData))) { + MOZ_ASSERT(fileListClonedData); + + // nsRefPtr<FileList> needs to go out of scope before toObjectOrNull() is + // called because the static analysis thinks dereferencing XPCOM objects + // can GC (because in some cases it can!), and a return statement with a + // JSObject* type means that JSObject* is on the stack as a raw pointer + // while destructors are running. + JS::Rooted<JS::Value> val(cx); + { + nsRefPtr<FileList> fileList = + FileList::Create(scInfo->window, fileListClonedData); + if (!fileList || !ToJSValue(cx, fileList, &val)) { + return nullptr; + } + } + + return &val.toObject(); + } + } + + const JSStructuredCloneCallbacks* runtimeCallbacks = + js::GetContextStructuredCloneCallbacks(cx); + + if (runtimeCallbacks) { + return runtimeCallbacks->read(cx, reader, tag, data, nullptr); + } + + return nullptr; +} + +/* static */ bool +PostMessageEvent::WriteStructuredClone(JSContext* cx, + JSStructuredCloneWriter* writer, + JS::Handle<JSObject*> obj, + void *closure) +{ + StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + // See if this is a File/Blob object. + { + Blob* blob = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) { + BlobImpl* blobImpl = blob->Impl(); + if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) && + JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) { + scInfo->event->StoreISupports(blobImpl); + return true; + } + } + } + + // See if this is a FileList object. + { + FileList* fileList = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, obj, fileList))) { + nsRefPtr<FileListClonedData> fileListClonedData = + fileList->CreateClonedData(); + MOZ_ASSERT(fileListClonedData); + FileListClonedData* ptr = fileListClonedData.get(); + if (JS_WriteUint32Pair(writer, SCTAG_DOM_FILELIST, 0) && + JS_WriteBytes(writer, &ptr, sizeof(ptr))) { + scInfo->event->StoreISupports(fileListClonedData); + return true; + } + } + } + + const JSStructuredCloneCallbacks* runtimeCallbacks = + js::GetContextStructuredCloneCallbacks(cx); + + if (runtimeCallbacks) { + return runtimeCallbacks->write(cx, writer, obj, nullptr); + } + + return false; +} + +/* static */ bool +PostMessageEvent::ReadTransferStructuredClone(JSContext* aCx, + JSStructuredCloneReader* reader, + uint32_t tag, void* aData, + uint64_t aExtraData, + void* aClosure, + JS::MutableHandle<JSObject*> returnObject) +{ + StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + if (tag == SCTAG_DOM_MAP_MESSAGEPORT) { + MOZ_ASSERT(!aData); + // aExtraData is the index of this port identifier. + ErrorResult rv; + nsRefPtr<MessagePort> port = + MessagePort::Create(scInfo->window, + scInfo->event->GetPortIdentifier(aExtraData), + rv); + if (NS_WARN_IF(rv.Failed())) { + return false; + } + + scInfo->clonedPorts.AppendElement(port); + + JS::Rooted<JS::Value> value(aCx); + if (!GetOrCreateDOMReflector(aCx, port, &value)) { + JS_ClearPendingException(aCx); + return false; + } + + returnObject.set(&value.toObject()); + return true; + } + + return false; +} + +/* static */ bool +PostMessageEvent::TransferStructuredClone(JSContext* aCx, + JS::Handle<JSObject*> aObj, + void* aClosure, + uint32_t* aTag, + JS::TransferableOwnership* aOwnership, + void** aContent, + uint64_t* aExtraData) +{ + StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + MessagePortBase* port = nullptr; + nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); + if (NS_SUCCEEDED(rv)) { + if (scInfo->transferredPorts.Contains(port)) { + // No duplicates. + return false; + } + + // We use aExtraData to store the index of this new port identifier. + MessagePortIdentifier* identifier = + scInfo->event->NewPortIdentifier(aExtraData); + + if (!port->CloneAndDisentangle(*identifier)) { + return false; + } + + scInfo->transferredPorts.AppendElement(port); + + *aTag = SCTAG_DOM_MAP_MESSAGEPORT; + *aOwnership = JS::SCTAG_TMO_CUSTOM; + *aContent = nullptr; + + return true; + } + + return false; +} + +/* static */ void +PostMessageEvent::FreeTransferStructuredClone(uint32_t aTag, + JS::TransferableOwnership aOwnership, + void *aContent, + uint64_t aExtraData, + void* aClosure) +{ + if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { + MOZ_ASSERT(aClosure); + MOZ_ASSERT(!aContent); + + StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure); + MessagePort::ForceClose(scInfo->event->GetPortIdentifier(aExtraData)); + } +} + PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource, const nsAString& aCallerOrigin, nsGlobalWindow* aTargetWindow, nsIPrincipal* aProvidedPrincipal, bool aTrustedCaller) : mSource(aSource), mCallerOrigin(aCallerOrigin), mTargetWindow(aTargetWindow), @@ -37,16 +277,30 @@ PostMessageEvent::PostMessageEvent(nsGlo MOZ_COUNT_CTOR(PostMessageEvent); } PostMessageEvent::~PostMessageEvent() { MOZ_COUNT_DTOR(PostMessageEvent); } +const MessagePortIdentifier& +PostMessageEvent::GetPortIdentifier(uint64_t aId) +{ + MOZ_ASSERT(aId < mPortIdentifiers.Length()); + return mPortIdentifiers[aId]; +} + +MessagePortIdentifier* +PostMessageEvent::NewPortIdentifier(uint64_t* aPosition) +{ + *aPosition = mPortIdentifiers.Length(); + return mPortIdentifiers.AppendElement(); +} + NS_IMETHODIMP PostMessageEvent::Run() { MOZ_ASSERT(mTargetWindow->IsOuterWindow(), "should have been passed an outer window!"); MOZ_ASSERT(!mSource || mSource->IsOuterWindow(), "should have been passed an outer window!"); @@ -88,34 +342,38 @@ PostMessageEvent::Run() // don't do that in other places it seems better to hold the line for // now. Long-term, we want HTML5 to address this so that we can // be compliant while being safer. if (!targetPrin->Equals(mProvidedPrincipal)) { return NS_OK; } } + // Deserialize the structured clone data JS::Rooted<JS::Value> messageData(cx); - nsCOMPtr<nsPIDOMWindow> window = targetWindow.get(); - if (!Read(window, cx, &messageData)) { + StructuredCloneInfo scInfo; + scInfo.event = this; + scInfo.window = targetWindow; + + if (!mBuffer.read(cx, &messageData, &sPostMessageCallbacks, &scInfo)) { return NS_ERROR_DOM_DATA_CLONE_ERR; } // Create the event nsCOMPtr<mozilla::dom::EventTarget> eventTarget = do_QueryInterface(static_cast<nsPIDOMWindow*>(targetWindow.get())); nsRefPtr<MessageEvent> event = new MessageEvent(eventTarget, nullptr, nullptr); event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */, false /*cancelable */, messageData, mCallerOrigin, EmptyString(), mSource); event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()), - GetTransferredPorts())); + scInfo.clonedPorts)); // We can't simply call dispatchEvent on the window because doing so ends // up flipping the trusted bit on the event, and we don't want that to // happen because then untrusted content can call postMessage on a chrome // window if it can get a reference to it. nsIPresShell *shell = targetWindow->GetExtantDoc()->GetShell(); nsRefPtr<nsPresContext> presContext; @@ -129,10 +387,24 @@ PostMessageEvent::Run() EventDispatcher::Dispatch(static_cast<nsPIDOMWindow*>(mTargetWindow), presContext, internalEvent, static_cast<dom::Event*>(event.get()), &status); return NS_OK; } +bool +PostMessageEvent::Write(JSContext* aCx, JS::Handle<JS::Value> aMessage, + JS::Handle<JS::Value> aTransfer, nsPIDOMWindow* aWindow) +{ + // We *must* clone the data here, or the JS::Value could be modified + // by script + StructuredCloneInfo scInfo; + scInfo.event = this; + scInfo.window = aWindow; + + return mBuffer.write(aCx, aMessage, aTransfer, &sPostMessageCallbacks, + &scInfo); +} + } // namespace dom } // namespace mozilla
--- a/dom/base/PostMessageEvent.h +++ b/dom/base/PostMessageEvent.h @@ -2,17 +2,17 @@ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */ #ifndef mozilla_dom_PostMessageEvent_h #define mozilla_dom_PostMessageEvent_h -#include "mozilla/dom/StructuredCloneHelper.h" +#include "js/StructuredClone.h" #include "nsCOMPtr.h" #include "nsRefPtr.h" #include "nsTArray.h" #include "nsThreadUtils.h" class nsGlobalWindow; class nsIPrincipal; class nsPIDOMWindow; @@ -23,33 +23,87 @@ namespace dom { class MessagePortBase; class MessagePortIdentifier; /** * Class used to represent events generated by calls to Window.postMessage, * which asynchronously creates and dispatches events. */ class PostMessageEvent final : public nsRunnable - , public StructuredCloneHelper { public: NS_DECL_NSIRUNNABLE PostMessageEvent(nsGlobalWindow* aSource, const nsAString& aCallerOrigin, nsGlobalWindow* aTargetWindow, nsIPrincipal* aProvidedPrincipal, bool aTrustedCaller); + bool Write(JSContext* aCx, JS::Handle<JS::Value> aMessage, + JS::Handle<JS::Value> aTransfer, nsPIDOMWindow* aWindow); + private: ~PostMessageEvent(); + const MessagePortIdentifier& GetPortIdentifier(uint64_t aId); + + MessagePortIdentifier* NewPortIdentifier(uint64_t* aPosition); + + bool StoreISupports(nsISupports* aSupports) + { + mSupportsArray.AppendElement(aSupports); + return true; + } + + static JSObject* + ReadStructuredClone(JSContext* cx, + JSStructuredCloneReader* reader, + uint32_t tag, + uint32_t data, + void* closure); + + static bool + WriteStructuredClone(JSContext* cx, + JSStructuredCloneWriter* writer, + JS::Handle<JSObject*> obj, + void *closure); + + static bool + ReadTransferStructuredClone(JSContext* aCx, + JSStructuredCloneReader* reader, + uint32_t tag, void* aData, + uint64_t aExtraData, + void* aClosure, + JS::MutableHandle<JSObject*> returnObject); + + static bool + TransferStructuredClone(JSContext* aCx, + JS::Handle<JSObject*> aObj, + void* aClosure, + uint32_t* aTag, + JS::TransferableOwnership* aOwnership, + void** aContent, + uint64_t* aExtraData); + + static void + FreeTransferStructuredClone(uint32_t aTag, + JS::TransferableOwnership aOwnership, + void *aContent, + uint64_t aExtraData, + void* aClosure); + + static const JSStructuredCloneCallbacks sPostMessageCallbacks; + + JSAutoStructuredCloneBuffer mBuffer; nsRefPtr<nsGlobalWindow> mSource; nsString mCallerOrigin; nsRefPtr<nsGlobalWindow> mTargetWindow; nsCOMPtr<nsIPrincipal> mProvidedPrincipal; bool mTrustedCaller; + nsTArray<nsCOMPtr<nsISupports>> mSupportsArray; + nsTArray<MessagePortIdentifier> mPortIdentifiers; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_PostMessageEvent_h
--- a/dom/base/StructuredCloneHelper.cpp +++ b/dom/base/StructuredCloneHelper.cpp @@ -1,20 +1,16 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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 "StructuredCloneHelper.h" -#include "mozilla/dom/BlobBinding.h" -#include "mozilla/dom/FileListBinding.h" -#include "mozilla/dom/StructuredCloneTags.h" - namespace mozilla { namespace dom { namespace { JSObject* StructuredCloneCallbacksRead(JSContext* aCx, JSStructuredCloneReader* aReader, @@ -84,85 +80,45 @@ StructuredCloneCallbacksFreeTransfer(uin MOZ_ASSERT(helper); return helper->FreeTransferCallback(aTag, aOwnership, aContent, aExtraData); } void StructuredCloneCallbacksError(JSContext* aCx, uint32_t aErrorId) { - NS_WARNING("Failed to clone data."); + NS_WARNING("Failed to clone data for the Console API in workers."); } const JSStructuredCloneCallbacks gCallbacks = { StructuredCloneCallbacksRead, StructuredCloneCallbacksWrite, StructuredCloneCallbacksError, StructuredCloneCallbacksReadTransfer, StructuredCloneCallbacksWriteTransfer, StructuredCloneCallbacksFreeTransfer }; } // anonymous namespace -// StructuredCloneHelperInternal class - -StructuredCloneHelperInternal::StructuredCloneHelperInternal() -#ifdef DEBUG - : mShutdownCalled(false) -#endif -{} - -StructuredCloneHelperInternal::~StructuredCloneHelperInternal() -{ -#ifdef DEBUG - MOZ_ASSERT(mShutdownCalled); -#endif -} - -void -StructuredCloneHelperInternal::Shutdown() -{ -#ifdef DEBUG - MOZ_ASSERT(!mShutdownCalled, "Shutdown already called!"); - mShutdownCalled = true; -#endif - - mBuffer = nullptr; -} - bool StructuredCloneHelperInternal::Write(JSContext* aCx, JS::Handle<JS::Value> aValue) { MOZ_ASSERT(!mBuffer, "Double Write is not allowed"); - MOZ_ASSERT(mShutdownCalled, "This method cannot be called after Shutdown."); mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this); return mBuffer->write(aCx, aValue, &gCallbacks, this); } bool -StructuredCloneHelperInternal::Write(JSContext* aCx, - JS::Handle<JS::Value> aValue, - JS::Handle<JS::Value> aTransfer) -{ - MOZ_ASSERT(!mBuffer, "Double Write is not allowed"); - MOZ_ASSERT(mShutdownCalled, "This method cannot be called after Shutdown."); - - mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this); - return mBuffer->write(aCx, aValue, aTransfer, &gCallbacks, this); -} - -bool StructuredCloneHelperInternal::Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue) { MOZ_ASSERT(mBuffer, "Read() without Write() is not allowed."); - MOZ_ASSERT(mShutdownCalled, "This method cannot be called after Shutdown."); bool ok = mBuffer->read(aCx, aValue, &gCallbacks, this); mBuffer = nullptr; return ok; } bool StructuredCloneHelperInternal::ReadTransferCallback(JSContext* aCx, @@ -171,16 +127,17 @@ StructuredCloneHelperInternal::ReadTrans void* aContent, uint64_t aExtraData, JS::MutableHandleObject aReturnObject) { MOZ_CRASH("Nothing to read."); return false; } + bool StructuredCloneHelperInternal::WriteTransferCallback(JSContext* aCx, JS::Handle<JSObject*> aObj, uint32_t* aTag, JS::TransferableOwnership* aOwnership, void** aContent, uint64_t* aExtraData) { @@ -192,227 +149,10 @@ void StructuredCloneHelperInternal::FreeTransferCallback(uint32_t aTag, JS::TransferableOwnership aOwnership, void* aContent, uint64_t aExtraData) { MOZ_CRASH("Nothing to free."); } -// StructuredCloneHelper class - -StructuredCloneHelper::StructuredCloneHelper(uint32_t aFlags) - : mFlags(aFlags) - , mParent(nullptr) -{} - -StructuredCloneHelper::~StructuredCloneHelper() -{ - Shutdown(); -} - -bool -StructuredCloneHelper::Write(JSContext* aCx, - JS::Handle<JS::Value> aValue, - JS::Handle<JS::Value> aTransfer) -{ - bool ok = StructuredCloneHelperInternal::Write(aCx, aValue, aTransfer); - mTransferringPort.Clear(); - return ok; -} - -bool -StructuredCloneHelper::Read(nsISupports* aParent, - JSContext* aCx, - JS::MutableHandle<JS::Value> aValue) -{ - mozilla::AutoRestore<nsISupports*> guard(mParent); - mParent = aParent; - - return StructuredCloneHelperInternal::Read(aCx, aValue); -} - -JSObject* -StructuredCloneHelper::ReadCallback(JSContext* aCx, - JSStructuredCloneReader* aReader, - uint32_t aTag, - uint32_t aIndex) -{ - if (aTag == SCTAG_DOM_BLOB) { - MOZ_ASSERT(!(mFlags & eBlobNotSupported)); - - BlobImpl* blobImpl; - if (JS_ReadBytes(aReader, &blobImpl, sizeof(blobImpl))) { - MOZ_ASSERT(blobImpl); - - // nsRefPtr<File> needs to go out of scope before toObjectOrNull() is - // called because the static analysis thinks dereferencing XPCOM objects - // can GC (because in some cases it can!), and a return statement with a - // JSObject* type means that JSObject* is on the stack as a raw pointer - // while destructors are running. - JS::Rooted<JS::Value> val(aCx); - { - nsRefPtr<Blob> blob = Blob::Create(mParent, blobImpl); - if (!ToJSValue(aCx, blob, &val)) { - return nullptr; - } - } - - return &val.toObject(); - } - } - - if (aTag == SCTAG_DOM_FILELIST) { - MOZ_ASSERT(!(mFlags & eFileListNotSupported)); - - FileListClonedData* fileListClonedData; - if (JS_ReadBytes(aReader, &fileListClonedData, - sizeof(fileListClonedData))) { - MOZ_ASSERT(fileListClonedData); - - // nsRefPtr<FileList> needs to go out of scope before toObjectOrNull() is - // called because the static analysis thinks dereferencing XPCOM objects - // can GC (because in some cases it can!), and a return statement with a - // JSObject* type means that JSObject* is on the stack as a raw pointer - // while destructors are running. - JS::Rooted<JS::Value> val(aCx); - { - nsRefPtr<FileList> fileList = - FileList::Create(mParent, fileListClonedData); - if (!fileList || !ToJSValue(aCx, fileList, &val)) { - return nullptr; - } - } - - return &val.toObject(); - } - } - - return NS_DOMReadStructuredClone(aCx, aReader, aTag, aIndex, nullptr); -} - -bool -StructuredCloneHelper::WriteCallback(JSContext* aCx, - JSStructuredCloneWriter* aWriter, - JS::Handle<JSObject*> aObj) -{ - // See if this is a File/Blob object. - if (!(mFlags & eBlobNotSupported)) { - Blob* blob = nullptr; - if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) { - BlobImpl* blobImpl = blob->Impl(); - return JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, 0) && - JS_WriteBytes(aWriter, &blobImpl, sizeof(blobImpl)) && - StoreISupports(blobImpl); - } - } - - if (!(mFlags & eFileListNotSupported)) { - FileList* fileList = nullptr; - if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) { - nsRefPtr<FileListClonedData> fileListClonedData = - fileList->CreateClonedData(); - MOZ_ASSERT(fileListClonedData); - FileListClonedData* ptr = fileListClonedData.get(); - return JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST, 0) && - JS_WriteBytes(aWriter, &ptr, sizeof(ptr)) && - StoreISupports(fileListClonedData); - } - } - - return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); -} - -bool -StructuredCloneHelper::ReadTransferCallback(JSContext* aCx, - JSStructuredCloneReader* aReader, - uint32_t aTag, - void* aContent, - uint64_t aExtraData, - JS::MutableHandleObject aReturnObject) -{ - if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { - MOZ_ASSERT(!(mFlags & eMessagePortNotSupported)); - - // This can be null. - nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mParent); - - MOZ_ASSERT(aExtraData < mPortIdentifiers.Length()); - const MessagePortIdentifier& portIdentifier = mPortIdentifiers[aExtraData]; - - // aExtraData is the index of this port identifier. - ErrorResult rv; - nsRefPtr<MessagePort> port = - MessagePort::Create(window, portIdentifier, rv); - if (NS_WARN_IF(rv.Failed())) { - return false; - } - - mTransferredPorts.AppendElement(port); - - JS::Rooted<JS::Value> value(aCx); - if (!GetOrCreateDOMReflector(aCx, port, &value)) { - JS_ClearPendingException(aCx); - return false; - } - - aReturnObject.set(&value.toObject()); - return true; - } - - return false; -} - - -bool -StructuredCloneHelper::WriteTransferCallback(JSContext* aCx, - JS::Handle<JSObject*> aObj, - uint32_t* aTag, - JS::TransferableOwnership* aOwnership, - void** aContent, - uint64_t* aExtraData) -{ - if (!(mFlags & eMessagePortNotSupported)) { - MessagePortBase* port = nullptr; - nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); - if (NS_SUCCEEDED(rv)) { - if (mTransferringPort.Contains(port)) { - // No duplicates. - return false; - } - - // We use aExtraData to store the index of this new port identifier. - *aExtraData = mPortIdentifiers.Length(); - MessagePortIdentifier* identifier = mPortIdentifiers.AppendElement(); - - if (!port->CloneAndDisentangle(*identifier)) { - return false; - } - - mTransferringPort.AppendElement(port); - - *aTag = SCTAG_DOM_MAP_MESSAGEPORT; - *aOwnership = JS::SCTAG_TMO_CUSTOM; - *aContent = nullptr; - - return true; - } - } - - return false; -} - -void -StructuredCloneHelper::FreeTransferCallback(uint32_t aTag, - JS::TransferableOwnership aOwnership, - void* aContent, - uint64_t aExtraData) -{ - if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { - MOZ_ASSERT(!(mFlags & eMessagePortNotSupported)); - MOZ_ASSERT(!aContent); - MOZ_ASSERT(aExtraData < mPortIdentifiers.Length()); - MessagePort::ForceClose(mPortIdentifiers[aExtraData]); - } -} - } // dom namespace } // mozilla namespace
--- a/dom/base/StructuredCloneHelper.h +++ b/dom/base/StructuredCloneHelper.h @@ -3,46 +3,35 @@ * 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/. */ #ifndef mozilla_dom_StructuredCloneHelper_h #define mozilla_dom_StructuredCloneHelper_h #include "js/StructuredClone.h" #include "nsAutoPtr.h" -#include "nsISupports.h" -#include "nsTArray.h" namespace mozilla { namespace dom { class StructuredCloneHelperInternal { public: - StructuredCloneHelperInternal(); - virtual ~StructuredCloneHelperInternal(); - // These methods should be implemented in order to clone data. // Read more documentation in js/public/StructuredClone.h. virtual JSObject* ReadCallback(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, uint32_t aIndex) = 0; virtual bool WriteCallback(JSContext* aCx, JSStructuredCloneWriter* aWriter, JS::Handle<JSObject*> aObj) = 0; - // This method has to be called when this object is not needed anymore. - // It will free memory and the buffer. This has to be called because - // otherwise the buffer will be freed in the DTOR of this class and at that - // point we cannot use the overridden methods. - void Shutdown(); - // If these 3 methods are not implement, transfering objects will not be // allowed. virtual bool ReadTransferCallback(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, void* aContent, @@ -73,121 +62,14 @@ public: JS::Handle<JS::Value> aValue, JS::Handle<JS::Value> aTransfer); bool Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue); protected: nsAutoPtr<JSAutoStructuredCloneBuffer> mBuffer; - -#ifdef DEBUG - bool mShutdownCalled; -#endif -}; - -class MessagePortBase; -class MessagePortIdentifier; - -class StructuredCloneHelper : public StructuredCloneHelperInternal -{ -public: - enum StructuredCloneHelperFlags { - eAll = 0, - - // Disable the cloning of blobs. If a blob is part of the cloning value, - // an exception will be thrown. - eBlobNotSupported = 1 << 0, - - // Disable the cloning of FileLists. If a FileList is part of the cloning - // value, an exception will be thrown. - eFileListNotSupported = 1 << 1, - - // MessagePort can just be transfered. Using this flag we do not support - // the transfering. - eMessagePortNotSupported = 1 << 2, - }; - - // aFlags is a bitmap of StructuredCloneHelperFlags. - explicit StructuredCloneHelper(uint32_t aFlags = eAll); - virtual ~StructuredCloneHelper(); - - bool Write(JSContext* aCx, - JS::Handle<JS::Value> aValue, - JS::Handle<JS::Value> aTransfer); - - bool Read(nsISupports* aParent, - JSContext* aCx, - JS::MutableHandle<JS::Value> aValue); - - nsTArray<nsRefPtr<MessagePortBase>>& GetTransferredPorts() - { - MOZ_ASSERT(!(mFlags & eMessagePortNotSupported)); - return mTransferredPorts; - } - - // Custom Callbacks - - virtual JSObject* ReadCallback(JSContext* aCx, - JSStructuredCloneReader* aReader, - uint32_t aTag, - uint32_t aIndex) override; - - virtual bool WriteCallback(JSContext* aCx, - JSStructuredCloneWriter* aWriter, - JS::Handle<JSObject*> aObj) override; - - virtual bool ReadTransferCallback(JSContext* aCx, - JSStructuredCloneReader* aReader, - uint32_t aTag, - void* aContent, - uint64_t aExtraData, - JS::MutableHandleObject aReturnObject) override; - - virtual bool WriteTransferCallback(JSContext* aCx, - JS::Handle<JSObject*> aObj, - uint32_t* aTag, - JS::TransferableOwnership* aOwnership, - void** aContent, - uint64_t* aExtraData) override; - - virtual void FreeTransferCallback(uint32_t aTag, - JS::TransferableOwnership aOwnership, - void* aContent, - uint64_t aExtraData) override; -private: - bool StoreISupports(nsISupports* aSupports) - { - MOZ_ASSERT(aSupports); - mSupportsArray.AppendElement(aSupports); - return true; - } - - // This is our bitmap. - uint32_t mFlags; - - // Useful for the structured clone algorithm: - - nsTArray<nsCOMPtr<nsISupports>> mSupportsArray; - - // This raw pointer is set and unset into the ::Read(). It's always null - // outside that method. For this reason it's a raw pointer. - nsISupports* MOZ_NON_OWNING_REF mParent; - - // This hashtable contains the ports while doing write (transferring and - // mapping transferred objects to the objects in the clone). It's an empty - // array outside the 'Write()' method. - nsTArray<nsRefPtr<MessagePortBase>> mTransferringPort; - - // This array contains the ports once we've finished the reading. It's - // generated from the mPortIdentifiers array. - nsTArray<nsRefPtr<MessagePortBase>> mTransferredPorts; - - // This array contains the identifiers of the MessagePorts. Based on these we - // are able to reconnect the new transferred ports with the other - // MessageChannel ports. - nsTArray<MessagePortIdentifier> mPortIdentifiers; }; } // dom namespace } // mozilla namespace #endif // mozilla_dom_StructuredCloneHelper_h
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -8577,17 +8577,17 @@ nsGlobalWindow::PostMessageMozOuter(JSCo origin, this, providedPrincipal, nsContentUtils::IsCallerChrome()); JS::Rooted<JS::Value> message(aCx, aMessage); JS::Rooted<JS::Value> transfer(aCx, aTransfer); - if (!event->Write(aCx, message, transfer)) { + if (!event->Write(aCx, message, transfer, this)) { aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } aError = NS_DispatchToCurrentThread(event); } void