diff -r 000000000000 -r 6474c204b198 dom/ipc/StructuredCloneUtils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/ipc/StructuredCloneUtils.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et 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 "StructuredCloneUtils.h" + +#include "nsIDOMFile.h" +#include "nsIDOMDOMException.h" +#include "nsIMutable.h" +#include "nsIXPConnect.h" + +#include "nsContentUtils.h" +#include "nsJSEnvironment.h" +#include "MainThreadUtils.h" +#include "StructuredCloneTags.h" +#include "jsapi.h" + +using namespace mozilla::dom; + +namespace { + +void +Error(JSContext* aCx, uint32_t aErrorId) +{ + MOZ_ASSERT(NS_IsMainThread()); + NS_DOMStructuredCloneError(aCx, aErrorId); +} + +JSObject* +Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, + uint32_t aData, void* aClosure) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aClosure); + + StructuredCloneClosure* closure = + static_cast(aClosure); + + if (aTag == SCTAG_DOM_FILE) { + MOZ_ASSERT(aData < closure->mBlobs.Length()); + + nsCOMPtr file = do_QueryInterface(closure->mBlobs[aData]); + MOZ_ASSERT(file); + +#ifdef DEBUG + { + // File should not be mutable. + nsCOMPtr mutableFile = do_QueryInterface(file); + bool isMutable; + MOZ_ASSERT(NS_SUCCEEDED(mutableFile->GetMutable(&isMutable))); + MOZ_ASSERT(!isMutable); + } +#endif + + JS::Rooted wrappedFile(aCx); + nsresult rv = nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile), + &wrappedFile); + if (NS_FAILED(rv)) { + Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR); + return nullptr; + } + + return &wrappedFile.toObject(); + } + + if (aTag == SCTAG_DOM_BLOB) { + MOZ_ASSERT(aData < closure->mBlobs.Length()); + + nsCOMPtr blob = do_QueryInterface(closure->mBlobs[aData]); + MOZ_ASSERT(blob); + +#ifdef DEBUG + { + // Blob should not be mutable. + nsCOMPtr mutableBlob = do_QueryInterface(blob); + bool isMutable; + MOZ_ASSERT(NS_SUCCEEDED(mutableBlob->GetMutable(&isMutable))); + MOZ_ASSERT(!isMutable); + } +#endif + + JS::Rooted wrappedBlob(aCx); + nsresult rv = nsContentUtils::WrapNative(aCx, blob, &NS_GET_IID(nsIDOMBlob), + &wrappedBlob); + if (NS_FAILED(rv)) { + Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR); + return nullptr; + } + + return &wrappedBlob.toObject(); + } + + return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr); +} + +bool +Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, + JS::Handle aObj, void* aClosure) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aClosure); + + StructuredCloneClosure* closure = + static_cast(aClosure); + + // See if this is a wrapped native. + nsCOMPtr wrappedNative; + nsContentUtils::XPConnect()-> + GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative)); + + if (wrappedNative) { + // Get the raw nsISupports out of it. + nsISupports* wrappedObject = wrappedNative->Native(); + MOZ_ASSERT(wrappedObject); + + // See if the wrapped native is a nsIDOMFile. + nsCOMPtr file = do_QueryInterface(wrappedObject); + if (file) { + nsCOMPtr mutableFile = do_QueryInterface(file); + if (mutableFile && + NS_SUCCEEDED(mutableFile->SetMutable(false)) && + JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILE, + closure->mBlobs.Length())) { + closure->mBlobs.AppendElement(file); + return true; + } + } + + // See if the wrapped native is a nsIDOMBlob. + nsCOMPtr blob = do_QueryInterface(wrappedObject); + if (blob) { + nsCOMPtr mutableBlob = do_QueryInterface(blob); + if (mutableBlob && + NS_SUCCEEDED(mutableBlob->SetMutable(false)) && + JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, + closure->mBlobs.Length())) { + closure->mBlobs.AppendElement(blob); + return true; + } + } + } + + return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); +} + +JSStructuredCloneCallbacks gCallbacks = { + Read, + Write, + Error, + nullptr, + nullptr, + nullptr +}; + +} // anonymous namespace + +namespace mozilla { +namespace dom { + +bool +ReadStructuredClone(JSContext* aCx, uint64_t* aData, size_t aDataLength, + const StructuredCloneClosure& aClosure, + JS::MutableHandle aClone) +{ + void* closure = &const_cast(aClosure); + return !!JS_ReadStructuredClone(aCx, aData, aDataLength, + JS_STRUCTURED_CLONE_VERSION, aClone, + &gCallbacks, closure); +} + +bool +WriteStructuredClone(JSContext* aCx, JS::Handle aSource, + JSAutoStructuredCloneBuffer& aBuffer, + StructuredCloneClosure& aClosure) +{ + return aBuffer.write(aCx, aSource, &gCallbacks, &aClosure); +} + +} // namespace dom +} // namespace mozilla