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"
11 #include "nsIGlobalObject.h"
12 #include "nsIVariant.h"
13 #include "nsIXPConnect.h"
14 #include "nsServiceManagerUtils.h"
15 #include "nsContentUtils.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
)
34 nsStructuredCloneContainer::nsStructuredCloneContainer()
35 : mData(nullptr), mSize(0), mVersion(0)
39 nsStructuredCloneContainer::~nsStructuredCloneContainer()
45 nsStructuredCloneContainer::InitFromJSVal(JS::Handle
<JS::Value
> aData
)
47 NS_ENSURE_STATE(!mData
);
49 uint64_t* jsBytes
= nullptr;
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.
56 success
= JS_WriteStructuredClone(jsapi
.cx(), aData
, &jsBytes
, &mSize
,
58 JS::UndefinedHandleValue
);
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
,
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
);
79 JS_ClearStructuredClone(jsBytes
, mSize
, nullptr, nullptr);
80 return NS_ERROR_FAILURE
;
83 mVersion
= JS_STRUCTURED_CLONE_VERSION
;
86 memcpy(mData
, jsBytes
, mSize
);
88 JS_ClearStructuredClone(jsBytes
, mSize
, nullptr, nullptr);
93 nsStructuredCloneContainer::InitFromBase64(const nsAString
&aData
,
94 uint32_t aFormatVersion
,
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
;
117 nsStructuredCloneContainer::DeserializeToVariant(JSContext
*aCx
,
120 NS_ENSURE_STATE(mData
);
121 NS_ENSURE_ARG_POINTER(aData
);
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
,
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
);
147 nsStructuredCloneContainer::GetDataAsBase64(nsAString
&aOut
)
149 NS_ENSURE_STATE(mData
);
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
));
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
176 nsStructuredCloneContainer::GetFormatVersion(uint32_t *aFormatVersion
)
178 NS_ENSURE_STATE(mData
);
179 NS_ENSURE_ARG_POINTER(aFormatVersion
);
180 *aFormatVersion
= mVersion
;