mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-25 20:01:50 +00:00
Bug 759427 - 'Multiprocess blob support for MessageManager and IndexedDB'. r=smaug+janv+khuey (rs=sicking for nsBlobURI changes).
--HG-- extra : transplant_source : %95%B5y%11%C5%AB%D9%CF%FF%7C%5E%BB%E5%DA%F5j%83o%29%EB
This commit is contained in:
parent
457ab097a2
commit
4893263a15
@ -17,15 +17,19 @@ interface nsIFrameMessageListener : nsISupports
|
||||
* receiveMessage is called with one parameter, which has the following
|
||||
* properties:
|
||||
* {
|
||||
* target: %the target of the message. Either an element owning
|
||||
* the message manager, or message manager itself if no
|
||||
* element owns it%
|
||||
* name: %message name%,
|
||||
* sync: %true or false%.
|
||||
* json: %json object or null%,
|
||||
* json: %structured clone of the sent message data%,
|
||||
* json: %same as .data, deprecated%,
|
||||
* objects: %array of handles or null, always null if sync is false%
|
||||
* }
|
||||
* @note objects property isn't implemented yet.
|
||||
*
|
||||
* if the message is synchronous, possible return value is sent back
|
||||
* as JSON.
|
||||
* as JSON (will be changed to use structured clones).
|
||||
*
|
||||
* When the listener is called, 'this' value is the target of the message.
|
||||
*/
|
||||
|
@ -128,6 +128,7 @@ CPPSRCS = \
|
||||
FragmentOrElement.cpp \
|
||||
Link.cpp \
|
||||
nsBlobProtocolHandler.cpp \
|
||||
nsBlobURI.cpp \
|
||||
nsFrameMessageManager.cpp \
|
||||
nsInProcessTabChildGlobal.cpp \
|
||||
ThirdPartyUtil.cpp \
|
||||
|
@ -3,19 +3,12 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsBlobProtocolHandler.h"
|
||||
#include "nsSimpleURI.h"
|
||||
#include "nsBlobURI.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIURIWithPrincipal.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsISerializable.h"
|
||||
#include "nsIClassInfo.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "nsIProgrammingLanguage.h"
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Hash table
|
||||
@ -89,233 +82,6 @@ GetFileDataInfo(const nsACString& aUri)
|
||||
return res;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Uri
|
||||
|
||||
#define NS_BLOBURI_CID \
|
||||
{ 0xf5475c51, 0x59a7, 0x4757, \
|
||||
{ 0xb3, 0xd9, 0xe2, 0x11, 0xa9, 0x41, 0x08, 0x72 } }
|
||||
|
||||
static NS_DEFINE_CID(kBLOBURICID, NS_BLOBURI_CID);
|
||||
|
||||
class nsBlobURI : public nsSimpleURI,
|
||||
public nsIURIWithPrincipal
|
||||
{
|
||||
public:
|
||||
nsBlobURI(nsIPrincipal* aPrincipal) :
|
||||
nsSimpleURI(), mPrincipal(aPrincipal)
|
||||
{}
|
||||
virtual ~nsBlobURI() {}
|
||||
|
||||
// For use only from deserialization
|
||||
nsBlobURI() : nsSimpleURI() {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIURIWITHPRINCIPAL
|
||||
NS_DECL_NSISERIALIZABLE
|
||||
NS_DECL_NSICLASSINFO
|
||||
|
||||
// Override CloneInternal() and EqualsInternal()
|
||||
virtual nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
|
||||
nsIURI** aClone);
|
||||
virtual nsresult EqualsInternal(nsIURI* aOther,
|
||||
RefHandlingEnum aRefHandlingMode,
|
||||
bool* aResult);
|
||||
|
||||
// Override StartClone to hand back a nsBlobURI
|
||||
virtual nsSimpleURI* StartClone(RefHandlingEnum /* unused */)
|
||||
{ return new nsBlobURI(); }
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
};
|
||||
|
||||
static NS_DEFINE_CID(kThisSimpleURIImplementationCID,
|
||||
NS_THIS_SIMPLEURI_IMPLEMENTATION_CID);
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsBlobURI, nsSimpleURI)
|
||||
NS_IMPL_RELEASE_INHERITED(nsBlobURI, nsSimpleURI)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsBlobURI)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIURIWithPrincipal)
|
||||
if (aIID.Equals(kBLOBURICID))
|
||||
foundInterface = static_cast<nsIURI*>(this);
|
||||
else if (aIID.Equals(kThisSimpleURIImplementationCID)) {
|
||||
// Need to return explicitly here, because if we just set foundInterface
|
||||
// to null the NS_INTERFACE_MAP_END_INHERITING will end up calling into
|
||||
// nsSimplURI::QueryInterface and finding something for this CID.
|
||||
*aInstancePtr = nullptr;
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
else
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsSimpleURI)
|
||||
|
||||
// nsIURIWithPrincipal methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetPrincipal(nsIPrincipal** aPrincipal)
|
||||
{
|
||||
NS_IF_ADDREF(*aPrincipal = mPrincipal);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetPrincipalUri(nsIURI** aUri)
|
||||
{
|
||||
if (mPrincipal) {
|
||||
mPrincipal->GetURI(aUri);
|
||||
}
|
||||
else {
|
||||
*aUri = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsISerializable methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::Read(nsIObjectInputStream* aStream)
|
||||
{
|
||||
nsresult rv = nsSimpleURI::Read(aStream);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_ReadOptionalObject(aStream, true, getter_AddRefs(mPrincipal));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::Write(nsIObjectOutputStream* aStream)
|
||||
{
|
||||
nsresult rv = nsSimpleURI::Write(aStream);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_WriteOptionalCompoundObject(aStream, mPrincipal,
|
||||
NS_GET_IID(nsIPrincipal),
|
||||
true);
|
||||
}
|
||||
|
||||
// nsIURI methods:
|
||||
nsresult
|
||||
nsBlobURI::CloneInternal(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
|
||||
nsIURI** aClone)
|
||||
{
|
||||
nsCOMPtr<nsIURI> simpleClone;
|
||||
nsresult rv =
|
||||
nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
#ifdef DEBUG
|
||||
nsRefPtr<nsBlobURI> uriCheck;
|
||||
rv = simpleClone->QueryInterface(kBLOBURICID, getter_AddRefs(uriCheck));
|
||||
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) && uriCheck,
|
||||
"Unexpected!");
|
||||
#endif
|
||||
|
||||
nsBlobURI* blobURI = static_cast<nsBlobURI*>(simpleClone.get());
|
||||
|
||||
blobURI->mPrincipal = mPrincipal;
|
||||
|
||||
simpleClone.forget(aClone);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* virtual */ nsresult
|
||||
nsBlobURI::EqualsInternal(nsIURI* aOther,
|
||||
nsSimpleURI::RefHandlingEnum aRefHandlingMode,
|
||||
bool* aResult)
|
||||
{
|
||||
if (!aOther) {
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<nsBlobURI> otherBlobUri;
|
||||
aOther->QueryInterface(kBLOBURICID, getter_AddRefs(otherBlobUri));
|
||||
if (!otherBlobUri) {
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Compare the member data that our base class knows about.
|
||||
if (!nsSimpleURI::EqualsInternal(otherBlobUri, aRefHandlingMode)) {
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Compare the piece of additional member data that we add to base class.
|
||||
if (mPrincipal && otherBlobUri->mPrincipal) {
|
||||
// Both of us have mPrincipals. Compare them.
|
||||
return mPrincipal->Equals(otherBlobUri->mPrincipal, aResult);
|
||||
}
|
||||
// else, at least one of us lacks a principal; only equal if *both* lack it.
|
||||
*aResult = (!mPrincipal && !otherBlobUri->mPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIClassInfo methods:
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetInterfaces(PRUint32 *count, nsIID * **array)
|
||||
{
|
||||
*count = 0;
|
||||
*array = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
|
||||
{
|
||||
*_retval = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetContractID(char * *aContractID)
|
||||
{
|
||||
// Make sure to modify any subclasses as needed if this ever
|
||||
// changes.
|
||||
*aContractID = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetClassDescription(char * *aClassDescription)
|
||||
{
|
||||
*aClassDescription = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetClassID(nsCID * *aClassID)
|
||||
{
|
||||
// Make sure to modify any subclasses as needed if this ever
|
||||
// changes to not call the virtual GetClassIDNoAlloc.
|
||||
*aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
|
||||
NS_ENSURE_TRUE(*aClassID, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return GetClassIDNoAlloc(*aClassID);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
|
||||
{
|
||||
*aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetFlags(PRUint32 *aFlags)
|
||||
{
|
||||
*aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
|
||||
{
|
||||
*aClassIDNoAlloc = kBLOBURICID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Protocol handler
|
||||
|
||||
|
199
content/base/src/nsBlobURI.cpp
Normal file
199
content/base/src/nsBlobURI.cpp
Normal file
@ -0,0 +1,199 @@
|
||||
/* 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 "nsBlobURI.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "nsIProgrammingLanguage.h"
|
||||
|
||||
static NS_DEFINE_CID(kBLOBURICID, NS_BLOBURI_CID);
|
||||
|
||||
static NS_DEFINE_CID(kThisSimpleURIImplementationCID,
|
||||
NS_THIS_SIMPLEURI_IMPLEMENTATION_CID);
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsBlobURI, nsSimpleURI)
|
||||
NS_IMPL_RELEASE_INHERITED(nsBlobURI, nsSimpleURI)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsBlobURI)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIURIWithPrincipal)
|
||||
if (aIID.Equals(kBLOBURICID))
|
||||
foundInterface = static_cast<nsIURI*>(this);
|
||||
else if (aIID.Equals(kThisSimpleURIImplementationCID)) {
|
||||
// Need to return explicitly here, because if we just set foundInterface
|
||||
// to null the NS_INTERFACE_MAP_END_INHERITING will end up calling into
|
||||
// nsSimplURI::QueryInterface and finding something for this CID.
|
||||
*aInstancePtr = nullptr;
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
else
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsSimpleURI)
|
||||
|
||||
// nsIURIWithPrincipal methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetPrincipal(nsIPrincipal** aPrincipal)
|
||||
{
|
||||
NS_IF_ADDREF(*aPrincipal = mPrincipal);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetPrincipalUri(nsIURI** aUri)
|
||||
{
|
||||
if (mPrincipal) {
|
||||
mPrincipal->GetURI(aUri);
|
||||
}
|
||||
else {
|
||||
*aUri = nullptr;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsISerializable methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::Read(nsIObjectInputStream* aStream)
|
||||
{
|
||||
nsresult rv = nsSimpleURI::Read(aStream);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_ReadOptionalObject(aStream, true, getter_AddRefs(mPrincipal));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::Write(nsIObjectOutputStream* aStream)
|
||||
{
|
||||
nsresult rv = nsSimpleURI::Write(aStream);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_WriteOptionalCompoundObject(aStream, mPrincipal,
|
||||
NS_GET_IID(nsIPrincipal),
|
||||
true);
|
||||
}
|
||||
|
||||
// nsIURI methods:
|
||||
nsresult
|
||||
nsBlobURI::CloneInternal(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
|
||||
nsIURI** aClone)
|
||||
{
|
||||
nsCOMPtr<nsIURI> simpleClone;
|
||||
nsresult rv =
|
||||
nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
#ifdef DEBUG
|
||||
nsRefPtr<nsBlobURI> uriCheck;
|
||||
rv = simpleClone->QueryInterface(kBLOBURICID, getter_AddRefs(uriCheck));
|
||||
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv) && uriCheck,
|
||||
"Unexpected!");
|
||||
#endif
|
||||
|
||||
nsBlobURI* blobURI = static_cast<nsBlobURI*>(simpleClone.get());
|
||||
|
||||
blobURI->mPrincipal = mPrincipal;
|
||||
|
||||
simpleClone.forget(aClone);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* virtual */ nsresult
|
||||
nsBlobURI::EqualsInternal(nsIURI* aOther,
|
||||
nsSimpleURI::RefHandlingEnum aRefHandlingMode,
|
||||
bool* aResult)
|
||||
{
|
||||
if (!aOther) {
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<nsBlobURI> otherBlobUri;
|
||||
aOther->QueryInterface(kBLOBURICID, getter_AddRefs(otherBlobUri));
|
||||
if (!otherBlobUri) {
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Compare the member data that our base class knows about.
|
||||
if (!nsSimpleURI::EqualsInternal(otherBlobUri, aRefHandlingMode)) {
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Compare the piece of additional member data that we add to base class.
|
||||
if (mPrincipal && otherBlobUri->mPrincipal) {
|
||||
// Both of us have mPrincipals. Compare them.
|
||||
return mPrincipal->Equals(otherBlobUri->mPrincipal, aResult);
|
||||
}
|
||||
// else, at least one of us lacks a principal; only equal if *both* lack it.
|
||||
*aResult = (!mPrincipal && !otherBlobUri->mPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIClassInfo methods:
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetInterfaces(PRUint32 *count, nsIID * **array)
|
||||
{
|
||||
*count = 0;
|
||||
*array = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
|
||||
{
|
||||
*_retval = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetContractID(char * *aContractID)
|
||||
{
|
||||
// Make sure to modify any subclasses as needed if this ever
|
||||
// changes.
|
||||
*aContractID = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetClassDescription(char * *aClassDescription)
|
||||
{
|
||||
*aClassDescription = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetClassID(nsCID * *aClassID)
|
||||
{
|
||||
// Make sure to modify any subclasses as needed if this ever
|
||||
// changes to not call the virtual GetClassIDNoAlloc.
|
||||
*aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
|
||||
NS_ENSURE_TRUE(*aClassID, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return GetClassIDNoAlloc(*aClassID);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
|
||||
{
|
||||
*aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetFlags(PRUint32 *aFlags)
|
||||
{
|
||||
*aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBlobURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
|
||||
{
|
||||
*aClassIDNoAlloc = kBLOBURICID;
|
||||
return NS_OK;
|
||||
}
|
50
content/base/src/nsBlobURI.h
Normal file
50
content/base/src/nsBlobURI.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsBlobURI_h
|
||||
#define nsBlobURI_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIClassInfo.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsISerializable.h"
|
||||
#include "nsIURIWithPrincipal.h"
|
||||
#include "nsSimpleURI.h"
|
||||
|
||||
class nsBlobURI : public nsSimpleURI,
|
||||
public nsIURIWithPrincipal
|
||||
{
|
||||
public:
|
||||
nsBlobURI(nsIPrincipal* aPrincipal) :
|
||||
nsSimpleURI(), mPrincipal(aPrincipal)
|
||||
{}
|
||||
virtual ~nsBlobURI() {}
|
||||
|
||||
// For use only from deserialization
|
||||
nsBlobURI() : nsSimpleURI() {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIURIWITHPRINCIPAL
|
||||
NS_DECL_NSISERIALIZABLE
|
||||
NS_DECL_NSICLASSINFO
|
||||
|
||||
// Override CloneInternal() and EqualsInternal()
|
||||
virtual nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
|
||||
nsIURI** aClone);
|
||||
virtual nsresult EqualsInternal(nsIURI* aOther,
|
||||
RefHandlingEnum aRefHandlingMode,
|
||||
bool* aResult);
|
||||
|
||||
// Override StartClone to hand back a nsBlobURI
|
||||
virtual nsSimpleURI* StartClone(RefHandlingEnum /* unused */)
|
||||
{ return new nsBlobURI(); }
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
};
|
||||
|
||||
#define NS_BLOBURI_CID \
|
||||
{ 0xf5475c51, 0x59a7, 0x4757, \
|
||||
{ 0xb3, 0xd9, 0xe2, 0x11, 0xa9, 0x41, 0x08, 0x72 } }
|
||||
|
||||
#endif /* nsBlobURI_h */
|
@ -22,6 +22,7 @@
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsIWebProgress.h"
|
||||
@ -83,6 +84,7 @@
|
||||
#include "nsIAppsService.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/dom/StructuredCloneUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -2156,8 +2158,15 @@ class nsAsyncMessageToChild : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsAsyncMessageToChild(nsFrameLoader* aFrameLoader,
|
||||
const nsAString& aMessage, const nsAString& aJSON)
|
||||
: mFrameLoader(aFrameLoader), mMessage(aMessage), mJSON(aJSON) {}
|
||||
const nsAString& aMessage,
|
||||
const StructuredCloneData& aData)
|
||||
: mFrameLoader(aFrameLoader), mMessage(aMessage)
|
||||
{
|
||||
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
|
||||
NS_RUNTIMEABORT("OOM");
|
||||
}
|
||||
mClosure = aData.mClosure;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
@ -2165,29 +2174,62 @@ public:
|
||||
static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get());
|
||||
if (tabChild && tabChild->GetInnerManager()) {
|
||||
nsFrameScriptCx cx(static_cast<nsIDOMEventTarget*>(tabChild), tabChild);
|
||||
|
||||
StructuredCloneData data;
|
||||
data.mData = mData.data();
|
||||
data.mDataLength = mData.nbytes();
|
||||
data.mClosure = mClosure;
|
||||
|
||||
nsRefPtr<nsFrameMessageManager> mm = tabChild->GetInnerManager();
|
||||
mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(tabChild), mMessage,
|
||||
false, mJSON, nullptr, nullptr);
|
||||
false, &data, nullptr, nullptr, nullptr);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
nsRefPtr<nsFrameLoader> mFrameLoader;
|
||||
nsString mMessage;
|
||||
nsString mJSON;
|
||||
JSAutoStructuredCloneBuffer mData;
|
||||
StructuredCloneClosure mClosure;
|
||||
};
|
||||
|
||||
bool SendAsyncMessageToChild(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON)
|
||||
const StructuredCloneData& aData)
|
||||
{
|
||||
mozilla::dom::PBrowserParent* tabParent =
|
||||
PBrowserParent* tabParent =
|
||||
static_cast<nsFrameLoader*>(aCallbackData)->GetRemoteBrowser();
|
||||
if (tabParent) {
|
||||
return tabParent->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
|
||||
ClonedMessageData data;
|
||||
|
||||
SerializedStructuredCloneBuffer& buffer = data.data();
|
||||
buffer.data = aData.mData;
|
||||
buffer.dataLength = aData.mDataLength;
|
||||
|
||||
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
|
||||
if (!blobs.IsEmpty()) {
|
||||
InfallibleTArray<PBlobParent*>& blobParents = data.blobsParent();
|
||||
|
||||
PRUint32 length = blobs.Length();
|
||||
blobParents.SetCapacity(length);
|
||||
|
||||
ContentParent* cp = static_cast<ContentParent*>(tabParent->Manager());
|
||||
|
||||
for (PRUint32 i = 0; i < length; ++i) {
|
||||
BlobParent* blobParent = cp->GetOrCreateActorForBlob(blobs[i]);
|
||||
if (!blobParent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
blobParents.AppendElement(blobParent);
|
||||
}
|
||||
}
|
||||
|
||||
return tabParent->SendAsyncMessage(nsString(aMessage), data);
|
||||
}
|
||||
|
||||
nsRefPtr<nsIRunnable> ev =
|
||||
new nsAsyncMessageToChild(static_cast<nsFrameLoader*>(aCallbackData),
|
||||
aMessage, aJSON);
|
||||
aMessage, aData);
|
||||
NS_DispatchToCurrentThread(ev);
|
||||
return true;
|
||||
}
|
||||
|
@ -3,9 +3,12 @@
|
||||
* 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 "base/basictypes.h"
|
||||
|
||||
#include "nsFrameMessageManager.h"
|
||||
|
||||
#include "ContentChild.h"
|
||||
#include "ContentParent.h"
|
||||
#include "nsFrameMessageManager.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "jsapi.h"
|
||||
@ -20,14 +23,17 @@
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIJSRuntimeService.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/StructuredCloneUtils.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
static bool
|
||||
IsChromeProcess()
|
||||
@ -170,15 +176,32 @@ JSONCreator(const jschar* aBuf, uint32_t aLen, void* aData)
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameMessageManager::GetParamsForMessage(const jsval& aObject,
|
||||
JSContext* aCx,
|
||||
nsAString& aJSON)
|
||||
static bool
|
||||
GetParamsForMessage(JSContext* aCx,
|
||||
const jsval& aObject,
|
||||
JSAutoStructuredCloneBuffer& aBuffer,
|
||||
StructuredCloneClosure& aClosure)
|
||||
{
|
||||
aJSON.Truncate();
|
||||
if (WriteStructuredClone(aCx, aObject, aBuffer, aClosure)) {
|
||||
return true;
|
||||
}
|
||||
JS_ClearPendingException(aCx);
|
||||
|
||||
// Not clonable, try JSON
|
||||
//XXX This is ugly but currently structured cloning doesn't handle
|
||||
// properly cases when interface is implemented in JS and used
|
||||
// as a dictionary.
|
||||
nsAutoString json;
|
||||
JSAutoRequest ar(aCx);
|
||||
jsval v = aObject;
|
||||
JS_Stringify(aCx, &v, nullptr, JSVAL_NULL, JSONCreator, &aJSON);
|
||||
NS_ENSURE_TRUE(JS_Stringify(aCx, &v, nullptr, JSVAL_NULL, JSONCreator, &json), false);
|
||||
NS_ENSURE_TRUE(!json.IsEmpty(), false);
|
||||
|
||||
jsval val = JSVAL_NULL;
|
||||
NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast<const jschar*>(PromiseFlatString(json).get()),
|
||||
json.Length(), &val), false);
|
||||
|
||||
return WriteStructuredClone(aCx, val, aBuffer, aClosure);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -194,12 +217,17 @@ nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
|
||||
*aRetval = JSVAL_VOID;
|
||||
if (mSyncCallback) {
|
||||
NS_ENSURE_TRUE(mCallbackData, NS_ERROR_NOT_INITIALIZED);
|
||||
nsString json;
|
||||
if (aArgc >= 2) {
|
||||
GetParamsForMessage(aObject, aCx, json);
|
||||
StructuredCloneData data;
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
if (aArgc >= 2 &&
|
||||
!GetParamsForMessage(aCx, aObject, buffer, data.mClosure)) {
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
data.mData = buffer.data();
|
||||
data.mDataLength = buffer.nbytes();
|
||||
|
||||
InfallibleTArray<nsString> retval;
|
||||
if (mSyncCallback(mCallbackData, aMessageName, json, &retval)) {
|
||||
if (mSyncCallback(mCallbackData, aMessageName, data, &retval)) {
|
||||
JSAutoRequest ar(aCx);
|
||||
PRUint32 len = retval.Length();
|
||||
JSObject* dataArray = JS_NewArrayObject(aCx, len, NULL);
|
||||
@ -226,16 +254,16 @@ nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
|
||||
|
||||
nsresult
|
||||
nsFrameMessageManager::SendAsyncMessageInternal(const nsAString& aMessage,
|
||||
const nsAString& aJSON)
|
||||
const StructuredCloneData& aData)
|
||||
{
|
||||
if (mAsyncCallback) {
|
||||
NS_ENSURE_TRUE(mCallbackData, NS_ERROR_NOT_INITIALIZED);
|
||||
mAsyncCallback(mCallbackData, aMessage, aJSON);
|
||||
mAsyncCallback(mCallbackData, aMessage, aData);
|
||||
}
|
||||
PRInt32 len = mChildManagers.Count();
|
||||
for (PRInt32 i = 0; i < len; ++i) {
|
||||
static_cast<nsFrameMessageManager*>(mChildManagers[i])->
|
||||
SendAsyncMessageInternal(aMessage, aJSON);
|
||||
SendAsyncMessageInternal(aMessage, aData);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -246,11 +274,18 @@ nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
|
||||
JSContext* aCx,
|
||||
PRUint8 aArgc)
|
||||
{
|
||||
nsString json;
|
||||
if (aArgc >= 2) {
|
||||
GetParamsForMessage(aObject, aCx, json);
|
||||
StructuredCloneData data;
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
|
||||
if (aArgc >= 2 &&
|
||||
!GetParamsForMessage(aCx, aObject, buffer, data.mClosure)) {
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
return SendAsyncMessageInternal(aMessageName, json);
|
||||
|
||||
data.mData = buffer.data();
|
||||
data.mDataLength = buffer.nbytes();
|
||||
|
||||
return SendAsyncMessageInternal(aMessageName, data);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -342,7 +377,8 @@ public:
|
||||
nsresult
|
||||
nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||
const nsAString& aMessage,
|
||||
bool aSync, const nsAString& aJSON,
|
||||
bool aSync,
|
||||
const StructuredCloneData* aCloneData,
|
||||
JSObject* aObjectsArray,
|
||||
InfallibleTArray<nsString>* aJSONRetVal,
|
||||
JSContext* aContext)
|
||||
@ -402,11 +438,10 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
jsval json = JSVAL_NULL;
|
||||
if (!aJSON.IsEmpty()) {
|
||||
if (!JS_ParseJSON(ctx, static_cast<const jschar*>(PromiseFlatString(aJSON).get()),
|
||||
aJSON.Length(), &json)) {
|
||||
json = JSVAL_NULL;
|
||||
}
|
||||
if (aCloneData && aCloneData->mDataLength &&
|
||||
!ReadStructuredClone(ctx, *aCloneData, &json)) {
|
||||
JS_ClearPendingException(ctx);
|
||||
return NS_OK;
|
||||
}
|
||||
JSString* jsMessage =
|
||||
JS_NewUCStringCopyN(ctx,
|
||||
@ -418,7 +453,8 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||
STRING_TO_JSVAL(jsMessage), NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_DefineProperty(ctx, param, "sync",
|
||||
BOOLEAN_TO_JSVAL(aSync), NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_DefineProperty(ctx, param, "json", json, NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_DefineProperty(ctx, param, "json", json, NULL, NULL, JSPROP_ENUMERATE); // deprecated
|
||||
JS_DefineProperty(ctx, param, "data", json, NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_DefineProperty(ctx, param, "objects", objectsv.jsval_value(), NULL, NULL, JSPROP_ENUMERATE);
|
||||
|
||||
jsval thisValue = JSVAL_VOID;
|
||||
@ -479,7 +515,8 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||
}
|
||||
nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = mParentManager;
|
||||
return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage,
|
||||
aSync, aJSON, aObjectsArray,
|
||||
aSync, aCloneData,
|
||||
aObjectsArray,
|
||||
aJSONRetVal, mContext) : NS_OK;
|
||||
}
|
||||
|
||||
@ -888,13 +925,31 @@ nsTArray<nsCOMPtr<nsIRunnable> >* nsFrameMessageManager::sPendingSameProcessAsyn
|
||||
|
||||
bool SendAsyncMessageToChildProcess(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON)
|
||||
const StructuredCloneData& aData)
|
||||
{
|
||||
mozilla::dom::ContentParent* cp =
|
||||
static_cast<mozilla::dom::ContentParent*>(aCallbackData);
|
||||
NS_WARN_IF_FALSE(cp, "No child process!");
|
||||
if (cp) {
|
||||
return cp->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
|
||||
ClonedMessageData data;
|
||||
SerializedStructuredCloneBuffer& buffer = data.data();
|
||||
buffer.data = aData.mData;
|
||||
buffer.dataLength = aData.mDataLength;
|
||||
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
|
||||
if (!blobs.IsEmpty()) {
|
||||
InfallibleTArray<PBlobParent*>& blobParents = data.blobsParent();
|
||||
PRUint32 length = blobs.Length();
|
||||
blobParents.SetCapacity(length);
|
||||
for (PRUint32 i = 0; i < length; ++i) {
|
||||
BlobParent* blobParent = cp->GetOrCreateActorForBlob(blobs[i]);
|
||||
if (!blobParent) {
|
||||
return false;
|
||||
}
|
||||
blobParents.AppendElement(blobParent);
|
||||
}
|
||||
}
|
||||
|
||||
return cp->SendAsyncMessage(nsString(aMessage), data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -902,49 +957,79 @@ bool SendAsyncMessageToChildProcess(void* aCallbackData,
|
||||
class nsAsyncMessageToSameProcessChild : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsAsyncMessageToSameProcessChild(const nsAString& aMessage, const nsAString& aJSON)
|
||||
: mMessage(aMessage), mJSON(aJSON) {}
|
||||
nsAsyncMessageToSameProcessChild(const nsAString& aMessage,
|
||||
const StructuredCloneData& aData)
|
||||
: mMessage(aMessage)
|
||||
{
|
||||
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
|
||||
NS_RUNTIMEABORT("OOM");
|
||||
}
|
||||
mClosure = aData.mClosure;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (nsFrameMessageManager::sChildProcessManager) {
|
||||
StructuredCloneData data;
|
||||
data.mData = mData.data();
|
||||
data.mDataLength = mData.nbytes();
|
||||
data.mClosure = mClosure;
|
||||
|
||||
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sChildProcessManager;
|
||||
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), mMessage,
|
||||
false, mJSON, nullptr, nullptr);
|
||||
false, &data, nullptr, nullptr, nullptr);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
nsString mMessage;
|
||||
nsString mJSON;
|
||||
JSAutoStructuredCloneBuffer mData;
|
||||
StructuredCloneClosure mClosure;
|
||||
};
|
||||
|
||||
bool SendAsyncMessageToSameProcessChild(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON)
|
||||
const StructuredCloneData& aData)
|
||||
{
|
||||
nsRefPtr<nsIRunnable> ev =
|
||||
new nsAsyncMessageToSameProcessChild(aMessage, aJSON);
|
||||
new nsAsyncMessageToSameProcessChild(aMessage, aData);
|
||||
NS_DispatchToCurrentThread(ev);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SendSyncMessageToParentProcess(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON,
|
||||
const StructuredCloneData& aData,
|
||||
InfallibleTArray<nsString>* aJSONRetVal)
|
||||
{
|
||||
mozilla::dom::ContentChild* cc =
|
||||
mozilla::dom::ContentChild::GetSingleton();
|
||||
if (cc) {
|
||||
ClonedMessageData data;
|
||||
SerializedStructuredCloneBuffer& buffer = data.data();
|
||||
buffer.data = aData.mData;
|
||||
buffer.dataLength = aData.mDataLength;
|
||||
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
|
||||
if (!blobs.IsEmpty()) {
|
||||
InfallibleTArray<PBlobChild*>& blobChildList = data.blobsChild();
|
||||
PRUint32 length = blobs.Length();
|
||||
blobChildList.SetCapacity(length);
|
||||
for (PRUint32 i = 0; i < length; ++i) {
|
||||
BlobChild* blobChild = cc->GetOrCreateActorForBlob(blobs[i]);
|
||||
if (!blobChild) {
|
||||
return false;
|
||||
}
|
||||
blobChildList.AppendElement(blobChild);
|
||||
}
|
||||
}
|
||||
return
|
||||
cc->SendSyncMessage(nsString(aMessage), nsString(aJSON), aJSONRetVal);
|
||||
cc->SendSyncMessage(nsString(aMessage), data, aJSONRetVal);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SendSyncMessageToSameProcessParent(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON,
|
||||
const StructuredCloneData& aData,
|
||||
InfallibleTArray<nsString>* aJSONRetVal)
|
||||
{
|
||||
nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
|
||||
@ -959,19 +1044,36 @@ bool SendSyncMessageToSameProcessParent(void* aCallbackData,
|
||||
if (nsFrameMessageManager::sSameProcessParentManager) {
|
||||
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
|
||||
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), aMessage,
|
||||
true, aJSON, nullptr, aJSONRetVal);
|
||||
true, &aData, nullptr, aJSONRetVal);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SendAsyncMessageToParentProcess(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON)
|
||||
const StructuredCloneData& aData)
|
||||
{
|
||||
mozilla::dom::ContentChild* cc =
|
||||
mozilla::dom::ContentChild::GetSingleton();
|
||||
if (cc) {
|
||||
return cc->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
|
||||
ClonedMessageData data;
|
||||
SerializedStructuredCloneBuffer& buffer = data.data();
|
||||
buffer.data = aData.mData;
|
||||
buffer.dataLength = aData.mDataLength;
|
||||
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
|
||||
if (!blobs.IsEmpty()) {
|
||||
InfallibleTArray<PBlobChild*>& blobChildList = data.blobsChild();
|
||||
PRUint32 length = blobs.Length();
|
||||
blobChildList.SetCapacity(length);
|
||||
for (PRUint32 i = 0; i < length; ++i) {
|
||||
BlobChild* blobChild = cc->GetOrCreateActorForBlob(blobs[i]);
|
||||
if (!blobChild) {
|
||||
return false;
|
||||
}
|
||||
blobChildList.AppendElement(blobChild);
|
||||
}
|
||||
}
|
||||
return cc->SendAsyncMessage(nsString(aMessage), data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -979,8 +1081,15 @@ bool SendAsyncMessageToParentProcess(void* aCallbackData,
|
||||
class nsAsyncMessageToSameProcessParent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsAsyncMessageToSameProcessParent(const nsAString& aMessage, const nsAString& aJSON)
|
||||
: mMessage(aMessage), mJSON(aJSON) {}
|
||||
nsAsyncMessageToSameProcessParent(const nsAString& aMessage,
|
||||
const StructuredCloneData& aData)
|
||||
: mMessage(aMessage)
|
||||
{
|
||||
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
|
||||
NS_RUNTIMEABORT("OOM");
|
||||
}
|
||||
mClosure = aData.mClosure;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
@ -988,25 +1097,32 @@ public:
|
||||
nsFrameMessageManager::sPendingSameProcessAsyncMessages->RemoveElement(this);
|
||||
}
|
||||
if (nsFrameMessageManager::sSameProcessParentManager) {
|
||||
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
|
||||
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), mMessage, false,
|
||||
mJSON, nullptr, nullptr);
|
||||
}
|
||||
return NS_OK;
|
||||
StructuredCloneData data;
|
||||
data.mData = mData.data();
|
||||
data.mDataLength = mData.nbytes();
|
||||
data.mClosure = mClosure;
|
||||
|
||||
nsRefPtr<nsFrameMessageManager> ppm =
|
||||
nsFrameMessageManager::sSameProcessParentManager;
|
||||
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
|
||||
mMessage, false, &data, nullptr, nullptr, nullptr);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
nsString mMessage;
|
||||
nsString mJSON;
|
||||
JSAutoStructuredCloneBuffer mData;
|
||||
StructuredCloneClosure mClosure;
|
||||
};
|
||||
|
||||
bool SendAsyncMessageToSameProcessParent(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON)
|
||||
const nsAString& aMessage,
|
||||
const StructuredCloneData& aData)
|
||||
{
|
||||
if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
|
||||
nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray<nsCOMPtr<nsIRunnable> >;
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
new nsAsyncMessageToSameProcessParent(aMessage, aJSON);
|
||||
new nsAsyncMessageToSameProcessParent(aMessage, aData);
|
||||
nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev);
|
||||
NS_DispatchToCurrentThread(ev);
|
||||
return true;
|
||||
@ -1089,4 +1205,4 @@ nsFrameMessageManager::MarkForCC()
|
||||
xpc_TryUnmarkWrappedGrayObject(mListeners[i].mListener);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
struct StructuredCloneData;
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,15 +42,16 @@ struct nsMessageListenerInfo
|
||||
typedef bool (*nsLoadScriptCallback)(void* aCallbackData, const nsAString& aURL);
|
||||
typedef bool (*nsSyncMessageCallback)(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON,
|
||||
const mozilla::dom::StructuredCloneData& aData,
|
||||
InfallibleTArray<nsString>* aJSONRetVal);
|
||||
typedef bool (*nsAsyncMessageCallback)(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON);
|
||||
const mozilla::dom::StructuredCloneData& aData);
|
||||
|
||||
class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
|
||||
public nsIChromeFrameMessageManager
|
||||
{
|
||||
typedef mozilla::dom::StructuredCloneData StructuredCloneData;
|
||||
public:
|
||||
nsFrameMessageManager(bool aChrome,
|
||||
nsSyncMessageCallback aSyncCallback,
|
||||
@ -63,7 +65,8 @@ public:
|
||||
: mChrome(aChrome), mGlobal(aGlobal), mIsProcessManager(aProcessManager),
|
||||
mHandlingMessage(false), mDisconnected(false), mParentManager(aParentManager),
|
||||
mSyncCallback(aSyncCallback), mAsyncCallback(aAsyncCallback),
|
||||
mLoadScriptCallback(aLoadScriptCallback), mCallbackData(aCallbackData),
|
||||
mLoadScriptCallback(aLoadScriptCallback),
|
||||
mCallbackData(aCallbackData),
|
||||
mContext(aContext)
|
||||
{
|
||||
NS_ASSERTION(mContext || (aChrome && !aParentManager) || aProcessManager,
|
||||
@ -112,10 +115,11 @@ public:
|
||||
NewProcessMessageManager(mozilla::dom::ContentParent* aProcess);
|
||||
|
||||
nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
|
||||
bool aSync, const nsAString& aJSON,
|
||||
bool aSync, const StructuredCloneData* aCloneData,
|
||||
JSObject* aObjectsArray,
|
||||
InfallibleTArray<nsString>* aJSONRetVal,
|
||||
JSContext* aContext = nullptr);
|
||||
|
||||
void AddChildManager(nsFrameMessageManager* aManager,
|
||||
bool aLoadScripts = true);
|
||||
void RemoveChildManager(nsFrameMessageManager* aManager)
|
||||
@ -126,11 +130,8 @@ public:
|
||||
void Disconnect(bool aRemoveFromParent = true);
|
||||
void SetCallbackData(void* aData, bool aLoadScripts = true);
|
||||
void* GetCallbackData() { return mCallbackData; }
|
||||
void GetParamsForMessage(const jsval& aObject,
|
||||
JSContext* aCx,
|
||||
nsAString& aJSON);
|
||||
nsresult SendAsyncMessageInternal(const nsAString& aMessage,
|
||||
const nsAString& aJSON);
|
||||
const StructuredCloneData& aData);
|
||||
JSContext* GetJSContext() { return mContext; }
|
||||
void SetJSContext(JSContext* aCx) { mContext = aCx; }
|
||||
void RemoveFromParent();
|
||||
@ -257,4 +258,4 @@ class nsScriptCacheCleaner MOZ_FINAL : public nsIObserver
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
@ -20,10 +20,14 @@
|
||||
#include "xpcpublic.h"
|
||||
#include "nsIMozBrowserFrame.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "mozilla/dom/StructuredCloneUtils.h"
|
||||
|
||||
using mozilla::dom::StructuredCloneData;
|
||||
using mozilla::dom::StructuredCloneClosure;
|
||||
|
||||
bool SendSyncMessageToParent(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON,
|
||||
const StructuredCloneData& aData,
|
||||
InfallibleTArray<nsString>* aJSONRetVal)
|
||||
{
|
||||
nsInProcessTabChildGlobal* tabChild =
|
||||
@ -38,7 +42,7 @@ bool SendSyncMessageToParent(void* aCallbackData,
|
||||
}
|
||||
if (tabChild->mChromeMessageManager) {
|
||||
nsRefPtr<nsFrameMessageManager> mm = tabChild->mChromeMessageManager;
|
||||
mm->ReceiveMessage(owner, aMessage, true, aJSON, nullptr, aJSONRetVal);
|
||||
mm->ReceiveMessage(owner, aMessage, true, &aData, nullptr, aJSONRetVal);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -47,32 +51,45 @@ class nsAsyncMessageToParent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsAsyncMessageToParent(nsInProcessTabChildGlobal* aTabChild,
|
||||
const nsAString& aMessage, const nsAString& aJSON)
|
||||
: mTabChild(aTabChild), mMessage(aMessage), mJSON(aJSON) {}
|
||||
const nsAString& aMessage,
|
||||
const StructuredCloneData& aData)
|
||||
: mTabChild(aTabChild), mMessage(aMessage)
|
||||
{
|
||||
if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
|
||||
NS_RUNTIMEABORT("OOM");
|
||||
}
|
||||
mClosure = aData.mClosure;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mTabChild->mASyncMessages.RemoveElement(this);
|
||||
if (mTabChild->mChromeMessageManager) {
|
||||
StructuredCloneData data;
|
||||
data.mData = mData.data();
|
||||
data.mDataLength = mData.nbytes();
|
||||
data.mClosure = mClosure;
|
||||
|
||||
nsRefPtr<nsFrameMessageManager> mm = mTabChild->mChromeMessageManager;
|
||||
mm->ReceiveMessage(mTabChild->mOwner, mMessage, false,
|
||||
mJSON, nullptr, nullptr);
|
||||
mm->ReceiveMessage(mTabChild->mOwner, mMessage, false, &data,
|
||||
nullptr, nullptr, nullptr);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
|
||||
nsString mMessage;
|
||||
nsString mJSON;
|
||||
JSAutoStructuredCloneBuffer mData;
|
||||
StructuredCloneClosure mClosure;
|
||||
};
|
||||
|
||||
bool SendAsyncMessageToParent(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON)
|
||||
const StructuredCloneData& aData)
|
||||
{
|
||||
nsInProcessTabChildGlobal* tabChild =
|
||||
static_cast<nsInProcessTabChildGlobal*>(aCallbackData);
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
new nsAsyncMessageToParent(tabChild, aMessage, aJSON);
|
||||
new nsAsyncMessageToParent(tabChild, aMessage, aData);
|
||||
tabChild->mASyncMessages.AppendElement(ev);
|
||||
NS_DispatchToCurrentThread(ev);
|
||||
return true;
|
||||
|
@ -552,6 +552,7 @@ MOCHITEST_FILES_B = \
|
||||
file_XHR_anon.sjs \
|
||||
test_XHR_system.html \
|
||||
test_XHR_parameters.html \
|
||||
test_ipc_messagemanager_blob.html \
|
||||
$(NULL)
|
||||
|
||||
MOCHITEST_CHROME_FILES = \
|
||||
|
111
content/base/test/test_ipc_messagemanager_blob.html
Normal file
111
content/base/test/test_ipc_messagemanager_blob.html
Normal file
@ -0,0 +1,111 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for OOP Blobs in MessageManager</title>
|
||||
<script type="application/javascript"
|
||||
src="/tests/SimpleTest/SimpleTest.js">
|
||||
</script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const childFrameURL =
|
||||
"data:text/html,<!DOCTYPE HTML><html><body></body></html>";
|
||||
|
||||
function childFrameScript() {
|
||||
"use strict";
|
||||
|
||||
addMessageListener("test:ipcClonedMessage", function(message) {
|
||||
if (!(message.json instanceof Components.interfaces.nsIDOMBlob)) {
|
||||
sendAsyncMessage(message.name, message.json);
|
||||
return;
|
||||
}
|
||||
|
||||
let reader =
|
||||
Components.classes["@mozilla.org/files/filereader;1"]
|
||||
.createInstance(Components.interfaces.nsIDOMFileReader);
|
||||
reader.addEventListener("load", function() {
|
||||
let response = reader.result == "this is a great success!" ?
|
||||
message.json :
|
||||
"error";
|
||||
sendAsyncMessage(message.name, response);
|
||||
});
|
||||
reader.readAsText(message.json);
|
||||
});
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
ok("Browser prefs set.");
|
||||
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.mozbrowser = true;
|
||||
iframe.id = "iframe";
|
||||
iframe.src = childFrameURL;
|
||||
|
||||
iframe.addEventListener("mozbrowserloadend", function() {
|
||||
ok(true, "Got iframe load event.");
|
||||
|
||||
const messages = [
|
||||
"hi!",
|
||||
"",
|
||||
2,
|
||||
-.04,
|
||||
3432987324987239872948732982,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
0,
|
||||
new Blob(["this ", "is ", "a ", "great ", "success!"],
|
||||
{"type" : "text\/plain"}),
|
||||
];
|
||||
let receivedMessageIndex = 0;
|
||||
|
||||
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
mm.addMessageListener("test:ipcClonedMessage", function(message) {
|
||||
is(message.json, messages[receivedMessageIndex++],
|
||||
"Got correct round-tripped response");
|
||||
if (receivedMessageIndex == messages.length) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
});
|
||||
mm.loadFrameScript("data:,(" + childFrameScript.toString() + ")();",
|
||||
false);
|
||||
|
||||
for each (let message in messages) {
|
||||
mm.sendAsyncMessage("test:ipcClonedMessage", message);
|
||||
}
|
||||
});
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
addEventListener("load", function() {
|
||||
info("Got load event.");
|
||||
|
||||
let whitelist;
|
||||
try {
|
||||
whitelist =
|
||||
SpecialPowers.getCharPref("dom.mozBrowserFramesWhitelist") + ", ";
|
||||
} catch (e) {
|
||||
whitelist = "";
|
||||
}
|
||||
|
||||
whitelist += window.location.protocol + "//" + window.location.host;
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.ipc.browser_frames.oop_by_default", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.mozBrowserFramesWhitelist", whitelist],
|
||||
["browser.pageThumbs.enabled", false]
|
||||
]
|
||||
}, runTests);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -8349,7 +8349,8 @@ nsGlobalWindow::GetIndexedDB(nsIIDBFactory** _retval)
|
||||
}
|
||||
|
||||
// This may be null if being created from a file.
|
||||
rv = indexedDB::IDBFactory::Create(this, getter_AddRefs(mIndexedDB));
|
||||
rv = indexedDB::IDBFactory::Create(this, nullptr,
|
||||
getter_AddRefs(mIndexedDB));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -749,7 +749,7 @@ IDBCursor::Advance(PRInt64 aCount)
|
||||
}
|
||||
|
||||
Key key;
|
||||
return ContinueInternal(key, aCount);
|
||||
return ContinueInternal(key, PRInt32(aCount));
|
||||
}
|
||||
|
||||
void
|
||||
@ -876,9 +876,26 @@ ContinueHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
return Success_NotSent;
|
||||
}
|
||||
|
||||
if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
|
||||
NS_WARNING("No support for transferring blobs across processes yet!");
|
||||
return Error;
|
||||
InfallibleTArray<PBlobParent*> blobsParent;
|
||||
|
||||
if (NS_SUCCEEDED(aResultCode)) {
|
||||
IDBDatabase* database = mTransaction->Database();
|
||||
NS_ASSERTION(database, "This should never be null!");
|
||||
|
||||
ContentParent* contentParent = database->GetContentParent();
|
||||
NS_ASSERTION(contentParent, "This should never be null!");
|
||||
|
||||
FileManager* fileManager = database->Manager();
|
||||
NS_ASSERTION(fileManager, "This should never be null!");
|
||||
|
||||
const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
|
||||
|
||||
aResultCode =
|
||||
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
|
||||
blobsParent);
|
||||
if (NS_FAILED(aResultCode)) {
|
||||
NS_WARNING("ConvertBlobsToActors failed!");
|
||||
}
|
||||
}
|
||||
|
||||
ResponseValue response;
|
||||
@ -890,6 +907,7 @@ ContinueHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
continueResponse.key() = mKey;
|
||||
continueResponse.objectKey() = mObjectKey;
|
||||
continueResponse.cloneInfo() = mCloneReadInfo;
|
||||
continueResponse.blobsParent().SwapElements(blobsParent);
|
||||
response = continueResponse;
|
||||
}
|
||||
|
||||
@ -925,6 +943,8 @@ ContinueHelper::UnpackResponseFromParentProcess(
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
IDBObjectStore::ConvertActorsToBlobs(response.blobsChild(),
|
||||
mCloneReadInfo.mFiles);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/storage.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsDOMLists.h"
|
||||
#include "nsJSUtils.h"
|
||||
@ -33,6 +34,7 @@
|
||||
#include "ipc/IndexedDBChild.h"
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
using mozilla::dom::ContentParent;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -170,7 +172,8 @@ already_AddRefed<IDBDatabase>
|
||||
IDBDatabase::Create(IDBWrapperCache* aOwnerCache,
|
||||
already_AddRefed<DatabaseInfo> aDatabaseInfo,
|
||||
const nsACString& aASCIIOrigin,
|
||||
FileManager* aFileManager)
|
||||
FileManager* aFileManager,
|
||||
mozilla::dom::ContentParent* aContentParent)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!");
|
||||
@ -191,6 +194,7 @@ IDBDatabase::Create(IDBWrapperCache* aOwnerCache,
|
||||
databaseInfo.swap(db->mDatabaseInfo);
|
||||
db->mASCIIOrigin = aASCIIOrigin;
|
||||
db->mFileManager = aFileManager;
|
||||
db->mContentParent = aContentParent;
|
||||
|
||||
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
|
||||
NS_ASSERTION(mgr, "This should never be null!");
|
||||
@ -207,6 +211,7 @@ IDBDatabase::IDBDatabase()
|
||||
: mDatabaseId(0),
|
||||
mActorChild(nullptr),
|
||||
mActorParent(nullptr),
|
||||
mContentParent(nullptr),
|
||||
mInvalidated(0),
|
||||
mRegistered(false),
|
||||
mClosed(false),
|
||||
|
@ -19,6 +19,12 @@
|
||||
class nsIScriptContext;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class AsyncConnectionHelper;
|
||||
@ -50,7 +56,8 @@ public:
|
||||
Create(IDBWrapperCache* aOwnerCache,
|
||||
already_AddRefed<DatabaseInfo> aDatabaseInfo,
|
||||
const nsACString& aASCIIOrigin,
|
||||
FileManager* aFileManager);
|
||||
FileManager* aFileManager,
|
||||
mozilla::dom::ContentParent* aContentParent);
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
|
||||
@ -135,6 +142,12 @@ public:
|
||||
return mActorChild;
|
||||
}
|
||||
|
||||
mozilla::dom::ContentParent*
|
||||
GetContentParent() const
|
||||
{
|
||||
return mContentParent;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreateObjectStoreInternal(IDBTransaction* aTransaction,
|
||||
const ObjectStoreInfoGuts& aInfo,
|
||||
@ -165,6 +178,8 @@ private:
|
||||
IndexedDBDatabaseChild* mActorChild;
|
||||
IndexedDBDatabaseParent* mActorParent;
|
||||
|
||||
mozilla::dom::ContentParent* mContentParent;
|
||||
|
||||
PRInt32 mInvalidated;
|
||||
bool mRegistered;
|
||||
bool mClosed;
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#include "IDBFactory.h"
|
||||
|
||||
#include "nsIFile.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsIPrincipal.h"
|
||||
@ -16,6 +15,7 @@
|
||||
#include "nsIXPCScriptable.h"
|
||||
|
||||
#include "jsdbgapi.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/PBrowserChild.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
@ -46,6 +46,7 @@
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
|
||||
using mozilla::dom::ContentChild;
|
||||
using mozilla::dom::ContentParent;
|
||||
using mozilla::dom::TabChild;
|
||||
|
||||
namespace {
|
||||
@ -63,7 +64,7 @@ struct ObjectStoreInfoMap
|
||||
|
||||
IDBFactory::IDBFactory()
|
||||
: mOwningObject(nullptr), mActorChild(nullptr), mActorParent(nullptr),
|
||||
mRootedOwningObject(false)
|
||||
mContentParent(nullptr), mRootedOwningObject(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -84,6 +85,7 @@ IDBFactory::~IDBFactory()
|
||||
nsresult
|
||||
IDBFactory::Create(nsPIDOMWindow* aWindow,
|
||||
const nsACString& aASCIIOrigin,
|
||||
ContentParent* aContentParent,
|
||||
IDBFactory** aFactory)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
@ -118,6 +120,7 @@ IDBFactory::Create(nsPIDOMWindow* aWindow,
|
||||
nsRefPtr<IDBFactory> factory = new IDBFactory();
|
||||
factory->mASCIIOrigin = origin;
|
||||
factory->mWindow = aWindow;
|
||||
factory->mContentParent = aContentParent;
|
||||
|
||||
if (!IndexedDatabaseManager::IsMainProcess()) {
|
||||
TabChild* tabChild = GetTabChildFrom(aWindow);
|
||||
@ -145,6 +148,7 @@ IDBFactory::Create(nsPIDOMWindow* aWindow,
|
||||
nsresult
|
||||
IDBFactory::Create(JSContext* aCx,
|
||||
JSObject* aOwningObject,
|
||||
ContentParent* aContentParent,
|
||||
IDBFactory** aFactory)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
@ -162,6 +166,7 @@ IDBFactory::Create(JSContext* aCx,
|
||||
nsRefPtr<IDBFactory> factory = new IDBFactory();
|
||||
factory->mASCIIOrigin = origin;
|
||||
factory->mOwningObject = aOwningObject;
|
||||
factory->mContentParent = aContentParent;
|
||||
|
||||
if (!IndexedDatabaseManager::IsMainProcess()) {
|
||||
ContentChild* contentChild = ContentChild::GetSingleton();
|
||||
@ -180,11 +185,13 @@ IDBFactory::Create(JSContext* aCx,
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IDBFactory::Create(IDBFactory** aFactory)
|
||||
IDBFactory::Create(ContentParent* aContentParent,
|
||||
IDBFactory** aFactory)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
|
||||
NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
|
||||
NS_ASSERTION(aContentParent, "Null ContentParent!");
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
@ -243,7 +250,7 @@ IDBFactory::Create(IDBFactory** aFactory)
|
||||
}
|
||||
|
||||
nsRefPtr<IDBFactory> factory;
|
||||
rv = Create(cx, global, getter_AddRefs(factory));
|
||||
rv = Create(cx, global, aContentParent, getter_AddRefs(factory));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_HOLD_JS_OBJECTS(factory, IDBFactory);
|
||||
@ -529,10 +536,10 @@ IDBFactory::OpenCommon(const nsAString& aName,
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (IndexedDatabaseManager::IsMainProcess()) {
|
||||
if (IndexedDatabaseManager::IsMainProcess()) {
|
||||
nsRefPtr<OpenDatabaseHelper> openHelper =
|
||||
new OpenDatabaseHelper(request, aName, mASCIIOrigin, aVersion, aDeleting,
|
||||
privilege);
|
||||
mContentParent, privilege);
|
||||
|
||||
rv = openHelper->Init();
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
@ -628,4 +635,4 @@ IDBFactory::Cmp(const jsval& aFirst,
|
||||
|
||||
*_retval = Key::CompareKeys(first, second);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
@ -17,6 +17,12 @@
|
||||
class nsIAtom;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
struct DatabaseInfo;
|
||||
@ -29,6 +35,7 @@ struct ObjectStoreInfo;
|
||||
|
||||
class IDBFactory MOZ_FINAL : public nsIIDBFactory
|
||||
{
|
||||
typedef mozilla::dom::ContentParent ContentParent;
|
||||
typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
|
||||
|
||||
public:
|
||||
@ -39,14 +46,17 @@ public:
|
||||
// Called when using IndexedDB from a window in a different process.
|
||||
static nsresult Create(nsPIDOMWindow* aWindow,
|
||||
const nsACString& aASCIIOrigin,
|
||||
ContentParent* aContentParent,
|
||||
IDBFactory** aFactory);
|
||||
|
||||
// Called when using IndexedDB from a window in the current process.
|
||||
static nsresult Create(nsPIDOMWindow* aWindow,
|
||||
ContentParent* aContentParent,
|
||||
nsIIDBFactory** aFactory)
|
||||
{
|
||||
nsRefPtr<IDBFactory> factory;
|
||||
nsresult rv = Create(aWindow, EmptyCString(), getter_AddRefs(factory));
|
||||
nsresult rv =
|
||||
Create(aWindow, EmptyCString(), aContentParent, getter_AddRefs(factory));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
factory.forget(aFactory);
|
||||
@ -57,11 +67,13 @@ public:
|
||||
// process.
|
||||
static nsresult Create(JSContext* aCx,
|
||||
JSObject* aOwningObject,
|
||||
ContentParent* aContentParent,
|
||||
IDBFactory** aFactory);
|
||||
|
||||
// Called when using IndexedDB from a JS component or a JSM in a different
|
||||
// process.
|
||||
static nsresult Create(IDBFactory** aFactory);
|
||||
static nsresult Create(ContentParent* aContentParent,
|
||||
IDBFactory** aFactory);
|
||||
|
||||
static already_AddRefed<mozIStorageConnection>
|
||||
GetConnection(const nsAString& aDatabaseFilePath);
|
||||
@ -118,6 +130,8 @@ private:
|
||||
IndexedDBChild* mActorChild;
|
||||
IndexedDBParent* mActorParent;
|
||||
|
||||
mozilla::dom::ContentParent* mContentParent;
|
||||
|
||||
bool mRootedOwningObject;
|
||||
};
|
||||
|
||||
|
@ -11,6 +11,9 @@
|
||||
#include "nsIIDBKeyRange.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ipc/Blob.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
@ -32,6 +35,7 @@
|
||||
#include "IndexedDatabaseInlines.h"
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::dom::indexedDB::ipc;
|
||||
|
||||
namespace {
|
||||
@ -634,6 +638,7 @@ IDBIndex::OpenCursorFromChildProcess(
|
||||
const Key& aKey,
|
||||
const Key& aObjectKey,
|
||||
const SerializedStructuredCloneReadInfo& aCloneInfo,
|
||||
nsTArray<StructuredCloneFile>& aBlobs,
|
||||
IDBCursor** _retval)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
@ -651,6 +656,8 @@ IDBIndex::OpenCursorFromChildProcess(
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
cloneInfo.mFiles.SwapElements(aBlobs);
|
||||
|
||||
nsRefPtr<IDBCursor> cursor =
|
||||
IDBCursor::Create(aRequest, mObjectStore->Transaction(), this, direction,
|
||||
Key(), EmptyCString(), EmptyCString(), aKey, aObjectKey,
|
||||
@ -1236,9 +1243,26 @@ GetHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
return Success_NotSent;
|
||||
}
|
||||
|
||||
if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
|
||||
NS_WARNING("No support for transferring blobs across processes yet!");
|
||||
return Error;
|
||||
InfallibleTArray<PBlobParent*> blobsParent;
|
||||
|
||||
if (NS_SUCCEEDED(aResultCode)) {
|
||||
IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
|
||||
NS_ASSERTION(database, "This should never be null!");
|
||||
|
||||
ContentParent* contentParent = database->GetContentParent();
|
||||
NS_ASSERTION(contentParent, "This should never be null!");
|
||||
|
||||
FileManager* fileManager = database->Manager();
|
||||
NS_ASSERTION(fileManager, "This should never be null!");
|
||||
|
||||
const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
|
||||
|
||||
aResultCode =
|
||||
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
|
||||
blobsParent);
|
||||
if (NS_FAILED(aResultCode)) {
|
||||
NS_WARNING("ConvertBlobActors failed!");
|
||||
}
|
||||
}
|
||||
|
||||
ResponseValue response;
|
||||
@ -1246,9 +1270,9 @@ GetHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
response = aResultCode;
|
||||
}
|
||||
else {
|
||||
SerializedStructuredCloneReadInfo readInfo;
|
||||
readInfo = mCloneReadInfo;
|
||||
GetResponse getResponse = readInfo;
|
||||
GetResponse getResponse;
|
||||
getResponse.cloneInfo() = mCloneReadInfo;
|
||||
getResponse.blobsParent().SwapElements(blobsParent);
|
||||
response = getResponse;
|
||||
}
|
||||
|
||||
@ -1265,8 +1289,8 @@ GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
|
||||
NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetResponse,
|
||||
"Bad response type!");
|
||||
|
||||
const SerializedStructuredCloneReadInfo& cloneInfo =
|
||||
aResponseValue.get_GetResponse().cloneInfo();
|
||||
const GetResponse& getResponse = aResponseValue.get_GetResponse();
|
||||
const SerializedStructuredCloneReadInfo& cloneInfo = getResponse.cloneInfo();
|
||||
|
||||
NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
|
||||
(cloneInfo.dataLength && cloneInfo.data),
|
||||
@ -1277,6 +1301,8 @@ GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(),
|
||||
mCloneReadInfo.mFiles);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1567,10 +1593,50 @@ GetAllHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
return Success_NotSent;
|
||||
}
|
||||
|
||||
for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
|
||||
if (!mCloneReadInfos[index].mFileInfos.IsEmpty()) {
|
||||
NS_WARNING("No support for transferring blobs across processes yet!");
|
||||
return Error;
|
||||
GetAllResponse getAllResponse;
|
||||
|
||||
if (NS_SUCCEEDED(aResultCode) && !mCloneReadInfos.IsEmpty()) {
|
||||
IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
|
||||
NS_ASSERTION(database, "This should never be null!");
|
||||
|
||||
ContentParent* contentParent = database->GetContentParent();
|
||||
NS_ASSERTION(contentParent, "This should never be null!");
|
||||
|
||||
FileManager* fileManager = database->Manager();
|
||||
NS_ASSERTION(fileManager, "This should never be null!");
|
||||
|
||||
PRUint32 length = mCloneReadInfos.Length();
|
||||
|
||||
InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
|
||||
getAllResponse.cloneInfos();
|
||||
infos.SetCapacity(length);
|
||||
|
||||
InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
|
||||
blobArrays.SetCapacity(length);
|
||||
|
||||
for (PRUint32 index = 0;
|
||||
NS_SUCCEEDED(aResultCode) && index < length;
|
||||
index++) {
|
||||
const StructuredCloneReadInfo& clone = mCloneReadInfos[index];
|
||||
|
||||
// Append the structured clone data.
|
||||
SerializedStructuredCloneReadInfo* info = infos.AppendElement();
|
||||
*info = clone;
|
||||
|
||||
const nsTArray<StructuredCloneFile>& files = clone.mFiles;
|
||||
|
||||
// Now take care of the files.
|
||||
BlobArray* blobArray = blobArrays.AppendElement();
|
||||
|
||||
InfallibleTArray<PBlobParent*>& blobs = blobArray->blobsParent();
|
||||
|
||||
aResultCode =
|
||||
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
|
||||
blobs);
|
||||
if (NS_FAILED(aResultCode)) {
|
||||
NS_WARNING("ConvertBlobsToActors failed!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1579,18 +1645,6 @@ GetAllHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
response = aResultCode;
|
||||
}
|
||||
else {
|
||||
GetAllResponse getAllResponse;
|
||||
|
||||
InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
|
||||
getAllResponse.cloneInfos();
|
||||
|
||||
infos.SetCapacity(mCloneReadInfos.Length());
|
||||
|
||||
for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
|
||||
SerializedStructuredCloneReadInfo* info = infos.AppendElement();
|
||||
*info = mCloneReadInfos[index];
|
||||
}
|
||||
|
||||
response = getAllResponse;
|
||||
}
|
||||
|
||||
@ -1608,19 +1662,24 @@ GetAllHelper::UnpackResponseFromParentProcess(
|
||||
NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetAllResponse,
|
||||
"Bad response type!");
|
||||
|
||||
const GetAllResponse& getAllResponse = aResponseValue.get_GetAllResponse();
|
||||
const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
|
||||
aResponseValue.get_GetAllResponse().cloneInfos();
|
||||
getAllResponse.cloneInfos();
|
||||
const InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
|
||||
|
||||
mCloneReadInfos.SetCapacity(cloneInfos.Length());
|
||||
|
||||
for (PRUint32 index = 0; index < cloneInfos.Length(); index++) {
|
||||
const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
|
||||
const InfallibleTArray<PBlobChild*> blobs = blobArrays[index].blobsChild();
|
||||
|
||||
StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
|
||||
if (!destInfo->SetFromSerialized(srcInfo)) {
|
||||
NS_WARNING("Failed to copy clone buffer!");
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -2199,13 +2258,30 @@ OpenCursorHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
return Success_NotSent;
|
||||
}
|
||||
|
||||
if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
|
||||
NS_WARNING("No support for transferring blobs across processes yet!");
|
||||
return Error;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
|
||||
|
||||
InfallibleTArray<PBlobParent*> blobsParent;
|
||||
|
||||
if (NS_SUCCEEDED(aResultCode)) {
|
||||
IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
|
||||
NS_ASSERTION(database, "This should never be null!");
|
||||
|
||||
ContentParent* contentParent = database->GetContentParent();
|
||||
NS_ASSERTION(contentParent, "This should never be null!");
|
||||
|
||||
FileManager* fileManager = database->Manager();
|
||||
NS_ASSERTION(fileManager, "This should never be null!");
|
||||
|
||||
const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
|
||||
|
||||
aResultCode =
|
||||
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
|
||||
blobsParent);
|
||||
if (NS_FAILED(aResultCode)) {
|
||||
NS_WARNING("ConvertBlobsToActors failed!");
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(aResultCode)) {
|
||||
nsresult rv = EnsureCursor();
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -2241,6 +2317,7 @@ OpenCursorHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
params.key() = mKey;
|
||||
params.objectKey() = mObjectKey;
|
||||
params.optionalCloneInfo() = mSerializedCloneReadInfo;
|
||||
params.blobsParent().SwapElements(blobsParent);
|
||||
|
||||
IndexedDBCursorParent* cursorActor = new IndexedDBCursorParent(mCursor);
|
||||
|
||||
|
@ -145,6 +145,7 @@ public:
|
||||
const Key& aKey,
|
||||
const Key& aObjectKey,
|
||||
const SerializedStructuredCloneReadInfo& aCloneInfo,
|
||||
nsTArray<StructuredCloneFile>& aBlobs,
|
||||
IDBCursor** _retval);
|
||||
|
||||
private:
|
||||
|
@ -12,7 +12,10 @@
|
||||
#include "nsIOutputStream.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/ipc/Blob.h"
|
||||
#include "mozilla/storage.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
@ -45,6 +48,7 @@
|
||||
#define FILE_COPY_BUFFER_SIZE 32768
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::dom::indexedDB::ipc;
|
||||
|
||||
namespace {
|
||||
@ -881,7 +885,8 @@ IDBObjectStore::GetStructuredCloneReadInfoFromStatement(
|
||||
nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(id);
|
||||
NS_ASSERTION(fileInfo, "Null file info!");
|
||||
|
||||
aInfo.mFileInfos.AppendElement(fileInfo);
|
||||
StructuredCloneFile* file = aInfo.mFiles.AppendElement();
|
||||
file->mFileInfo.swap(fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -954,9 +959,9 @@ static inline PRUint32
|
||||
SwapBytes(PRUint32 u)
|
||||
{
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
return ((u & 0x000000ffU) << 24) |
|
||||
((u & 0x0000ff00U) << 8) |
|
||||
((u & 0x00ff0000U) >> 8) |
|
||||
return ((u & 0x000000ffU) << 24) |
|
||||
((u & 0x0000ff00U) << 8) |
|
||||
((u & 0x00ff0000U) >> 8) |
|
||||
((u & 0xff000000U) >> 24);
|
||||
#else
|
||||
return u;
|
||||
@ -1005,6 +1010,7 @@ StructuredCloneReadString(JSStructuredCloneReader* aReader,
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
JSObject*
|
||||
IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader,
|
||||
@ -1017,12 +1023,15 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
||||
StructuredCloneReadInfo* cloneReadInfo =
|
||||
reinterpret_cast<StructuredCloneReadInfo*>(aClosure);
|
||||
|
||||
if (aData >= cloneReadInfo->mFileInfos.Length()) {
|
||||
if (aData >= cloneReadInfo->mFiles.Length()) {
|
||||
NS_ERROR("Bad blob index!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FileInfo> fileInfo = cloneReadInfo->mFileInfos[aData];
|
||||
nsresult rv;
|
||||
|
||||
StructuredCloneFile& file = cloneReadInfo->mFiles[aData];
|
||||
nsRefPtr<FileInfo>& fileInfo = file.mFileInfo;
|
||||
IDBDatabase* database = cloneReadInfo->mDatabase;
|
||||
|
||||
if (aTag == SCTAG_DOM_FILEHANDLE) {
|
||||
@ -1042,7 +1051,7 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
||||
convName, convType, fileInfo.forget());
|
||||
|
||||
jsval wrappedFileHandle;
|
||||
nsresult rv =
|
||||
rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx),
|
||||
static_cast<nsIDOMFileHandle*>(fileHandle),
|
||||
&NS_GET_IID(nsIDOMFileHandle),
|
||||
@ -1055,21 +1064,6 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
||||
return JSVAL_TO_OBJECT(wrappedFileHandle);
|
||||
}
|
||||
|
||||
FileManager* fileManager = database->Manager();
|
||||
|
||||
nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
|
||||
if (!directory) {
|
||||
NS_WARNING("Failed to get directory!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> nativeFile =
|
||||
fileManager->GetFileForId(directory, fileInfo->Id());
|
||||
if (!nativeFile) {
|
||||
NS_WARNING("Failed to get file!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PRUint64 size;
|
||||
if (!JS_ReadBytes(aReader, &size, sizeof(PRUint64))) {
|
||||
NS_WARNING("Failed to read size!");
|
||||
@ -1083,13 +1077,36 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 convType(type);
|
||||
|
||||
nsCOMPtr<nsIFile> nativeFile;
|
||||
if (!file.mFile) {
|
||||
FileManager* fileManager = database->Manager();
|
||||
NS_ASSERTION(fileManager, "This should never be null!");
|
||||
|
||||
nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
|
||||
if (!directory) {
|
||||
NS_WARNING("Failed to get directory!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nativeFile = fileManager->GetFileForId(directory, fileInfo->Id());
|
||||
if (!nativeFile) {
|
||||
NS_WARNING("Failed to get file!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_BLOB) {
|
||||
nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(convType, size,
|
||||
nativeFile, fileInfo);
|
||||
nsCOMPtr<nsIDOMBlob> domBlob;
|
||||
if (file.mFile) {
|
||||
domBlob = file.mFile;
|
||||
}
|
||||
else {
|
||||
domBlob = new nsDOMFileFile(convType, size, nativeFile, fileInfo);
|
||||
}
|
||||
|
||||
jsval wrappedBlob;
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), blob,
|
||||
rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domBlob,
|
||||
&NS_GET_IID(nsIDOMBlob), &wrappedBlob);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to wrap native!");
|
||||
@ -1099,18 +1116,27 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
||||
return JSVAL_TO_OBJECT(wrappedBlob);
|
||||
}
|
||||
|
||||
NS_ASSERTION(aTag == SCTAG_DOM_FILE, "Huh?!");
|
||||
|
||||
nsCString name;
|
||||
if (!StructuredCloneReadString(aReader, name)) {
|
||||
return nullptr;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 convName(name);
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = new nsDOMFileFile(convName, convType, size,
|
||||
nativeFile, fileInfo);
|
||||
nsCOMPtr<nsIDOMFile> domFile;
|
||||
if (file.mFile) {
|
||||
domFile = do_QueryInterface(file.mFile);
|
||||
NS_ASSERTION(domFile, "This should never fail!");
|
||||
}
|
||||
else {
|
||||
domFile = new nsDOMFileFile(convName, convType, size, nativeFile,
|
||||
fileInfo);
|
||||
}
|
||||
|
||||
jsval wrappedFile;
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), file,
|
||||
rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domFile,
|
||||
&NS_GET_IID(nsIDOMFile), &wrappedFile);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to wrap native!");
|
||||
@ -1130,6 +1156,7 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
JSBool
|
||||
IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
JSStructuredCloneWriter* aWriter,
|
||||
@ -1160,29 +1187,28 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
|
||||
if (blob) {
|
||||
// Check if it is a blob created from this db or the blob was already
|
||||
// stored in this db
|
||||
|
||||
nsRefPtr<FileInfo> fileInfo = transaction->GetFileInfo(blob);
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
|
||||
if (!fileInfo) {
|
||||
// Check if it is a blob created from this db or the blob was already
|
||||
// stored in this db
|
||||
nsRefPtr<FileInfo> fileInfo = transaction->GetFileInfo(blob);
|
||||
if (!fileInfo && fileManager) {
|
||||
fileInfo = blob->GetFileInfo(fileManager);
|
||||
}
|
||||
|
||||
if (!fileInfo) {
|
||||
fileInfo = fileManager->GetNewFileInfo();
|
||||
if (!fileInfo) {
|
||||
NS_WARNING("Failed to get new file info!");
|
||||
return false;
|
||||
}
|
||||
fileInfo = fileManager->GetNewFileInfo();
|
||||
if (!fileInfo) {
|
||||
NS_WARNING("Failed to get new file info!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) {
|
||||
NS_WARNING("Failed to get internal steam!");
|
||||
return false;
|
||||
}
|
||||
if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) {
|
||||
NS_WARNING("Failed to get internal steam!");
|
||||
return false;
|
||||
}
|
||||
|
||||
transaction->AddFileInfo(blob, fileInfo);
|
||||
transaction->AddFileInfo(blob, fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
PRUint64 size;
|
||||
@ -1204,8 +1230,8 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
|
||||
if (!JS_WriteUint32Pair(aWriter, file ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB,
|
||||
cloneWriteInfo->mFiles.Length()) ||
|
||||
!JS_WriteBytes(aWriter, &size, sizeof(PRUint64)) ||
|
||||
!JS_WriteBytes(aWriter, &convTypeLength, sizeof(PRUint32)) ||
|
||||
!JS_WriteBytes(aWriter, &size, sizeof(size)) ||
|
||||
!JS_WriteBytes(aWriter, &convTypeLength, sizeof(convTypeLength)) ||
|
||||
!JS_WriteBytes(aWriter, convType.get(), convType.Length())) {
|
||||
return false;
|
||||
}
|
||||
@ -1219,7 +1245,7 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
NS_ConvertUTF16toUTF8 convName(name);
|
||||
PRUint32 convNameLength = SwapBytes(convName.Length());
|
||||
|
||||
if (!JS_WriteBytes(aWriter, &convNameLength, sizeof(PRUint32)) ||
|
||||
if (!JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) ||
|
||||
!JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
|
||||
return false;
|
||||
}
|
||||
@ -1285,6 +1311,7 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IDBObjectStore::ConvertFileIdsToArray(const nsAString& aFileIds,
|
||||
nsTArray<PRInt64>& aResult)
|
||||
@ -1307,6 +1334,79 @@ IDBObjectStore::ConvertFileIdsToArray(const nsAString& aFileIds,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IDBObjectStore::ConvertActorsToBlobs(
|
||||
const InfallibleTArray<PBlobChild*>& aActors,
|
||||
nsTArray<StructuredCloneFile>& aFiles)
|
||||
{
|
||||
NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aFiles.IsEmpty(), "Should be empty!");
|
||||
|
||||
if (!aActors.IsEmpty()) {
|
||||
ContentChild* contentChild = ContentChild::GetSingleton();
|
||||
NS_ASSERTION(contentChild, "This should never be null!");
|
||||
|
||||
PRUint32 length = aActors.Length();
|
||||
aFiles.SetCapacity(length);
|
||||
|
||||
for (PRUint32 index = 0; index < length; index++) {
|
||||
BlobChild* actor = static_cast<BlobChild*>(aActors[index]);
|
||||
|
||||
StructuredCloneFile* file = aFiles.AppendElement();
|
||||
file->mFile = actor->GetBlob();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IDBObjectStore::ConvertBlobsToActors(
|
||||
ContentParent* aContentParent,
|
||||
FileManager* aFileManager,
|
||||
const nsTArray<StructuredCloneFile>& aFiles,
|
||||
InfallibleTArray<PBlobParent*>& aActors)
|
||||
{
|
||||
NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aContentParent, "Null contentParent!");
|
||||
NS_ASSERTION(aFileManager, "Null file manager!");
|
||||
|
||||
if (!aFiles.IsEmpty()) {
|
||||
nsCOMPtr<nsIFile> directory = aFileManager->GetDirectory();
|
||||
if (!directory) {
|
||||
NS_WARNING("Failed to get directory!");
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
PRUint32 fileCount = aFiles.Length();
|
||||
aActors.SetCapacity(fileCount);
|
||||
|
||||
for (PRUint32 index = 0; index < fileCount; index++) {
|
||||
const StructuredCloneFile& file = aFiles[index];
|
||||
NS_ASSERTION(file.mFileInfo, "This should never be null!");
|
||||
|
||||
nsCOMPtr<nsIFile> nativeFile =
|
||||
aFileManager->GetFileForId(directory, file.mFileInfo->Id());
|
||||
if (!nativeFile) {
|
||||
NS_WARNING("Failed to get file!");
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(nativeFile);
|
||||
|
||||
BlobParent* actor =
|
||||
aContentParent->GetOrCreateActorForBlob(blob);
|
||||
NS_ASSERTION(actor, "This should never fail without aborting!");
|
||||
|
||||
aActors.AppendElement(actor);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
IDBObjectStore::IDBObjectStore()
|
||||
: mId(LL_MININT),
|
||||
mKeyPath(0),
|
||||
@ -1448,6 +1548,7 @@ IDBObjectStore::AddOrPutInternal(
|
||||
const SerializedStructuredCloneWriteInfo& aCloneWriteInfo,
|
||||
const Key& aKey,
|
||||
const InfallibleTArray<IndexUpdateInfo>& aUpdateInfoArray,
|
||||
const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs,
|
||||
bool aOverwrite,
|
||||
IDBRequest** _retval)
|
||||
{
|
||||
@ -1471,6 +1572,48 @@ IDBObjectStore::AddOrPutInternal(
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
if (!aBlobs.IsEmpty()) {
|
||||
FileManager* fileManager = Transaction()->Database()->Manager();
|
||||
NS_ASSERTION(fileManager, "Null file manager?!");
|
||||
|
||||
PRUint32 length = aBlobs.Length();
|
||||
cloneWriteInfo.mFiles.SetCapacity(length);
|
||||
|
||||
for (PRUint32 index = 0; index < length; index++) {
|
||||
const nsCOMPtr<nsIDOMBlob>& blob = aBlobs[index];
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
|
||||
nsRefPtr<FileInfo> fileInfo = Transaction()->GetFileInfo(blob);
|
||||
if (!fileInfo) {
|
||||
fileInfo = blob->GetFileInfo(fileManager);
|
||||
|
||||
if (!fileInfo) {
|
||||
fileInfo = fileManager->GetNewFileInfo();
|
||||
if (!fileInfo) {
|
||||
NS_WARNING("Failed to get new file info!");
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) {
|
||||
NS_WARNING("Failed to get internal steam!");
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
// XXXbent This is where we should send a message back to the child to
|
||||
// update the file id.
|
||||
|
||||
Transaction()->AddFileInfo(blob, fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
StructuredCloneFile* file = cloneWriteInfo.mFiles.AppendElement();
|
||||
file->mFile = blob;
|
||||
file->mFileInfo.swap(fileInfo);
|
||||
file->mInputStream.swap(inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
Key key(aKey);
|
||||
|
||||
nsTArray<IndexUpdateInfo> updateInfo(aUpdateInfoArray);
|
||||
@ -1648,6 +1791,7 @@ IDBObjectStore::OpenCursorFromChildProcess(
|
||||
size_t aDirection,
|
||||
const Key& aKey,
|
||||
const SerializedStructuredCloneReadInfo& aCloneInfo,
|
||||
nsTArray<StructuredCloneFile>& aBlobs,
|
||||
IDBCursor** _retval)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
@ -1665,6 +1809,8 @@ IDBObjectStore::OpenCursorFromChildProcess(
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
cloneInfo.mFiles.SwapElements(aBlobs);
|
||||
|
||||
nsRefPtr<IDBCursor> cursor =
|
||||
IDBCursor::Create(aRequest, mTransaction, this, direction, Key(),
|
||||
EmptyCString(), EmptyCString(), aKey, cloneInfo);
|
||||
@ -2546,6 +2692,31 @@ AddHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
|
||||
commonParams.key() = mKey;
|
||||
commonParams.indexUpdateInfos().AppendElements(mIndexUpdateInfo);
|
||||
|
||||
const nsTArray<StructuredCloneFile>& files = mCloneWriteInfo.mFiles;
|
||||
|
||||
if (!files.IsEmpty()) {
|
||||
PRUint32 fileCount = files.Length();
|
||||
|
||||
InfallibleTArray<PBlobChild*>& blobsChild = commonParams.blobsChild();
|
||||
blobsChild.SetCapacity(fileCount);
|
||||
|
||||
ContentChild* contentChild = ContentChild::GetSingleton();
|
||||
NS_ASSERTION(contentChild, "This should never be null!");
|
||||
|
||||
for (PRUint32 index = 0; index < fileCount; index++) {
|
||||
const StructuredCloneFile& file = files[index];
|
||||
|
||||
NS_ASSERTION(file.mFile, "This should never be null!");
|
||||
NS_ASSERTION(!file.mFileInfo, "This is not yet supported!");
|
||||
|
||||
BlobChild* actor =
|
||||
contentChild->GetOrCreateActorForBlob(file.mFile);
|
||||
NS_ASSERTION(actor, "This should never fail without aborting!");
|
||||
|
||||
blobsChild.AppendElement(actor);
|
||||
}
|
||||
}
|
||||
|
||||
if (mOverwrite) {
|
||||
PutParams putParams;
|
||||
putParams.commonParams() = commonParams;
|
||||
@ -2690,9 +2861,26 @@ GetHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
return Success_NotSent;
|
||||
}
|
||||
|
||||
if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
|
||||
NS_WARNING("No support for transferring blobs across processes yet!");
|
||||
return Error;
|
||||
InfallibleTArray<PBlobParent*> blobsParent;
|
||||
|
||||
if (NS_SUCCEEDED(aResultCode)) {
|
||||
IDBDatabase* database = mObjectStore->Transaction()->Database();
|
||||
NS_ASSERTION(database, "This should never be null!");
|
||||
|
||||
ContentParent* contentParent = database->GetContentParent();
|
||||
NS_ASSERTION(contentParent, "This should never be null!");
|
||||
|
||||
FileManager* fileManager = database->Manager();
|
||||
NS_ASSERTION(fileManager, "This should never be null!");
|
||||
|
||||
const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
|
||||
|
||||
aResultCode =
|
||||
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
|
||||
blobsParent);
|
||||
if (NS_FAILED(aResultCode)) {
|
||||
NS_WARNING("ConvertBlobsToActors failed!");
|
||||
}
|
||||
}
|
||||
|
||||
ResponseValue response;
|
||||
@ -2700,9 +2888,9 @@ GetHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
response = aResultCode;
|
||||
}
|
||||
else {
|
||||
SerializedStructuredCloneReadInfo readInfo;
|
||||
readInfo = mCloneReadInfo;
|
||||
GetResponse getResponse = readInfo;
|
||||
GetResponse getResponse;
|
||||
getResponse.cloneInfo() = mCloneReadInfo;
|
||||
getResponse.blobsParent().SwapElements(blobsParent);
|
||||
response = getResponse;
|
||||
}
|
||||
|
||||
@ -2719,8 +2907,8 @@ GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
|
||||
NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetResponse,
|
||||
"Bad response type!");
|
||||
|
||||
const SerializedStructuredCloneReadInfo& cloneInfo =
|
||||
aResponseValue.get_GetResponse().cloneInfo();
|
||||
const GetResponse& getResponse = aResponseValue.get_GetResponse();
|
||||
const SerializedStructuredCloneReadInfo& cloneInfo = getResponse.cloneInfo();
|
||||
|
||||
NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
|
||||
(cloneInfo.dataLength && cloneInfo.data),
|
||||
@ -2731,6 +2919,8 @@ GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(),
|
||||
mCloneReadInfo.mFiles);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -3099,13 +3289,30 @@ OpenCursorHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
return Success_NotSent;
|
||||
}
|
||||
|
||||
if (!mCloneReadInfo.mFileInfos.IsEmpty()) {
|
||||
NS_WARNING("No support for transferring blobs across processes yet!");
|
||||
return Error;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
|
||||
|
||||
InfallibleTArray<PBlobParent*> blobsParent;
|
||||
|
||||
if (NS_SUCCEEDED(aResultCode)) {
|
||||
IDBDatabase* database = mObjectStore->Transaction()->Database();
|
||||
NS_ASSERTION(database, "This should never be null!");
|
||||
|
||||
ContentParent* contentParent = database->GetContentParent();
|
||||
NS_ASSERTION(contentParent, "This should never be null!");
|
||||
|
||||
FileManager* fileManager = database->Manager();
|
||||
NS_ASSERTION(fileManager, "This should never be null!");
|
||||
|
||||
const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
|
||||
|
||||
aResultCode =
|
||||
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
|
||||
blobsParent);
|
||||
if (NS_FAILED(aResultCode)) {
|
||||
NS_WARNING("ConvertBlobsToActors failed!");
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(aResultCode)) {
|
||||
nsresult rv = EnsureCursor();
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -3141,6 +3348,7 @@ OpenCursorHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
params.direction() = mDirection;
|
||||
params.key() = mKey;
|
||||
params.cloneInfo() = mSerializedCloneReadInfo;
|
||||
params.blobsParent().SwapElements(blobsParent);
|
||||
|
||||
IndexedDBCursorParent* cursorActor = new IndexedDBCursorParent(mCursor);
|
||||
|
||||
@ -3525,10 +3733,47 @@ GetAllHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
return Success_NotSent;
|
||||
}
|
||||
|
||||
for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
|
||||
if (!mCloneReadInfos[index].mFileInfos.IsEmpty()) {
|
||||
NS_WARNING("No support for transferring blobs across processes yet!");
|
||||
return Error;
|
||||
GetAllResponse getAllResponse;
|
||||
|
||||
if (NS_SUCCEEDED(aResultCode) && !mCloneReadInfos.IsEmpty()) {
|
||||
IDBDatabase* database = mObjectStore->Transaction()->Database();
|
||||
NS_ASSERTION(database, "This should never be null!");
|
||||
|
||||
ContentParent* contentParent = database->GetContentParent();
|
||||
NS_ASSERTION(contentParent, "This should never be null!");
|
||||
|
||||
FileManager* fileManager = database->Manager();
|
||||
NS_ASSERTION(fileManager, "This should never be null!");
|
||||
|
||||
PRUint32 length = mCloneReadInfos.Length();
|
||||
|
||||
InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
|
||||
getAllResponse.cloneInfos();
|
||||
infos.SetCapacity(length);
|
||||
|
||||
InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
|
||||
blobArrays.SetCapacity(length);
|
||||
|
||||
for (PRUint32 index = 0;
|
||||
NS_SUCCEEDED(aResultCode) && index < length;
|
||||
index++) {
|
||||
// Append the structured clone data.
|
||||
const StructuredCloneReadInfo& clone = mCloneReadInfos[index];
|
||||
SerializedStructuredCloneReadInfo* info = infos.AppendElement();
|
||||
*info = clone;
|
||||
|
||||
// Now take care of the files.
|
||||
const nsTArray<StructuredCloneFile>& files = clone.mFiles;
|
||||
BlobArray* blobArray = blobArrays.AppendElement();
|
||||
InfallibleTArray<PBlobParent*>& blobs = blobArray->blobsParent();
|
||||
|
||||
aResultCode =
|
||||
IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
|
||||
blobs);
|
||||
if (NS_FAILED(aResultCode)) {
|
||||
NS_WARNING("ConvertBlobsToActors failed!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3537,19 +3782,6 @@ GetAllHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
|
||||
response = aResultCode;
|
||||
}
|
||||
else {
|
||||
GetAllResponse getAllResponse;
|
||||
|
||||
InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
|
||||
getAllResponse.cloneInfos();
|
||||
|
||||
infos.SetCapacity(mCloneReadInfos.Length());
|
||||
|
||||
for (PRUint32 index = 0; index < mCloneReadInfos.Length(); index++) {
|
||||
SerializedStructuredCloneReadInfo* info = infos.AppendElement();
|
||||
*info = mCloneReadInfos[index];
|
||||
}
|
||||
|
||||
getAllResponse = infos;
|
||||
response = getAllResponse;
|
||||
}
|
||||
|
||||
@ -3567,19 +3799,24 @@ GetAllHelper::UnpackResponseFromParentProcess(
|
||||
NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetAllResponse,
|
||||
"Bad response type!");
|
||||
|
||||
const GetAllResponse& getAllResponse = aResponseValue.get_GetAllResponse();
|
||||
const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
|
||||
aResponseValue.get_GetAllResponse().cloneInfos();
|
||||
getAllResponse.cloneInfos();
|
||||
const InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
|
||||
|
||||
mCloneReadInfos.SetCapacity(cloneInfos.Length());
|
||||
|
||||
for (PRUint32 index = 0; index < cloneInfos.Length(); index++) {
|
||||
const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
|
||||
const InfallibleTArray<PBlobChild*> blobs = blobArrays[index].blobsChild();
|
||||
|
||||
StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
|
||||
if (!destInfo->SetFromSerialized(srcInfo)) {
|
||||
NS_WARNING("Failed to copy clone buffer!");
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -17,12 +17,22 @@
|
||||
#include "mozilla/dom/indexedDB/IDBTransaction.h"
|
||||
#include "mozilla/dom/indexedDB/KeyPath.h"
|
||||
|
||||
class nsIDOMBlob;
|
||||
class nsIScriptContext;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
class PBlobChild;
|
||||
class PBlobParent;
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class AsyncConnectionHelper;
|
||||
class FileManager;
|
||||
class IDBCursor;
|
||||
class IDBKeyRange;
|
||||
class IDBRequest;
|
||||
@ -33,8 +43,6 @@ class Key;
|
||||
struct IndexInfo;
|
||||
struct IndexUpdateInfo;
|
||||
struct ObjectStoreInfo;
|
||||
struct StructuredCloneReadInfo;
|
||||
struct StructuredCloneWriteInfo;
|
||||
|
||||
class IDBObjectStore MOZ_FINAL : public nsIIDBObjectStore
|
||||
{
|
||||
@ -103,6 +111,18 @@ public:
|
||||
ConvertFileIdsToArray(const nsAString& aFileIds,
|
||||
nsTArray<PRInt64>& aResult);
|
||||
|
||||
// Called only in the main process.
|
||||
static nsresult
|
||||
ConvertBlobsToActors(ContentParent* aContentParent,
|
||||
FileManager* aFileManager,
|
||||
const nsTArray<StructuredCloneFile>& aFiles,
|
||||
InfallibleTArray<PBlobParent*>& aActors);
|
||||
|
||||
// Called only in the child process.
|
||||
static void
|
||||
ConvertActorsToBlobs(const InfallibleTArray<PBlobChild*>& aActors,
|
||||
nsTArray<StructuredCloneFile>& aFiles);
|
||||
|
||||
const nsString& Name() const
|
||||
{
|
||||
return mName;
|
||||
@ -183,6 +203,7 @@ public:
|
||||
const SerializedStructuredCloneWriteInfo& aCloneWriteInfo,
|
||||
const Key& aKey,
|
||||
const InfallibleTArray<IndexUpdateInfo>& aUpdateInfoArray,
|
||||
const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs,
|
||||
bool aOverwrite,
|
||||
IDBRequest** _retval);
|
||||
|
||||
@ -216,6 +237,7 @@ public:
|
||||
size_t aDirection,
|
||||
const Key& aKey,
|
||||
const SerializedStructuredCloneReadInfo& aCloneInfo,
|
||||
nsTArray<StructuredCloneFile>& aBlobs,
|
||||
IDBCursor** _retval);
|
||||
|
||||
void
|
||||
|
@ -49,6 +49,20 @@ void SwapData(T& aData1, T& aData2)
|
||||
aData1 = temp;
|
||||
}
|
||||
|
||||
struct StructuredCloneFile
|
||||
{
|
||||
bool operator==(const StructuredCloneFile& aOther) const
|
||||
{
|
||||
return this->mFile == aOther.mFile &&
|
||||
this->mFileInfo == aOther.mFileInfo &&
|
||||
this->mInputStream == aOther.mInputStream;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> mFile;
|
||||
nsRefPtr<FileInfo> mFileInfo;
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
};
|
||||
|
||||
struct SerializedStructuredCloneReadInfo;
|
||||
|
||||
struct StructuredCloneReadInfo
|
||||
@ -59,7 +73,7 @@ struct StructuredCloneReadInfo
|
||||
void Swap(StructuredCloneReadInfo& aCloneReadInfo)
|
||||
{
|
||||
mCloneBuffer.swap(aCloneReadInfo.mCloneBuffer);
|
||||
mFileInfos.SwapElements(aCloneReadInfo.mFileInfos);
|
||||
mFiles.SwapElements(aCloneReadInfo.mFiles);
|
||||
SwapData(mDatabase, aCloneReadInfo.mDatabase);
|
||||
}
|
||||
|
||||
@ -68,7 +82,7 @@ struct StructuredCloneReadInfo
|
||||
SetFromSerialized(const SerializedStructuredCloneReadInfo& aOther);
|
||||
|
||||
JSAutoStructuredCloneBuffer mCloneBuffer;
|
||||
nsTArray<nsRefPtr<FileInfo> > mFileInfos;
|
||||
nsTArray<StructuredCloneFile> mFiles;
|
||||
IDBDatabase* mDatabase;
|
||||
};
|
||||
|
||||
@ -98,20 +112,6 @@ struct SerializedStructuredCloneReadInfo
|
||||
size_t dataLength;
|
||||
};
|
||||
|
||||
struct StructuredCloneFile
|
||||
{
|
||||
bool operator==(const StructuredCloneFile& aOther) const
|
||||
{
|
||||
return this->mFile == aOther.mFile &&
|
||||
this->mFileInfo == aOther.mFileInfo &&
|
||||
this->mInputStream == aOther.mInputStream;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> mFile;
|
||||
nsRefPtr<FileInfo> mFileInfo;
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
};
|
||||
|
||||
struct SerializedStructuredCloneWriteInfo;
|
||||
|
||||
struct StructuredCloneWriteInfo
|
||||
|
@ -50,7 +50,7 @@ StructuredCloneReadInfo::SetFromSerialized(
|
||||
return false;
|
||||
}
|
||||
|
||||
mFileInfos.Clear();
|
||||
mFiles.Clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -217,9 +217,11 @@ IndexedDatabaseManager::GetOrCreate()
|
||||
|
||||
if (sIsMainProcess) {
|
||||
nsCOMPtr<nsIFile> dbBaseDirectory;
|
||||
rv = NS_GetSpecialDirectory(NS_APP_INDEXEDDB_PARENT_DIR, getter_AddRefs(dbBaseDirectory));
|
||||
rv = NS_GetSpecialDirectory(NS_APP_INDEXEDDB_PARENT_DIR,
|
||||
getter_AddRefs(dbBaseDirectory));
|
||||
if (NS_FAILED(rv)) {
|
||||
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(dbBaseDirectory));
|
||||
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(dbBaseDirectory));
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
@ -231,9 +233,10 @@ IndexedDatabaseManager::GetOrCreate()
|
||||
|
||||
// Make a lazy thread for any IO we need (like clearing or enumerating the
|
||||
// contents of indexedDB database directories).
|
||||
instance->mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
|
||||
NS_LITERAL_CSTRING("IndexedDB I/O"),
|
||||
LazyIdleThread::ManualShutdown);
|
||||
instance->mIOThread =
|
||||
new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
|
||||
NS_LITERAL_CSTRING("IndexedDB I/O"),
|
||||
LazyIdleThread::ManualShutdown);
|
||||
|
||||
// We need one quota callback object to hand to SQLite.
|
||||
instance->mQuotaCallbackSingleton = new QuotaCallback();
|
||||
@ -1910,7 +1913,8 @@ IndexedDatabaseManager::InitWindowless(const jsval& aObj, JSContext* aCx)
|
||||
JSObject* global = JS_GetGlobalForObject(aCx, obj);
|
||||
|
||||
nsRefPtr<IDBFactory> factory;
|
||||
nsresult rv = IDBFactory::Create(aCx, global, getter_AddRefs(factory));
|
||||
nsresult rv =
|
||||
IDBFactory::Create(aCx, global, nullptr, getter_AddRefs(factory));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
NS_ASSERTION(factory, "This should never fail for chrome!");
|
||||
|
@ -2106,10 +2106,8 @@ OpenDatabaseHelper::EnsureSuccessResult()
|
||||
dbInfo->nextIndexId = mLastIndexId + 1;
|
||||
|
||||
nsRefPtr<IDBDatabase> database =
|
||||
IDBDatabase::Create(mOpenDBRequest,
|
||||
dbInfo.forget(),
|
||||
mASCIIOrigin,
|
||||
mFileManager);
|
||||
IDBDatabase::Create(mOpenDBRequest, dbInfo.forget(), mASCIIOrigin,
|
||||
mFileManager, mContentParent);
|
||||
if (!database) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
@ -14,6 +14,12 @@
|
||||
|
||||
class mozIStorageConnection;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
|
||||
class OpenDatabaseHelper : public HelperBase
|
||||
@ -24,12 +30,14 @@ public:
|
||||
const nsACString& aASCIIOrigin,
|
||||
PRUint64 aRequestedVersion,
|
||||
bool aForDeletion,
|
||||
mozilla::dom::ContentParent* aContentParent,
|
||||
FactoryPrivilege aPrivilege)
|
||||
: HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName),
|
||||
mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion),
|
||||
mForDeletion(aForDeletion), mPrivilege(aPrivilege), mDatabaseId(nullptr),
|
||||
mCurrentVersion(0), mLastObjectStoreId(0), mLastIndexId(0),
|
||||
mState(eCreated), mResultCode(NS_OK), mLoadDBMetadata(false)
|
||||
mContentParent(aContentParent), mCurrentVersion(0), mLastObjectStoreId(0),
|
||||
mLastIndexId(0), mState(eCreated), mResultCode(NS_OK),
|
||||
mLoadDBMetadata(false)
|
||||
{
|
||||
NS_ASSERTION(!aForDeletion || !aRequestedVersion,
|
||||
"Can't be for deletion and request a version!");
|
||||
@ -103,6 +111,7 @@ protected:
|
||||
bool mForDeletion;
|
||||
FactoryPrivilege mPrivilege;
|
||||
nsCOMPtr<nsIAtom> mDatabaseId;
|
||||
mozilla::dom::ContentParent* mContentParent;
|
||||
|
||||
// Out-params.
|
||||
nsTArray<nsRefPtr<ObjectStoreInfo> > mObjectStores;
|
||||
@ -133,4 +142,4 @@ protected:
|
||||
|
||||
END_INDEXEDDB_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_indexeddb_opendatabasehelper_h__
|
||||
#endif // mozilla_dom_indexeddb_opendatabasehelper_h__
|
@ -6,10 +6,11 @@
|
||||
|
||||
#include "IndexedDBChild.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include "nsIAtom.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
|
||||
#include "AsyncConnectionHelper.h"
|
||||
#include "DatabaseInfo.h"
|
||||
#include "IDBEvents.h"
|
||||
@ -21,6 +22,8 @@
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace {
|
||||
|
||||
class IPCOpenDatabaseHelper : public AsyncConnectionHelper
|
||||
@ -289,7 +292,8 @@ IndexedDBDatabaseChild::EnsureDatabase(
|
||||
|
||||
if (!mDatabase) {
|
||||
nsRefPtr<IDBDatabase> database =
|
||||
IDBDatabase::Create(aRequest, dbInfo.forget(), aDBInfo.origin, NULL);
|
||||
IDBDatabase::Create(aRequest, dbInfo.forget(), aDBInfo.origin, NULL,
|
||||
NULL);
|
||||
if (!database) {
|
||||
NS_WARNING("Failed to create database!");
|
||||
return false;
|
||||
@ -646,13 +650,18 @@ IndexedDBObjectStoreChild::RecvPIndexedDBCursorConstructor(
|
||||
|
||||
size_t direction = static_cast<size_t>(aParams.direction());
|
||||
|
||||
nsTArray<StructuredCloneFile> blobs;
|
||||
IDBObjectStore::ConvertActorsToBlobs(aParams.blobsChild(), blobs);
|
||||
|
||||
nsRefPtr<IDBCursor> cursor;
|
||||
nsresult rv =
|
||||
mObjectStore->OpenCursorFromChildProcess(request, direction, aParams.key(),
|
||||
aParams.cloneInfo(),
|
||||
aParams.cloneInfo(), blobs,
|
||||
getter_AddRefs(cursor));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
MOZ_ASSERT(blobs.IsEmpty(), "Should have swapped blob elements!");
|
||||
|
||||
actor->SetCursor(cursor);
|
||||
return true;
|
||||
}
|
||||
@ -754,16 +763,22 @@ IndexedDBIndexChild::RecvPIndexedDBCursorConstructor(
|
||||
|
||||
switch (aParams.optionalCloneInfo().type()) {
|
||||
case CursorUnionType::TSerializedStructuredCloneReadInfo: {
|
||||
nsTArray<StructuredCloneFile> blobs;
|
||||
IDBObjectStore::ConvertActorsToBlobs(aParams.blobsChild(), blobs);
|
||||
|
||||
const SerializedStructuredCloneReadInfo& cloneInfo =
|
||||
aParams.optionalCloneInfo().get_SerializedStructuredCloneReadInfo();
|
||||
|
||||
rv = mIndex->OpenCursorFromChildProcess(request, direction, aParams.key(),
|
||||
aParams.objectKey(), cloneInfo,
|
||||
blobs,
|
||||
getter_AddRefs(cursor));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
} break;
|
||||
|
||||
case CursorUnionType::Tvoid_t:
|
||||
MOZ_ASSERT(aParams.blobsChild().IsEmpty());
|
||||
|
||||
rv = mIndex->OpenCursorFromChildProcess(request, direction, aParams.key(),
|
||||
aParams.objectKey(),
|
||||
getter_AddRefs(cursor));
|
||||
|
@ -6,12 +6,15 @@
|
||||
|
||||
#include "IndexedDBParent.h"
|
||||
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsIIDBVersionChangeEvent.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsIXPConnect.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ipc/Blob.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "AsyncConnectionHelper.h"
|
||||
@ -26,6 +29,8 @@
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
/*******************************************************************************
|
||||
* AutoSetCurrentTransaction
|
||||
******************************************************************************/
|
||||
@ -1183,6 +1188,29 @@ IndexedDBObjectStoreRequestParent::~IndexedDBObjectStoreRequestParent()
|
||||
MOZ_COUNT_DTOR(IndexedDBObjectStoreRequestParent);
|
||||
}
|
||||
|
||||
void
|
||||
IndexedDBObjectStoreRequestParent::ConvertBlobActors(
|
||||
const InfallibleTArray<PBlobParent*>& aActors,
|
||||
nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs)
|
||||
{
|
||||
MOZ_ASSERT(aBlobs.IsEmpty());
|
||||
|
||||
if (!aActors.IsEmpty()) {
|
||||
// Walk the chain to get to ContentParent.
|
||||
ContentParent* contentParent =
|
||||
mObjectStore->Transaction()->Database()->GetContentParent();
|
||||
MOZ_ASSERT(contentParent);
|
||||
|
||||
uint32_t length = aActors.Length();
|
||||
aBlobs.SetCapacity(length);
|
||||
|
||||
for (uint32_t index = 0; index < length; index++) {
|
||||
BlobParent* actor = static_cast<BlobParent*>(aActors[index]);
|
||||
aBlobs.AppendElement(actor->GetBlob());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IndexedDBObjectStoreRequestParent::Get(const GetParams& aParams)
|
||||
{
|
||||
@ -1254,6 +1282,9 @@ IndexedDBObjectStoreRequestParent::Add(const AddParams& aParams)
|
||||
|
||||
ipc::AddPutParams params = aParams.commonParams();
|
||||
|
||||
nsTArray<nsCOMPtr<nsIDOMBlob> > blobs;
|
||||
ConvertBlobActors(params.blobsParent(), blobs);
|
||||
|
||||
nsRefPtr<IDBRequest> request;
|
||||
|
||||
{
|
||||
@ -1261,7 +1292,7 @@ IndexedDBObjectStoreRequestParent::Add(const AddParams& aParams)
|
||||
|
||||
nsresult rv =
|
||||
mObjectStore->AddOrPutInternal(params.cloneInfo(), params.key(),
|
||||
params.indexUpdateInfos(), false,
|
||||
params.indexUpdateInfos(), blobs, false,
|
||||
getter_AddRefs(request));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
}
|
||||
@ -1278,6 +1309,9 @@ IndexedDBObjectStoreRequestParent::Put(const PutParams& aParams)
|
||||
|
||||
ipc::AddPutParams params = aParams.commonParams();
|
||||
|
||||
nsTArray<nsCOMPtr<nsIDOMBlob> > blobs;
|
||||
ConvertBlobActors(params.blobsParent(), blobs);
|
||||
|
||||
nsRefPtr<IDBRequest> request;
|
||||
|
||||
{
|
||||
@ -1285,7 +1319,7 @@ IndexedDBObjectStoreRequestParent::Put(const PutParams& aParams)
|
||||
|
||||
nsresult rv =
|
||||
mObjectStore->AddOrPutInternal(params.cloneInfo(), params.key(),
|
||||
params.indexUpdateInfos(), true,
|
||||
params.indexUpdateInfos(), blobs, true,
|
||||
getter_AddRefs(request));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
}
|
||||
|
@ -23,10 +23,12 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ContentParent;
|
||||
class PBlobParent;
|
||||
class TabParent;
|
||||
}
|
||||
}
|
||||
|
||||
class nsIDOMBlob;
|
||||
class nsIDOMEvent;
|
||||
|
||||
BEGIN_INDEXEDDB_NAMESPACE
|
||||
@ -531,6 +533,11 @@ public:
|
||||
|
||||
bool
|
||||
OpenCursor(const OpenCursorParams& aParams);
|
||||
|
||||
protected:
|
||||
void
|
||||
ConvertBlobActors(const InfallibleTArray<PBlobParent*>& aActors,
|
||||
nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs);
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -48,4 +48,4 @@ copy-xpcshell-tests:
|
||||
$(call install_cmd,$(wildcard $(topsrcdir)/dom/indexedDB/test/unit/test_*.js) \
|
||||
$(testxpcobjdir)/$(relativesrcdir)/$(XPCSHELL_TESTS))
|
||||
|
||||
libs-xpcshell-tests: copy-xpcshell-tests
|
||||
libs-xpcshell-tests: copy-xpcshell-tests
|
@ -2,6 +2,7 @@
|
||||
* 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 protocol PBlob;
|
||||
include protocol PIndexedDBCursor;
|
||||
include protocol PIndexedDBObjectStore;
|
||||
include protocol PIndexedDBRequest;
|
||||
@ -102,6 +103,7 @@ struct IndexCursorConstructorParams
|
||||
Key key;
|
||||
Key objectKey;
|
||||
OptionalStructuredCloneReadInfo optionalCloneInfo;
|
||||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
@ -2,6 +2,7 @@
|
||||
* 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 protocol PBlob;
|
||||
include protocol PIndexedDBCursor;
|
||||
include protocol PIndexedDBIndex;
|
||||
include protocol PIndexedDBRequest;
|
||||
@ -70,6 +71,7 @@ struct AddPutParams
|
||||
SerializedStructuredCloneWriteInfo cloneInfo;
|
||||
Key key;
|
||||
IndexUpdateInfo[] indexUpdateInfos;
|
||||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
struct AddParams
|
||||
@ -126,6 +128,7 @@ struct ObjectStoreCursorConstructorParams
|
||||
Direction direction;
|
||||
Key key;
|
||||
SerializedStructuredCloneReadInfo cloneInfo;
|
||||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
@ -2,6 +2,7 @@
|
||||
* 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 protocol PBlob;
|
||||
include protocol PIndexedDBCursor;
|
||||
include protocol PIndexedDBIndex;
|
||||
include protocol PIndexedDBObjectStore;
|
||||
@ -22,6 +23,7 @@ namespace ipc {
|
||||
struct GetResponse
|
||||
{
|
||||
SerializedStructuredCloneReadInfo cloneInfo;
|
||||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
struct GetKeyResponse
|
||||
@ -29,9 +31,15 @@ struct GetKeyResponse
|
||||
Key key;
|
||||
};
|
||||
|
||||
struct BlobArray
|
||||
{
|
||||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
struct GetAllResponse
|
||||
{
|
||||
SerializedStructuredCloneReadInfo[] cloneInfos;
|
||||
BlobArray[] blobs;
|
||||
};
|
||||
|
||||
struct GetAllKeysResponse
|
||||
@ -75,6 +83,7 @@ struct ContinueResponse
|
||||
Key key;
|
||||
Key objectKey;
|
||||
SerializedStructuredCloneReadInfo cloneInfo;
|
||||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
union ResponseValue
|
||||
|
@ -29,6 +29,7 @@ MOCHITEST_FILES = \
|
||||
test_autoIncrement_indexes.html \
|
||||
test_autoIncrement.html \
|
||||
test_bfcache.html \
|
||||
test_blob_simple.html \
|
||||
test_clear.html \
|
||||
test_complex_keyPaths.html \
|
||||
test_count.html \
|
||||
|
192
dom/indexedDB/test/test_blob_simple.html
Normal file
192
dom/indexedDB/test/test_blob_simple.html
Normal file
@ -0,0 +1,192 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function testSteps()
|
||||
{
|
||||
const BLOB_DATA = ["fun ", "times ", "all ", "around!"];
|
||||
const INDEX_KEY = 5;
|
||||
|
||||
let request = indexedDB.open(window.location.pathname, 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
let event = yield;
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let objectStore = db.createObjectStore("foo", { autoIncrement: true });
|
||||
let index = objectStore.createIndex("foo", "index");
|
||||
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let blob = new Blob(BLOB_DATA, { type: "text/plain" });
|
||||
let data = { blob: blob, index: INDEX_KEY };
|
||||
|
||||
objectStore = db.transaction("foo", "readwrite").objectStore("foo");
|
||||
objectStore.add(data).onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let key = event.target.result;
|
||||
|
||||
objectStore.add(data).onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
objectStore = db.transaction("foo").objectStore("foo");
|
||||
objectStore.get(key).onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
let fileReader = new FileReader();
|
||||
fileReader.onload = grabEventAndContinueHandler;
|
||||
fileReader.readAsText(event.target.result.blob);
|
||||
event = yield;
|
||||
|
||||
is(event.target.result, BLOB_DATA.join(""), "Correct text");
|
||||
|
||||
objectStore = db.transaction("foo").objectStore("foo");
|
||||
objectStore.mozGetAll().onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
is(event.target.result.length, 2, "Got right number of items");
|
||||
|
||||
fileReader = new FileReader();
|
||||
fileReader.onload = grabEventAndContinueHandler;
|
||||
fileReader.readAsText(event.target.result[0].blob);
|
||||
event = yield;
|
||||
|
||||
is(event.target.result, BLOB_DATA.join(""), "Correct text");
|
||||
|
||||
let cursorResults = [];
|
||||
|
||||
objectStore = db.transaction("foo").objectStore("foo");
|
||||
objectStore.openCursor().onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
cursorResults.push(cursor.value);
|
||||
cursor.continue();
|
||||
}
|
||||
else {
|
||||
continueToNextStep();
|
||||
}
|
||||
};
|
||||
yield;
|
||||
|
||||
is(cursorResults.length, 2, "Got right number of items");
|
||||
|
||||
fileReader = new FileReader();
|
||||
fileReader.onload = grabEventAndContinueHandler;
|
||||
fileReader.readAsText(cursorResults[0].blob);
|
||||
event = yield;
|
||||
|
||||
is(event.target.result, BLOB_DATA.join(""), "Correct text");
|
||||
|
||||
let index = db.transaction("foo").objectStore("foo").index("foo");
|
||||
index.get(INDEX_KEY).onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
fileReader = new FileReader();
|
||||
fileReader.onload = grabEventAndContinueHandler;
|
||||
fileReader.readAsText(event.target.result.blob);
|
||||
event = yield;
|
||||
|
||||
is(event.target.result, BLOB_DATA.join(""), "Correct text");
|
||||
|
||||
index = db.transaction("foo").objectStore("foo").index("foo");
|
||||
index.mozGetAll().onsuccess = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
is(event.target.result.length, 2, "Got right number of items");
|
||||
|
||||
fileReader = new FileReader();
|
||||
fileReader.onload = grabEventAndContinueHandler;
|
||||
fileReader.readAsText(event.target.result[0].blob);
|
||||
event = yield;
|
||||
|
||||
is(event.target.result, BLOB_DATA.join(""), "Correct text");
|
||||
|
||||
cursorResults = [];
|
||||
|
||||
index = db.transaction("foo").objectStore("foo").index("foo");
|
||||
index.openCursor().onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
cursorResults.push(cursor.value);
|
||||
cursor.continue();
|
||||
}
|
||||
else {
|
||||
continueToNextStep();
|
||||
}
|
||||
};
|
||||
yield;
|
||||
|
||||
is(cursorResults.length, 2, "Got right number of items");
|
||||
|
||||
fileReader = new FileReader();
|
||||
fileReader.onload = grabEventAndContinueHandler;
|
||||
fileReader.readAsText(cursorResults[0].blob);
|
||||
event = yield;
|
||||
|
||||
is(event.target.result, BLOB_DATA.join(""), "Correct text");
|
||||
|
||||
fileReader = new FileReader();
|
||||
fileReader.onload = grabEventAndContinueHandler;
|
||||
fileReader.readAsText(cursorResults[1].blob);
|
||||
event = yield;
|
||||
|
||||
is(event.target.result, BLOB_DATA.join(""), "Correct text");
|
||||
|
||||
let slice = cursorResults[1].blob.slice(0, BLOB_DATA[0].length);
|
||||
|
||||
fileReader = new FileReader();
|
||||
fileReader.onload = grabEventAndContinueHandler;
|
||||
fileReader.readAsText(slice);
|
||||
event = yield;
|
||||
|
||||
is(event.target.result, BLOB_DATA[0], "Correct text");
|
||||
|
||||
function workerScript() {
|
||||
onmessage = function(event) {
|
||||
var reader = new FileReaderSync();
|
||||
postMessage(reader.readAsText(event.data));
|
||||
|
||||
var slice = event.data.slice(1, 2);
|
||||
postMessage(reader.readAsText(slice));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let url =
|
||||
URL.createObjectURL(new Blob(["(", workerScript.toSource(), ")()"]));
|
||||
|
||||
let worker = new Worker(url);
|
||||
worker.postMessage(slice);
|
||||
worker.onmessage = grabEventAndContinueHandler;
|
||||
event = yield;
|
||||
|
||||
is(event.data, BLOB_DATA[0], "Correct text");
|
||||
event = yield;
|
||||
|
||||
is(event.data, BLOB_DATA[0][1], "Correct text");
|
||||
|
||||
finishTest();
|
||||
yield;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="file.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
797
dom/ipc/Blob.cpp
Normal file
797
dom/ipc/Blob.cpp
Normal file
@ -0,0 +1,797 @@
|
||||
/* -*- 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 "base/basictypes.h"
|
||||
|
||||
#include "Blob.h"
|
||||
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIRemoteBlob.h"
|
||||
#include "nsISeekableStream.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/net/NeckoMessageUtils.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "ContentChild.h"
|
||||
#include "ContentParent.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::dom::ipc;
|
||||
|
||||
namespace {
|
||||
|
||||
class RemoteInputStream : public nsIInputStream,
|
||||
public nsISeekableStream
|
||||
{
|
||||
mozilla::Monitor mMonitor;
|
||||
nsCOMPtr<nsIDOMBlob> mSourceBlob;
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
nsCOMPtr<nsISeekableStream> mSeekableStream;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
RemoteInputStream(nsIDOMBlob* aSourceBlob)
|
||||
: mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aSourceBlob);
|
||||
}
|
||||
|
||||
void
|
||||
SetStream(nsIInputStream* aStream)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aStream);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream = aStream;
|
||||
nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream);
|
||||
|
||||
{
|
||||
mozilla::MonitorAutoLock lock(mMonitor);
|
||||
|
||||
MOZ_ASSERT(!mStream);
|
||||
MOZ_ASSERT(!mSeekableStream);
|
||||
|
||||
mStream.swap(stream);
|
||||
mSeekableStream.swap(seekableStream);
|
||||
|
||||
mMonitor.Notify();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Close() MOZ_OVERRIDE
|
||||
{
|
||||
nsresult rv = BlockAndWaitForStream();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> sourceBlob;
|
||||
mSourceBlob.swap(sourceBlob);
|
||||
|
||||
rv = mStream->Close();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Available(PRUint32* aAvailable) MOZ_OVERRIDE
|
||||
{
|
||||
// See large comment in FileInputStreamWrapper::Available.
|
||||
if (NS_IsMainThread()) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
nsresult rv = BlockAndWaitForStream();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mStream->Available(aAvailable);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Read(char* aBuffer, PRUint32 aCount, PRUint32* aResult) MOZ_OVERRIDE
|
||||
{
|
||||
nsresult rv = BlockAndWaitForStream();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mStream->Read(aBuffer, aCount, aResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, PRUint32 aCount,
|
||||
PRUint32* aResult) MOZ_OVERRIDE
|
||||
{
|
||||
nsresult rv = BlockAndWaitForStream();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mStream->ReadSegments(aWriter, aClosure, aCount, aResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
IsNonBlocking(bool* aNonBlocking) MOZ_OVERRIDE
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aNonBlocking);
|
||||
|
||||
*aNonBlocking = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Seek(PRInt32 aWhence, PRInt64 aOffset) MOZ_OVERRIDE
|
||||
{
|
||||
nsresult rv = BlockAndWaitForStream();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mSeekableStream) {
|
||||
NS_WARNING("Underlying blob stream is not seekable!");
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
rv = mSeekableStream->Seek(aWhence, aOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Tell(PRInt64* aResult)
|
||||
{
|
||||
nsresult rv = BlockAndWaitForStream();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mSeekableStream) {
|
||||
NS_WARNING("Underlying blob stream is not seekable!");
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
rv = mSeekableStream->Tell(aResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
SetEOF()
|
||||
{
|
||||
nsresult rv = BlockAndWaitForStream();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!mSeekableStream) {
|
||||
NS_WARNING("Underlying blob stream is not seekable!");
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
rv = mSeekableStream->SetEOF();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~RemoteInputStream()
|
||||
{ }
|
||||
|
||||
void
|
||||
ReallyBlockAndWaitForStream()
|
||||
{
|
||||
mozilla::MonitorAutoLock lock(mMonitor);
|
||||
while (!mStream) {
|
||||
mMonitor.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
BlockAndWaitForStream()
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
NS_WARNING("Blocking the main thread is not supported!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ReallyBlockAndWaitForStream();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
IsSeekableStream()
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
if (!mStream) {
|
||||
NS_WARNING("Don't know if this stream is seekable yet!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ReallyBlockAndWaitForStream();
|
||||
}
|
||||
|
||||
return !!mSeekableStream;
|
||||
}
|
||||
};
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
class InputStreamActor : public BlobTraits<ActorFlavor>::StreamType
|
||||
{
|
||||
typedef typename BlobTraits<ActorFlavor>::StreamType::InputStream InputStream;
|
||||
nsRefPtr<RemoteInputStream> mRemoteStream;
|
||||
|
||||
public:
|
||||
InputStreamActor(RemoteInputStream* aRemoteStream)
|
||||
: mRemoteStream(aRemoteStream)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aRemoteStream);
|
||||
}
|
||||
|
||||
InputStreamActor()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
private:
|
||||
// This method is only called by the IPDL message machinery.
|
||||
virtual bool
|
||||
Recv__delete__(const InputStream& aStream) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mRemoteStream);
|
||||
|
||||
mRemoteStream->SetStream(aStream);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
inline
|
||||
already_AddRefed<nsIDOMBlob>
|
||||
GetBlobFromParams(const SlicedBlobConstructorParams& aParams)
|
||||
{
|
||||
MOZ_STATIC_ASSERT(ActorFlavor == mozilla::dom::ipc::Parent,
|
||||
"No other flavor is supported here!");
|
||||
|
||||
BlobParent* actor =
|
||||
const_cast<BlobParent*>(
|
||||
static_cast<const BlobParent*>(aParams.sourceParent()));
|
||||
MOZ_ASSERT(actor);
|
||||
|
||||
return actor->GetBlob();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline
|
||||
already_AddRefed<nsIDOMBlob>
|
||||
GetBlobFromParams<Child>(const SlicedBlobConstructorParams& aParams)
|
||||
{
|
||||
BlobChild* actor =
|
||||
const_cast<BlobChild*>(
|
||||
static_cast<const BlobChild*>(aParams.sourceChild()));
|
||||
MOZ_ASSERT(actor);
|
||||
|
||||
return actor->GetBlob();
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
SetBlobOnParams(BlobChild* aActor, SlicedBlobConstructorParams& aParams)
|
||||
{
|
||||
aParams.sourceChild() = aActor;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
SetBlobOnParams(BlobParent* aActor, SlicedBlobConstructorParams& aParams)
|
||||
{
|
||||
aParams.sourceParent() = aActor;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace ipc {
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
class RemoteBlob : public nsDOMFile,
|
||||
public nsIRemoteBlob
|
||||
{
|
||||
public:
|
||||
typedef RemoteBlob<ActorFlavor> SelfType;
|
||||
typedef Blob<ActorFlavor> ActorType;
|
||||
typedef InputStreamActor<ActorFlavor> StreamActorType;
|
||||
|
||||
private:
|
||||
ActorType* mActor;
|
||||
|
||||
class StreamHelper : public nsRunnable
|
||||
{
|
||||
typedef Blob<ActorFlavor> ActorType;
|
||||
typedef InputStreamActor<ActorFlavor> StreamActorType;
|
||||
|
||||
mozilla::Monitor mMonitor;
|
||||
ActorType* mActor;
|
||||
nsCOMPtr<nsIDOMBlob> mSourceBlob;
|
||||
nsRefPtr<RemoteInputStream> mInputStream;
|
||||
bool mDone;
|
||||
|
||||
public:
|
||||
StreamHelper(ActorType* aActor, nsIDOMBlob* aSourceBlob)
|
||||
: mMonitor("RemoteBlob::StreamHelper::mMonitor"), mActor(aActor),
|
||||
mSourceBlob(aSourceBlob), mDone(false)
|
||||
{
|
||||
// This may be created on any thread.
|
||||
MOZ_ASSERT(aActor);
|
||||
MOZ_ASSERT(aSourceBlob);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetStream(nsIInputStream** aInputStream)
|
||||
{
|
||||
// This may be called on any thread.
|
||||
MOZ_ASSERT(aInputStream);
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(!mInputStream);
|
||||
MOZ_ASSERT(!mDone);
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
RunInternal(false);
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
while (!mDone) {
|
||||
lock.Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mActor);
|
||||
MOZ_ASSERT(mDone);
|
||||
|
||||
if (!mInputStream) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
mInputStream.forget(aInputStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
RunInternal(true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
RunInternal(bool aNotify)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(!mInputStream);
|
||||
MOZ_ASSERT(!mDone);
|
||||
|
||||
nsRefPtr<RemoteInputStream> stream = new RemoteInputStream(mSourceBlob);
|
||||
|
||||
StreamActorType* streamActor = new StreamActorType(stream);
|
||||
if (mActor->SendPBlobStreamConstructor(streamActor)) {
|
||||
stream.swap(mInputStream);
|
||||
}
|
||||
|
||||
mActor = nullptr;
|
||||
|
||||
if (aNotify) {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mDone = true;
|
||||
lock.Notify();
|
||||
}
|
||||
else {
|
||||
mDone = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SliceHelper : public nsRunnable
|
||||
{
|
||||
typedef Blob<ActorFlavor> ActorType;
|
||||
|
||||
mozilla::Monitor mMonitor;
|
||||
ActorType* mActor;
|
||||
nsCOMPtr<nsIDOMBlob> mSlice;
|
||||
PRUint64 mStart;
|
||||
PRUint64 mLength;
|
||||
nsString mContentType;
|
||||
bool mDone;
|
||||
|
||||
public:
|
||||
SliceHelper(ActorType* aActor)
|
||||
: mMonitor("RemoteBlob::SliceHelper::mMonitor"), mActor(aActor), mStart(0),
|
||||
mLength(0), mDone(false)
|
||||
{
|
||||
// This may be created on any thread.
|
||||
MOZ_ASSERT(aActor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetSlice(PRUint64 aStart, PRUint64 aLength, const nsAString& aContentType,
|
||||
nsIDOMBlob** aSlice)
|
||||
{
|
||||
// This may be called on any thread.
|
||||
MOZ_ASSERT(aSlice);
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(!mSlice);
|
||||
MOZ_ASSERT(!mDone);
|
||||
|
||||
mStart = aStart;
|
||||
mLength = aLength;
|
||||
mContentType = aContentType;
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
RunInternal(false);
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
while (!mDone) {
|
||||
lock.Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mActor);
|
||||
MOZ_ASSERT(mDone);
|
||||
|
||||
if (!mSlice) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
mSlice.forget(aSlice);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
RunInternal(true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
RunInternal(bool aNotify)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(!mSlice);
|
||||
MOZ_ASSERT(!mDone);
|
||||
|
||||
NormalBlobConstructorParams normalParams;
|
||||
normalParams.contentType() = mContentType;
|
||||
normalParams.length() = mLength;
|
||||
|
||||
ActorType* newActor = ActorType::Create(normalParams);
|
||||
MOZ_ASSERT(newActor);
|
||||
|
||||
SlicedBlobConstructorParams slicedParams;
|
||||
slicedParams.contentType() = mContentType;
|
||||
slicedParams.begin() = mStart;
|
||||
slicedParams.end() = mStart + mLength;
|
||||
SetBlobOnParams(mActor, slicedParams);
|
||||
|
||||
if (mActor->Manager()->SendPBlobConstructor(newActor, slicedParams)) {
|
||||
mSlice = newActor->GetBlob();
|
||||
}
|
||||
|
||||
mActor = nullptr;
|
||||
|
||||
if (aNotify) {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mDone = true;
|
||||
lock.Notify();
|
||||
}
|
||||
else {
|
||||
mDone = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
RemoteBlob(const nsAString& aName, const nsAString& aContentType,
|
||||
PRUint64 aLength)
|
||||
: nsDOMFile(aName, aContentType, aLength), mActor(nullptr)
|
||||
{ }
|
||||
|
||||
RemoteBlob(const nsAString& aContentType, PRUint64 aLength)
|
||||
: nsDOMFile(aContentType, aLength), mActor(nullptr)
|
||||
{ }
|
||||
|
||||
virtual ~RemoteBlob()
|
||||
{
|
||||
if (mActor) {
|
||||
mActor->NoteDyingRemoteBlob();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SetActor(ActorType* aActor)
|
||||
{
|
||||
MOZ_ASSERT(!aActor || !mActor);
|
||||
mActor = aActor;
|
||||
}
|
||||
|
||||
virtual already_AddRefed<nsIDOMBlob>
|
||||
CreateSlice(PRUint64 aStart, PRUint64 aLength, const nsAString& aContentType)
|
||||
MOZ_OVERRIDE
|
||||
{
|
||||
if (!mActor) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> slice;
|
||||
nsresult rv =
|
||||
helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
return slice.forget();
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE
|
||||
{
|
||||
if (!mActor) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
|
||||
return helper->GetStream(aStream);
|
||||
}
|
||||
|
||||
virtual void*
|
||||
GetPBlob() MOZ_OVERRIDE
|
||||
{
|
||||
return static_cast<typename ActorType::BaseType*>(mActor);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
Blob<ActorFlavor>::Blob(nsIDOMBlob* aBlob)
|
||||
: mBlob(aBlob), mRemoteBlob(nullptr), mOwnsBlob(true)
|
||||
{
|
||||
MOZ_ASSERT(aBlob);
|
||||
aBlob->AddRef();
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
Blob<ActorFlavor>::Blob(const BlobConstructorParams& aParams)
|
||||
: mBlob(nullptr), mRemoteBlob(nullptr), mOwnsBlob(true)
|
||||
{
|
||||
nsRefPtr<RemoteBlobType> remoteBlob;
|
||||
|
||||
switch (aParams.type()) {
|
||||
case BlobConstructorParams::TNormalBlobConstructorParams: {
|
||||
const NormalBlobConstructorParams& params =
|
||||
aParams.get_NormalBlobConstructorParams();
|
||||
remoteBlob = new RemoteBlobType(params.contentType(), params.length());
|
||||
break;
|
||||
}
|
||||
|
||||
case BlobConstructorParams::TFileBlobConstructorParams: {
|
||||
const FileBlobConstructorParams& params =
|
||||
aParams.get_FileBlobConstructorParams();
|
||||
remoteBlob =
|
||||
new RemoteBlobType(params.name(), params.contentType(),
|
||||
params.length());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_NOT_REACHED("Unknown params!");
|
||||
}
|
||||
|
||||
MOZ_ASSERT(remoteBlob);
|
||||
|
||||
if (NS_FAILED(remoteBlob->SetMutable(false))) {
|
||||
MOZ_NOT_REACHED("Failed to make remote blob immutable!");
|
||||
}
|
||||
|
||||
remoteBlob->SetActor(this);
|
||||
remoteBlob.forget(&mRemoteBlob);
|
||||
|
||||
mBlob = mRemoteBlob;
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
Blob<ActorFlavor>*
|
||||
Blob<ActorFlavor>::Create(const BlobConstructorParams& aParams)
|
||||
{
|
||||
switch (aParams.type()) {
|
||||
case BlobConstructorParams::TNormalBlobConstructorParams:
|
||||
case BlobConstructorParams::TFileBlobConstructorParams:
|
||||
return new Blob<ActorFlavor>(aParams);
|
||||
|
||||
case BlobConstructorParams::TSlicedBlobConstructorParams: {
|
||||
const SlicedBlobConstructorParams& params =
|
||||
aParams.get_SlicedBlobConstructorParams();
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> source = GetBlobFromParams<ActorFlavor>(params);
|
||||
MOZ_ASSERT(source);
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> slice;
|
||||
nsresult rv =
|
||||
source->Slice(params.begin(), params.end(), params.contentType(), 3,
|
||||
getter_AddRefs(slice));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
return new Blob<ActorFlavor>(slice);
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_NOT_REACHED("Unknown params!");
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
already_AddRefed<nsIDOMBlob>
|
||||
Blob<ActorFlavor>::GetBlob()
|
||||
{
|
||||
MOZ_ASSERT(mBlob);
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob;
|
||||
|
||||
// Remote blobs are held alive until the first call to GetBlob. Thereafter we
|
||||
// only hold a weak reference. Normal blobs are held alive until the actor is
|
||||
// destroyed.
|
||||
if (mRemoteBlob && mOwnsBlob) {
|
||||
blob = dont_AddRef(mBlob);
|
||||
mOwnsBlob = false;
|
||||
}
|
||||
else {
|
||||
blob = mBlob;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(blob);
|
||||
|
||||
return blob.forget();
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
void
|
||||
Blob<ActorFlavor>::NoteDyingRemoteBlob()
|
||||
{
|
||||
MOZ_ASSERT(mBlob);
|
||||
MOZ_ASSERT(mRemoteBlob);
|
||||
MOZ_ASSERT(!mOwnsBlob);
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewNonOwningRunnableMethod(this,
|
||||
&Blob<ActorFlavor>::NoteDyingRemoteBlob);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
|
||||
MOZ_NOT_REACHED("Should never fail!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Must do this before calling Send__delete__ or we'll crash there trying to
|
||||
// access a dangling pointer.
|
||||
mRemoteBlob = nullptr;
|
||||
|
||||
BaseType::Send__delete__(this);
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
void
|
||||
Blob<ActorFlavor>::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
MOZ_ASSERT(mBlob);
|
||||
|
||||
if (mRemoteBlob) {
|
||||
mRemoteBlob->SetActor(nullptr);
|
||||
}
|
||||
|
||||
if (mOwnsBlob) {
|
||||
mBlob->Release();
|
||||
}
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
bool
|
||||
Blob<ActorFlavor>::RecvPBlobStreamConstructor(StreamType* aActor)
|
||||
{
|
||||
MOZ_ASSERT(mBlob);
|
||||
MOZ_ASSERT(!mRemoteBlob);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return aActor->Send__delete__(aActor, stream.get());
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
typename Blob<ActorFlavor>::StreamType*
|
||||
Blob<ActorFlavor>::AllocPBlobStream()
|
||||
{
|
||||
return new InputStreamActor<ActorFlavor>();
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
bool
|
||||
Blob<ActorFlavor>::DeallocPBlobStream(StreamType* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
NS_IMPL_ADDREF_INHERITED(RemoteBlob<ActorFlavor>, nsDOMFile)
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
NS_IMPL_RELEASE_INHERITED(RemoteBlob<ActorFlavor>, nsDOMFile)
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
NS_IMPL_QUERY_INTERFACE_INHERITED1(RemoteBlob<ActorFlavor>, nsDOMFile,
|
||||
nsIRemoteBlob)
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(RemoteInputStream)
|
||||
NS_IMPL_THREADSAFE_RELEASE(RemoteInputStream)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(RemoteInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream())
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace ipc {
|
||||
|
||||
// Explicit instantiation of both classes.
|
||||
template class Blob<Parent>;
|
||||
template class Blob<Child>;
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
120
dom/ipc/Blob.h
Normal file
120
dom/ipc/Blob.h
Normal file
@ -0,0 +1,120 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_ipc_Blob_h
|
||||
#define mozilla_dom_ipc_Blob_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/PBlobChild.h"
|
||||
#include "mozilla/dom/PBlobParent.h"
|
||||
#include "mozilla/dom/PBlobStreamChild.h"
|
||||
#include "mozilla/dom/PBlobStreamParent.h"
|
||||
#include "mozilla/dom/PContentChild.h"
|
||||
#include "mozilla/dom/PContentParent.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIDOMBlob;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace ipc {
|
||||
|
||||
enum ActorFlavorEnum
|
||||
{
|
||||
Parent = 0,
|
||||
Child
|
||||
};
|
||||
|
||||
template <ActorFlavorEnum>
|
||||
struct BlobTraits
|
||||
{ };
|
||||
|
||||
template <>
|
||||
struct BlobTraits<Parent>
|
||||
{
|
||||
typedef mozilla::dom::PBlobParent BaseType;
|
||||
typedef mozilla::dom::PBlobStreamParent StreamType;
|
||||
typedef mozilla::dom::PContentParent ManagerType;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BlobTraits<Child>
|
||||
{
|
||||
typedef mozilla::dom::PBlobChild BaseType;
|
||||
typedef mozilla::dom::PBlobStreamChild StreamType;
|
||||
typedef mozilla::dom::PContentChild ManagerType;
|
||||
};
|
||||
|
||||
template <ActorFlavorEnum>
|
||||
class RemoteBlob;
|
||||
|
||||
template <ActorFlavorEnum ActorFlavor>
|
||||
class Blob : public BlobTraits<ActorFlavor>::BaseType
|
||||
{
|
||||
public:
|
||||
typedef typename BlobTraits<ActorFlavor>::BaseType BaseType;
|
||||
typedef typename BlobTraits<ActorFlavor>::StreamType StreamType;
|
||||
typedef typename BlobTraits<ActorFlavor>::ManagerType ManagerType;
|
||||
typedef RemoteBlob<ActorFlavor> RemoteBlobType;
|
||||
typedef mozilla::ipc::IProtocolManager<
|
||||
mozilla::ipc::RPCChannel::RPCListener>::ActorDestroyReason
|
||||
ActorDestroyReason;
|
||||
typedef mozilla::dom::BlobConstructorParams BlobConstructorParams;
|
||||
|
||||
protected:
|
||||
nsIDOMBlob* mBlob;
|
||||
RemoteBlobType* mRemoteBlob;
|
||||
bool mOwnsBlob;
|
||||
|
||||
public:
|
||||
// This create function is called on the sending side.
|
||||
static Blob*
|
||||
Create(nsIDOMBlob* aBlob)
|
||||
{
|
||||
return new Blob(aBlob);
|
||||
}
|
||||
|
||||
// This create function is called on the receiving side.
|
||||
static Blob*
|
||||
Create(const BlobConstructorParams& aParams);
|
||||
|
||||
already_AddRefed<nsIDOMBlob>
|
||||
GetBlob();
|
||||
|
||||
void
|
||||
NoteDyingRemoteBlob();
|
||||
|
||||
private:
|
||||
// This constructor is called on the sending side.
|
||||
Blob(nsIDOMBlob* aBlob);
|
||||
|
||||
// This constructor is called on the receiving side.
|
||||
Blob(const BlobConstructorParams& aParams);
|
||||
|
||||
// These methods are only called by the IPDL message machinery.
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvPBlobStreamConstructor(StreamType* aActor) MOZ_OVERRIDE;
|
||||
|
||||
virtual StreamType*
|
||||
AllocPBlobStream() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
DeallocPBlobStream(StreamType* aActor) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
||||
typedef mozilla::dom::ipc::Blob<mozilla::dom::ipc::Child> BlobChild;
|
||||
typedef mozilla::dom::ipc::Blob<mozilla::dom::ipc::Parent> BlobParent;
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ipc_Blob_h
|
@ -81,9 +81,13 @@
|
||||
#include "nsIAccessibilityService.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/dom/indexedDB/PIndexedDBChild.h"
|
||||
#include "mozilla/dom/sms/SmsChild.h"
|
||||
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
|
||||
#include "mozilla/dom/indexedDB/PIndexedDBChild.h"
|
||||
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIRemoteBlob.h"
|
||||
#include "StructuredCloneUtils.h"
|
||||
|
||||
using namespace mozilla::docshell;
|
||||
using namespace mozilla::dom::devicestorage;
|
||||
@ -390,7 +394,7 @@ ContentChild::DeallocPMemoryReportRequest(PMemoryReportRequestChild* actor)
|
||||
}
|
||||
|
||||
PCompositorChild*
|
||||
ContentChild::AllocPCompositor(ipc::Transport* aTransport,
|
||||
ContentChild::AllocPCompositor(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess)
|
||||
{
|
||||
return CompositorChild::Create(aTransport, aOtherProcess);
|
||||
@ -413,6 +417,71 @@ ContentChild::DeallocPBrowser(PBrowserChild* iframe)
|
||||
return true;
|
||||
}
|
||||
|
||||
PBlobChild*
|
||||
ContentChild::AllocPBlob(const BlobConstructorParams& aParams)
|
||||
{
|
||||
return BlobChild::Create(aParams);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPBlob(PBlobChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
BlobChild*
|
||||
ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||
{
|
||||
NS_ASSERTION(aBlob, "Null pointer!");
|
||||
|
||||
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
|
||||
if (remoteBlob) {
|
||||
BlobChild* actor =
|
||||
static_cast<BlobChild*>(static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
|
||||
NS_ASSERTION(actor, "Null actor?!");
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
BlobConstructorParams params;
|
||||
|
||||
nsString contentType;
|
||||
nsresult rv = aBlob->GetType(contentType);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
PRUint64 length;
|
||||
rv = aBlob->GetSize(&length);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
|
||||
if (file) {
|
||||
FileBlobConstructorParams fileParams;
|
||||
|
||||
rv = file->GetName(fileParams.name());
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
fileParams.contentType() = contentType;
|
||||
fileParams.length() = length;
|
||||
|
||||
params = fileParams;
|
||||
} else {
|
||||
NormalBlobConstructorParams blobParams;
|
||||
blobParams.contentType() = contentType;
|
||||
blobParams.length() = length;
|
||||
params = blobParams;
|
||||
}
|
||||
|
||||
BlobChild* actor = BlobChild::Create(aBlob);
|
||||
NS_ENSURE_TRUE(actor, nullptr);
|
||||
|
||||
if (!SendPBlobConstructor(actor, params)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
PCrashReporterChild*
|
||||
ContentChild::AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
|
||||
const PRUint32& processType)
|
||||
@ -704,14 +773,30 @@ ContentChild::RecvNotifyVisited(const IPC::URI& aURI)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ContentChild::RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON)
|
||||
ContentChild::RecvAsyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData)
|
||||
{
|
||||
nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
|
||||
if (cpm) {
|
||||
const SerializedStructuredCloneBuffer& buffer = aData.data();
|
||||
const InfallibleTArray<PBlobChild*>& blobChildList = aData.blobsChild();
|
||||
StructuredCloneData cloneData;
|
||||
cloneData.mData = buffer.data;
|
||||
cloneData.mDataLength = buffer.dataLength;
|
||||
if (!blobChildList.IsEmpty()) {
|
||||
PRUint32 length = blobChildList.Length();
|
||||
cloneData.mClosure.mBlobs.SetCapacity(length);
|
||||
for (PRUint32 i = 0; i < length; ++i) {
|
||||
BlobChild* blobChild = static_cast<BlobChild*>(blobChildList[i]);
|
||||
MOZ_ASSERT(blobChild);
|
||||
nsCOMPtr<nsIDOMBlob> blob = blobChild->GetBlob();
|
||||
MOZ_ASSERT(blob);
|
||||
cloneData.mClosure.mBlobs.AppendElement(blob);
|
||||
}
|
||||
}
|
||||
cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
|
||||
aMsg, false, aJSON, nullptr, nullptr);
|
||||
aMsg, false, &cloneData, nullptr, nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -827,4 +912,4 @@ ContentChild::RecvLastPrivateDocShellDestroyed()
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla
|
@ -9,11 +9,13 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/PContentChild.h"
|
||||
#include "mozilla/dom/ipc/Blob.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nsIConsoleListener.h"
|
||||
|
||||
struct ChromePackage;
|
||||
class nsIDOMBlob;
|
||||
class nsIObserver;
|
||||
struct ResourceMapping;
|
||||
struct OverrideMapping;
|
||||
@ -30,10 +32,12 @@ class AlertObserver;
|
||||
class PrefObserver;
|
||||
class ConsoleListener;
|
||||
class PStorageChild;
|
||||
class ClonedMessageData;
|
||||
|
||||
class ContentChild : public PContentChild
|
||||
{
|
||||
typedef layers::PCompositorChild PCompositorChild;
|
||||
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
|
||||
|
||||
public:
|
||||
ContentChild();
|
||||
@ -59,7 +63,7 @@ public:
|
||||
return mAppInfo;
|
||||
}
|
||||
|
||||
PCompositorChild* AllocPCompositor(ipc::Transport* aTransport,
|
||||
PCompositorChild* AllocPCompositor(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess) MOZ_OVERRIDE;
|
||||
|
||||
virtual PBrowserChild* AllocPBrowser(const PRUint32& aChromeFlags,
|
||||
@ -70,6 +74,9 @@ public:
|
||||
virtual PDeviceStorageRequestChild* AllocPDeviceStorageRequest(const DeviceStorageParams&);
|
||||
virtual bool DeallocPDeviceStorageRequest(PDeviceStorageRequestChild*);
|
||||
|
||||
virtual PBlobChild* AllocPBlob(const BlobConstructorParams& aParams);
|
||||
virtual bool DeallocPBlob(PBlobChild*);
|
||||
|
||||
virtual PCrashReporterChild*
|
||||
AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
|
||||
const PRUint32& processType);
|
||||
@ -134,7 +141,8 @@ public:
|
||||
|
||||
virtual bool RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData);
|
||||
|
||||
virtual bool RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON);
|
||||
virtual bool RecvAsyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData);
|
||||
|
||||
virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere);
|
||||
|
||||
@ -164,6 +172,8 @@ public:
|
||||
|
||||
PRUint64 GetID() { return mID; }
|
||||
|
||||
BlobChild* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
|
||||
|
||||
private:
|
||||
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -6,12 +6,13 @@
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#include "ContentParent.h"
|
||||
|
||||
#if defined(ANDROID) || defined(LINUX)
|
||||
# include <sys/time.h>
|
||||
# include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#include "ContentParent.h"
|
||||
#include "CrashReporterParent.h"
|
||||
#include "History.h"
|
||||
#include "IDBFactory.h"
|
||||
@ -47,12 +48,14 @@
|
||||
#include "nsIAlertsService.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "nsIDOMGeoGeolocation.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIFilePicker.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIRemoteBlob.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
@ -63,6 +66,7 @@
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "SandboxHal.h"
|
||||
#include "StructuredCloneUtils.h"
|
||||
#include "TabParent.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
@ -827,7 +831,7 @@ ContentParent::Observe(nsISupports* aSubject,
|
||||
}
|
||||
|
||||
PCompositorParent*
|
||||
ContentParent::AllocPCompositor(ipc::Transport* aTransport,
|
||||
ContentParent::AllocPCompositor(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess)
|
||||
{
|
||||
return CompositorParent::Create(aTransport, aOtherProcess);
|
||||
@ -866,6 +870,72 @@ ContentParent::DeallocPDeviceStorageRequest(PDeviceStorageRequestParent* doomed)
|
||||
return true;
|
||||
}
|
||||
|
||||
PBlobParent*
|
||||
ContentParent::AllocPBlob(const BlobConstructorParams& aParams)
|
||||
{
|
||||
return BlobParent::Create(aParams);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPBlob(PBlobParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
BlobParent*
|
||||
ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||
{
|
||||
NS_ASSERTION(aBlob, "Null pointer!");
|
||||
|
||||
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
|
||||
if (remoteBlob) {
|
||||
BlobParent* actor =
|
||||
static_cast<BlobParent*>(
|
||||
static_cast<PBlobParent*>(remoteBlob->GetPBlob()));
|
||||
NS_ASSERTION(actor, "Null actor?!");
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
BlobConstructorParams params;
|
||||
|
||||
nsString contentType;
|
||||
nsresult rv = aBlob->GetType(contentType);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
PRUint64 length;
|
||||
rv = aBlob->GetSize(&length);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
|
||||
if (file) {
|
||||
FileBlobConstructorParams fileParams;
|
||||
|
||||
rv = file->GetName(fileParams.name());
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
fileParams.contentType() = contentType;
|
||||
fileParams.length() = length;
|
||||
|
||||
params = fileParams;
|
||||
} else {
|
||||
NormalBlobConstructorParams blobParams;
|
||||
blobParams.contentType() = contentType;
|
||||
blobParams.length() = length;
|
||||
params = blobParams;
|
||||
}
|
||||
|
||||
BlobParent* actor = BlobParent::Create(aBlob);
|
||||
NS_ENSURE_TRUE(actor, nullptr);
|
||||
|
||||
if (!SendPBlobConstructor(actor, params)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
PCrashReporterParent*
|
||||
ContentParent::AllocPCrashReporter(const NativeThreadId& tid,
|
||||
const PRUint32& processType)
|
||||
@ -930,7 +1000,7 @@ ContentParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor)
|
||||
}
|
||||
|
||||
nsRefPtr<IDBFactory> factory;
|
||||
nsresult rv = IDBFactory::Create(getter_AddRefs(factory));
|
||||
nsresult rv = IDBFactory::Create(this, getter_AddRefs(factory));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
NS_ASSERTION(factory, "This should never be null!");
|
||||
@ -1291,24 +1361,59 @@ ContentParent::RecvShowAlertNotification(const nsString& aImageUrl, const nsStri
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvSyncMessage(const nsString& aMsg, const nsString& aJSON,
|
||||
ContentParent::RecvSyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData,
|
||||
InfallibleTArray<nsString>* aRetvals)
|
||||
{
|
||||
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
|
||||
if (ppm) {
|
||||
const SerializedStructuredCloneBuffer& buffer = aData.data();
|
||||
const InfallibleTArray<PBlobParent*>& blobParents = aData.blobsParent();
|
||||
StructuredCloneData cloneData;
|
||||
cloneData.mData = buffer.data;
|
||||
cloneData.mDataLength = buffer.dataLength;
|
||||
if (!blobParents.IsEmpty()) {
|
||||
PRUint32 length = blobParents.Length();
|
||||
cloneData.mClosure.mBlobs.SetCapacity(length);
|
||||
for (PRUint32 index = 0; index < length; index++) {
|
||||
BlobParent* blobParent = static_cast<BlobParent*>(blobParents[index]);
|
||||
MOZ_ASSERT(blobParent);
|
||||
nsCOMPtr<nsIDOMBlob> blob = blobParent->GetBlob();
|
||||
MOZ_ASSERT(blob);
|
||||
cloneData.mClosure.mBlobs.AppendElement(blob);
|
||||
}
|
||||
}
|
||||
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
|
||||
aMsg,true, aJSON, nullptr, aRetvals);
|
||||
aMsg, true, &cloneData, nullptr, aRetvals);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON)
|
||||
ContentParent::RecvAsyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData)
|
||||
{
|
||||
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
|
||||
if (ppm) {
|
||||
const SerializedStructuredCloneBuffer& buffer = aData.data();
|
||||
const InfallibleTArray<PBlobParent*>& blobParents = aData.blobsParent();
|
||||
StructuredCloneData cloneData;
|
||||
cloneData.mData = buffer.data;
|
||||
cloneData.mDataLength = buffer.dataLength;
|
||||
if (!blobParents.IsEmpty()) {
|
||||
PRUint32 length = blobParents.Length();
|
||||
cloneData.mClosure.mBlobs.SetCapacity(length);
|
||||
for (PRUint32 index = 0; index < length; index++) {
|
||||
BlobParent* blobParent = static_cast<BlobParent*>(blobParents[index]);
|
||||
MOZ_ASSERT(blobParent);
|
||||
nsCOMPtr<nsIDOMBlob> blob = blobParent->GetBlob();
|
||||
MOZ_ASSERT(blob);
|
||||
cloneData.mClosure.mBlobs.AppendElement(blob);
|
||||
}
|
||||
}
|
||||
|
||||
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
|
||||
aMsg, false, aJSON, nullptr, nullptr);
|
||||
aMsg, false, &cloneData, nullptr, nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1403,4 +1508,4 @@ ContentParent::RecvPrivateDocShellsExist(const bool& aExist)
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
} // namespace mozilla
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/dom/PContentParent.h"
|
||||
#include "mozilla/dom/PMemoryReportRequestParent.h"
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
#include "mozilla/dom/ipc/Blob.h"
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIThreadInternal.h"
|
||||
@ -21,8 +22,11 @@
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
class nsFrameMessageManager;
|
||||
class nsIDOMBlob;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace ipc {
|
||||
@ -37,6 +41,7 @@ namespace dom {
|
||||
|
||||
class TabParent;
|
||||
class PStorageParent;
|
||||
class ClonedMessageData;
|
||||
|
||||
class ContentParent : public PContentParent
|
||||
, public nsIObserver
|
||||
@ -47,6 +52,7 @@ private:
|
||||
typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
|
||||
typedef mozilla::ipc::TestShellParent TestShellParent;
|
||||
typedef mozilla::layers::PCompositorParent PCompositorParent;
|
||||
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
|
||||
|
||||
public:
|
||||
static ContentParent* GetNewOrUsed();
|
||||
@ -97,6 +103,8 @@ public:
|
||||
return mSendPermissionUpdates;
|
||||
}
|
||||
|
||||
BlobParent* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
|
||||
|
||||
protected:
|
||||
void OnChannelConnected(int32 pid);
|
||||
virtual void ActorDestroy(ActorDestroyReason why);
|
||||
@ -130,7 +138,7 @@ private:
|
||||
*/
|
||||
void ShutDown();
|
||||
|
||||
PCompositorParent* AllocPCompositor(ipc::Transport* aTransport,
|
||||
PCompositorParent* AllocPCompositor(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess) MOZ_OVERRIDE;
|
||||
|
||||
virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags, const bool& aIsBrowserElement, const PRUint32& aAppId);
|
||||
@ -139,6 +147,9 @@ private:
|
||||
virtual PDeviceStorageRequestParent* AllocPDeviceStorageRequest(const DeviceStorageParams&);
|
||||
virtual bool DeallocPDeviceStorageRequest(PDeviceStorageRequestParent*);
|
||||
|
||||
virtual PBlobParent* AllocPBlob(const BlobConstructorParams& aParams);
|
||||
virtual bool DeallocPBlob(PBlobParent*);
|
||||
|
||||
virtual PCrashReporterParent* AllocPCrashReporter(const NativeThreadId& tid,
|
||||
const PRUint32& processType);
|
||||
virtual bool DeallocPCrashReporter(PCrashReporterParent* crashreporter);
|
||||
@ -226,9 +237,11 @@ private:
|
||||
|
||||
virtual bool RecvLoadURIExternal(const IPC::URI& uri);
|
||||
|
||||
virtual bool RecvSyncMessage(const nsString& aMsg, const nsString& aJSON,
|
||||
virtual bool RecvSyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData,
|
||||
InfallibleTArray<nsString>* aRetvals);
|
||||
virtual bool RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON);
|
||||
virtual bool RecvAsyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData);
|
||||
|
||||
virtual bool RecvAddGeolocationListener();
|
||||
virtual bool RecvRemoveGeolocationListener();
|
||||
|
21
dom/ipc/DOMTypes.ipdlh
Normal file
21
dom/ipc/DOMTypes.ipdlh
Normal file
@ -0,0 +1,21 @@
|
||||
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
|
||||
/* 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 protocol PBlob;
|
||||
|
||||
using mozilla::SerializedStructuredCloneBuffer;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct ClonedMessageData
|
||||
{
|
||||
SerializedStructuredCloneBuffer data;
|
||||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -21,7 +21,10 @@ endif
|
||||
|
||||
EXPORTS = PCOMContentPermissionRequestChild.h
|
||||
|
||||
EXPORTS_NAMESPACES = mozilla/dom
|
||||
EXPORTS_NAMESPACES = \
|
||||
mozilla/dom \
|
||||
mozilla/dom/ipc \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_mozilla/dom = \
|
||||
ContentChild.h \
|
||||
@ -29,17 +32,25 @@ EXPORTS_mozilla/dom = \
|
||||
ContentProcess.h \
|
||||
CrashReporterChild.h \
|
||||
CrashReporterParent.h \
|
||||
StructuredCloneUtils.h \
|
||||
TabParent.h \
|
||||
TabChild.h \
|
||||
TabMessageUtils.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_mozilla/dom/ipc = \
|
||||
Blob.h \
|
||||
nsIRemoteBlob.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
Blob.cpp \
|
||||
ContentProcess.cpp \
|
||||
ContentParent.cpp \
|
||||
ContentChild.cpp \
|
||||
CrashReporterParent.cpp \
|
||||
CrashReporterChild.cpp \
|
||||
StructuredCloneUtils.cpp \
|
||||
TabParent.cpp \
|
||||
TabChild.cpp \
|
||||
TabMessageUtils.cpp \
|
||||
|
23
dom/ipc/PBlob.ipdl
Normal file
23
dom/ipc/PBlob.ipdl
Normal file
@ -0,0 +1,23 @@
|
||||
/* 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 protocol PBlobStream;
|
||||
include protocol PContent;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
protocol PBlob
|
||||
{
|
||||
manager PContent;
|
||||
manages PBlobStream;
|
||||
|
||||
both:
|
||||
__delete__();
|
||||
|
||||
PBlobStream();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
23
dom/ipc/PBlobStream.ipdl
Normal file
23
dom/ipc/PBlobStream.ipdl
Normal file
@ -0,0 +1,23 @@
|
||||
/* 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 protocol PBlob;
|
||||
|
||||
include "mozilla/net/NeckoMessageUtils.h";
|
||||
|
||||
using IPC::InputStream;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
protocol PBlobStream
|
||||
{
|
||||
manager PBlob;
|
||||
|
||||
both:
|
||||
__delete__(InputStream stream);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -5,6 +5,7 @@
|
||||
* 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 protocol PBlob;
|
||||
include protocol PContent;
|
||||
include protocol PContentDialog;
|
||||
include protocol PDocumentRenderer;
|
||||
@ -19,6 +20,8 @@ include "mozilla/dom/TabMessageUtils.h";
|
||||
include "mozilla/layout/RenderFrameUtils.h";
|
||||
include "mozilla/net/NeckoMessageUtils.h";
|
||||
|
||||
include DOMTypes;
|
||||
|
||||
using IPC::URI;
|
||||
using gfxMatrix;
|
||||
using gfxSize;
|
||||
@ -56,7 +59,7 @@ rpc protocol PBrowser
|
||||
manages PIndexedDB;
|
||||
|
||||
both:
|
||||
AsyncMessage(nsString aMessage, nsString aJSON);
|
||||
AsyncMessage(nsString aMessage, ClonedMessageData aData);
|
||||
|
||||
parent:
|
||||
/**
|
||||
@ -69,7 +72,7 @@ parent:
|
||||
|
||||
rpc CreateWindow() returns (PBrowser window);
|
||||
|
||||
sync SyncMessage(nsString aMessage, nsString aJSON)
|
||||
sync SyncMessage(nsString aMessage, ClonedMessageData aData)
|
||||
returns (nsString[] retval);
|
||||
|
||||
/**
|
||||
@ -339,4 +342,4 @@ state DYING:
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PAudio;
|
||||
include protocol PBlob;
|
||||
include protocol PBrowser;
|
||||
include protocol PCompositor;
|
||||
include protocol PCrashReporter;
|
||||
@ -25,6 +26,8 @@ include "mozilla/dom/TabMessageUtils.h";
|
||||
include "nsGeoPositionIPCSerialiser.h";
|
||||
include "PPrefTuple.h";
|
||||
|
||||
include DOMTypes;
|
||||
|
||||
using GeoPosition;
|
||||
using PrefTuple;
|
||||
|
||||
@ -34,6 +37,7 @@ using OverrideMapping;
|
||||
using IPC::URI;
|
||||
using IPC::Permission;
|
||||
using mozilla::null_t;
|
||||
using mozilla::void_t;
|
||||
using mozilla::dom::NativeThreadId;
|
||||
using gfxIntSize;
|
||||
|
||||
@ -96,11 +100,41 @@ union DeviceStorageParams
|
||||
DeviceStorageDeleteParams;
|
||||
DeviceStorageEnumerationParams;
|
||||
};
|
||||
|
||||
struct NormalBlobConstructorParams
|
||||
{
|
||||
nsString contentType;
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
struct FileBlobConstructorParams
|
||||
{
|
||||
nsString name;
|
||||
nsString contentType;
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
struct SlicedBlobConstructorParams
|
||||
{
|
||||
PBlob source;
|
||||
uint64_t begin;
|
||||
uint64_t end;
|
||||
nsString contentType;
|
||||
};
|
||||
|
||||
union BlobConstructorParams
|
||||
{
|
||||
NormalBlobConstructorParams;
|
||||
FileBlobConstructorParams;
|
||||
SlicedBlobConstructorParams;
|
||||
};
|
||||
|
||||
rpc protocol PContent
|
||||
{
|
||||
parent opens PCompositor;
|
||||
|
||||
manages PAudio;
|
||||
manages PBlob;
|
||||
manages PBrowser;
|
||||
manages PCrashReporter;
|
||||
manages PDeviceStorageRequest;
|
||||
@ -122,6 +156,8 @@ both:
|
||||
// as part of ContentParent::CreateTab.
|
||||
async PBrowser(PRUint32 chromeFlags, bool isBrowserElement, PRUint32 appId);
|
||||
|
||||
async PBlob(BlobConstructorParams params);
|
||||
|
||||
child:
|
||||
PMemoryReportRequest();
|
||||
|
||||
@ -199,7 +235,7 @@ parent:
|
||||
|
||||
sync ReadFontList() returns (FontListEntry[] retValue);
|
||||
|
||||
sync SyncMessage(nsString aMessage, nsString aJSON)
|
||||
sync SyncMessage(nsString aMessage, ClonedMessageData aData)
|
||||
returns (nsString[] retval);
|
||||
|
||||
ShowAlertNotification(nsString imageUrl,
|
||||
@ -246,8 +282,7 @@ parent:
|
||||
PrivateDocShellsExist(bool aExist);
|
||||
|
||||
both:
|
||||
AsyncMessage(nsString aMessage, nsString aJSON);
|
||||
|
||||
AsyncMessage(nsString aMessage, ClonedMessageData aData);
|
||||
};
|
||||
|
||||
}
|
||||
|
187
dom/ipc/StructuredCloneUtils.cpp
Normal file
187
dom/ipc/StructuredCloneUtils.cpp
Normal file
@ -0,0 +1,187 @@
|
||||
/* -*- 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 "nsThreadUtils.h"
|
||||
#include "StructuredCloneTags.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<StructuredCloneClosure*>(aClosure);
|
||||
|
||||
if (aTag == SCTAG_DOM_FILE) {
|
||||
MOZ_ASSERT(aData < closure->mBlobs.Length());
|
||||
|
||||
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(closure->mBlobs[aData]);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// File should not be mutable.
|
||||
nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file);
|
||||
bool isMutable;
|
||||
if (NS_FAILED(mutableFile->GetMutable(&isMutable))) {
|
||||
MOZ_NOT_REACHED("GetMutable failed!");
|
||||
}
|
||||
else {
|
||||
MOZ_ASSERT(!isMutable);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
jsval wrappedFile;
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(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<nsIDOMBlob> blob = do_QueryInterface(closure->mBlobs[aData]);
|
||||
MOZ_ASSERT(blob);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Blob should not be mutable.
|
||||
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
|
||||
bool isMutable;
|
||||
if (NS_FAILED(mutableBlob->GetMutable(&isMutable))) {
|
||||
MOZ_NOT_REACHED("GetMutable failed!");
|
||||
}
|
||||
else {
|
||||
MOZ_ASSERT(!isMutable);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
jsval wrappedBlob;
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(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);
|
||||
}
|
||||
|
||||
JSBool
|
||||
Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, JSObject* aObj,
|
||||
void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
StructuredCloneClosure* closure =
|
||||
static_cast<StructuredCloneClosure*>(aClosure);
|
||||
|
||||
// See if this is a wrapped native.
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> 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<nsIDOMFile> file = do_QueryInterface(wrappedObject);
|
||||
if (file) {
|
||||
nsCOMPtr<nsIMutable> 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<nsIDOMBlob> blob = do_QueryInterface(wrappedObject);
|
||||
if (blob) {
|
||||
nsCOMPtr<nsIMutable> 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
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
bool
|
||||
ReadStructuredClone(JSContext* aCx, const uint64_t* aData, size_t aDataLength,
|
||||
const StructuredCloneClosure& aClosure, JS::Value* aClone)
|
||||
{
|
||||
void* closure = &const_cast<StructuredCloneClosure&>(aClosure);
|
||||
return !!JS_ReadStructuredClone(aCx, aData, aDataLength,
|
||||
JS_STRUCTURED_CLONE_VERSION, aClone,
|
||||
&gCallbacks, closure);
|
||||
}
|
||||
|
||||
bool
|
||||
WriteStructuredClone(JSContext* aCx, const JS::Value& aSource,
|
||||
JSAutoStructuredCloneBuffer& aBuffer,
|
||||
StructuredCloneClosure& aClosure)
|
||||
{
|
||||
return aBuffer.write(aCx, aSource, &gCallbacks, &aClosure);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
56
dom/ipc/StructuredCloneUtils.h
Normal file
56
dom/ipc/StructuredCloneUtils.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_StructuredCloneUtils_h
|
||||
#define mozilla_dom_StructuredCloneUtils_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIDOMFile.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct SerializedStructuredCloneBuffer;
|
||||
|
||||
namespace dom {
|
||||
|
||||
struct
|
||||
StructuredCloneClosure
|
||||
{
|
||||
nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
|
||||
};
|
||||
|
||||
struct
|
||||
StructuredCloneData
|
||||
{
|
||||
StructuredCloneData() : mData(nullptr), mDataLength(0) {}
|
||||
uint64_t* mData;
|
||||
size_t mDataLength;
|
||||
StructuredCloneClosure mClosure;
|
||||
};
|
||||
|
||||
bool
|
||||
ReadStructuredClone(JSContext* aCx, const uint64_t* aData, size_t aDataLength,
|
||||
const StructuredCloneClosure& aClosure, JS::Value* aClone);
|
||||
|
||||
inline bool
|
||||
ReadStructuredClone(JSContext* aCx, const StructuredCloneData& aData,
|
||||
JS::Value* aClone)
|
||||
{
|
||||
return ReadStructuredClone(aCx, aData.mData, aData.mDataLength,
|
||||
aData.mClosure, aClone);
|
||||
}
|
||||
|
||||
bool
|
||||
WriteStructuredClone(JSContext* aCx, const JS::Value& aSource,
|
||||
JSAutoStructuredCloneBuffer& aBuffer,
|
||||
StructuredCloneClosure& aClosure);
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_StructuredCloneUtils_h
|
@ -6,7 +6,11 @@
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#include "TabChild.h"
|
||||
|
||||
#include "BasicLayers.h"
|
||||
#include "Blob.h"
|
||||
#include "ContentChild.h"
|
||||
#include "IndexedDBChild.h"
|
||||
#include "mozilla/IntentionalCrash.h"
|
||||
#include "mozilla/docshell/OfflineCacheUpdateChild.h"
|
||||
@ -58,9 +62,10 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "PCOMContentPermissionRequestChild.h"
|
||||
#include "TabChild.h"
|
||||
#include "StructuredCloneUtils.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::layers;
|
||||
@ -646,6 +651,9 @@ TabChild::RecvUpdateFrame(const nsIntRect& aDisplayPort,
|
||||
const gfxSize& aResolution,
|
||||
const nsIntRect& aScreenSize)
|
||||
{
|
||||
if (!mCx || !mTabChildGlobal) {
|
||||
return true;
|
||||
}
|
||||
nsCString data;
|
||||
data += nsPrintfCString("{ \"x\" : %d", aScrollOffset.x);
|
||||
data += nsPrintfCString(", \"y\" : %d", aScrollOffset.y);
|
||||
@ -665,10 +673,25 @@ TabChild::RecvUpdateFrame(const nsIntRect& aDisplayPort,
|
||||
data += nsPrintfCString(" }");
|
||||
data += nsPrintfCString(" }");
|
||||
|
||||
jsval json = JSVAL_NULL;
|
||||
StructuredCloneData cloneData;
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
if (JS_ParseJSON(mCx,
|
||||
static_cast<const jschar*>(NS_ConvertUTF8toUTF16(data).get()),
|
||||
data.Length(),
|
||||
&json)) {
|
||||
WriteStructuredClone(mCx, json, buffer, cloneData.mClosure);
|
||||
}
|
||||
|
||||
nsFrameScriptCx cx(static_cast<nsIWebBrowserChrome*>(this), this);
|
||||
// Let the BrowserElementScrolling helper (if it exists) for this
|
||||
// content manipulate the frame state.
|
||||
return RecvAsyncMessage(NS_LITERAL_STRING("Viewport:Change"),
|
||||
NS_ConvertUTF8toUTF16(data));
|
||||
nsRefPtr<nsFrameMessageManager> mm =
|
||||
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
|
||||
mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(mTabChildGlobal),
|
||||
NS_LITERAL_STRING("Viewport:Change"), false,
|
||||
&cloneData, nullptr, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -958,14 +981,36 @@ TabChild::RecvLoadRemoteScript(const nsString& aURL)
|
||||
|
||||
bool
|
||||
TabChild::RecvAsyncMessage(const nsString& aMessage,
|
||||
const nsString& aJSON)
|
||||
const ClonedMessageData& aData)
|
||||
{
|
||||
if (mTabChildGlobal) {
|
||||
nsFrameScriptCx cx(static_cast<nsIWebBrowserChrome*>(this), this);
|
||||
|
||||
const SerializedStructuredCloneBuffer& buffer = aData.data();
|
||||
const InfallibleTArray<PBlobChild*>& blobChildList = aData.blobsChild();
|
||||
|
||||
StructuredCloneData cloneData;
|
||||
cloneData.mData = buffer.data;
|
||||
cloneData.mDataLength = buffer.dataLength;
|
||||
|
||||
if (!blobChildList.IsEmpty()) {
|
||||
PRUint32 length = blobChildList.Length();
|
||||
cloneData.mClosure.mBlobs.SetCapacity(length);
|
||||
for (PRUint32 i = 0; i < length; ++i) {
|
||||
BlobChild* blobChild = static_cast<BlobChild*>(blobChildList[i]);
|
||||
MOZ_ASSERT(blobChild);
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> blob = blobChild->GetBlob();
|
||||
MOZ_ASSERT(blob);
|
||||
|
||||
cloneData.mClosure.mBlobs.AppendElement(blob);
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<nsFrameMessageManager> mm =
|
||||
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
|
||||
mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(mTabChildGlobal),
|
||||
aMessage, false, aJSON, nullptr, nullptr);
|
||||
aMessage, false, &cloneData, nullptr, nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1184,23 +1229,62 @@ TabChild::DeallocPIndexedDB(PIndexedDBChild* aActor)
|
||||
static bool
|
||||
SendSyncMessageToParent(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON,
|
||||
const StructuredCloneData& aData,
|
||||
InfallibleTArray<nsString>* aJSONRetVal)
|
||||
{
|
||||
return static_cast<TabChild*>(aCallbackData)->
|
||||
SendSyncMessage(nsString(aMessage), nsString(aJSON),
|
||||
aJSONRetVal);
|
||||
TabChild* tabChild = static_cast<TabChild*>(aCallbackData);
|
||||
ContentChild* cc = static_cast<ContentChild*>(tabChild->Manager());
|
||||
ClonedMessageData data;
|
||||
SerializedStructuredCloneBuffer& buffer = data.data();
|
||||
buffer.data = aData.mData;
|
||||
buffer.dataLength = aData.mDataLength;
|
||||
|
||||
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
|
||||
if (!blobs.IsEmpty()) {
|
||||
InfallibleTArray<PBlobChild*>& blobChildList = data.blobsChild();
|
||||
PRUint32 length = blobs.Length();
|
||||
blobChildList.SetCapacity(length);
|
||||
for (PRUint32 i = 0; i < length; ++i) {
|
||||
BlobChild* blobChild = cc->GetOrCreateActorForBlob(blobs[i]);
|
||||
if (!blobChild) {
|
||||
return false;
|
||||
}
|
||||
blobChildList.AppendElement(blobChild);
|
||||
}
|
||||
}
|
||||
return tabChild->SendSyncMessage(nsString(aMessage), data, aJSONRetVal);
|
||||
}
|
||||
|
||||
static bool
|
||||
SendAsyncMessageToParent(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
const nsAString& aJSON)
|
||||
const StructuredCloneData& aData)
|
||||
{
|
||||
return static_cast<TabChild*>(aCallbackData)->
|
||||
SendAsyncMessage(nsString(aMessage), nsString(aJSON));
|
||||
TabChild* tabChild = static_cast<TabChild*>(aCallbackData);
|
||||
ContentChild* cc = static_cast<ContentChild*>(tabChild->Manager());
|
||||
ClonedMessageData data;
|
||||
SerializedStructuredCloneBuffer& buffer = data.data();
|
||||
buffer.data = aData.mData;
|
||||
buffer.dataLength = aData.mDataLength;
|
||||
|
||||
const nsTArray<nsCOMPtr<nsIDOMBlob> >& blobs = aData.mClosure.mBlobs;
|
||||
if (!blobs.IsEmpty()) {
|
||||
InfallibleTArray<PBlobChild*>& blobChildList = data.blobsChild();
|
||||
PRUint32 length = blobs.Length();
|
||||
blobChildList.SetCapacity(length);
|
||||
for (PRUint32 i = 0; i < length; ++i) {
|
||||
BlobChild* blobChild = cc->GetOrCreateActorForBlob(blobs[i]);
|
||||
if (!blobChild) {
|
||||
return false;
|
||||
}
|
||||
blobChildList.AppendElement(blobChild);
|
||||
}
|
||||
}
|
||||
|
||||
return tabChild->SendAsyncMessage(nsString(aMessage), data);
|
||||
}
|
||||
|
||||
|
||||
TabChildGlobal::TabChildGlobal(TabChild* aTabChild)
|
||||
: mTabChild(aTabChild)
|
||||
{
|
||||
|
@ -59,6 +59,7 @@ namespace dom {
|
||||
|
||||
class TabChild;
|
||||
class PContentDialogChild;
|
||||
class ClonedMessageData;
|
||||
|
||||
class TabChildGlobal : public nsDOMEventTargetHelper,
|
||||
public nsIContentFrameMessageManager,
|
||||
@ -142,6 +143,7 @@ class TabChild : public PBrowserChild,
|
||||
public nsITabChild
|
||||
{
|
||||
typedef mozilla::layout::RenderFrameChild RenderFrameChild;
|
||||
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
|
||||
|
||||
public:
|
||||
/**
|
||||
@ -196,7 +198,7 @@ public:
|
||||
virtual bool RecvActivateFrameEvent(const nsString& aType, const bool& capture);
|
||||
virtual bool RecvLoadRemoteScript(const nsString& aURL);
|
||||
virtual bool RecvAsyncMessage(const nsString& aMessage,
|
||||
const nsString& aJSON);
|
||||
const ClonedMessageData& aData);
|
||||
|
||||
virtual PDocumentRendererChild*
|
||||
AllocPDocumentRenderer(const nsRect& documentRect, const gfxMatrix& transform,
|
||||
|
@ -6,6 +6,9 @@
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#include "TabParent.h"
|
||||
|
||||
#include "Blob.h"
|
||||
#include "IDBFactory.h"
|
||||
#include "IndexedDBParent.h"
|
||||
#include "mozilla/BrowserElementParent.h"
|
||||
@ -42,8 +45,8 @@
|
||||
#include "nsSerializationHelper.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "StructuredCloneUtils.h"
|
||||
#include "TabChild.h"
|
||||
#include "TabParent.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
@ -344,17 +347,51 @@ bool TabParent::SendRealTouchEvent(nsTouchEvent& event)
|
||||
|
||||
bool
|
||||
TabParent::RecvSyncMessage(const nsString& aMessage,
|
||||
const nsString& aJSON,
|
||||
const ClonedMessageData& aData,
|
||||
InfallibleTArray<nsString>* aJSONRetVal)
|
||||
{
|
||||
return ReceiveMessage(aMessage, true, aJSON, aJSONRetVal);
|
||||
const SerializedStructuredCloneBuffer& buffer = aData.data();
|
||||
const InfallibleTArray<PBlobParent*>& blobParents = aData.blobsParent();
|
||||
StructuredCloneData cloneData;
|
||||
cloneData.mData = buffer.data;
|
||||
cloneData.mDataLength = buffer.dataLength;
|
||||
if (!blobParents.IsEmpty()) {
|
||||
PRUint32 length = blobParents.Length();
|
||||
cloneData.mClosure.mBlobs.SetCapacity(length);
|
||||
for (PRUint32 i = 0; i < length; ++i) {
|
||||
BlobParent* blobParent = static_cast<BlobParent*>(blobParents[i]);
|
||||
MOZ_ASSERT(blobParent);
|
||||
nsCOMPtr<nsIDOMBlob> blob = blobParent->GetBlob();
|
||||
MOZ_ASSERT(blob);
|
||||
cloneData.mClosure.mBlobs.AppendElement(blob);
|
||||
}
|
||||
}
|
||||
return ReceiveMessage(aMessage, true, &cloneData, aJSONRetVal);
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvAsyncMessage(const nsString& aMessage,
|
||||
const nsString& aJSON)
|
||||
const ClonedMessageData& aData)
|
||||
{
|
||||
return ReceiveMessage(aMessage, false, aJSON, nullptr);
|
||||
const SerializedStructuredCloneBuffer& buffer = aData.data();
|
||||
const InfallibleTArray<PBlobParent*>& blobParents = aData.blobsParent();
|
||||
|
||||
StructuredCloneData cloneData;
|
||||
cloneData.mData = buffer.data;
|
||||
cloneData.mDataLength = buffer.dataLength;
|
||||
|
||||
if (!blobParents.IsEmpty()) {
|
||||
PRUint32 length = blobParents.Length();
|
||||
cloneData.mClosure.mBlobs.SetCapacity(length);
|
||||
for (PRUint32 i = 0; i < length; ++i) {
|
||||
BlobParent* blobParent = static_cast<BlobParent*>(blobParents[i]);
|
||||
MOZ_ASSERT(blobParent);
|
||||
nsCOMPtr<nsIDOMBlob> blob = blobParent->GetBlob();
|
||||
MOZ_ASSERT(blob);
|
||||
cloneData.mClosure.mBlobs.AppendElement(blob);
|
||||
}
|
||||
}
|
||||
return ReceiveMessage(aMessage, false, &cloneData, nullptr);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -697,7 +734,7 @@ TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue)
|
||||
bool
|
||||
TabParent::ReceiveMessage(const nsString& aMessage,
|
||||
bool aSync,
|
||||
const nsString& aJSON,
|
||||
const StructuredCloneData* aCloneData,
|
||||
InfallibleTArray<nsString>* aJSONRetVal)
|
||||
{
|
||||
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
|
||||
@ -717,7 +754,7 @@ TabParent::ReceiveMessage(const nsString& aMessage,
|
||||
manager->ReceiveMessage(mFrameElement,
|
||||
aMessage,
|
||||
aSync,
|
||||
aJSON,
|
||||
aCloneData,
|
||||
objectsArray,
|
||||
aJSONRetVal);
|
||||
}
|
||||
@ -758,9 +795,13 @@ TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
|
||||
nsCOMPtr<nsPIDOMWindow> window = doc->GetInnerWindow();
|
||||
NS_ENSURE_TRUE(window, false);
|
||||
|
||||
ContentParent* contentParent = static_cast<ContentParent*>(Manager());
|
||||
NS_ASSERTION(contentParent, "Null manager?!");
|
||||
|
||||
nsRefPtr<IDBFactory> factory;
|
||||
nsresult rv =
|
||||
IDBFactory::Create(window, aASCIIOrigin, getter_AddRefs(factory));
|
||||
IDBFactory::Create(window, aASCIIOrigin, contentParent,
|
||||
getter_AddRefs(factory));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
if (!factory) {
|
||||
|
@ -40,6 +40,9 @@ class RenderFrameParent;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class ClonedMessageData;
|
||||
struct StructuredCloneData;
|
||||
|
||||
class ContentDialogParent : public PContentDialogParent {};
|
||||
|
||||
class TabParent : public PBrowserParent
|
||||
@ -47,6 +50,8 @@ class TabParent : public PBrowserParent
|
||||
, public nsIAuthPromptProvider
|
||||
, public nsISecureBrowserUI
|
||||
{
|
||||
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
|
||||
|
||||
public:
|
||||
TabParent();
|
||||
virtual ~TabParent();
|
||||
@ -68,10 +73,10 @@ public:
|
||||
bool* aOutWindowOpened);
|
||||
virtual bool AnswerCreateWindow(PBrowserParent** retval);
|
||||
virtual bool RecvSyncMessage(const nsString& aMessage,
|
||||
const nsString& aJSON,
|
||||
const ClonedMessageData& aData,
|
||||
InfallibleTArray<nsString>* aJSONRetVal);
|
||||
virtual bool RecvAsyncMessage(const nsString& aMessage,
|
||||
const nsString& aJSON);
|
||||
const ClonedMessageData& aData);
|
||||
virtual bool RecvNotifyIMEFocus(const bool& aFocus,
|
||||
nsIMEUpdatePreference* aPreference,
|
||||
PRUint32* aSeqno);
|
||||
@ -172,7 +177,7 @@ public:
|
||||
protected:
|
||||
bool ReceiveMessage(const nsString& aMessage,
|
||||
bool aSync,
|
||||
const nsString& aJSON,
|
||||
const StructuredCloneData* aCloneData,
|
||||
InfallibleTArray<nsString>* aJSONRetVal = nullptr);
|
||||
|
||||
virtual bool Recv__delete__() MOZ_OVERRIDE;
|
||||
|
@ -3,7 +3,10 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
IPDLSRCS = \
|
||||
DOMTypes.ipdlh \
|
||||
PAudio.ipdl \
|
||||
PBlob.ipdl \
|
||||
PBlobStream.ipdl \
|
||||
PBrowser.ipdl \
|
||||
PContent.ipdl \
|
||||
PContentDialog.ipdl \
|
||||
|
28
dom/ipc/nsIRemoteBlob.h
Normal file
28
dom/ipc/nsIRemoteBlob.h
Normal file
@ -0,0 +1,28 @@
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_ipc_nsIRemoteBlob_h
|
||||
#define mozilla_dom_ipc_nsIRemoteBlob_h
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
#ifndef NS_NO_VTABLE
|
||||
#define NS_NO_VTABLE
|
||||
#endif
|
||||
|
||||
#define NS_IREMOTEBLOB_IID \
|
||||
{0x74ce3cdd, 0xbfc9, 0x4edb, {0x98, 0x26, 0x50, 0xcf, 0x00, 0x26, 0x58, 0x70}}
|
||||
|
||||
class NS_NO_VTABLE nsIRemoteBlob : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IREMOTEBLOB_IID)
|
||||
|
||||
// This will either return a PBlobChild or PBlobParent.
|
||||
virtual void* GetPBlob() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIRemoteBlob, NS_IREMOTEBLOB_IID)
|
||||
|
||||
#endif // mozilla_dom_ipc_nsIRemoteBlob_h
|
@ -17,6 +17,8 @@ const int Pickle::kPayloadUnit = 64;
|
||||
// We mark a read only pickle with a special capacity_.
|
||||
static const uint32 kCapacityReadOnly = (uint32) -1;
|
||||
|
||||
static const char kBytePaddingMarker = char(0xbf);
|
||||
|
||||
// Payload is uint32 aligned.
|
||||
|
||||
Pickle::Pickle()
|
||||
@ -359,16 +361,34 @@ bool Pickle::ReadString16(void** iter, string16* result) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pickle::ReadBytes(void** iter, const char** data, int length) const {
|
||||
bool Pickle::ReadBytes(void** iter, const char** data, int length,
|
||||
uint32 alignment) const {
|
||||
DCHECK(iter);
|
||||
DCHECK(data);
|
||||
DCHECK(alignment == 4 || alignment == 8);
|
||||
DCHECK(intptr_t(header_) % alignment == 0);
|
||||
|
||||
if (!*iter)
|
||||
*iter = const_cast<char*>(payload());
|
||||
|
||||
uint32 paddingLen = intptr_t(*iter) % alignment;
|
||||
if (paddingLen) {
|
||||
#ifdef DEBUG
|
||||
{
|
||||
const char* padding = static_cast<const char*>(*iter);
|
||||
for (uint32 i = 0; i < paddingLen; i++) {
|
||||
DCHECK(*(padding + i) == kBytePaddingMarker);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
length += paddingLen;
|
||||
}
|
||||
|
||||
if (!IteratorHasRoomFor(*iter, length))
|
||||
return false;
|
||||
|
||||
*data = reinterpret_cast<const char*>(*iter);
|
||||
*data = static_cast<const char*>(*iter) + paddingLen;
|
||||
DCHECK(intptr_t(*data) % alignment == 0);
|
||||
|
||||
UpdateIter(iter, length);
|
||||
return true;
|
||||
@ -387,21 +407,35 @@ bool Pickle::ReadData(void** iter, const char** data, int* length) const {
|
||||
return ReadBytes(iter, data, *length);
|
||||
}
|
||||
|
||||
char* Pickle::BeginWrite(uint32 length) {
|
||||
// write at a uint32-aligned offset from the beginning of the header
|
||||
char* Pickle::BeginWrite(uint32 length, uint32 alignment) {
|
||||
DCHECK(alignment % 4 == 0) << "Must be at least 32-bit aligned!";
|
||||
|
||||
// write at an alignment-aligned offset from the beginning of the header
|
||||
uint32 offset = AlignInt(header_->payload_size, sizeof(uint32));
|
||||
uint32 new_size = offset + AlignInt(length, sizeof(uint32));
|
||||
uint32 padding = (header_size_ + offset) % alignment;
|
||||
uint32 new_size = offset + padding + AlignInt(length, sizeof(uint32));
|
||||
uint32 needed_size = header_size_ + new_size;
|
||||
|
||||
if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
|
||||
return NULL;
|
||||
|
||||
DCHECK(intptr_t(header_) % alignment == 0);
|
||||
|
||||
#ifdef ARCH_CPU_64_BITS
|
||||
DCHECK_LE(length, std::numeric_limits<uint32>::max());
|
||||
#endif
|
||||
|
||||
header_->payload_size = static_cast<uint32>(new_size);
|
||||
return payload() + offset;
|
||||
char* buffer = payload() + offset;
|
||||
|
||||
if (padding) {
|
||||
memset(buffer, kBytePaddingMarker, padding);
|
||||
buffer += padding;
|
||||
}
|
||||
|
||||
DCHECK(intptr_t(buffer) % alignment == 0);
|
||||
|
||||
header_->payload_size = new_size;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void Pickle::EndWrite(char* dest, int length) {
|
||||
@ -411,10 +445,12 @@ void Pickle::EndWrite(char* dest, int length) {
|
||||
memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32)));
|
||||
}
|
||||
|
||||
bool Pickle::WriteBytes(const void* data, int data_len) {
|
||||
bool Pickle::WriteBytes(const void* data, int data_len, uint32 alignment) {
|
||||
DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly";
|
||||
DCHECK(alignment == 4 || alignment == 8);
|
||||
DCHECK(intptr_t(header_) % alignment == 0);
|
||||
|
||||
char* dest = BeginWrite(data_len);
|
||||
char* dest = BeginWrite(data_len, alignment);
|
||||
if (!dest)
|
||||
return false;
|
||||
|
||||
@ -458,7 +494,7 @@ char* Pickle::BeginWriteData(int length) {
|
||||
if (!WriteInt(length))
|
||||
return false;
|
||||
|
||||
char *data_ptr = BeginWrite(length);
|
||||
char *data_ptr = BeginWrite(length, sizeof(uint32));
|
||||
if (!data_ptr)
|
||||
return NULL;
|
||||
|
||||
|
@ -83,7 +83,8 @@ class Pickle {
|
||||
bool ReadWString(void** iter, std::wstring* result) const;
|
||||
bool ReadString16(void** iter, string16* result) const;
|
||||
bool ReadData(void** iter, const char** data, int* length) const;
|
||||
bool ReadBytes(void** iter, const char** data, int length) const;
|
||||
bool ReadBytes(void** iter, const char** data, int length,
|
||||
uint32 alignment = sizeof(uint32)) const;
|
||||
|
||||
// Safer version of ReadInt() checks for the result not being negative.
|
||||
// Use it for reading the object sizes.
|
||||
@ -147,7 +148,8 @@ class Pickle {
|
||||
bool WriteWString(const std::wstring& value);
|
||||
bool WriteString16(const string16& value);
|
||||
bool WriteData(const char* data, int length);
|
||||
bool WriteBytes(const void* data, int data_len);
|
||||
bool WriteBytes(const void* data, int data_len,
|
||||
uint32 alignment = sizeof(uint32));
|
||||
|
||||
// Same as WriteData, but allows the caller to write directly into the
|
||||
// Pickle. This saves a copy in cases where the data is not already
|
||||
@ -231,7 +233,7 @@ class Pickle {
|
||||
// location that the data should be written at is returned, or NULL if there
|
||||
// was an error. Call EndWrite with the returned offset and the given length
|
||||
// to pad out for the next write.
|
||||
char* BeginWrite(uint32 length);
|
||||
char* BeginWrite(uint32 length, uint32 alignment);
|
||||
|
||||
// Completes the write operation by padding the data with NULL bytes until it
|
||||
// is padded. Should be paired with BeginWrite, but it does not necessarily
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "nsRect.h"
|
||||
#include "nsRegion.h"
|
||||
#include "gfxASurface.h"
|
||||
#include "jsapi.h"
|
||||
#include "LayersTypes.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -62,6 +63,36 @@ struct null_t {
|
||||
bool operator==(const null_t&) const { return true; }
|
||||
};
|
||||
|
||||
struct SerializedStructuredCloneBuffer
|
||||
{
|
||||
SerializedStructuredCloneBuffer()
|
||||
: data(nullptr), dataLength(0)
|
||||
{ }
|
||||
|
||||
SerializedStructuredCloneBuffer(const JSAutoStructuredCloneBuffer& aOther)
|
||||
{
|
||||
*this = aOther;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const SerializedStructuredCloneBuffer& aOther) const
|
||||
{
|
||||
return this->data == aOther.data &&
|
||||
this->dataLength == aOther.dataLength;
|
||||
}
|
||||
|
||||
SerializedStructuredCloneBuffer&
|
||||
operator=(const JSAutoStructuredCloneBuffer& aOther)
|
||||
{
|
||||
data = aOther.data();
|
||||
dataLength = aOther.nbytes();
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint64_t* data;
|
||||
size_t dataLength;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
namespace IPC {
|
||||
@ -830,6 +861,47 @@ struct ParamTraits<mozilla::TimeStamp>
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::SerializedStructuredCloneBuffer>
|
||||
{
|
||||
typedef mozilla::SerializedStructuredCloneBuffer paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.dataLength);
|
||||
if (aParam.dataLength) {
|
||||
// Structured clone data must be 64-bit aligned.
|
||||
aMsg->WriteBytes(aParam.data, aParam.dataLength, sizeof(uint64_t));
|
||||
}
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (!ReadParam(aMsg, aIter, &aResult->dataLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aResult->dataLength) {
|
||||
const char** buffer =
|
||||
const_cast<const char**>(reinterpret_cast<char**>(&aResult->data));
|
||||
// Structured clone data must be 64-bit aligned.
|
||||
if (!aMsg->ReadBytes(aIter, buffer, aResult->dataLength,
|
||||
sizeof(uint64_t))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
aResult->data = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
LogParam(aParam.dataLength, aLog);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace IPC */
|
||||
|
||||
#endif /* __IPC_GLUE_IPCMESSAGEUTILS_H__ */
|
||||
|
@ -84,6 +84,7 @@ using namespace mozilla::dom::file;
|
||||
|
||||
#include "nsFormData.h"
|
||||
#include "nsBlobProtocolHandler.h"
|
||||
#include "nsBlobURI.h"
|
||||
#include "nsGlobalWindowCommands.h"
|
||||
#include "nsIControllerCommandTable.h"
|
||||
#include "nsJSProtocolHandler.h"
|
||||
@ -260,6 +261,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsDOMFileReader, Init)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(ArchiveReader)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFormData)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsBlobProtocolHandler)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsBlobURI)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMParser)
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsDOMStorageManager,
|
||||
nsDOMStorageManager::GetInstance)
|
||||
@ -740,6 +742,7 @@ NS_DEFINE_NAMED_CID(NS_FILEREADER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ARCHIVEREADER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_FORMDATA_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_BLOBPROTOCOLHANDLER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_BLOBURI_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_XMLHTTPREQUEST_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_EVENTSOURCE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_WEBSOCKET_CID);
|
||||
@ -1013,6 +1016,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
|
||||
{ &kNS_ARCHIVEREADER_CID, false, NULL, ArchiveReaderConstructor },
|
||||
{ &kNS_FORMDATA_CID, false, NULL, nsFormDataConstructor },
|
||||
{ &kNS_BLOBPROTOCOLHANDLER_CID, false, NULL, nsBlobProtocolHandlerConstructor },
|
||||
{ &kNS_BLOBURI_CID, false, NULL, nsBlobURIConstructor },
|
||||
{ &kNS_XMLHTTPREQUEST_CID, false, NULL, nsXMLHttpRequestConstructor },
|
||||
{ &kNS_EVENTSOURCE_CID, false, NULL, nsEventSourceConstructor },
|
||||
{ &kNS_WEBSOCKET_CID, false, NULL, nsWebSocketConstructor },
|
||||
|
Loading…
x
Reference in New Issue
Block a user