Bumping manifests a=b2g-bump
[gecko.git] / dom / base / nsStructuredCloneContainer.cpp
bloba2f8e1483c9520f643a33a4ccbbf6c0f280a5a5b
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sw=2 et tw=80:
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "nsStructuredCloneContainer.h"
10 #include "nsCOMPtr.h"
11 #include "nsIGlobalObject.h"
12 #include "nsIVariant.h"
13 #include "nsIXPConnect.h"
14 #include "nsServiceManagerUtils.h"
15 #include "nsContentUtils.h"
16 #include "jsapi.h"
17 #include "jsfriendapi.h"
18 #include "js/StructuredClone.h"
19 #include "xpcpublic.h"
21 #include "mozilla/Base64.h"
22 #include "mozilla/dom/ScriptSettings.h"
24 using namespace mozilla;
26 NS_IMPL_ADDREF(nsStructuredCloneContainer)
27 NS_IMPL_RELEASE(nsStructuredCloneContainer)
29 NS_INTERFACE_MAP_BEGIN(nsStructuredCloneContainer)
30 NS_INTERFACE_MAP_ENTRY(nsIStructuredCloneContainer)
31 NS_INTERFACE_MAP_ENTRY(nsISupports)
32 NS_INTERFACE_MAP_END
34 nsStructuredCloneContainer::nsStructuredCloneContainer()
35 : mData(nullptr), mSize(0), mVersion(0)
39 nsStructuredCloneContainer::~nsStructuredCloneContainer()
41 free(mData);
44 nsresult
45 nsStructuredCloneContainer::InitFromJSVal(JS::Handle<JS::Value> aData)
47 NS_ENSURE_STATE(!mData);
49 uint64_t* jsBytes = nullptr;
50 bool success = false;
51 if (aData.isPrimitive()) {
52 // |aData| is a primitive, so the structured clone algorithm won't run
53 // script and we can just use AutoJSAPI.
54 dom::AutoJSAPI jsapi;
55 jsapi.Init();
56 success = JS_WriteStructuredClone(jsapi.cx(), aData, &jsBytes, &mSize,
57 nullptr, nullptr,
58 JS::UndefinedHandleValue);
59 } else {
60 // |aData| is an object and the structured clone algorithm can run script as
61 // part of the "own" "deep clone" sub-steps, so we need an AutoEntryScript.
62 // http://www.whatwg.org/specs/web-apps/current-work/#internal-structured-cloning-algorithm
63 nsIGlobalObject* nativeGlobal =
64 xpc::GetNativeForGlobal(js::GetGlobalForObjectCrossCompartment(&aData.toObject()));
65 dom::AutoEntryScript aes(nativeGlobal);
66 success = JS_WriteStructuredClone(aes.cx(), aData, &jsBytes, &mSize,
67 nullptr, nullptr,
68 JS::UndefinedHandleValue);
70 NS_ENSURE_STATE(success);
71 NS_ENSURE_STATE(jsBytes);
73 // Copy jsBytes into our own buffer.
74 mData = (uint64_t*) malloc(mSize);
75 if (!mData) {
76 mSize = 0;
77 mVersion = 0;
79 JS_ClearStructuredClone(jsBytes, mSize, nullptr, nullptr);
80 return NS_ERROR_FAILURE;
82 else {
83 mVersion = JS_STRUCTURED_CLONE_VERSION;
86 memcpy(mData, jsBytes, mSize);
88 JS_ClearStructuredClone(jsBytes, mSize, nullptr, nullptr);
89 return NS_OK;
92 nsresult
93 nsStructuredCloneContainer::InitFromBase64(const nsAString &aData,
94 uint32_t aFormatVersion,
95 JSContext *aCx)
97 NS_ENSURE_STATE(!mData);
99 NS_ConvertUTF16toUTF8 data(aData);
101 nsAutoCString binaryData;
102 nsresult rv = Base64Decode(data, binaryData);
103 NS_ENSURE_SUCCESS(rv, rv);
105 // Copy the string's data into our own buffer.
106 mData = (uint64_t*) malloc(binaryData.Length());
107 NS_ENSURE_STATE(mData);
108 memcpy(mData, binaryData.get(), binaryData.Length());
110 mSize = binaryData.Length();
111 mVersion = aFormatVersion;
112 return NS_OK;
116 nsresult
117 nsStructuredCloneContainer::DeserializeToVariant(JSContext *aCx,
118 nsIVariant **aData)
120 NS_ENSURE_STATE(mData);
121 NS_ENSURE_ARG_POINTER(aData);
122 *aData = nullptr;
124 // Deserialize to a JS::Value.
125 JS::Rooted<JS::Value> jsStateObj(aCx);
126 bool hasTransferable = false;
127 bool success = JS_ReadStructuredClone(aCx, mData, mSize, mVersion,
128 &jsStateObj, nullptr, nullptr) &&
129 JS_StructuredCloneHasTransferables(mData, mSize,
130 &hasTransferable);
131 // We want to be sure that mData doesn't contain transferable objects
132 MOZ_ASSERT(!hasTransferable);
133 NS_ENSURE_STATE(success && !hasTransferable);
135 // Now wrap the JS::Value as an nsIVariant.
136 nsCOMPtr<nsIVariant> varStateObj;
137 nsCOMPtr<nsIXPConnect> xpconnect = do_GetService(nsIXPConnect::GetCID());
138 NS_ENSURE_STATE(xpconnect);
139 xpconnect->JSValToVariant(aCx, jsStateObj, getter_AddRefs(varStateObj));
140 NS_ENSURE_STATE(varStateObj);
142 NS_ADDREF(*aData = varStateObj);
143 return NS_OK;
146 nsresult
147 nsStructuredCloneContainer::GetDataAsBase64(nsAString &aOut)
149 NS_ENSURE_STATE(mData);
150 aOut.Truncate();
152 nsAutoCString binaryData(reinterpret_cast<char*>(mData), mSize);
153 nsAutoCString base64Data;
154 nsresult rv = Base64Encode(binaryData, base64Data);
155 NS_ENSURE_SUCCESS(rv, rv);
157 aOut.Assign(NS_ConvertASCIItoUTF16(base64Data));
158 return NS_OK;
161 nsresult
162 nsStructuredCloneContainer::GetSerializedNBytes(uint64_t *aSize)
164 NS_ENSURE_STATE(mData);
165 NS_ENSURE_ARG_POINTER(aSize);
167 // mSize is a size_t, while aSize is a uint64_t. We rely on an implicit cast
168 // here so that we'll get a compile error if a size_t-to-uint64_t cast is
169 // narrowing.
170 *aSize = mSize;
172 return NS_OK;
175 nsresult
176 nsStructuredCloneContainer::GetFormatVersion(uint32_t *aFormatVersion)
178 NS_ENSURE_STATE(mData);
179 NS_ENSURE_ARG_POINTER(aFormatVersion);
180 *aFormatVersion = mVersion;
181 return NS_OK;