1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/base/nsStructuredCloneContainer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,170 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: set ts=8 sw=2 et tw=80: 1.6 + * 1.7 + * This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#include "nsStructuredCloneContainer.h" 1.12 + 1.13 +#include "nsCOMPtr.h" 1.14 +#include "nsIScriptContext.h" 1.15 +#include "nsIVariant.h" 1.16 +#include "nsIXPConnect.h" 1.17 +#include "nsServiceManagerUtils.h" 1.18 +#include "nsContentUtils.h" 1.19 +#include "jsapi.h" 1.20 +#include "js/StructuredClone.h" 1.21 + 1.22 +#include "mozilla/Base64.h" 1.23 + 1.24 +using namespace mozilla; 1.25 + 1.26 +NS_IMPL_ADDREF(nsStructuredCloneContainer) 1.27 +NS_IMPL_RELEASE(nsStructuredCloneContainer) 1.28 + 1.29 +NS_INTERFACE_MAP_BEGIN(nsStructuredCloneContainer) 1.30 + NS_INTERFACE_MAP_ENTRY(nsIStructuredCloneContainer) 1.31 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.32 +NS_INTERFACE_MAP_END 1.33 + 1.34 +nsStructuredCloneContainer::nsStructuredCloneContainer() 1.35 + : mData(nullptr), mSize(0), mVersion(0) 1.36 +{ 1.37 +} 1.38 + 1.39 +nsStructuredCloneContainer::~nsStructuredCloneContainer() 1.40 +{ 1.41 + free(mData); 1.42 +} 1.43 + 1.44 +nsresult 1.45 +nsStructuredCloneContainer::InitFromJSVal(JS::Handle<JS::Value> aData, 1.46 + JSContext* aCx) 1.47 +{ 1.48 + NS_ENSURE_STATE(!mData); 1.49 + NS_ENSURE_ARG_POINTER(aCx); 1.50 + 1.51 + // Make sure that we serialize in the right context. 1.52 + MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); 1.53 + JS::Rooted<JS::Value> jsData(aCx, aData); 1.54 + bool success = JS_WrapValue(aCx, &jsData); 1.55 + NS_ENSURE_STATE(success); 1.56 + 1.57 + uint64_t* jsBytes = nullptr; 1.58 + success = JS_WriteStructuredClone(aCx, jsData, &jsBytes, &mSize, 1.59 + nullptr, nullptr, 1.60 + JS::UndefinedHandleValue); 1.61 + NS_ENSURE_STATE(success); 1.62 + NS_ENSURE_STATE(jsBytes); 1.63 + 1.64 + // Copy jsBytes into our own buffer. 1.65 + mData = (uint64_t*) malloc(mSize); 1.66 + if (!mData) { 1.67 + mSize = 0; 1.68 + mVersion = 0; 1.69 + 1.70 + JS_ClearStructuredClone(jsBytes, mSize, nullptr, nullptr); 1.71 + return NS_ERROR_FAILURE; 1.72 + } 1.73 + else { 1.74 + mVersion = JS_STRUCTURED_CLONE_VERSION; 1.75 + } 1.76 + 1.77 + memcpy(mData, jsBytes, mSize); 1.78 + 1.79 + JS_ClearStructuredClone(jsBytes, mSize, nullptr, nullptr); 1.80 + return NS_OK; 1.81 +} 1.82 + 1.83 +nsresult 1.84 +nsStructuredCloneContainer::InitFromBase64(const nsAString &aData, 1.85 + uint32_t aFormatVersion, 1.86 + JSContext *aCx) 1.87 +{ 1.88 + NS_ENSURE_STATE(!mData); 1.89 + 1.90 + NS_ConvertUTF16toUTF8 data(aData); 1.91 + 1.92 + nsAutoCString binaryData; 1.93 + nsresult rv = Base64Decode(data, binaryData); 1.94 + NS_ENSURE_SUCCESS(rv, rv); 1.95 + 1.96 + // Copy the string's data into our own buffer. 1.97 + mData = (uint64_t*) malloc(binaryData.Length()); 1.98 + NS_ENSURE_STATE(mData); 1.99 + memcpy(mData, binaryData.get(), binaryData.Length()); 1.100 + 1.101 + mSize = binaryData.Length(); 1.102 + mVersion = aFormatVersion; 1.103 + return NS_OK; 1.104 +} 1.105 + 1.106 + 1.107 +nsresult 1.108 +nsStructuredCloneContainer::DeserializeToVariant(JSContext *aCx, 1.109 + nsIVariant **aData) 1.110 +{ 1.111 + NS_ENSURE_STATE(mData); 1.112 + NS_ENSURE_ARG_POINTER(aData); 1.113 + *aData = nullptr; 1.114 + 1.115 + // Deserialize to a JS::Value. 1.116 + JS::Rooted<JS::Value> jsStateObj(aCx); 1.117 + bool hasTransferable = false; 1.118 + bool success = JS_ReadStructuredClone(aCx, mData, mSize, mVersion, 1.119 + &jsStateObj, nullptr, nullptr) && 1.120 + JS_StructuredCloneHasTransferables(mData, mSize, 1.121 + &hasTransferable); 1.122 + // We want to be sure that mData doesn't contain transferable objects 1.123 + MOZ_ASSERT(!hasTransferable); 1.124 + NS_ENSURE_STATE(success && !hasTransferable); 1.125 + 1.126 + // Now wrap the JS::Value as an nsIVariant. 1.127 + nsCOMPtr<nsIVariant> varStateObj; 1.128 + nsCOMPtr<nsIXPConnect> xpconnect = do_GetService(nsIXPConnect::GetCID()); 1.129 + NS_ENSURE_STATE(xpconnect); 1.130 + xpconnect->JSValToVariant(aCx, jsStateObj, getter_AddRefs(varStateObj)); 1.131 + NS_ENSURE_STATE(varStateObj); 1.132 + 1.133 + NS_ADDREF(*aData = varStateObj); 1.134 + return NS_OK; 1.135 +} 1.136 + 1.137 +nsresult 1.138 +nsStructuredCloneContainer::GetDataAsBase64(nsAString &aOut) 1.139 +{ 1.140 + NS_ENSURE_STATE(mData); 1.141 + aOut.Truncate(); 1.142 + 1.143 + nsAutoCString binaryData(reinterpret_cast<char*>(mData), mSize); 1.144 + nsAutoCString base64Data; 1.145 + nsresult rv = Base64Encode(binaryData, base64Data); 1.146 + NS_ENSURE_SUCCESS(rv, rv); 1.147 + 1.148 + aOut.Assign(NS_ConvertASCIItoUTF16(base64Data)); 1.149 + return NS_OK; 1.150 +} 1.151 + 1.152 +nsresult 1.153 +nsStructuredCloneContainer::GetSerializedNBytes(uint64_t *aSize) 1.154 +{ 1.155 + NS_ENSURE_STATE(mData); 1.156 + NS_ENSURE_ARG_POINTER(aSize); 1.157 + 1.158 + // mSize is a size_t, while aSize is a uint64_t. We rely on an implicit cast 1.159 + // here so that we'll get a compile error if a size_t-to-uint64_t cast is 1.160 + // narrowing. 1.161 + *aSize = mSize; 1.162 + 1.163 + return NS_OK; 1.164 +} 1.165 + 1.166 +nsresult 1.167 +nsStructuredCloneContainer::GetFormatVersion(uint32_t *aFormatVersion) 1.168 +{ 1.169 + NS_ENSURE_STATE(mData); 1.170 + NS_ENSURE_ARG_POINTER(aFormatVersion); 1.171 + *aFormatVersion = mVersion; 1.172 + return NS_OK; 1.173 +}