Bug 1371246: Handle serializing Blobs in StructuredCloneHolder instances. r=billm

MozReview-Commit-ID: 2n15NCnLC48

--HG--
extra : rebase_source : b9769b5b79d6d9dd6277a783963d83a0e0ab88eb
extra : amend_source : ac9167122891a374b4fd7219feaa7d7afbf6f5f0
This commit is contained in:
Kris Maglione 2017-06-12 14:42:49 -07:00
Родитель c2afdb09bd
Коммит 7bb88fc9de
4 изменённых файлов: 70 добавлений и 20 удалений

Просмотреть файл

@ -99,13 +99,14 @@ StructuredCloneBlob::Deserialize(JSContext* aCx, JS::HandleObject aTargetScope,
/* static */ JSObject*
StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader)
StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader,
StructuredCloneHolder* aHolder)
{
JS::RootedObject obj(aCx);
{
RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
if (!holder->ReadStructuredCloneInternal(aCx, aReader) ||
if (!holder->ReadStructuredCloneInternal(aCx, aReader, aHolder) ||
!holder->WrapObject(aCx, nullptr, &obj)) {
return nullptr;
}
@ -114,7 +115,8 @@ StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader
}
bool
StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader)
StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader,
StructuredCloneHolder* aHolder)
{
uint32_t length;
uint32_t version;
@ -122,6 +124,15 @@ StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredClo
return false;
}
uint32_t blobOffset;
uint32_t blobCount;
if (!JS_ReadUint32Pair(aReader, &blobOffset, &blobCount)) {
return false;
}
if (blobCount) {
BlobImpls().AppendElements(&aHolder->BlobImpls()[blobOffset], blobCount);
}
JSStructuredCloneData data(length, length, 4096);
if (!JS_ReadBytes(aReader, data.Start(), length)) {
return false;
@ -136,14 +147,18 @@ StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredClo
}
bool
StructuredCloneBlob::WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter)
StructuredCloneBlob::WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter,
StructuredCloneHolder* aHolder)
{
auto& data = mBuffer->data();
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_STRUCTURED_CLONE_HOLDER, 0) ||
!JS_WriteUint32Pair(aWriter, data.Size(), JS_STRUCTURED_CLONE_VERSION)) {
!JS_WriteUint32Pair(aWriter, data.Size(), JS_STRUCTURED_CLONE_VERSION) ||
!JS_WriteUint32Pair(aWriter, aHolder->BlobImpls().Length(), BlobImpls().Length())) {
return false;
}
aHolder->BlobImpls().AppendElements(BlobImpls());
auto iter = data.Iter();
while (!iter.Done()) {
if (!JS_WriteBytes(aWriter, iter.Data(), iter.RemainingInSegment())) {

Просмотреть файл

@ -26,8 +26,10 @@ public:
explicit StructuredCloneBlob();
static JSObject* ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader);
bool WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter);
static JSObject* ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader,
StructuredCloneHolder* aHolder);
bool WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter,
StructuredCloneHolder* aHolder);
static already_AddRefed<StructuredCloneBlob>
Constructor(GlobalObject& aGlobal, JS::HandleValue aValue, JS::HandleObject aTargetGlobal, ErrorResult& aRv);
@ -47,7 +49,8 @@ protected:
~StructuredCloneBlob() = default;
private:
bool ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader);
bool ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader,
StructuredCloneHolder* aHolder);
};
} // namespace dom

Просмотреть файл

@ -358,10 +358,6 @@ StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
return ReadStructuredCloneImageData(aCx, aReader);
}
if (aTag == SCTAG_DOM_STRUCTURED_CLONE_HOLDER) {
return StructuredCloneBlob::ReadStructuredClone(aCx, aReader);
}
if (aTag == SCTAG_DOM_WEBCRYPTO_KEY || aTag == SCTAG_DOM_URLSEARCHPARAMS) {
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
if (!global) {
@ -458,14 +454,6 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
}
}
// See if this is a StructuredCloneBlob object.
{
StructuredCloneBlob* holder = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(StructuredCloneHolder, aObj, holder))) {
return holder->WriteStructuredClone(aCx, aWriter);
}
}
// Handle URLSearchParams cloning
{
URLSearchParams* usp = nullptr;
@ -999,6 +987,10 @@ StructuredCloneHolder::CustomReadHandler(JSContext* aCx,
parent, GetSurfaces(), aIndex);
}
if (aTag == SCTAG_DOM_STRUCTURED_CLONE_HOLDER) {
return StructuredCloneBlob::ReadStructuredClone(aCx, aReader, this);
}
if (aTag == SCTAG_DOM_WASM) {
return ReadWasmModule(aCx, aIndex, this);
}
@ -1062,6 +1054,14 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
}
}
// See if this is a StructuredCloneBlob object.
{
StructuredCloneBlob* holder = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(StructuredCloneHolder, aObj, holder))) {
return holder->WriteStructuredClone(aCx, aWriter, this);
}
}
// See if this is a WasmModule.
if ((mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) &&

Просмотреть файл

@ -77,3 +77,35 @@ add_task(async function tabsSendMessageReply() {
await extension.awaitFinish("sendMessage");
await extension.unload();
});
add_task(async function tabsSendMessageBlob() {
function background() {
browser.runtime.onMessage.addListener(msg => {
browser.test.assertTrue(msg.blob instanceof Blob, "Message is a blob");
return Promise.resolve(msg);
});
let childFrame = document.createElement("iframe");
childFrame.src = "extensionpage.html";
document.body.appendChild(childFrame);
}
function senderScript() {
browser.runtime.sendMessage({blob: new Blob(["hello"])}).then(response => {
browser.test.assertTrue(response.blob instanceof Blob, "Response is a blob");
browser.test.notifyPass("sendBlob");
});
}
let extension = ExtensionTestUtils.loadExtension({
background,
files: {
"senderScript.js": senderScript,
"extensionpage.html": `<!DOCTYPE html><meta charset="utf-8"><script src="senderScript.js"></script>`,
},
});
await extension.startup();
await extension.awaitFinish("sendBlob");
await extension.unload();
});