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:
Ben Turner 2012-08-01 23:02:29 -07:00
parent 457ab097a2
commit 4893263a15
59 changed files with 3290 additions and 543 deletions

View File

@ -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.
*/

View File

@ -128,6 +128,7 @@ CPPSRCS = \
FragmentOrElement.cpp \
Link.cpp \
nsBlobProtocolHandler.cpp \
nsBlobURI.cpp \
nsFrameMessageManager.cpp \
nsInProcessTabChildGlobal.cpp \
ThirdPartyUtil.cpp \

View File

@ -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

View 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;
}

View 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 */

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;

View File

@ -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 = \

View 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>

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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),

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
};

View File

@ -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);

View File

@ -145,6 +145,7 @@ public:
const Key& aKey,
const Key& aObjectKey,
const SerializedStructuredCloneReadInfo& aCloneInfo,
nsTArray<StructuredCloneFile>& aBlobs,
IDBCursor** _retval);
private:

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -50,7 +50,7 @@ StructuredCloneReadInfo::SetFromSerialized(
return false;
}
mFileInfos.Clear();
mFiles.Clear();
return true;
}

View File

@ -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!");

View File

@ -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;
}

View File

@ -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__

View File

@ -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));

View File

@ -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);
}

View File

@ -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);
};
/*******************************************************************************

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 \

View 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
View 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
View 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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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
View 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

View File

@ -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
View 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
View 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

View File

@ -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:
};
}
}
}

View File

@ -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);
};
}

View 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

View 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

View File

@ -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)
{

View File

@ -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,

View File

@ -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) {

View File

@ -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;

View File

@ -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
View 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

View File

@ -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;

View File

@ -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

View File

@ -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__ */

View File

@ -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 },