Backed out changeset 19f871364039 (bug 1110485) for causing bc1 winxp memory leaks on a CLOSED TREE

This commit is contained in:
Carsten "Tomcat" Book 2015-04-15 09:55:53 +02:00
parent 2b2cc53c16
commit 221df621f6
33 changed files with 2334 additions and 1790 deletions

View File

@ -7,7 +7,6 @@
#include "mozilla/dom/cache/AutoUtils.h"
#include "mozilla/unused.h"
#include "mozilla/dom/cache/CacheParent.h"
#include "mozilla/dom/cache/CachePushStreamChild.h"
#include "mozilla/dom/cache/CacheStreamControlParent.h"
#include "mozilla/dom/cache/ReadStream.h"
@ -137,381 +136,171 @@ namespace cache {
using mozilla::ipc::PBackgroundParent;
// --------------------------------------------
AutoChildOpArgs::AutoChildOpArgs(TypeUtils* aTypeUtils,
const CacheOpArgs& aOpArgs)
AutoChildBase::AutoChildBase(TypeUtils* aTypeUtils)
: mTypeUtils(aTypeUtils)
, mOpArgs(aOpArgs)
, mSent(false)
{
MOZ_ASSERT(mTypeUtils);
}
AutoChildOpArgs::~AutoChildOpArgs()
AutoChildBase::~AutoChildBase()
{
CleanupAction action = mSent ? Forget : Delete;
switch(mOpArgs.type()) {
case CacheOpArgs::TCacheMatchArgs:
{
CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs();
CleanupChild(args.request().body(), action);
break;
}
case CacheOpArgs::TCacheMatchAllArgs:
{
CacheMatchAllArgs& args = mOpArgs.get_CacheMatchAllArgs();
if (args.requestOrVoid().type() == PCacheRequestOrVoid::Tvoid_t) {
break;
}
CleanupChild(args.requestOrVoid().get_PCacheRequest().body(), action);
break;
}
case CacheOpArgs::TCacheAddAllArgs:
{
CacheAddAllArgs& args = mOpArgs.get_CacheAddAllArgs();
auto& list = args.requestList();
for (uint32_t i = 0; i < list.Length(); ++i) {
CleanupChild(list[i].body(), action);
}
break;
}
case CacheOpArgs::TCachePutAllArgs:
{
CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
auto& list = args.requestResponseList();
for (uint32_t i = 0; i < list.Length(); ++i) {
CleanupChild(list[i].request().body(), action);
CleanupChild(list[i].response().body(), action);
}
break;
}
case CacheOpArgs::TCacheDeleteArgs:
{
CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs();
CleanupChild(args.request().body(), action);
break;
}
case CacheOpArgs::TCacheKeysArgs:
{
CacheKeysArgs& args = mOpArgs.get_CacheKeysArgs();
if (args.requestOrVoid().type() == PCacheRequestOrVoid::Tvoid_t) {
break;
}
CleanupChild(args.requestOrVoid().get_PCacheRequest().body(), action);
break;
}
case CacheOpArgs::TStorageMatchArgs:
{
StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs();
CleanupChild(args.request().body(), action);
break;
}
default:
// Other types do not need cleanup
break;
}
}
void
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
ErrorResult& aRv)
{
MOZ_ASSERT(!mSent);
switch(mOpArgs.type()) {
case CacheOpArgs::TCacheMatchArgs:
{
CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs();
mTypeUtils->ToPCacheRequest(args.request(), aRequest, aBodyAction,
aReferrerAction, aSchemeAction, aRv);
break;
}
case CacheOpArgs::TCacheMatchAllArgs:
{
CacheMatchAllArgs& args = mOpArgs.get_CacheMatchAllArgs();
MOZ_ASSERT(args.requestOrVoid().type() == PCacheRequestOrVoid::Tvoid_t);
args.requestOrVoid() = PCacheRequest();
mTypeUtils->ToPCacheRequest(args.requestOrVoid().get_PCacheRequest(),
aRequest, aBodyAction, aReferrerAction,
aSchemeAction, aRv);
break;
}
case CacheOpArgs::TCacheAddAllArgs:
{
CacheAddAllArgs& args = mOpArgs.get_CacheAddAllArgs();
// The FileDescriptorSetChild asserts in its destructor that all fds have
// been removed. The copy constructor, however, simply duplicates the
// fds without removing any. This means each temporary and copy must be
// explicitly cleaned up.
//
// Avoid a lot of this hassle by making sure we only create one here. On
// error we remove it.
PCacheRequest& request = *args.requestList().AppendElement();
mTypeUtils->ToPCacheRequest(request, aRequest, aBodyAction,
aReferrerAction, aSchemeAction, aRv);
if (aRv.Failed()) {
args.requestList().RemoveElementAt(args.requestList().Length() - 1);
}
break;
}
case CacheOpArgs::TCacheDeleteArgs:
{
CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs();
mTypeUtils->ToPCacheRequest(args.request(), aRequest, aBodyAction,
aReferrerAction, aSchemeAction, aRv);
break;
}
case CacheOpArgs::TCacheKeysArgs:
{
CacheKeysArgs& args = mOpArgs.get_CacheKeysArgs();
MOZ_ASSERT(args.requestOrVoid().type() == PCacheRequestOrVoid::Tvoid_t);
args.requestOrVoid() = PCacheRequest();
mTypeUtils->ToPCacheRequest(args.requestOrVoid().get_PCacheRequest(),
aRequest, aBodyAction, aReferrerAction,
aSchemeAction, aRv);
break;
}
case CacheOpArgs::TStorageMatchArgs:
{
StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs();
mTypeUtils->ToPCacheRequest(args.request(), aRequest, aBodyAction,
aReferrerAction, aSchemeAction, aRv);
break;
}
default:
MOZ_CRASH("Cache args type cannot send a Request!");
}
}
void
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
Response& aResponse, ErrorResult& aRv)
{
MOZ_ASSERT(!mSent);
switch(mOpArgs.type()) {
case CacheOpArgs::TCachePutAllArgs:
{
CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
// The FileDescriptorSetChild asserts in its destructor that all fds have
// been removed. The copy constructor, however, simply duplicates the
// fds without removing any. This means each temporary and copy must be
// explicitly cleaned up.
//
// Avoid a lot of this hassle by making sure we only create one here. On
// error we remove it.
CacheRequestResponse& pair = *args.requestResponseList().AppendElement();
pair.request().body() = void_t();
pair.response().body() = void_t();
mTypeUtils->ToPCacheRequest(pair.request(), aRequest, aBodyAction,
aReferrerAction, aSchemeAction, aRv);
if (!aRv.Failed()) {
mTypeUtils->ToPCacheResponse(pair.response(), aResponse, aRv);
}
if (aRv.Failed()) {
CleanupChild(pair.request().body(), Delete);
args.requestResponseList().RemoveElementAt(
args.requestResponseList().Length() - 1);
}
break;
}
default:
MOZ_CRASH("Cache args type cannot send a Request/Response pair!");
}
}
const CacheOpArgs&
AutoChildOpArgs::SendAsOpArgs()
{
MOZ_ASSERT(!mSent);
mSent = true;
return mOpArgs;
}
// --------------------------------------------
AutoParentOpResult::AutoParentOpResult(mozilla::ipc::PBackgroundParent* aManager,
const CacheOpResult& aOpResult)
AutoChildRequest::AutoChildRequest(TypeUtils* aTypeUtils)
: AutoChildBase(aTypeUtils)
{
mRequestOrVoid = void_t();
}
AutoChildRequest::~AutoChildRequest()
{
if (mRequestOrVoid.type() != PCacheRequestOrVoid::TPCacheRequest) {
return;
}
CleanupAction action = mSent ? Forget : Delete;
CleanupChild(mRequestOrVoid.get_PCacheRequest().body(), action);
}
void
AutoChildRequest::Add(InternalRequest* aRequest, BodyAction aBodyAction,
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
ErrorResult& aRv)
{
MOZ_ASSERT(!mSent);
MOZ_ASSERT(mRequestOrVoid.type() == PCacheRequestOrVoid::Tvoid_t);
mRequestOrVoid = PCacheRequest();
mTypeUtils->ToPCacheRequest(mRequestOrVoid.get_PCacheRequest(), aRequest,
aBodyAction, aReferrerAction, aSchemeAction, aRv);
}
const PCacheRequest&
AutoChildRequest::SendAsRequest()
{
MOZ_ASSERT(mRequestOrVoid.type() == PCacheRequestOrVoid::TPCacheRequest);
return mRequestOrVoid.get_PCacheRequest();
}
const PCacheRequestOrVoid&
AutoChildRequest::SendAsRequestOrVoid()
{
return mRequestOrVoid;
}
// --------------------------------------------
AutoChildRequestList::AutoChildRequestList(TypeUtils* aTypeUtils,
uint32_t aCapacity)
: AutoChildBase(aTypeUtils)
{
mRequestList.SetCapacity(aCapacity);
}
AutoChildRequestList::~AutoChildRequestList()
{
CleanupAction action = mSent ? Forget : Delete;
for (uint32_t i = 0; i < mRequestList.Length(); ++i) {
CleanupChild(mRequestList[i].body(), action);
}
}
void
AutoChildRequestList::Add(InternalRequest* aRequest, BodyAction aBodyAction,
ReferrerAction aReferrerAction,
SchemeAction aSchemeAction, ErrorResult& aRv)
{
MOZ_ASSERT(!mSent);
// The FileDescriptorSetChild asserts in its destructor that all fds have
// been removed. The copy constructor, however, simply duplicates the
// fds without removing any. This means each temporary and copy must be
// explicitly cleaned up.
//
// Avoid a lot of this hassle by making sure we only create one here. On
// error we remove it.
PCacheRequest* request = mRequestList.AppendElement();
mTypeUtils->ToPCacheRequest(*request, aRequest, aBodyAction, aReferrerAction,
aSchemeAction, aRv);
if (aRv.Failed()) {
mRequestList.RemoveElementAt(mRequestList.Length() - 1);
}
}
const nsTArray<PCacheRequest>&
AutoChildRequestList::SendAsRequestList()
{
MOZ_ASSERT(!mSent);
mSent = true;
return mRequestList;
}
// --------------------------------------------
AutoChildRequestResponse::AutoChildRequestResponse(TypeUtils* aTypeUtils)
: AutoChildBase(aTypeUtils)
{
// Default IPC-generated constructor does not initialize these correctly
// and we check them later when cleaning up.
mRequestResponse.request().body() = void_t();
mRequestResponse.response().body() = void_t();
}
AutoChildRequestResponse::~AutoChildRequestResponse()
{
CleanupAction action = mSent ? Forget : Delete;
CleanupChild(mRequestResponse.request().body(), action);
CleanupChild(mRequestResponse.response().body(), action);
}
void
AutoChildRequestResponse::Add(InternalRequest* aRequest, BodyAction aBodyAction,
ReferrerAction aReferrerAction,
SchemeAction aSchemeAction, ErrorResult& aRv)
{
MOZ_ASSERT(!mSent);
mTypeUtils->ToPCacheRequest(mRequestResponse.request(), aRequest, aBodyAction,
aReferrerAction, aSchemeAction, aRv);
}
void
AutoChildRequestResponse::Add(Response& aResponse, ErrorResult& aRv)
{
MOZ_ASSERT(!mSent);
mTypeUtils->ToPCacheResponse(mRequestResponse.response(), aResponse, aRv);
}
const CacheRequestResponse&
AutoChildRequestResponse::SendAsRequestResponse()
{
MOZ_ASSERT(!mSent);
mSent = true;
return mRequestResponse;
}
// --------------------------------------------
AutoParentBase::AutoParentBase(PBackgroundParent* aManager)
: mManager(aManager)
, mOpResult(aOpResult)
, mStreamControl(nullptr)
, mSent(false)
{
MOZ_ASSERT(mManager);
}
AutoParentOpResult::~AutoParentOpResult()
AutoParentBase::~AutoParentBase()
{
CleanupAction action = mSent ? Forget : Delete;
switch (mOpResult.type()) {
case CacheOpResult::TCacheMatchResult:
{
CacheMatchResult& result = mOpResult.get_CacheMatchResult();
if (result.responseOrVoid().type() == PCacheResponseOrVoid::Tvoid_t) {
break;
}
CleanupParentFds(result.responseOrVoid().get_PCacheResponse().body(),
action);
break;
}
case CacheOpResult::TCacheMatchAllResult:
{
CacheMatchAllResult& result = mOpResult.get_CacheMatchAllResult();
for (uint32_t i = 0; i < result.responseList().Length(); ++i) {
CleanupParentFds(result.responseList()[i].body(), action);
}
break;
}
case CacheOpResult::TCacheKeysResult:
{
CacheKeysResult& result = mOpResult.get_CacheKeysResult();
for (uint32_t i = 0; i < result.requestList().Length(); ++i) {
CleanupParentFds(result.requestList()[i].body(), action);
}
break;
}
case CacheOpResult::TStorageMatchResult:
{
StorageMatchResult& result = mOpResult.get_StorageMatchResult();
if (result.responseOrVoid().type() == PCacheResponseOrVoid::Tvoid_t) {
break;
}
CleanupParentFds(result.responseOrVoid().get_PCacheResponse().body(),
action);
break;
}
case CacheOpResult::TStorageOpenResult:
{
StorageOpenResult& result = mOpResult.get_StorageOpenResult();
if (action == Forget || result.actorParent() == nullptr) {
break;
}
unused << PCacheParent::Send__delete__(result.actorParent());
}
default:
// other types do not need clean up
break;
}
if (action == Delete && mStreamControl) {
if (!mSent && mStreamControl) {
unused << PCacheStreamControlParent::Send__delete__(mStreamControl);
}
}
void
AutoParentOpResult::Add(CacheId aOpenedCacheId, Manager* aManager)
{
MOZ_ASSERT(mOpResult.type() == CacheOpResult::TStorageOpenResult);
MOZ_ASSERT(mOpResult.get_StorageOpenResult().actorParent() == nullptr);
mOpResult.get_StorageOpenResult().actorParent() =
mManager->SendPCacheConstructor(new CacheParent(aManager, aOpenedCacheId));
}
void
AutoParentOpResult::Add(const SavedResponse& aSavedResponse,
StreamList* aStreamList)
{
MOZ_ASSERT(!mSent);
switch (mOpResult.type()) {
case CacheOpResult::TCacheMatchResult:
{
CacheMatchResult& result = mOpResult.get_CacheMatchResult();
MOZ_ASSERT(result.responseOrVoid().type() == PCacheResponseOrVoid::Tvoid_t);
result.responseOrVoid() = aSavedResponse.mValue;
SerializeResponseBody(aSavedResponse, aStreamList,
&result.responseOrVoid().get_PCacheResponse());
break;
}
case CacheOpResult::TCacheMatchAllResult:
{
CacheMatchAllResult& result = mOpResult.get_CacheMatchAllResult();
result.responseList().AppendElement(aSavedResponse.mValue);
SerializeResponseBody(aSavedResponse, aStreamList,
&result.responseList().LastElement());
break;
}
case CacheOpResult::TStorageMatchResult:
{
StorageMatchResult& result = mOpResult.get_StorageMatchResult();
MOZ_ASSERT(result.responseOrVoid().type() == PCacheResponseOrVoid::Tvoid_t);
result.responseOrVoid() = aSavedResponse.mValue;
SerializeResponseBody(aSavedResponse, aStreamList,
&result.responseOrVoid().get_PCacheResponse());
break;
}
default:
MOZ_CRASH("Cache result type cannot handle returning a Response!");
}
}
void
AutoParentOpResult::Add(const SavedRequest& aSavedRequest,
StreamList* aStreamList)
{
MOZ_ASSERT(!mSent);
switch (mOpResult.type()) {
case CacheOpResult::TCacheKeysResult:
{
CacheKeysResult& result = mOpResult.get_CacheKeysResult();
result.requestList().AppendElement(aSavedRequest.mValue);
PCacheRequest& request = result.requestList().LastElement();
if (!aSavedRequest.mHasBodyId) {
request.body() = void_t();
break;
}
request.body() = PCacheReadStream();
SerializeReadStream(aSavedRequest.mBodyId, aStreamList,
&request.body().get_PCacheReadStream());
break;
}
default:
MOZ_CRASH("Cache result type cannot handle returning a Request!");
}
}
const CacheOpResult&
AutoParentOpResult::SendAsOpResult()
{
MOZ_ASSERT(!mSent);
mSent = true;
return mOpResult;
}
void
AutoParentOpResult::SerializeResponseBody(const SavedResponse& aSavedResponse,
StreamList* aStreamList,
PCacheResponse* aResponseOut)
{
MOZ_ASSERT(aResponseOut);
if (!aSavedResponse.mHasBodyId) {
aResponseOut->body() = void_t();
return;
}
aResponseOut->body() = PCacheReadStream();
SerializeReadStream(aSavedResponse.mBodyId, aStreamList,
&aResponseOut->body().get_PCacheReadStream());
}
void
AutoParentOpResult::SerializeReadStream(const nsID& aId, StreamList* aStreamList,
PCacheReadStream* aReadStreamOut)
AutoParentBase::SerializeReadStream(const nsID& aId, StreamList* aStreamList,
PCacheReadStream* aReadStreamOut)
{
MOZ_ASSERT(aStreamList);
MOZ_ASSERT(aReadStreamOut);
@ -539,6 +328,139 @@ AutoParentOpResult::SerializeReadStream(const nsID& aId, StreamList* aStreamList
readStream->Serialize(aReadStreamOut);
}
// --------------------------------------------
AutoParentRequestList::AutoParentRequestList(PBackgroundParent* aManager,
uint32_t aCapacity)
: AutoParentBase(aManager)
{
mRequestList.SetCapacity(aCapacity);
}
AutoParentRequestList::~AutoParentRequestList()
{
CleanupAction action = mSent ? Forget : Delete;
for (uint32_t i = 0; i < mRequestList.Length(); ++i) {
CleanupParentFds(mRequestList[i].body(), action);
}
}
void
AutoParentRequestList::Add(const SavedRequest& aSavedRequest,
StreamList* aStreamList)
{
MOZ_ASSERT(!mSent);
mRequestList.AppendElement(aSavedRequest.mValue);
PCacheRequest& request = mRequestList.LastElement();
if (!aSavedRequest.mHasBodyId) {
request.body() = void_t();
return;
}
request.body() = PCacheReadStream();
SerializeReadStream(aSavedRequest.mBodyId, aStreamList,
&request.body().get_PCacheReadStream());
}
const nsTArray<PCacheRequest>&
AutoParentRequestList::SendAsRequestList()
{
MOZ_ASSERT(!mSent);
mSent = true;
return mRequestList;
}
// --------------------------------------------
AutoParentResponseList::AutoParentResponseList(PBackgroundParent* aManager,
uint32_t aCapacity)
: AutoParentBase(aManager)
{
mResponseList.SetCapacity(aCapacity);
}
AutoParentResponseList::~AutoParentResponseList()
{
CleanupAction action = mSent ? Forget : Delete;
for (uint32_t i = 0; i < mResponseList.Length(); ++i) {
CleanupParentFds(mResponseList[i].body(), action);
}
}
void
AutoParentResponseList::Add(const SavedResponse& aSavedResponse,
StreamList* aStreamList)
{
MOZ_ASSERT(!mSent);
mResponseList.AppendElement(aSavedResponse.mValue);
PCacheResponse& response = mResponseList.LastElement();
if (!aSavedResponse.mHasBodyId) {
response.body() = void_t();
return;
}
response.body() = PCacheReadStream();
SerializeReadStream(aSavedResponse.mBodyId, aStreamList,
&response.body().get_PCacheReadStream());
}
const nsTArray<PCacheResponse>&
AutoParentResponseList::SendAsResponseList()
{
MOZ_ASSERT(!mSent);
mSent = true;
return mResponseList;
}
// --------------------------------------------
AutoParentResponseOrVoid::AutoParentResponseOrVoid(ipc::PBackgroundParent* aManager)
: AutoParentBase(aManager)
{
mResponseOrVoid = void_t();
}
AutoParentResponseOrVoid::~AutoParentResponseOrVoid()
{
if (mResponseOrVoid.type() != PCacheResponseOrVoid::TPCacheResponse) {
return;
}
CleanupAction action = mSent ? Forget : Delete;
CleanupParentFds(mResponseOrVoid.get_PCacheResponse().body(), action);
}
void
AutoParentResponseOrVoid::Add(const SavedResponse& aSavedResponse,
StreamList* aStreamList)
{
MOZ_ASSERT(!mSent);
mResponseOrVoid = aSavedResponse.mValue;
PCacheResponse& response = mResponseOrVoid.get_PCacheResponse();
if (!aSavedResponse.mHasBodyId) {
response.body() = void_t();
return;
}
response.body() = PCacheReadStream();
SerializeReadStream(aSavedResponse.mBodyId, aStreamList,
&response.body().get_PCacheReadStream());
}
const PCacheResponseOrVoid&
AutoParentResponseOrVoid::SendAsResponseOrVoid()
{
MOZ_ASSERT(!mSent);
mSent = true;
return mResponseOrVoid;
}
} // namespace cache
} // namespace dom
} // namespace mozilla

121
dom/cache/AutoUtils.h vendored
View File

@ -9,7 +9,6 @@
#include "mozilla/Attributes.h"
#include "mozilla/dom/cache/PCacheTypes.h"
#include "mozilla/dom/cache/Types.h"
#include "mozilla/dom/cache/TypeUtils.h"
#include "nsTArray.h"
@ -30,7 +29,6 @@ class InternalRequest;
namespace cache {
class CacheStreamControlParent;
class Manager;
struct SavedRequest;
struct SavedResponse;
class StreamList;
@ -43,58 +41,131 @@ class StreamList;
// Note, these should only be used when *sending* streams across IPC. The
// deserialization case is handled by creating a ReadStream object.
class MOZ_STACK_CLASS AutoChildOpArgs final
class MOZ_STACK_CLASS AutoChildBase
{
public:
protected:
typedef TypeUtils::BodyAction BodyAction;
typedef TypeUtils::ReferrerAction ReferrerAction;
typedef TypeUtils::SchemeAction SchemeAction;
AutoChildOpArgs(TypeUtils* aTypeUtils, const CacheOpArgs& aOpArgs);
~AutoChildOpArgs();
AutoChildBase(TypeUtils* aTypeUtils);
virtual ~AutoChildBase() = 0;
TypeUtils* mTypeUtils;
bool mSent;
};
class MOZ_STACK_CLASS AutoChildRequest final : public AutoChildBase
{
public:
explicit AutoChildRequest(TypeUtils* aTypeUtils);
~AutoChildRequest();
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
ErrorResult& aRv);
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
Response& aResponse, ErrorResult& aRv);
const CacheOpArgs& SendAsOpArgs();
const PCacheRequest& SendAsRequest();
const PCacheRequestOrVoid& SendAsRequestOrVoid();
private:
TypeUtils* mTypeUtils;
CacheOpArgs mOpArgs;
bool mSent;
PCacheRequestOrVoid mRequestOrVoid;
};
class MOZ_STACK_CLASS AutoParentOpResult final
class MOZ_STACK_CLASS AutoChildRequestList final : public AutoChildBase
{
public:
AutoParentOpResult(mozilla::ipc::PBackgroundParent* aManager,
const CacheOpResult& aOpResult);
~AutoParentOpResult();
AutoChildRequestList(TypeUtils* aTypeUtils, uint32_t aCapacity);
~AutoChildRequestList();
void Add(CacheId aOpenedCacheId, Manager* aManager);
void Add(const SavedResponse& aSavedResponse, StreamList* aStreamList);
void Add(const SavedRequest& aSavedRequest, StreamList* aStreamList);
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
ErrorResult& aRv);
const CacheOpResult& SendAsOpResult();
const nsTArray<PCacheRequest>& SendAsRequestList();
private:
void SerializeResponseBody(const SavedResponse& aSavedResponse,
StreamList* aStreamList,
PCacheResponse* aResponseOut);
// Allocates ~5k inline in the stack-only class
nsAutoTArray<PCacheRequest, 32> mRequestList;
};
class MOZ_STACK_CLASS AutoChildRequestResponse final : public AutoChildBase
{
public:
explicit AutoChildRequestResponse(TypeUtils* aTypeUtils);
~AutoChildRequestResponse();
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
ErrorResult& aRv);
void Add(Response& aResponse, ErrorResult& aRv);
const CacheRequestResponse& SendAsRequestResponse();
private:
CacheRequestResponse mRequestResponse;
};
class MOZ_STACK_CLASS AutoParentBase
{
protected:
explicit AutoParentBase(mozilla::ipc::PBackgroundParent* aManager);
virtual ~AutoParentBase() = 0;
void SerializeReadStream(const nsID& aId, StreamList* aStreamList,
PCacheReadStream* aReadStreamOut);
mozilla::ipc::PBackgroundParent* mManager;
CacheOpResult mOpResult;
CacheStreamControlParent* mStreamControl;
bool mSent;
};
class MOZ_STACK_CLASS AutoParentRequestList final : public AutoParentBase
{
public:
AutoParentRequestList(mozilla::ipc::PBackgroundParent* aManager,
uint32_t aCapacity);
~AutoParentRequestList();
void Add(const SavedRequest& aSavedRequest, StreamList* aStreamList);
const nsTArray<PCacheRequest>& SendAsRequestList();
private:
// Allocates ~5k inline in the stack-only class
nsAutoTArray<PCacheRequest, 32> mRequestList;
};
class MOZ_STACK_CLASS AutoParentResponseList final : public AutoParentBase
{
public:
AutoParentResponseList(mozilla::ipc::PBackgroundParent* aManager,
uint32_t aCapacity);
~AutoParentResponseList();
void Add(const SavedResponse& aSavedResponse, StreamList* aStreamList);
const nsTArray<PCacheResponse>& SendAsResponseList();
private:
// Allocates ~4k inline in the stack-only class
nsAutoTArray<PCacheResponse, 32> mResponseList;
};
class MOZ_STACK_CLASS AutoParentResponseOrVoid final : public AutoParentBase
{
public:
explicit AutoParentResponseOrVoid(mozilla::ipc::PBackgroundParent* aManager);
~AutoParentResponseOrVoid();
void Add(const SavedResponse& aSavedResponse, StreamList* aStreamList);
const PCacheResponseOrVoid& SendAsResponseOrVoid();
private:
PCacheResponseOrVoid mResponseOrVoid;
};
} // namespace cache
} // namespace dom
} // namespace mozilla

337
dom/cache/Cache.cpp vendored
View File

@ -14,9 +14,9 @@
#include "mozilla/dom/CacheBinding.h"
#include "mozilla/dom/cache/AutoUtils.h"
#include "mozilla/dom/cache/CacheChild.h"
#include "mozilla/dom/cache/CacheOpChild.h"
#include "mozilla/dom/cache/CachePushStreamChild.h"
#include "mozilla/dom/cache/ReadStream.h"
#include "mozilla/dom/cache/TypeUtils.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/Preferences.h"
#include "mozilla/unused.h"
@ -79,7 +79,17 @@ using mozilla::dom::workers::WorkerPrivate;
NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::cache::Cache);
NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::cache::Cache);
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(mozilla::dom::cache::Cache, mGlobal);
NS_IMPL_CYCLE_COLLECTION_CLASS(mozilla::dom::cache::Cache)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(mozilla::dom::cache::Cache)
tmp->DisconnectFromActor();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal, mRequestPromises)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(mozilla::dom::cache::Cache)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal, mRequestPromises)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(mozilla::dom::cache::Cache)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Cache)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
@ -101,22 +111,31 @@ Cache::Match(const RequestOrUSVString& aRequest,
{
MOZ_ASSERT(mActor);
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
if (NS_WARN_IF(aRv.Failed())) {
if (aRv.Failed()) {
return nullptr;
}
AutoChildRequest request(this);
request.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
if (aRv.Failed()) {
return nullptr;
}
PCacheQueryParams params;
ToPCacheQueryParams(params, aOptions);
AutoChildOpArgs args(this, CacheMatchArgs(PCacheRequest(), params));
RequestId requestId = AddRequestPromise(promise, aRv);
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
unused << mActor->SendMatch(requestId, request.SendAsRequest(), params);
return ExecuteOp(args, aRv);
return promise.forget();
}
already_AddRefed<Promise>
@ -125,10 +144,12 @@ Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
{
MOZ_ASSERT(mActor);
PCacheQueryParams params;
ToPCacheQueryParams(params, aOptions);
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
AutoChildOpArgs args(this, CacheMatchAllArgs(void_t(), params));
AutoChildRequest request(this);
if (aRequest.WasPassed()) {
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
@ -137,13 +158,21 @@ Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
return nullptr;
}
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
request.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
if (aRv.Failed()) {
return nullptr;
}
}
return ExecuteOp(args, aRv);
PCacheQueryParams params;
ToPCacheQueryParams(params, aOptions);
RequestId requestId = AddRequestPromise(promise, aRv);
unused << mActor->SendMatchAll(requestId, request.SendAsRequestOrVoid(),
params);
return promise.forget();
}
already_AddRefed<Promise>
@ -155,19 +184,27 @@ Cache::Add(const RequestOrUSVString& aRequest, ErrorResult& aRv)
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
if (aRv.Failed()) {
return nullptr;
}
AutoChildOpArgs args(this, CacheAddAllArgs());
args.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
AutoChildRequestList requests(this, 1);
requests.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
if (aRv.Failed()) {
return nullptr;
}
return ExecuteOp(args, aRv);
RequestId requestId = AddRequestPromise(promise, aRv);
unused << mActor->SendAddAll(requestId, requests.SendAsRequestList());
return promise.forget();
}
already_AddRefed<Promise>
@ -176,18 +213,18 @@ Cache::AddAll(const Sequence<OwningRequestOrUSVString>& aRequests,
{
MOZ_ASSERT(mActor);
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
// If there is no work to do, then resolve immediately
if (aRequests.IsEmpty()) {
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
promise->MaybeResolve(JS::UndefinedHandleValue);
return promise.forget();
}
AutoChildOpArgs args(this, CacheAddAllArgs());
AutoChildRequestList requests(this, aRequests.Length());
for (uint32_t i = 0; i < aRequests.Length(); ++i) {
if (!IsValidPutRequestMethod(aRequests[i], aRv)) {
@ -200,13 +237,18 @@ Cache::AddAll(const Sequence<OwningRequestOrUSVString>& aRequests,
return nullptr;
}
args.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
requests.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme,
aRv);
if (aRv.Failed()) {
return nullptr;
}
}
return ExecuteOp(args, aRv);
RequestId requestId = AddRequestPromise(promise, aRv);
unused << mActor->SendAddAll(requestId, requests.SendAsRequestList());
return promise.forget();
}
already_AddRefed<Promise>
@ -219,20 +261,32 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
if (aRv.Failed()) {
return nullptr;
}
AutoChildOpArgs args(this, CachePutAllArgs());
args.Add(ir, ReadBody, PassThroughReferrer, TypeErrorOnInvalidScheme,
aResponse, aRv);
AutoChildRequestResponse put(this);
put.Add(ir, ReadBody, PassThroughReferrer, TypeErrorOnInvalidScheme, aRv);
if (aRv.Failed()) {
return nullptr;
}
return ExecuteOp(args, aRv);
put.Add(aResponse, aRv);
if (aRv.Failed()) {
return nullptr;
}
RequestId requestId = AddRequestPromise(promise, aRv);
unused << mActor->SendPut(requestId, put.SendAsRequestResponse());
return promise.forget();
}
already_AddRefed<Promise>
@ -241,22 +295,30 @@ Cache::Delete(const RequestOrUSVString& aRequest,
{
MOZ_ASSERT(mActor);
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
if (aRv.Failed()) {
return nullptr;
}
AutoChildRequest request(this);
request.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
if (aRv.Failed()) {
return nullptr;
}
PCacheQueryParams params;
ToPCacheQueryParams(params, aOptions);
AutoChildOpArgs args(this, CacheDeleteArgs(PCacheRequest(), params));
RequestId requestId = AddRequestPromise(promise, aRv);
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
if (aRv.Failed()) {
return nullptr;
}
unused << mActor->SendDelete(requestId, request.SendAsRequest(), params);
return ExecuteOp(args, aRv);
return promise.forget();
}
already_AddRefed<Promise>
@ -265,10 +327,12 @@ Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
{
MOZ_ASSERT(mActor);
PCacheQueryParams params;
ToPCacheQueryParams(params, aOptions);
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
AutoChildOpArgs args(this, CacheKeysArgs(void_t(), params));
AutoChildRequest request(this);
if (aRequest.WasPassed()) {
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
@ -277,13 +341,20 @@ Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
return nullptr;
}
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
request.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
if (aRv.Failed()) {
return nullptr;
}
}
return ExecuteOp(args, aRv);
PCacheQueryParams params;
ToPCacheQueryParams(params, aOptions);
RequestId requestId = AddRequestPromise(promise, aRv);
unused << mActor->SendKeys(requestId, request.SendAsRequestOrVoid(), params);
return promise.forget();
}
// static
@ -330,6 +401,119 @@ Cache::DestroyInternal(CacheChild* aActor)
mActor = nullptr;
}
void
Cache::RecvMatchResponse(RequestId aRequestId, nsresult aRv,
const PCacheResponseOrVoid& aResponse)
{
// Convert the response immediately if its present. This ensures that
// any stream actors are cleaned up, even if we error out below.
nsRefPtr<Response> response;
if (aResponse.type() == PCacheResponseOrVoid::TPCacheResponse) {
response = ToResponse(aResponse);
}
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
if (NS_FAILED(aRv)) {
promise->MaybeReject(aRv);
return;
}
if (!response) {
promise->MaybeResolve(JS::UndefinedHandleValue);
return;
}
promise->MaybeResolve(response);
}
void
Cache::RecvMatchAllResponse(RequestId aRequestId, nsresult aRv,
const nsTArray<PCacheResponse>& aResponses)
{
// Convert responses immediately. This ensures that any stream actors are
// cleaned up, even if we error out below.
nsAutoTArray<nsRefPtr<Response>, 256> responses;
responses.SetCapacity(aResponses.Length());
for (uint32_t i = 0; i < aResponses.Length(); ++i) {
nsRefPtr<Response> response = ToResponse(aResponses[i]);
responses.AppendElement(response.forget());
}
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
if (NS_FAILED(aRv)) {
promise->MaybeReject(aRv);
return;
}
promise->MaybeResolve(responses);
}
void
Cache::RecvAddAllResponse(RequestId aRequestId, nsresult aRv)
{
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
if (NS_FAILED(aRv)) {
promise->MaybeReject(aRv);
return;
}
promise->MaybeResolve(JS::UndefinedHandleValue);
}
void
Cache::RecvPutResponse(RequestId aRequestId, nsresult aRv)
{
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
if (NS_FAILED(aRv)) {
promise->MaybeReject(aRv);
return;
}
promise->MaybeResolve(JS::UndefinedHandleValue);
}
void
Cache::RecvDeleteResponse(RequestId aRequestId, nsresult aRv, bool aSuccess)
{
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
if (NS_FAILED(aRv)) {
promise->MaybeReject(aRv);
return;
}
promise->MaybeResolve(aSuccess);
}
void
Cache::RecvKeysResponse(RequestId aRequestId, nsresult aRv,
const nsTArray<PCacheRequest>& aRequests)
{
// Convert requests immediately. This ensures that any stream actors are
// cleaned up, even if we error out below.
nsAutoTArray<nsRefPtr<Request>, 256> requests;
requests.SetCapacity(aRequests.Length());
for (uint32_t i = 0; i < aRequests.Length(); ++i) {
nsRefPtr<Request> request = ToRequest(aRequests[i]);
requests.AppendElement(request.forget());
}
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
if (NS_FAILED(aRv)) {
promise->MaybeReject(aRv);
return;
}
promise->MaybeResolve(requests);
}
nsIGlobalObject*
Cache::GetGlobalObject() const
{
@ -356,9 +540,30 @@ Cache::CreatePushStream(nsIAsyncInputStream* aStream)
return static_cast<CachePushStreamChild*>(actor);
}
void
Cache::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{
// Do nothing. The Promise will automatically drop the ref to us after
// calling the callback. This is what we want as we only registered in order
// to be held alive via the Promise handle.
}
void
Cache::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{
// Do nothing. The Promise will automatically drop the ref to us after
// calling the callback. This is what we want as we only registered in order
// to be held alive via the Promise handle.
}
Cache::~Cache()
{
NS_ASSERT_OWNINGTHREAD(Cache);
DisconnectFromActor();
}
void
Cache::DisconnectFromActor()
{
if (mActor) {
mActor->StartDestroy();
// DestroyInternal() is called synchronously by StartDestroy(). So we
@ -367,19 +572,43 @@ Cache::~Cache()
}
}
already_AddRefed<Promise>
Cache::ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv)
RequestId
Cache::AddRequestPromise(Promise* aPromise, ErrorResult& aRv)
{
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
MOZ_ASSERT(aPromise);
MOZ_ASSERT(!mRequestPromises.Contains(aPromise));
// Register ourself as a promise handler so that the promise will hold us
// alive. This allows the client code to drop the ref to the Cache
// object and just keep their promise. This is fairly common in promise
// chaining code.
aPromise->AppendNativeHandler(this);
mRequestPromises.AppendElement(aPromise);
// (Ab)use the promise pointer as our request ID. This is a fast, thread-safe
// way to get a unique ID for the promise to be resolved later.
return reinterpret_cast<RequestId>(aPromise);
}
already_AddRefed<Promise>
Cache::RemoveRequestPromise(RequestId aRequestId)
{
MOZ_ASSERT(aRequestId != INVALID_REQUEST_ID);
for (uint32_t i = 0; i < mRequestPromises.Length(); ++i) {
nsRefPtr<Promise>& promise = mRequestPromises.ElementAt(i);
// To be safe, only cast promise pointers to our integer RequestId
// type and never cast an integer to a pointer.
if (aRequestId == reinterpret_cast<RequestId>(promise.get())) {
nsRefPtr<Promise> ref;
ref.swap(promise);
mRequestPromises.RemoveElementAt(i);
return ref.forget();
}
}
unused << mActor->SendPCacheOpConstructor(
new CacheOpChild(mActor->GetFeature(), mGlobal, this, promise),
aOpArgs.SendAsOpArgs());
return promise.forget();
MOZ_ASSERT_UNREACHABLE("Received response without a matching promise!");
return nullptr;
}
} // namespace cache

36
dom/cache/Cache.h vendored
View File

@ -7,6 +7,7 @@
#ifndef mozilla_dom_cache_Cache_h
#define mozilla_dom_cache_Cache_h
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/cache/Types.h"
#include "mozilla/dom/cache/TypeUtils.h"
#include "nsCOMPtr.h"
@ -32,10 +33,12 @@ template<typename T> class Sequence;
namespace cache {
class AutoChildOpArgs;
class CacheChild;
class PCacheRequest;
class PCacheResponse;
class PCacheResponseOrVoid;
class Cache final : public nsISupports
class Cache final : public PromiseNativeHandler
, public nsWrapperCache
, public TypeUtils
{
@ -73,6 +76,19 @@ public:
// Called when CacheChild actor is being destroyed
void DestroyInternal(CacheChild* aActor);
// methods forwarded from CacheChild
void RecvMatchResponse(RequestId aRequestId, nsresult aRv,
const PCacheResponseOrVoid& aResponse);
void RecvMatchAllResponse(RequestId aRequestId, nsresult aRv,
const nsTArray<PCacheResponse>& aResponses);
void RecvAddAllResponse(RequestId aRequestId, nsresult aRv);
void RecvPutResponse(RequestId aRequestId, nsresult aRv);
void RecvDeleteResponse(RequestId aRequestId, nsresult aRv,
bool aSuccess);
void RecvKeysResponse(RequestId aRequestId, nsresult aRv,
const nsTArray<PCacheRequest>& aRequests);
// TypeUtils methods
virtual nsIGlobalObject*
GetGlobalObject() const override;
@ -84,14 +100,26 @@ public:
virtual CachePushStreamChild*
CreatePushStream(nsIAsyncInputStream* aStream) override;
// PromiseNativeHandler methods
virtual void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
virtual void
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
private:
~Cache();
already_AddRefed<Promise>
ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv);
// Called when we're destroyed or CCed.
void DisconnectFromActor();
// TODO: Replace with actor-per-request model during refactor (bug 1110485)
RequestId AddRequestPromise(Promise* aPromise, ErrorResult& aRv);
already_AddRefed<Promise> RemoveRequestPromise(RequestId aRequestId);
nsCOMPtr<nsIGlobalObject> mGlobal;
CacheChild* mActor;
nsTArray<nsRefPtr<Promise>> mRequestPromises;
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS

View File

@ -9,7 +9,6 @@
#include "mozilla/unused.h"
#include "mozilla/dom/cache/ActorUtils.h"
#include "mozilla/dom/cache/Cache.h"
#include "mozilla/dom/cache/PCacheOpChild.h"
#include "mozilla/dom/cache/PCachePushStreamChild.h"
#include "mozilla/dom/cache/StreamUtils.h"
@ -73,8 +72,6 @@ CacheChild::StartDestroy()
return;
}
// TODO: only destroy if there are no ops or push streams still running
listener->DestroyInternal(this);
// Cache listener should call ClearListener() in DestroyInternal()
@ -98,20 +95,6 @@ CacheChild::ActorDestroy(ActorDestroyReason aReason)
RemoveFeature();
}
PCacheOpChild*
CacheChild::AllocPCacheOpChild(const CacheOpArgs& aOpArgs)
{
MOZ_CRASH("CacheOpChild should be manually constructed.");
return nullptr;
}
bool
CacheChild::DeallocPCacheOpChild(PCacheOpChild* aActor)
{
delete aActor;
return true;
}
PCachePushStreamChild*
CacheChild::AllocPCachePushStreamChild()
{
@ -126,6 +109,94 @@ CacheChild::DeallocPCachePushStreamChild(PCachePushStreamChild* aActor)
return true;
}
bool
CacheChild::RecvMatchResponse(const RequestId& requestId, const nsresult& aRv,
const PCacheResponseOrVoid& aResponse)
{
NS_ASSERT_OWNINGTHREAD(CacheChild);
AddFeatureToStreamChild(aResponse, GetFeature());
nsRefPtr<Cache> listener = mListener;
if (!listener) {
StartDestroyStreamChild(aResponse);
return true;
}
listener->RecvMatchResponse(requestId, aRv, aResponse);
return true;
}
bool
CacheChild::RecvMatchAllResponse(const RequestId& requestId, const nsresult& aRv,
nsTArray<PCacheResponse>&& aResponses)
{
NS_ASSERT_OWNINGTHREAD(CacheChild);
AddFeatureToStreamChild(aResponses, GetFeature());
nsRefPtr<Cache> listener = mListener;
if (!listener) {
StartDestroyStreamChild(aResponses);
return true;
}
listener->RecvMatchAllResponse(requestId, aRv, aResponses);
return true;
}
bool
CacheChild::RecvAddAllResponse(const RequestId& requestId, const nsresult& aRv)
{
NS_ASSERT_OWNINGTHREAD(CacheChild);
nsRefPtr<Cache> listener = mListener;
if (listener) {
listener->RecvAddAllResponse(requestId, aRv);
}
return true;
}
bool
CacheChild::RecvPutResponse(const RequestId& aRequestId, const nsresult& aRv)
{
NS_ASSERT_OWNINGTHREAD(CacheChild);
nsRefPtr<Cache> listener = mListener;
if (listener) {
listener->RecvPutResponse(aRequestId, aRv);
}
return true;
}
bool
CacheChild::RecvDeleteResponse(const RequestId& requestId, const nsresult& aRv,
const bool& result)
{
NS_ASSERT_OWNINGTHREAD(CacheChild);
nsRefPtr<Cache> listener = mListener;
if (listener) {
listener->RecvDeleteResponse(requestId, aRv, result);
}
return true;
}
bool
CacheChild::RecvKeysResponse(const RequestId& requestId, const nsresult& aRv,
nsTArray<PCacheRequest>&& aRequests)
{
NS_ASSERT_OWNINGTHREAD(CacheChild);
AddFeatureToStreamChild(aRequests, GetFeature());
nsRefPtr<Cache> listener = mListener;
if (!listener) {
StartDestroyStreamChild(aRequests);
return true;
}
listener->RecvKeysResponse(requestId, aRv, aRequests);
return true;
}
} // namespace cache
} // namespace dom
} // namesapce mozilla

View File

@ -41,18 +41,31 @@ private:
virtual void
ActorDestroy(ActorDestroyReason aReason) override;
virtual PCacheOpChild*
AllocPCacheOpChild(const CacheOpArgs& aOpArgs) override;
virtual bool
DeallocPCacheOpChild(PCacheOpChild* aActor) override;
virtual PCachePushStreamChild*
AllocPCachePushStreamChild() override;
virtual bool
DeallocPCachePushStreamChild(PCachePushStreamChild* aActor) override;
virtual bool
RecvMatchResponse(const RequestId& requestId, const nsresult& aRv,
const PCacheResponseOrVoid& aResponse) override;
virtual bool
RecvMatchAllResponse(const RequestId& requestId, const nsresult& aRv,
nsTArray<PCacheResponse>&& responses) override;
virtual bool
RecvAddAllResponse(const RequestId& requestId,
const nsresult& aRv) override;
virtual bool
RecvPutResponse(const RequestId& aRequestId,
const nsresult& aRv) override;
virtual bool
RecvDeleteResponse(const RequestId& requestId, const nsresult& aRv,
const bool& result) override;
virtual bool
RecvKeysResponse(const RequestId& requestId, const nsresult& aRv,
nsTArray<PCacheRequest>&& requests) override;
// Use a weak ref so actor does not hold DOM object alive past content use.
// The Cache object must call ClearListener() to null this before its
// destroyed.

24
dom/cache/CacheInitData.ipdlh vendored Normal file
View File

@ -0,0 +1,24 @@
/* 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 PBackgroundSharedTypes;
using mozilla::dom::cache::Namespace from "mozilla/dom/cache/Types.h";
namespace mozilla {
namespace dom {
namespace cache {
// Data needed to initialize a CacheStorage or Cache backend. Don't put
// this with the other types in PCacheTypes.ipdlh since we want to import
// it into PBackground.ipdl.
struct CacheInitData
{
Namespace namespaceEnum;
PrincipalInfo principalInfo;
};
} // namespace cache
} // namespace dom
} // namespace mozilla

View File

@ -1,201 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 "mozilla/dom/cache/CacheOpChild.h"
#include "mozilla/dom/cache/Cache.h"
#include "mozilla/dom/cache/CacheChild.h"
namespace mozilla {
namespace dom {
namespace cache {
CacheOpChild::CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal,
nsISupports* aParent, Promise* aPromise)
: mGlobal(aGlobal)
, mParent(aParent)
, mPromise(aPromise)
{
MOZ_ASSERT(mGlobal);
MOZ_ASSERT(mParent);
MOZ_ASSERT(mPromise);
MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
SetFeature(aFeature);
}
CacheOpChild::~CacheOpChild()
{
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
MOZ_ASSERT(!mPromise);
}
void
CacheOpChild::ActorDestroy(ActorDestroyReason aReason)
{
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
// If the actor was terminated for some unknown reason, then indicate the
// operation is dead.
if (mPromise) {
mPromise->MaybeReject(NS_ERROR_FAILURE);
mPromise = nullptr;
}
RemoveFeature();
}
bool
CacheOpChild::Recv__delete__(const nsresult& aStatus,
const CacheOpResult& aResult)
{
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
if (NS_FAILED(aStatus)) {
mPromise->MaybeReject(aStatus);
mPromise = nullptr;
return true;
}
switch (aResult.type()) {
case CacheOpResult::TCacheMatchResult:
{
HandleResponse(aResult.get_CacheMatchResult().responseOrVoid());
break;
}
case CacheOpResult::TCacheMatchAllResult:
{
HandleResponseList(aResult.get_CacheMatchAllResult().responseList());
break;
}
case CacheOpResult::TCacheAddAllResult:
case CacheOpResult::TCachePutAllResult:
{
mPromise->MaybeResolve(JS::UndefinedHandleValue);
break;
}
case CacheOpResult::TCacheDeleteResult:
{
mPromise->MaybeResolve(aResult.get_CacheDeleteResult().success());
break;
}
case CacheOpResult::TCacheKeysResult:
{
HandleRequestList(aResult.get_CacheKeysResult().requestList());
break;
}
case CacheOpResult::TStorageMatchResult:
{
HandleResponse(aResult.get_StorageMatchResult().responseOrVoid());
break;
}
case CacheOpResult::TStorageHasResult:
{
mPromise->MaybeResolve(aResult.get_StorageHasResult().success());
break;
}
case CacheOpResult::TStorageOpenResult:
{
auto actor = static_cast<CacheChild*>(
aResult.get_StorageOpenResult().actorChild());
actor->SetFeature(GetFeature());
nsRefPtr<Cache> cache = new Cache(mGlobal, actor);
mPromise->MaybeResolve(cache);
break;
}
case CacheOpResult::TStorageDeleteResult:
{
mPromise->MaybeResolve(aResult.get_StorageDeleteResult().success());
break;
}
case CacheOpResult::TStorageKeysResult:
{
mPromise->MaybeResolve(aResult.get_StorageKeysResult().keyList());
break;
}
default:
MOZ_CRASH("Unknown Cache op result type!");
}
mPromise = nullptr;
return true;
}
void
CacheOpChild::StartDestroy()
{
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
// Do not cancel on-going operations when Feature calls this. Instead, keep
// the Worker alive until we are done.
}
nsIGlobalObject*
CacheOpChild::GetGlobalObject() const
{
return mGlobal;
}
#ifdef DEBUG
void
CacheOpChild::AssertOwningThread() const
{
NS_ASSERT_OWNINGTHREAD(CacheOpChild);
}
#endif
CachePushStreamChild*
CacheOpChild::CreatePushStream(nsIAsyncInputStream* aStream)
{
MOZ_CRASH("CacheOpChild should never create a push stream actor!");
}
void
CacheOpChild::HandleResponse(const PCacheResponseOrVoid& aResponseOrVoid)
{
nsRefPtr<Response> response;
if (aResponseOrVoid.type() == PCacheResponseOrVoid::TPCacheResponse) {
response = ToResponse(aResponseOrVoid);
}
if (!response) {
mPromise->MaybeResolve(JS::UndefinedHandleValue);
return;
}
mPromise->MaybeResolve(response);
}
void
CacheOpChild::HandleResponseList(const nsTArray<PCacheResponse>& aResponseList)
{
nsAutoTArray<nsRefPtr<Response>, 256> responses;
responses.SetCapacity(aResponseList.Length());
for (uint32_t i = 0; i < aResponseList.Length(); ++i) {
responses.AppendElement(ToResponse(aResponseList[i]));
}
mPromise->MaybeResolve(responses);
}
void
CacheOpChild::HandleRequestList(const nsTArray<PCacheRequest>& aRequestList)
{
nsAutoTArray<nsRefPtr<Request>, 256> requests;
requests.SetCapacity(aRequestList.Length());
for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
requests.AppendElement(ToRequest(aRequestList[i]));
}
mPromise->MaybeResolve(requests);
}
} // namespace cache
} // namespace dom
} // namespace mozilla

View File

@ -1,78 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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_cache_CacheOpChild_h
#define mozilla_dom_cache_CacheOpChild_h
#include "mozilla/dom/cache/ActorChild.h"
#include "mozilla/dom/cache/PCacheOpChild.h"
#include "mozilla/dom/cache/TypeUtils.h"
#include "nsRefPtr.h"
class nsIGlobalObject;
namespace mozilla {
namespace dom {
class Promise;
namespace cache {
class CacheOpChild final : public PCacheOpChild
, public ActorChild
, public TypeUtils
{
public:
CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal,
nsISupports* aParent, Promise* aPromise);
~CacheOpChild();
private:
// PCacheOpChild methods
virtual void
ActorDestroy(ActorDestroyReason aReason) override;
virtual bool
Recv__delete__(const nsresult& aStatus, const CacheOpResult& aResult) override;
// ActorChild methods
virtual void
StartDestroy() override;
// TypeUtils methods
virtual nsIGlobalObject*
GetGlobalObject() const override;
#ifdef DEBUG
virtual void
AssertOwningThread() const override;
#endif
virtual CachePushStreamChild*
CreatePushStream(nsIAsyncInputStream* aStream) override;
// Utility methods
void
HandleResponse(const PCacheResponseOrVoid& aResponseOrVoid);
void
HandleResponseList(const nsTArray<PCacheResponse>& aResponseList);
void
HandleRequestList(const nsTArray<PCacheRequest>& aRequestList);
nsCOMPtr<nsIGlobalObject> mGlobal;
nsCOMPtr<nsISupports> mParent;
nsRefPtr<Promise> mPromise;
NS_DECL_OWNINGTHREAD
};
} // namespace cache
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_cache_CacheOpChild_h

View File

@ -1,284 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 "mozilla/dom/cache/CacheOpParent.h"
#include "mozilla/unused.h"
#include "mozilla/dom/cache/AutoUtils.h"
#include "mozilla/dom/cache/CachePushStreamParent.h"
#include "mozilla/dom/cache/ReadStream.h"
#include "mozilla/dom/cache/SavedTypes.h"
#include "mozilla/ipc/FileDescriptorSetParent.h"
#include "mozilla/ipc/InputStreamUtils.h"
namespace mozilla {
namespace dom {
namespace cache {
using mozilla::ipc::FileDescriptorSetParent;
using mozilla::ipc::PBackgroundParent;
CacheOpParent::CacheOpParent(PBackgroundParent* aIpcManager, CacheId aCacheId,
const CacheOpArgs& aOpArgs)
: mIpcManager(aIpcManager)
, mCacheId(aCacheId)
, mNamespace(INVALID_NAMESPACE)
, mOpArgs(aOpArgs)
{
MOZ_ASSERT(mIpcManager);
}
CacheOpParent::CacheOpParent(PBackgroundParent* aIpcManager,
Namespace aNamespace, const CacheOpArgs& aOpArgs)
: mIpcManager(aIpcManager)
, mCacheId(INVALID_CACHE_ID)
, mNamespace(aNamespace)
, mOpArgs(aOpArgs)
{
MOZ_ASSERT(mIpcManager);
}
CacheOpParent::~CacheOpParent()
{
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
}
void
CacheOpParent::Execute(ManagerId* aManagerId)
{
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
MOZ_ASSERT(!mManager);
MOZ_ASSERT(!mVerifier);
nsRefPtr<Manager> manager;
nsresult rv = Manager::GetOrCreate(aManagerId, getter_AddRefs(manager));
if (NS_WARN_IF(NS_FAILED(rv))) {
unused << Send__delete__(this, rv, void_t());
return;
}
Execute(manager);
}
void
CacheOpParent::Execute(Manager* aManager)
{
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
MOZ_ASSERT(!mManager);
MOZ_ASSERT(!mVerifier);
mManager = aManager;
// Handle add/addAll op with a FetchPut object
if (mOpArgs.type() == CacheOpArgs::TCacheAddAllArgs) {
MOZ_ASSERT(mCacheId != INVALID_CACHE_ID);
const CacheAddAllArgs& args = mOpArgs.get_CacheAddAllArgs();
const nsTArray<PCacheRequest>& list = args.requestList();
nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> requestStreamList;
for (uint32_t i = 0; i < list.Length(); ++i) {
requestStreamList.AppendElement(DeserializeCacheStream(list[i].body()));
}
nsRefPtr<FetchPut> fetchPut;
nsresult rv = FetchPut::Create(this, mManager, mCacheId, list,
requestStreamList, getter_AddRefs(fetchPut));
if (NS_WARN_IF(NS_FAILED(rv))) {
OnOpComplete(rv, CacheAddAllResult());
return;
}
mFetchPutList.AppendElement(fetchPut.forget());
return;
}
// Handle put op
if (mOpArgs.type() == CacheOpArgs::TCachePutAllArgs) {
MOZ_ASSERT(mCacheId != INVALID_CACHE_ID);
const CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
const nsTArray<CacheRequestResponse>& list = args.requestResponseList();
nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> requestStreamList;
nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> responseStreamList;
for (uint32_t i = 0; i < list.Length(); ++i) {
requestStreamList.AppendElement(
DeserializeCacheStream(list[i].request().body()));
responseStreamList.AppendElement(
DeserializeCacheStream(list[i].response().body()));
}
mManager->ExecutePutAll(this, mCacheId, args.requestResponseList(),
requestStreamList, responseStreamList);
return;
}
// Handle all other cache ops
if (mCacheId != INVALID_CACHE_ID) {
MOZ_ASSERT(mNamespace == INVALID_NAMESPACE);
mManager->ExecuteCacheOp(this, mCacheId, mOpArgs);
return;
}
// Handle all storage ops
MOZ_ASSERT(mNamespace != INVALID_NAMESPACE);
mManager->ExecuteStorageOp(this, mNamespace, mOpArgs);
}
void
CacheOpParent::WaitForVerification(PrincipalVerifier* aVerifier)
{
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
MOZ_ASSERT(!mManager);
MOZ_ASSERT(!mVerifier);
mVerifier = aVerifier;
mVerifier->AddListener(this);
}
void
CacheOpParent::ActorDestroy(ActorDestroyReason aReason)
{
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
if (mVerifier) {
mVerifier->RemoveListener(this);
mVerifier = nullptr;
}
for (uint32_t i = 0; i < mFetchPutList.Length(); ++i) {
mFetchPutList[i]->ClearListener();
}
mFetchPutList.Clear();
if (mManager) {
mManager->RemoveListener(this);
mManager = nullptr;
}
mIpcManager = nullptr;
}
void
CacheOpParent::OnPrincipalVerified(nsresult aRv, ManagerId* aManagerId)
{
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
mVerifier->RemoveListener(this);
mVerifier = nullptr;
if (NS_WARN_IF(NS_FAILED(aRv))) {
unused << Send__delete__(this, aRv, void_t());
return;
}
Execute(aManagerId);
}
void
CacheOpParent::OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
CacheId aOpenedCacheId,
const nsTArray<SavedResponse>& aSavedResponseList,
const nsTArray<SavedRequest>& aSavedRequestList,
StreamList* aStreamList)
{
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
MOZ_ASSERT(mIpcManager);
MOZ_ASSERT(mManager);
// The result must contain the appropriate type at this point. It may
// or may not contain the additional result data yet. For types that
// do not need special processing, it should already be set. If the
// result requires actor-specific operations, then we do that below.
// If the type and data types don't match, then we will trigger an
// assertion in AutoParentOpResult::Add().
AutoParentOpResult result(mIpcManager, aResult);
if (NS_FAILED(aRv)) {
unused << Send__delete__(this, aRv, result.SendAsOpResult());
return;
}
if (aOpenedCacheId != INVALID_CACHE_ID) {
result.Add(aOpenedCacheId, mManager);
}
for (uint32_t i = 0; i < aSavedResponseList.Length(); ++i) {
result.Add(aSavedResponseList[i], aStreamList);
}
for (uint32_t i = 0; i < aSavedRequestList.Length(); ++i) {
result.Add(aSavedRequestList[i], aStreamList);
}
unused << Send__delete__(this, aRv, result.SendAsOpResult());
}
void
CacheOpParent::OnFetchPut(FetchPut* aFetchPut, nsresult aRv)
{
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
MOZ_ASSERT(aFetchPut);
aFetchPut->ClearListener();
MOZ_ALWAYS_TRUE(mFetchPutList.RemoveElement(aFetchPut));
OnOpComplete(aRv, CacheAddAllResult());
}
already_AddRefed<nsIInputStream>
CacheOpParent::DeserializeCacheStream(const PCacheReadStreamOrVoid& aStreamOrVoid)
{
if (aStreamOrVoid.type() == PCacheReadStreamOrVoid::Tvoid_t) {
return nullptr;
}
nsCOMPtr<nsIInputStream> stream;
const PCacheReadStream& readStream = aStreamOrVoid.get_PCacheReadStream();
// Option 1: A push stream actor was sent for nsPipe data
if (readStream.pushStreamParent()) {
MOZ_ASSERT(!readStream.controlParent());
CachePushStreamParent* pushStream =
static_cast<CachePushStreamParent*>(readStream.pushStreamParent());
stream = pushStream->TakeReader();
MOZ_ASSERT(stream);
return stream.forget();
}
// Option 2: One of our own ReadStreams was passed back to us with a stream
// control actor.
stream = ReadStream::Create(readStream);
if (stream) {
return stream.forget();
}
// Option 3: A stream was serialized using normal methods.
nsAutoTArray<FileDescriptor, 4> fds;
if (readStream.fds().type() ==
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
FileDescriptorSetParent* fdSetActor =
static_cast<FileDescriptorSetParent*>(readStream.fds().get_PFileDescriptorSetParent());
MOZ_ASSERT(fdSetActor);
fdSetActor->ForgetFileDescriptors(fds);
MOZ_ASSERT(!fds.IsEmpty());
if (!fdSetActor->Send__delete__(fdSetActor)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to delete fd set actor.");
}
}
return DeserializeInputStream(readStream.params(), fds);
}
} // namespace cache
} // namespace dom
} // namespace mozilla

View File

@ -1,87 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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_cache_CacheOpParent_h
#define mozilla_dom_cache_CacheOpParent_h
#include "mozilla/dom/cache/FetchPut.h"
#include "mozilla/dom/cache/Manager.h"
#include "mozilla/dom/cache/PCacheOpParent.h"
#include "mozilla/dom/cache/PrincipalVerifier.h"
#include "nsTArray.h"
namespace mozilla {
namespace ipc {
class PBackgroundParent;
}
namespace dom {
namespace cache {
class CacheOpParent final : public PCacheOpParent
, public PrincipalVerifier::Listener
, public Manager::Listener
, public FetchPut::Listener
{
// to allow use of convenience overrides
using Manager::Listener::OnOpComplete;
public:
CacheOpParent(mozilla::ipc::PBackgroundParent* aIpcManager, CacheId aCacheId,
const CacheOpArgs& aOpArgs);
CacheOpParent(mozilla::ipc::PBackgroundParent* aIpcManager,
Namespace aNamespace, const CacheOpArgs& aOpArgs);
~CacheOpParent();
void
Execute(ManagerId* aManagerId);
void
Execute(Manager* aManager);
void
WaitForVerification(PrincipalVerifier* aVerifier);
private:
// PCacheOpParent methods
virtual void
ActorDestroy(ActorDestroyReason aReason) override;
// PrincipalVerifier::Listener methods
virtual void
OnPrincipalVerified(nsresult aRv, ManagerId* aManagerId) override;
// Manager::Listener methods
virtual void
OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
CacheId aOpenedCacheId,
const nsTArray<SavedResponse>& aSavedResponseList,
const nsTArray<SavedRequest>& aSavedRequestList,
StreamList* aStreamList) override;
// FetchPut::Listener methods
virtual void
OnFetchPut(FetchPut* aFetchPut, nsresult aRv) override;
// utility methods
already_AddRefed<nsIInputStream>
DeserializeCacheStream(const PCacheReadStreamOrVoid& aStreamOrVoid);
mozilla::ipc::PBackgroundParent* mIpcManager;
const CacheId mCacheId;
const Namespace mNamespace;
const CacheOpArgs mOpArgs;
nsRefPtr<Manager> mManager;
nsRefPtr<PrincipalVerifier> mVerifier;
nsTArray<nsRefPtr<FetchPut>> mFetchPutList;
NS_DECL_OWNINGTHREAD
};
} // namespace cache
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_cache_CacheOpParent_h

View File

@ -6,14 +6,25 @@
#include "mozilla/dom/cache/CacheParent.h"
#include "mozilla/dom/cache/CacheOpParent.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/dom/cache/AutoUtils.h"
#include "mozilla/dom/cache/CachePushStreamParent.h"
#include "mozilla/dom/cache/CacheStreamControlParent.h"
#include "mozilla/dom/cache/ReadStream.h"
#include "mozilla/dom/cache/SavedTypes.h"
#include "mozilla/dom/cache/StreamList.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/ipc/PBackgroundParent.h"
#include "mozilla/ipc/FileDescriptorSetParent.h"
#include "mozilla/ipc/PFileDescriptorSetParent.h"
#include "nsCOMPtr.h"
namespace mozilla {
namespace dom {
namespace cache {
using mozilla::ipc::FileDescriptorSetParent;
using mozilla::ipc::PFileDescriptorSetParent;
// Declared in ActorUtils.h
void
@ -35,48 +46,22 @@ CacheParent::~CacheParent()
{
MOZ_COUNT_DTOR(cache::CacheParent);
MOZ_ASSERT(!mManager);
MOZ_ASSERT(mFetchPutList.IsEmpty());
}
void
CacheParent::ActorDestroy(ActorDestroyReason aReason)
{
MOZ_ASSERT(mManager);
for (uint32_t i = 0; i < mFetchPutList.Length(); ++i) {
mFetchPutList[i]->ClearListener();
}
mFetchPutList.Clear();
mManager->RemoveListener(this);
mManager->ReleaseCacheId(mCacheId);
mManager = nullptr;
}
PCacheOpParent*
CacheParent::AllocPCacheOpParent(const CacheOpArgs& aOpArgs)
{
if (aOpArgs.type() != CacheOpArgs::TCacheMatchArgs &&
aOpArgs.type() != CacheOpArgs::TCacheMatchAllArgs &&
aOpArgs.type() != CacheOpArgs::TCacheAddAllArgs &&
aOpArgs.type() != CacheOpArgs::TCachePutAllArgs &&
aOpArgs.type() != CacheOpArgs::TCacheDeleteArgs &&
aOpArgs.type() != CacheOpArgs::TCacheKeysArgs)
{
MOZ_CRASH("Invalid operation sent to Cache actor!");
}
return new CacheOpParent(Manager(), mCacheId, aOpArgs);
}
bool
CacheParent::DeallocPCacheOpParent(PCacheOpParent* aActor)
{
delete aActor;
return true;
}
bool
CacheParent::RecvPCacheOpConstructor(PCacheOpParent* aActor,
const CacheOpArgs& aOpArgs)
{
auto actor = static_cast<CacheOpParent*>(aActor);
actor->Execute(mManager);
return true;
}
PCachePushStreamParent*
CacheParent::AllocPCachePushStreamParent()
{
@ -100,6 +85,235 @@ CacheParent::RecvTeardown()
return true;
}
bool
CacheParent::RecvMatch(const RequestId& aRequestId, const PCacheRequest& aRequest,
const PCacheQueryParams& aParams)
{
MOZ_ASSERT(mManager);
mManager->CacheMatch(this, aRequestId, mCacheId, aRequest,
aParams);
return true;
}
bool
CacheParent::RecvMatchAll(const RequestId& aRequestId,
const PCacheRequestOrVoid& aRequest,
const PCacheQueryParams& aParams)
{
MOZ_ASSERT(mManager);
mManager->CacheMatchAll(this, aRequestId, mCacheId, aRequest, aParams);
return true;
}
bool
CacheParent::RecvAddAll(const RequestId& aRequestId,
nsTArray<PCacheRequest>&& aRequests)
{
nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> requestStreams;
requestStreams.SetCapacity(aRequests.Length());
for (uint32_t i = 0; i < aRequests.Length(); ++i) {
requestStreams.AppendElement(DeserializeCacheStream(aRequests[i].body()));
}
nsRefPtr<FetchPut> fetchPut;
nsresult rv = FetchPut::Create(this, mManager, aRequestId, mCacheId,
aRequests, requestStreams,
getter_AddRefs(fetchPut));
if (NS_WARN_IF(NS_FAILED(rv))) {
if (!SendAddAllResponse(aRequestId, rv)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to send AddAll response.");
}
return true;
}
mFetchPutList.AppendElement(fetchPut.forget());
return true;
}
bool
CacheParent::RecvPut(const RequestId& aRequestId,
const CacheRequestResponse& aPut)
{
MOZ_ASSERT(mManager);
nsAutoTArray<CacheRequestResponse, 1> putList;
putList.AppendElement(aPut);
nsAutoTArray<nsCOMPtr<nsIInputStream>, 1> requestStreamList;
nsAutoTArray<nsCOMPtr<nsIInputStream>, 1> responseStreamList;
requestStreamList.AppendElement(
DeserializeCacheStream(aPut.request().body()));
responseStreamList.AppendElement(
DeserializeCacheStream(aPut.response().body()));
mManager->CachePutAll(this, aRequestId, mCacheId, putList, requestStreamList,
responseStreamList);
return true;
}
bool
CacheParent::RecvDelete(const RequestId& aRequestId,
const PCacheRequest& aRequest,
const PCacheQueryParams& aParams)
{
MOZ_ASSERT(mManager);
mManager->CacheDelete(this, aRequestId, mCacheId, aRequest, aParams);
return true;
}
bool
CacheParent::RecvKeys(const RequestId& aRequestId,
const PCacheRequestOrVoid& aRequest,
const PCacheQueryParams& aParams)
{
MOZ_ASSERT(mManager);
mManager->CacheKeys(this, aRequestId, mCacheId, aRequest, aParams);
return true;
}
void
CacheParent::OnCacheMatch(RequestId aRequestId, nsresult aRv,
const SavedResponse* aSavedResponse,
StreamList* aStreamList)
{
AutoParentResponseOrVoid response(Manager());
// no match
if (NS_FAILED(aRv) || !aSavedResponse || !aStreamList) {
if (!SendMatchResponse(aRequestId, aRv, response.SendAsResponseOrVoid())) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to send Match response.");
}
return;
}
if (aSavedResponse) {
response.Add(*aSavedResponse, aStreamList);
}
if (!SendMatchResponse(aRequestId, aRv, response.SendAsResponseOrVoid())) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to send Match response.");
}
}
void
CacheParent::OnCacheMatchAll(RequestId aRequestId, nsresult aRv,
const nsTArray<SavedResponse>& aSavedResponses,
StreamList* aStreamList)
{
AutoParentResponseList responses(Manager(), aSavedResponses.Length());
for (uint32_t i = 0; i < aSavedResponses.Length(); ++i) {
responses.Add(aSavedResponses[i], aStreamList);
}
if (!SendMatchAllResponse(aRequestId, aRv, responses.SendAsResponseList())) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to send MatchAll response.");
}
}
void
CacheParent::OnCachePutAll(RequestId aRequestId, nsresult aRv)
{
if (!SendPutResponse(aRequestId, aRv)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to send Put response.");
}
}
void
CacheParent::OnCacheDelete(RequestId aRequestId, nsresult aRv, bool aSuccess)
{
if (!SendDeleteResponse(aRequestId, aRv, aSuccess)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to send Delete response.");
}
}
void
CacheParent::OnCacheKeys(RequestId aRequestId, nsresult aRv,
const nsTArray<SavedRequest>& aSavedRequests,
StreamList* aStreamList)
{
AutoParentRequestList requests(Manager(), aSavedRequests.Length());
for (uint32_t i = 0; i < aSavedRequests.Length(); ++i) {
requests.Add(aSavedRequests[i], aStreamList);
}
if (!SendKeysResponse(aRequestId, aRv, requests.SendAsRequestList())) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to send Keys response.");
}
}
void
CacheParent::OnFetchPut(FetchPut* aFetchPut, RequestId aRequestId, nsresult aRv)
{
aFetchPut->ClearListener();
mFetchPutList.RemoveElement(aFetchPut);
if (!SendAddAllResponse(aRequestId, aRv)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to send AddAll response.");
}
}
already_AddRefed<nsIInputStream>
CacheParent::DeserializeCacheStream(const PCacheReadStreamOrVoid& aStreamOrVoid)
{
if (aStreamOrVoid.type() == PCacheReadStreamOrVoid::Tvoid_t) {
return nullptr;
}
nsCOMPtr<nsIInputStream> stream;
const PCacheReadStream& readStream = aStreamOrVoid.get_PCacheReadStream();
// Option 1: A push stream actor was sent for nsPipe data
if (readStream.pushStreamParent()) {
MOZ_ASSERT(!readStream.controlParent());
CachePushStreamParent* pushStream =
static_cast<CachePushStreamParent*>(readStream.pushStreamParent());
stream = pushStream->TakeReader();
MOZ_ASSERT(stream);
return stream.forget();
}
// Option 2: One of our own ReadStreams was passed back to us with a stream
// control actor.
stream = ReadStream::Create(readStream);
if (stream) {
return stream.forget();
}
// Option 3: A stream was serialized using normal methods.
nsAutoTArray<FileDescriptor, 4> fds;
if (readStream.fds().type() ==
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
FileDescriptorSetParent* fdSetActor =
static_cast<FileDescriptorSetParent*>(readStream.fds().get_PFileDescriptorSetParent());
MOZ_ASSERT(fdSetActor);
fdSetActor->ForgetFileDescriptors(fds);
MOZ_ASSERT(!fds.IsEmpty());
if (!fdSetActor->Send__delete__(fdSetActor)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to delete fd set actor.");
}
}
return DeserializeInputStream(readStream.params(), fds);
}
} // namespace cache
} // namespace dom
} // namesapce mozilla

View File

@ -7,46 +7,77 @@
#ifndef mozilla_dom_cache_CacheParent_h
#define mozilla_dom_cache_CacheParent_h
#include "mozilla/dom/cache/FetchPut.h"
#include "mozilla/dom/cache/Manager.h"
#include "mozilla/dom/cache/PCacheParent.h"
#include "mozilla/dom/cache/Types.h"
struct nsID;
template <class T> class nsRefPtr;
namespace mozilla {
namespace dom {
namespace cache {
class Manager;
struct SavedResponse;
class CacheParent final : public PCacheParent
, public Manager::Listener
, public FetchPut::Listener
{
public:
CacheParent(cache::Manager* aManager, CacheId aCacheId);
virtual ~CacheParent();
private:
// PCacheParent methods
// PCacheParent method
virtual void ActorDestroy(ActorDestroyReason aReason) override;
virtual PCacheOpParent*
AllocPCacheOpParent(const CacheOpArgs& aOpArgs) override;
virtual PCachePushStreamParent* AllocPCachePushStreamParent() override;
virtual bool DeallocPCachePushStreamParent(PCachePushStreamParent* aActor) override;
virtual bool RecvTeardown() override;
virtual bool
DeallocPCacheOpParent(PCacheOpParent* aActor) override;
RecvMatch(const RequestId& aRequestId, const PCacheRequest& aRequest,
const PCacheQueryParams& aParams) override;
virtual bool
RecvPCacheOpConstructor(PCacheOpParent* actor,
const CacheOpArgs& aOpArgs) override;
virtual PCachePushStreamParent*
AllocPCachePushStreamParent() override;
RecvMatchAll(const RequestId& aRequestId, const PCacheRequestOrVoid& aRequest,
const PCacheQueryParams& aParams) override;
virtual bool
DeallocPCachePushStreamParent(PCachePushStreamParent* aActor) override;
RecvAddAll(const RequestId& aRequestId,
nsTArray<PCacheRequest>&& aRequests) override;
virtual bool
RecvTeardown() override;
RecvPut(const RequestId& aRequestId,
const CacheRequestResponse& aPut) override;
virtual bool
RecvDelete(const RequestId& aRequestId, const PCacheRequest& aRequest,
const PCacheQueryParams& aParams) override;
virtual bool
RecvKeys(const RequestId& aRequestId, const PCacheRequestOrVoid& aRequest,
const PCacheQueryParams& aParams) override;
// Manager::Listener methods
virtual void OnCacheMatch(RequestId aRequestId, nsresult aRv,
const SavedResponse* aSavedResponse,
StreamList* aStreamList) override;
virtual void OnCacheMatchAll(RequestId aRequestId, nsresult aRv,
const nsTArray<SavedResponse>& aSavedResponses,
StreamList* aStreamList) override;
virtual void OnCachePutAll(RequestId aRequestId, nsresult aRv) override;
virtual void OnCacheDelete(RequestId aRequestId, nsresult aRv,
bool aSuccess) override;
virtual void OnCacheKeys(RequestId aRequestId, nsresult aRv,
const nsTArray<SavedRequest>& aSavedRequests,
StreamList* aStreamList) override;
// FetchPut::Listener methods
virtual void OnFetchPut(FetchPut* aFetchPut, RequestId aRequestId,
nsresult aRv) override;
already_AddRefed<nsIInputStream>
DeserializeCacheStream(const PCacheReadStreamOrVoid& aStreamOrVoid);
nsRefPtr<cache::Manager> mManager;
const CacheId mCacheId;
nsTArray<nsRefPtr<FetchPut>> mFetchPutList;
};
} // namespace cache

View File

@ -13,7 +13,6 @@
#include "mozilla/dom/cache/AutoUtils.h"
#include "mozilla/dom/cache/Cache.h"
#include "mozilla/dom/cache/CacheChild.h"
#include "mozilla/dom/cache/CacheOpChild.h"
#include "mozilla/dom/cache/CacheStorageChild.h"
#include "mozilla/dom/cache/Feature.h"
#include "mozilla/dom/cache/PCacheChild.h"
@ -42,26 +41,24 @@ using mozilla::ipc::PrincipalToPrincipalInfo;
NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::cache::CacheStorage);
NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::cache::CacheStorage);
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(mozilla::dom::cache::CacheStorage,
mGlobal);
NS_IMPL_CYCLE_COLLECTION_CLASS(mozilla::dom::cache::CacheStorage)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(mozilla::dom::cache::CacheStorage)
tmp->DisconnectFromActor();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal, mRequestPromises)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(mozilla::dom::cache::CacheStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal, mRequestPromises)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(mozilla::dom::cache::CacheStorage)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CacheStorage)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIIPCBackgroundChildCreateCallback)
NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
NS_INTERFACE_MAP_END
// We cannot reference IPC types in a webidl binding implementation header. So
// define this in the .cpp and use heap storage in the mPendingRequests list.
struct CacheStorage::Entry final
{
nsRefPtr<Promise> mPromise;
CacheOpArgs mArgs;
// We cannot add the requests until after the actor is present. So store
// the request data separately for now.
nsRefPtr<InternalRequest> mRequest;
};
// static
already_AddRefed<CacheStorage>
CacheStorage::CreateOnMainThread(Namespace aNamespace, nsIGlobalObject* aGlobal,
@ -178,31 +175,29 @@ CacheStorage::Match(const RequestOrUSVString& aRequest,
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
if (mFailedActor) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<InternalRequest> request = ToInternalRequest(aRequest, IgnoreBody,
aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
PCacheQueryParams params;
ToPCacheQueryParams(params, aOptions);
if (mFailedActor) {
promise->MaybeReject(NS_ERROR_UNEXPECTED);
return promise.forget();
}
nsAutoPtr<Entry> entry(new Entry());
entry->mPromise = promise;
entry->mArgs = StorageMatchArgs(PCacheRequest(), params);
entry->mRequest = request;
RequestId requestId = AddRequestPromise(promise, aRv);
Entry entry;
entry.mRequestId = requestId;
entry.mOp = OP_MATCH;
entry.mOptions = aOptions;
entry.mRequest = ToInternalRequest(aRequest, IgnoreBody, aRv);
if (aRv.Failed()) {
return nullptr;
}
mPendingRequests.AppendElement(entry);
mPendingRequests.AppendElement(entry.forget());
MaybeRunPendingRequests();
return promise.forget();
@ -213,21 +208,23 @@ CacheStorage::Has(const nsAString& aKey, ErrorResult& aRv)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
if (mFailedActor) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
nsAutoPtr<Entry> entry(new Entry());
entry->mPromise = promise;
entry->mArgs = StorageHasArgs(nsString(aKey));
if (mFailedActor) {
promise->MaybeReject(NS_ERROR_UNEXPECTED);
return promise.forget();
}
RequestId requestId = AddRequestPromise(promise, aRv);
Entry* entry = mPendingRequests.AppendElement();
entry->mRequestId = requestId;
entry->mOp = OP_HAS;
entry->mKey = aKey;
mPendingRequests.AppendElement(entry.forget());
MaybeRunPendingRequests();
return promise.forget();
@ -238,21 +235,23 @@ CacheStorage::Open(const nsAString& aKey, ErrorResult& aRv)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
if (mFailedActor) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
nsAutoPtr<Entry> entry(new Entry());
entry->mPromise = promise;
entry->mArgs = StorageOpenArgs(nsString(aKey));
if (mFailedActor) {
promise->MaybeReject(NS_ERROR_UNEXPECTED);
return promise.forget();
}
RequestId requestId = AddRequestPromise(promise, aRv);
Entry* entry = mPendingRequests.AppendElement();
entry->mRequestId = requestId;
entry->mOp = OP_OPEN;
entry->mKey = aKey;
mPendingRequests.AppendElement(entry.forget());
MaybeRunPendingRequests();
return promise.forget();
@ -263,21 +262,23 @@ CacheStorage::Delete(const nsAString& aKey, ErrorResult& aRv)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
if (mFailedActor) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
nsAutoPtr<Entry> entry(new Entry());
entry->mPromise = promise;
entry->mArgs = StorageDeleteArgs(nsString(aKey));
if (mFailedActor) {
promise->MaybeReject(NS_ERROR_UNEXPECTED);
return promise.forget();
}
RequestId requestId = AddRequestPromise(promise, aRv);
Entry* entry = mPendingRequests.AppendElement();
entry->mRequestId = requestId;
entry->mOp = OP_DELETE;
entry->mKey = aKey;
mPendingRequests.AppendElement(entry.forget());
MaybeRunPendingRequests();
return promise.forget();
@ -288,21 +289,22 @@ CacheStorage::Keys(ErrorResult& aRv)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
if (mFailedActor) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
if (!promise) {
return nullptr;
}
nsAutoPtr<Entry> entry(new Entry());
entry->mPromise = promise;
entry->mArgs = StorageKeysArgs();
if (mFailedActor) {
promise->MaybeReject(NS_ERROR_UNEXPECTED);
return promise.forget();
}
RequestId requestId = AddRequestPromise(promise, aRv);
Entry* entry = mPendingRequests.AppendElement();
entry->mRequestId = requestId;
entry->mOp = OP_KEYS;
mPendingRequests.AppendElement(entry.forget());
MaybeRunPendingRequests();
return promise.forget();
@ -369,8 +371,9 @@ CacheStorage::ActorFailed()
mFeature = nullptr;
for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) {
nsAutoPtr<Entry> entry(mPendingRequests[i].forget());
entry->mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
RequestId requestId = mPendingRequests[i].mRequestId;
nsRefPtr<Promise> promise = RemoveRequestPromise(requestId);
promise->MaybeReject(NS_ERROR_UNEXPECTED);
}
mPendingRequests.Clear();
}
@ -389,6 +392,117 @@ CacheStorage::DestroyInternal(CacheStorageChild* aActor)
ActorFailed();
}
void
CacheStorage::RecvMatchResponse(RequestId aRequestId, nsresult aRv,
const PCacheResponseOrVoid& aResponse)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
// Convert the response immediately if its present. This ensures that
// any stream actors are cleaned up, even if we error out below.
nsRefPtr<Response> response;
if (aResponse.type() == PCacheResponseOrVoid::TPCacheResponse) {
response = ToResponse(aResponse);
}
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
if (NS_FAILED(aRv)) {
promise->MaybeReject(aRv);
return;
}
// If cache name was specified in the request options and the cache does
// not exist, then an error code will already have been set. If we
// still do not have a response, then we just resolve undefined like a
// normal Cache::Match.
if (!response) {
promise->MaybeResolve(JS::UndefinedHandleValue);
return;
}
promise->MaybeResolve(response);
}
void
CacheStorage::RecvHasResponse(RequestId aRequestId, nsresult aRv, bool aSuccess)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
if (NS_FAILED(aRv)) {
promise->MaybeReject(aRv);
return;
}
promise->MaybeResolve(aSuccess);
}
void
CacheStorage::RecvOpenResponse(RequestId aRequestId, nsresult aRv,
CacheChild* aActor)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
// Unlike most of our async callback Recv*() methods, this one gets back
// an actor. We need to make sure to clean it up in case of error.
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
if (NS_FAILED(aRv)) {
if (aActor) {
// We cannot use the CacheChild::StartDestroy() method because there
// is no Cache object associated with the actor yet. Instead, just
// send the underlying Teardown message.
unused << aActor->SendTeardown();
}
promise->MaybeReject(aRv);
return;
}
if (!aActor) {
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return;
}
nsRefPtr<Cache> cache = new Cache(mGlobal, aActor);
promise->MaybeResolve(cache);
}
void
CacheStorage::RecvDeleteResponse(RequestId aRequestId, nsresult aRv,
bool aSuccess)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
if (NS_FAILED(aRv)) {
promise->MaybeReject(aRv);
return;
}
promise->MaybeResolve(aSuccess);
}
void
CacheStorage::RecvKeysResponse(RequestId aRequestId, nsresult aRv,
const nsTArray<nsString>& aKeys)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
if (NS_FAILED(aRv)) {
promise->MaybeReject(aRv);
return;
}
promise->MaybeResolve(aKeys);
}
nsIGlobalObject*
CacheStorage::GetGlobalObject() const
{
@ -410,9 +524,32 @@ CacheStorage::CreatePushStream(nsIAsyncInputStream* aStream)
MOZ_CRASH("CacheStorage should never create a push stream.");
}
void
CacheStorage::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{
// Do nothing. The Promise will automatically drop the ref to us after
// calling the callback. This is what we want as we only registered in order
// to be held alive via the Promise handle.
}
void
CacheStorage::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{
// Do nothing. The Promise will automatically drop the ref to us after
// calling the callback. This is what we want as we only registered in order
// to be held alive via the Promise handle.
}
CacheStorage::~CacheStorage()
{
DisconnectFromActor();
}
void
CacheStorage::DisconnectFromActor()
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
if (mActor) {
mActor->StartDestroy();
// DestroyInternal() is called synchronously by StartDestroy(). So we
@ -429,24 +566,89 @@ CacheStorage::MaybeRunPendingRequests()
}
for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) {
ErrorResult rv;
nsAutoPtr<Entry> entry(mPendingRequests[i].forget());
AutoChildOpArgs args(this, entry->mArgs);
if (entry->mRequest) {
args.Add(entry->mRequest, IgnoreBody, PassThroughReferrer,
IgnoreInvalidScheme, rv);
// Note, the entry can be modified below due to Request/Response body
// being marked used.
Entry& entry = mPendingRequests[i];
RequestId requestId = entry.mRequestId;
switch(entry.mOp) {
case OP_MATCH:
{
AutoChildRequest request(this);
ErrorResult rv;
request.Add(entry.mRequest, IgnoreBody, PassThroughReferrer,
IgnoreInvalidScheme, rv);
if (NS_WARN_IF(rv.Failed())) {
nsRefPtr<Promise> promise = RemoveRequestPromise(requestId);
promise->MaybeReject(rv);
break;
}
PCacheQueryParams params;
ToPCacheQueryParams(params, entry.mOptions);
unused << mActor->SendMatch(requestId, request.SendAsRequest(), params);
break;
}
case OP_HAS:
unused << mActor->SendHas(requestId, entry.mKey);
break;
case OP_OPEN:
unused << mActor->SendOpen(requestId, entry.mKey);
break;
case OP_DELETE:
unused << mActor->SendDelete(requestId, entry.mKey);
break;
case OP_KEYS:
unused << mActor->SendKeys(requestId);
break;
default:
MOZ_ASSERT_UNREACHABLE("Unknown pending CacheStorage op.");
}
if (rv.Failed()) {
entry->mPromise->MaybeReject(rv);
continue;
}
unused << mActor->SendPCacheOpConstructor(
new CacheOpChild(mActor->GetFeature(), mGlobal, this, entry->mPromise),
args.SendAsOpArgs());
}
mPendingRequests.Clear();
}
RequestId
CacheStorage::AddRequestPromise(Promise* aPromise, ErrorResult& aRv)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
MOZ_ASSERT(aPromise);
MOZ_ASSERT(!mRequestPromises.Contains(aPromise));
// Register ourself as a promise handler so that the promise will hold us
// alive. This allows the client code to drop the ref to the CacheStorage
// object and just keep their promise. This is fairly common in promise
// chaining code.
aPromise->AppendNativeHandler(this);
mRequestPromises.AppendElement(aPromise);
// (Ab)use the promise pointer as our request ID. This is a fast, thread-safe
// way to get a unique ID for the promise to be resolved later.
return reinterpret_cast<RequestId>(aPromise);
}
already_AddRefed<Promise>
CacheStorage::RemoveRequestPromise(RequestId aRequestId)
{
NS_ASSERT_OWNINGTHREAD(CacheStorage);
MOZ_ASSERT(aRequestId != INVALID_REQUEST_ID);
for (uint32_t i = 0; i < mRequestPromises.Length(); ++i) {
nsRefPtr<Promise>& promise = mRequestPromises.ElementAt(i);
// To be safe, only cast promise pointers to our integer RequestId
// type and never cast an integer to a pointer.
if (aRequestId == reinterpret_cast<RequestId>(promise.get())) {
nsRefPtr<Promise> ref;
ref.swap(promise);
mRequestPromises.RemoveElementAt(i);
return ref.forget();
}
}
MOZ_ASSERT_UNREACHABLE("Received response without a matching promise!");
return nullptr;
}
} // namespace cache
} // namespace dom
} // namespace mozilla

View File

@ -8,6 +8,7 @@
#define mozilla_dom_cache_CacheStorage_h
#include "mozilla/dom/CacheBinding.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/cache/Types.h"
#include "mozilla/dom/cache/TypeUtils.h"
#include "nsAutoPtr.h"
@ -45,6 +46,7 @@ class PCacheResponseOrVoid;
class CacheStorage final : public nsIIPCBackgroundChildCreateCallback
, public nsWrapperCache
, public TypeUtils
, public PromiseNativeHandler
{
typedef mozilla::ipc::PBackgroundChild PBackgroundChild;
@ -79,6 +81,16 @@ public:
// Called when CacheStorageChild actor is being destroyed
void DestroyInternal(CacheStorageChild* aActor);
// Methods forwarded from CacheStorageChild
void RecvMatchResponse(RequestId aRequestId, nsresult aRv,
const PCacheResponseOrVoid& aResponse);
void RecvHasResponse(RequestId aRequestId, nsresult aRv, bool aSuccess);
void RecvOpenResponse(RequestId aRequestId, nsresult aRv,
CacheChild* aActor);
void RecvDeleteResponse(RequestId aRequestId, nsresult aRv, bool aSuccess);
void RecvKeysResponse(RequestId aRequestId, nsresult aRv,
const nsTArray<nsString>& aKeys);
// TypeUtils methods
virtual nsIGlobalObject* GetGlobalObject() const override;
#ifdef DEBUG
@ -88,24 +100,60 @@ public:
virtual CachePushStreamChild*
CreatePushStream(nsIAsyncInputStream* aStream) override;
// PromiseNativeHandler methods
virtual void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
virtual void
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
private:
CacheStorage(Namespace aNamespace, nsIGlobalObject* aGlobal,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo, Feature* aFeature);
~CacheStorage();
// Called when we're destroyed or CCed.
void DisconnectFromActor();
void MaybeRunPendingRequests();
RequestId AddRequestPromise(Promise* aPromise, ErrorResult& aRv);
already_AddRefed<Promise> RemoveRequestPromise(RequestId aRequestId);
// Would like to use CacheInitData here, but we cannot because
// its an IPC struct which breaks webidl by including windows.h.
const Namespace mNamespace;
nsCOMPtr<nsIGlobalObject> mGlobal;
UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
nsRefPtr<Feature> mFeature;
// weak ref cleared in DestroyInternal
CacheStorageChild* mActor;
nsTArray<nsRefPtr<Promise>> mRequestPromises;
struct Entry;
nsTArray<nsAutoPtr<Entry>> mPendingRequests;
enum Op
{
OP_MATCH,
OP_HAS,
OP_OPEN,
OP_DELETE,
OP_KEYS
};
struct Entry
{
RequestId mRequestId;
Op mOp;
// Would prefer to use PCacheRequest/PCacheCacheQueryOptions, but can't
// because they introduce a header dependency on windows.h which
// breaks the bindings build.
nsRefPtr<InternalRequest> mRequest;
CacheQueryOptions mOptions;
// It would also be nice to union the key with the match args above,
// but VS2013 doesn't like these types in unions because of copy
// constructors.
nsString mKey;
};
nsTArray<Entry> mPendingRequests;
bool mFailedActor;
public:

View File

@ -9,7 +9,6 @@
#include "mozilla/unused.h"
#include "mozilla/dom/cache/CacheChild.h"
#include "mozilla/dom/cache/CacheStorage.h"
#include "mozilla/dom/cache/PCacheOpChild.h"
#include "mozilla/dom/cache/StreamUtils.h"
namespace mozilla {
@ -61,8 +60,6 @@ CacheStorageChild::StartDestroy()
return;
}
// TODO: don't destroy if we have outstanding ops
listener->DestroyInternal(this);
// CacheStorage listener should call ClearListener() in DestroyInternal()
@ -86,17 +83,91 @@ CacheStorageChild::ActorDestroy(ActorDestroyReason aReason)
RemoveFeature();
}
PCacheOpChild*
CacheStorageChild::AllocPCacheOpChild(const CacheOpArgs& aOpArgs)
bool
CacheStorageChild::RecvMatchResponse(const RequestId& aRequestId,
const nsresult& aRv,
const PCacheResponseOrVoid& aResponseOrVoid)
{
MOZ_CRASH("CacheOpChild should be manually constructed.");
return nullptr;
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
AddFeatureToStreamChild(aResponseOrVoid, GetFeature());
nsRefPtr<CacheStorage> listener = mListener;
if (!listener) {
StartDestroyStreamChild(aResponseOrVoid);
return true;
}
listener->RecvMatchResponse(aRequestId, aRv, aResponseOrVoid);
return true;
}
bool
CacheStorageChild::DeallocPCacheOpChild(PCacheOpChild* aActor)
CacheStorageChild::RecvHasResponse(const RequestId& aRequestId,
const nsresult& aRv,
const bool& aSuccess)
{
delete aActor;
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
nsRefPtr<CacheStorage> listener = mListener;
if (listener) {
listener->RecvHasResponse(aRequestId, aRv, aSuccess);
}
return true;
}
bool
CacheStorageChild::RecvOpenResponse(const RequestId& aRequestId,
const nsresult& aRv,
PCacheChild* aActor)
{
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
nsRefPtr<CacheStorage> listener = mListener;
if (!listener || FeatureNotified()) {
if (aActor) {
unused << aActor->SendTeardown();
}
return true;
}
CacheChild* cacheChild = static_cast<CacheChild*>(aActor);
// Since FeatureNotified() returned false above, we are guaranteed that
// the feature won't try to shutdown the actor until after we create the
// Cache DOM object in the listener's RecvOpenResponse() method. This
// is important because StartShutdown() expects a Cache object listener.
if (cacheChild) {
cacheChild->SetFeature(GetFeature());
}
listener->RecvOpenResponse(aRequestId, aRv, cacheChild);
return true;
}
bool
CacheStorageChild::RecvDeleteResponse(const RequestId& aRequestId,
const nsresult& aRv,
const bool& aResult)
{
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
nsRefPtr<CacheStorage> listener = mListener;
if (listener) {
listener->RecvDeleteResponse(aRequestId, aRv, aResult);
}
return true;
}
bool
CacheStorageChild::RecvKeysResponse(const RequestId& aRequestId,
const nsresult& aRv,
nsTArray<nsString>&& aKeys)
{
NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
nsRefPtr<CacheStorage> listener = mListener;
if (listener) {
listener->RecvKeysResponse(aRequestId, aRv, aKeys);
}
return true;
}

View File

@ -27,7 +27,7 @@ public:
~CacheStorageChild();
// Must be called by the associated CacheStorage listener in its
// ActorDestroy() method. Also, CacheStorage must call SendDestroy() on the
// ActorDestroy() method. Also, CacheStorage must Send__delete__() the
// actor in its destructor to trigger ActorDestroy() if it has not been
// called yet.
void ClearListener();
@ -42,11 +42,21 @@ private:
// PCacheStorageChild methods
virtual void ActorDestroy(ActorDestroyReason aReason) override;
virtual PCacheOpChild*
AllocPCacheOpChild(const CacheOpArgs& aOpArgs) override;
virtual bool
DeallocPCacheOpChild(PCacheOpChild* aActor) override;
virtual bool RecvMatchResponse(const RequestId& aRequestId,
const nsresult& aRv,
const PCacheResponseOrVoid& response) override;
virtual bool RecvHasResponse(const cache::RequestId& aRequestId,
const nsresult& aRv,
const bool& aSuccess) override;
virtual bool RecvOpenResponse(const cache::RequestId& aRequestId,
const nsresult& aRv,
PCacheChild* aActor) override;
virtual bool RecvDeleteResponse(const cache::RequestId& aRequestId,
const nsresult& aRv,
const bool& aResult) override;
virtual bool RecvKeysResponse(const cache::RequestId& aRequestId,
const nsresult& aRv,
nsTArray<nsString>&& aKeys) override;
// Use a weak ref so actor does not hold DOM object alive past content use.
// The CacheStorage object must call ClearListener() to null this before its

View File

@ -6,18 +6,28 @@
#include "mozilla/dom/cache/CacheStorageParent.h"
#include "mozilla/unused.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/cache/ActorUtils.h"
#include "mozilla/dom/cache/CacheOpParent.h"
#include "mozilla/dom/cache/AutoUtils.h"
#include "mozilla/dom/cache/CacheParent.h"
#include "mozilla/dom/cache/CacheStreamControlParent.h"
#include "mozilla/dom/cache/Manager.h"
#include "mozilla/dom/cache/ManagerId.h"
#include "mozilla/dom/cache/ReadStream.h"
#include "mozilla/dom/cache/SavedTypes.h"
#include "mozilla/dom/cache/StreamList.h"
#include "mozilla/ipc/PBackgroundParent.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/ipc/PFileDescriptorSetParent.h"
#include "mozilla/DebugOnly.h"
#include "nsCOMPtr.h"
namespace mozilla {
namespace dom {
namespace cache {
using mozilla::ipc::PBackgroundParent;
using mozilla::ipc::PFileDescriptorSetParent;
using mozilla::ipc::PrincipalInfo;
// declared in ActorUtils.h
@ -55,59 +65,22 @@ CacheStorageParent::~CacheStorageParent()
{
MOZ_COUNT_DTOR(cache::CacheStorageParent);
MOZ_ASSERT(!mVerifier);
MOZ_ASSERT(!mManager);
}
void
CacheStorageParent::ActorDestroy(ActorDestroyReason aReason)
{
if (mVerifier) {
mVerifier->RemoveListener(this);
mVerifier->ClearListener();
mVerifier = nullptr;
}
}
PCacheOpParent*
CacheStorageParent::AllocPCacheOpParent(const CacheOpArgs& aOpArgs)
{
if (aOpArgs.type() != CacheOpArgs::TStorageMatchArgs &&
aOpArgs.type() != CacheOpArgs::TStorageHasArgs &&
aOpArgs.type() != CacheOpArgs::TStorageOpenArgs &&
aOpArgs.type() != CacheOpArgs::TStorageDeleteArgs &&
aOpArgs.type() != CacheOpArgs::TStorageKeysArgs)
{
MOZ_CRASH("Invalid operation sent to CacheStorage actor!");
if (mManager) {
MOZ_ASSERT(!mActiveRequests.IsEmpty());
mManager->RemoveListener(this);
mManager = nullptr;
}
return new CacheOpParent(Manager(), mNamespace, aOpArgs);
}
bool
CacheStorageParent::DeallocPCacheOpParent(PCacheOpParent* aActor)
{
delete aActor;
return true;
}
bool
CacheStorageParent::RecvPCacheOpConstructor(PCacheOpParent* aActor,
const CacheOpArgs& aOpArgs)
{
auto actor = static_cast<CacheOpParent*>(aActor);
if (mVerifier) {
MOZ_ASSERT(!mManagerId);
actor->WaitForVerification(mVerifier);
return true;
}
if (NS_FAILED(mVerifiedStatus)) {
unused << CacheOpParent::Send__delete__(actor, mVerifiedStatus, void_t());
return true;
}
MOZ_ASSERT(mManagerId);
actor->Execute(mManagerId);
return true;
}
bool
@ -120,11 +93,190 @@ CacheStorageParent::RecvTeardown()
return true;
}
bool
CacheStorageParent::RecvMatch(const RequestId& aRequestId,
const PCacheRequest& aRequest,
const PCacheQueryParams& aParams)
{
if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
if (!SendMatchResponse(aRequestId, mVerifiedStatus, void_t())) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Match response.");
}
return true;
}
// queue requests if we are still waiting for principal verification
if (!mManagerId) {
Entry* entry = mPendingRequests.AppendElement();
entry->mOp = OP_MATCH;
entry->mRequestId = aRequestId;
entry->mRequest = aRequest;
entry->mParams = aParams;
return true;
}
nsRefPtr<cache::Manager> manager;
nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
if (NS_WARN_IF(NS_FAILED(rv))) {
if (!SendMatchResponse(aRequestId, rv, void_t())) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Match response.");
}
return true;
}
manager->StorageMatch(this, aRequestId, mNamespace, aRequest,
aParams);
return true;
}
bool
CacheStorageParent::RecvHas(const RequestId& aRequestId, const nsString& aKey)
{
if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
if (!SendHasResponse(aRequestId, mVerifiedStatus, false)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Has response.");
}
return true;
}
// queue requests if we are still waiting for principal verification
if (!mManagerId) {
Entry* entry = mPendingRequests.AppendElement();
entry->mOp = OP_HAS;
entry->mRequestId = aRequestId;
entry->mKey = aKey;
return true;
}
nsRefPtr<cache::Manager> manager;
nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
if (NS_WARN_IF(NS_FAILED(rv))) {
if (!SendHasResponse(aRequestId, rv, false)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Has response.");
}
return true;
}
manager->StorageHas(this, aRequestId, mNamespace, aKey);
return true;
}
bool
CacheStorageParent::RecvOpen(const RequestId& aRequestId, const nsString& aKey)
{
if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
if (!SendOpenResponse(aRequestId, mVerifiedStatus, nullptr)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Open response.");
}
return true;
}
// queue requests if we are still waiting for principal verification
if (!mManagerId) {
Entry* entry = mPendingRequests.AppendElement();
entry->mOp = OP_OPEN;
entry->mRequestId = aRequestId;
entry->mKey = aKey;
return true;
}
nsRefPtr<cache::Manager> manager;
nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
if (NS_WARN_IF(NS_FAILED(rv))) {
if (!SendOpenResponse(aRequestId, rv, nullptr)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Open response.");
}
return true;
}
manager->StorageOpen(this, aRequestId, mNamespace, aKey);
return true;
}
bool
CacheStorageParent::RecvDelete(const RequestId& aRequestId,
const nsString& aKey)
{
if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
if (!SendDeleteResponse(aRequestId, mVerifiedStatus, false)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Delete response.");
}
return true;
}
// queue requests if we are still waiting for principal verification
if (!mManagerId) {
Entry* entry = mPendingRequests.AppendElement();
entry->mOp = OP_DELETE;
entry->mRequestId = aRequestId;
entry->mKey = aKey;
return true;
}
nsRefPtr<cache::Manager> manager;
nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
if (NS_WARN_IF(NS_FAILED(rv))) {
if (!SendDeleteResponse(aRequestId, rv, false)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Delete response.");
}
return true;
}
manager->StorageDelete(this, aRequestId, mNamespace, aKey);
return true;
}
bool
CacheStorageParent::RecvKeys(const RequestId& aRequestId)
{
if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
if (!SendKeysResponse(aRequestId, mVerifiedStatus, nsTArray<nsString>())) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Keys response.");
}
}
// queue requests if we are still waiting for principal verification
if (!mManagerId) {
Entry* entry = mPendingRequests.AppendElement();
entry->mOp = OP_DELETE;
entry->mRequestId = aRequestId;
return true;
}
nsRefPtr<cache::Manager> manager;
nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
if (NS_WARN_IF(NS_FAILED(rv))) {
if (!SendKeysResponse(aRequestId, rv, nsTArray<nsString>())) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Keys response.");
}
return true;
}
manager->StorageKeys(this, aRequestId, mNamespace);
return true;
}
void
CacheStorageParent::OnPrincipalVerified(nsresult aRv, ManagerId* aManagerId)
{
MOZ_ASSERT(mVerifier);
MOZ_ASSERT(!mManagerId);
MOZ_ASSERT(!mManager);
MOZ_ASSERT(NS_SUCCEEDED(mVerifiedStatus));
if (NS_WARN_IF(NS_FAILED(aRv))) {
@ -132,8 +284,165 @@ CacheStorageParent::OnPrincipalVerified(nsresult aRv, ManagerId* aManagerId)
}
mManagerId = aManagerId;
mVerifier->RemoveListener(this);
mVerifier->ClearListener();
mVerifier = nullptr;
RetryPendingRequests();
}
void
CacheStorageParent::OnStorageMatch(RequestId aRequestId, nsresult aRv,
const SavedResponse* aSavedResponse,
StreamList* aStreamList)
{
PCacheResponseOrVoid responseOrVoid;
ReleaseManager(aRequestId);
AutoParentResponseOrVoid response(Manager());
// no match
if (NS_FAILED(aRv) || !aSavedResponse) {
if (!SendMatchResponse(aRequestId, aRv, response.SendAsResponseOrVoid())) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Match response.");
}
return;
}
if (aSavedResponse) {
response.Add(*aSavedResponse, aStreamList);
}
if (!SendMatchResponse(aRequestId, aRv, response.SendAsResponseOrVoid())) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Match response.");
}
}
void
CacheStorageParent::OnStorageHas(RequestId aRequestId, nsresult aRv,
bool aCacheFound)
{
ReleaseManager(aRequestId);
if (!SendHasResponse(aRequestId, aRv, aCacheFound)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Has response.");
}
}
void
CacheStorageParent::OnStorageOpen(RequestId aRequestId, nsresult aRv,
CacheId aCacheId)
{
if (NS_FAILED(aRv)) {
ReleaseManager(aRequestId);
if (!SendOpenResponse(aRequestId, aRv, nullptr)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Open response.");
}
return;
}
MOZ_ASSERT(mManager);
CacheParent* actor = new CacheParent(mManager, aCacheId);
ReleaseManager(aRequestId);
PCacheParent* base = Manager()->SendPCacheConstructor(actor);
actor = static_cast<CacheParent*>(base);
if (!SendOpenResponse(aRequestId, aRv, actor)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Open response.");
}
}
void
CacheStorageParent::OnStorageDelete(RequestId aRequestId, nsresult aRv,
bool aCacheDeleted)
{
ReleaseManager(aRequestId);
if (!SendDeleteResponse(aRequestId, aRv, aCacheDeleted)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Delete response.");
}
}
void
CacheStorageParent::OnStorageKeys(RequestId aRequestId, nsresult aRv,
const nsTArray<nsString>& aKeys)
{
ReleaseManager(aRequestId);
if (!SendKeysResponse(aRequestId, aRv, aKeys)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("CacheStorage failed to send Keys response.");
}
}
void
CacheStorageParent::RetryPendingRequests()
{
MOZ_ASSERT(mManagerId || NS_FAILED(mVerifiedStatus));
for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) {
const Entry& entry = mPendingRequests[i];
switch(entry.mOp) {
case OP_MATCH:
RecvMatch(entry.mRequestId, entry.mRequest, entry.mParams);
break;
case OP_HAS:
RecvHas(entry.mRequestId, entry.mKey);
break;
case OP_OPEN:
RecvOpen(entry.mRequestId, entry.mKey);
break;
case OP_DELETE:
RecvDelete(entry.mRequestId, entry.mKey);
break;
case OP_KEYS:
RecvKeys(entry.mRequestId);
break;
default:
MOZ_ASSERT_UNREACHABLE("Pending request within unknown op");
}
}
mPendingRequests.Clear();
mPendingRequests.Compact();
}
nsresult
CacheStorageParent::RequestManager(RequestId aRequestId,
cache::Manager** aManagerOut)
{
MOZ_ASSERT(!mActiveRequests.Contains(aRequestId));
nsRefPtr<cache::Manager> ref = mManager;
if (!ref) {
MOZ_ASSERT(mActiveRequests.IsEmpty());
nsresult rv = cache::Manager::GetOrCreate(mManagerId, getter_AddRefs(ref));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
mManager = ref;
}
mActiveRequests.AppendElement(aRequestId);
ref.forget(aManagerOut);
return NS_OK;
}
void
CacheStorageParent::ReleaseManager(RequestId aRequestId)
{
// Note that if the child process dies we also clean up the mManager in
// ActorDestroy(). There is no race with this method, however, because
// ActorDestroy removes this object from the Manager's listener list.
// Therefore ReleaseManager() should never be called after ActorDestroy()
// runs.
MOZ_ASSERT(mManager);
MOZ_ASSERT(!mActiveRequests.IsEmpty());
MOZ_ALWAYS_TRUE(mActiveRequests.RemoveElement(aRequestId));
if (mActiveRequests.IsEmpty()) {
mManager->RemoveListener(this);
mManager = nullptr;
}
}
} // namespace cache

View File

@ -7,18 +7,24 @@
#ifndef mozilla_dom_cache_CacheStorageParent_h
#define mozilla_dom_cache_CacheStorageParent_h
#include "mozilla/dom/cache/CacheInitData.h"
#include "mozilla/dom/cache/PCacheStorageParent.h"
#include "mozilla/dom/cache/Manager.h"
#include "mozilla/dom/cache/PrincipalVerifier.h"
#include "mozilla/dom/cache/Types.h"
template <class T> class nsRefPtr;
namespace mozilla {
namespace dom {
namespace cache {
class CacheStreamControlParent;
class ManagerId;
class CacheStorageParent final : public PCacheStorageParent
, public PrincipalVerifier::Listener
, public Manager::Listener
{
public:
CacheStorageParent(PBackgroundParent* aManagingActor, Namespace aNamespace,
@ -27,30 +33,72 @@ public:
private:
// PCacheStorageParent methods
virtual void
ActorDestroy(ActorDestroyReason aReason) override;
virtual PCacheOpParent*
AllocPCacheOpParent(const CacheOpArgs& aOpArgs) override;
virtual bool
DeallocPCacheOpParent(PCacheOpParent* aActor) override;
virtual bool
RecvPCacheOpConstructor(PCacheOpParent* actor,
const CacheOpArgs& aOpArgs) override;
virtual bool
RecvTeardown() override;
virtual void ActorDestroy(ActorDestroyReason aReason) override;
virtual bool RecvTeardown() override;
virtual bool RecvMatch(const RequestId& aRequestId,
const PCacheRequest& aRequest,
const PCacheQueryParams& aParams) override;
virtual bool RecvHas(const RequestId& aRequestId,
const nsString& aKey) override;
virtual bool RecvOpen(const RequestId& aRequestId,
const nsString& aKey) override;
virtual bool RecvDelete(const RequestId& aRequestId,
const nsString& aKey) override;
virtual bool RecvKeys(const RequestId& aRequestId) override;
// PrincipalVerifier::Listener methods
virtual void OnPrincipalVerified(nsresult aRv,
ManagerId* aManagerId) override;
// Manager::Listener methods
virtual void OnStorageMatch(RequestId aRequestId, nsresult aRv,
const SavedResponse* aResponse,
StreamList* aStreamList) override;
virtual void OnStorageHas(RequestId aRequestId, nsresult aRv,
bool aCacheFound) override;
virtual void OnStorageOpen(RequestId aRequestId, nsresult aRv,
CacheId aCacheId) override;
virtual void OnStorageDelete(RequestId aRequestId, nsresult aRv,
bool aCacheDeleted) override;
virtual void OnStorageKeys(RequestId aRequestId, nsresult aRv,
const nsTArray<nsString>& aKeys) override;
CacheStreamControlParent*
SerializeReadStream(CacheStreamControlParent *aStreamControl, const nsID& aId,
StreamList* aStreamList,
PCacheReadStream* aReadStreamOut);
void RetryPendingRequests();
nsresult RequestManager(RequestId aRequestId, cache::Manager** aManagerOut);
void ReleaseManager(RequestId aRequestId);
const Namespace mNamespace;
nsRefPtr<PrincipalVerifier> mVerifier;
nsresult mVerifiedStatus;
nsRefPtr<ManagerId> mManagerId;
nsRefPtr<cache::Manager> mManager;
enum Op
{
OP_MATCH,
OP_HAS,
OP_OPEN,
OP_DELETE,
OP_KEYS
};
struct Entry
{
Op mOp;
RequestId mRequestId;
nsString mKey;
PCacheRequest mRequest;
PCacheQueryParams mParams;
};
nsTArray<Entry> mPendingRequests;
nsTArray<RequestId> mActiveRequests;
};
} // namesapce cache

View File

@ -14,7 +14,6 @@
#include "nsIFile.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
#include "nsThreadUtils.h"
#include "DBSchema.h"
#include "FileUtils.h"

View File

@ -8,6 +8,7 @@
#define mozilla_dom_cache_DBAction_h
#include "mozilla/dom/cache/Action.h"
#include "mozilla/dom/cache/CacheInitData.h"
#include "nsRefPtr.h"
#include "nsString.h"

View File

@ -90,7 +90,8 @@ private:
// static
nsresult
FetchPut::Create(Listener* aListener, Manager* aManager, CacheId aCacheId,
FetchPut::Create(Listener* aListener, Manager* aManager,
RequestId aRequestId, CacheId aCacheId,
const nsTArray<PCacheRequest>& aRequests,
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams,
FetchPut** aFetchPutOut)
@ -106,7 +107,7 @@ FetchPut::Create(Listener* aListener, Manager* aManager, CacheId aCacheId,
}
#endif
nsRefPtr<FetchPut> ref = new FetchPut(aListener, aManager, aCacheId,
nsRefPtr<FetchPut> ref = new FetchPut(aListener, aManager, aRequestId, aCacheId,
aRequests, aRequestStreams);
nsresult rv = ref->DispatchToMainThread();
@ -124,11 +125,13 @@ FetchPut::ClearListener()
mListener = nullptr;
}
FetchPut::FetchPut(Listener* aListener, Manager* aManager, CacheId aCacheId,
FetchPut::FetchPut(Listener* aListener, Manager* aManager,
RequestId aRequestId, CacheId aCacheId,
const nsTArray<PCacheRequest>& aRequests,
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams)
: mListener(aListener)
, mManager(aManager)
, mRequestId(aRequestId)
, mCacheId(aCacheId)
, mInitiatingThread(NS_GetCurrentThread())
, mStateList(aRequests.Length())
@ -319,8 +322,8 @@ FetchPut::DoPutOnWorkerThread()
}
mStateList.Clear();
mManager->ExecutePutAll(this, mCacheId, putList, requestStreamList,
responseStreamList);
mManager->CachePutAll(this, mRequestId, mCacheId, putList, requestStreamList,
responseStreamList);
}
// static
@ -415,14 +418,9 @@ FetchPut::MatchInPutList(const PCacheRequest& aRequest,
}
void
FetchPut::OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
CacheId aOpenedCacheId,
const nsTArray<SavedResponse>& aSavedResponseList,
const nsTArray<SavedRequest>& aSavedRequestList,
StreamList* aStreamList)
FetchPut::OnCachePutAll(RequestId aRequestId, nsresult aRv)
{
MOZ_ASSERT(mInitiatingThread == NS_GetCurrentThread());
MOZ_ASSERT(aResult.type() == CacheOpResult::TCachePutAllResult);
MaybeSetError(aRv);
MaybeNotifyListener();
}
@ -443,7 +441,7 @@ FetchPut::MaybeNotifyListener()
if (!mListener) {
return;
}
mListener->OnFetchPut(this, mResult);
mListener->OnFetchPut(this, mRequestId, mResult);
}
nsIGlobalObject*

17
dom/cache/FetchPut.h vendored
View File

@ -39,11 +39,12 @@ public:
{
public:
virtual void
OnFetchPut(FetchPut* aFetchPut, nsresult aRv) = 0;
OnFetchPut(FetchPut* aFetchPut, RequestId aRequestId, nsresult aRv) = 0;
};
static nsresult
Create(Listener* aListener, Manager* aManager, CacheId aCacheId,
Create(Listener* aListener, Manager* aManager,
RequestId aRequestId, CacheId aCacheId,
const nsTArray<PCacheRequest>& aRequests,
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams,
FetchPut** aFetchPutOut);
@ -65,7 +66,8 @@ private:
nsRefPtr<Response> mResponse;
};
FetchPut(Listener* aListener, Manager* aManager, CacheId aCacheId,
FetchPut(Listener* aListener, Manager* aManager,
RequestId aRequestId, CacheId aCacheId,
const nsTArray<PCacheRequest>& aRequests,
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams);
~FetchPut();
@ -81,13 +83,7 @@ private:
void DoPutOnWorkerThread();
static bool MatchInPutList(const PCacheRequest& aRequest,
const nsTArray<CacheRequestResponse>& aPutList);
virtual void
OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
CacheId aOpenedCacheId,
const nsTArray<SavedResponse>& aSavedResponseList,
const nsTArray<SavedRequest>& aSavedRequestList,
StreamList* aStreamList) override;
virtual void OnCachePutAll(RequestId aRequestId, nsresult aRv) override;
void MaybeSetError(nsresult aRv);
void MaybeNotifyListener();
@ -103,6 +99,7 @@ private:
Listener* mListener;
nsRefPtr<Manager> mManager;
const RequestId mRequestId;
const CacheId mCacheId;
nsCOMPtr<nsIThread> mInitiatingThread;
nsTArray<State> mStateList;

435
dom/cache/Manager.cpp vendored
View File

@ -409,10 +409,11 @@ StaticRefPtr<nsIThread> Manager::Factory::sBackgroundThread;
class Manager::BaseAction : public SyncDBAction
{
protected:
BaseAction(Manager* aManager, ListenerId aListenerId)
BaseAction(Manager* aManager, ListenerId aListenerId, RequestId aRequestId)
: SyncDBAction(DBAction::Existing)
, mManager(aManager)
, mListenerId(aListenerId)
, mRequestId (aRequestId)
{
}
@ -434,6 +435,7 @@ protected:
nsRefPtr<Manager> mManager;
const ListenerId mListenerId;
const RequestId mRequestId;
};
// ----------------------------------------------------------------------------
@ -486,11 +488,14 @@ class Manager::CacheMatchAction final : public Manager::BaseAction
{
public:
CacheMatchAction(Manager* aManager, ListenerId aListenerId,
CacheId aCacheId, const CacheMatchArgs& aArgs,
RequestId aRequestId, CacheId aCacheId,
const PCacheRequest& aRequest,
const PCacheQueryParams& aParams,
StreamList* aStreamList)
: BaseAction(aManager, aListenerId)
: BaseAction(aManager, aListenerId, aRequestId)
, mCacheId(aCacheId)
, mArgs(aArgs)
, mRequest(aRequest)
, mParams(aParams)
, mStreamList(aStreamList)
, mFoundResponse(false)
{ }
@ -499,9 +504,8 @@ public:
RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
mozIStorageConnection* aConn) override
{
nsresult rv = DBSchema::CacheMatch(aConn, mCacheId, mArgs.request(),
mArgs.params(), &mFoundResponse,
&mResponse);
nsresult rv = DBSchema::CacheMatch(aConn, mCacheId, mRequest, mParams,
&mFoundResponse, &mResponse);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
if (!mFoundResponse || !mResponse.mHasBodyId) {
@ -523,11 +527,10 @@ public:
Complete(Listener* aListener, nsresult aRv) override
{
if (!mFoundResponse) {
aListener->OnOpComplete(aRv, CacheMatchResult(void_t()));
aListener->OnCacheMatch(mRequestId, aRv, nullptr, nullptr);
} else {
mStreamList->Activate(mCacheId);
aListener->OnOpComplete(aRv, CacheMatchResult(void_t()), mResponse,
mStreamList);
aListener->OnCacheMatch(mRequestId, aRv, &mResponse, mStreamList);
}
mStreamList = nullptr;
}
@ -539,7 +542,8 @@ public:
private:
const CacheId mCacheId;
const CacheMatchArgs mArgs;
const PCacheRequest mRequest;
const PCacheQueryParams mParams;
nsRefPtr<StreamList> mStreamList;
bool mFoundResponse;
SavedResponse mResponse;
@ -551,11 +555,14 @@ class Manager::CacheMatchAllAction final : public Manager::BaseAction
{
public:
CacheMatchAllAction(Manager* aManager, ListenerId aListenerId,
CacheId aCacheId, const CacheMatchAllArgs& aArgs,
RequestId aRequestId, CacheId aCacheId,
const PCacheRequestOrVoid& aRequestOrVoid,
const PCacheQueryParams& aParams,
StreamList* aStreamList)
: BaseAction(aManager, aListenerId)
: BaseAction(aManager, aListenerId, aRequestId)
, mCacheId(aCacheId)
, mArgs(aArgs)
, mRequestOrVoid(aRequestOrVoid)
, mParams(aParams)
, mStreamList(aStreamList)
{ }
@ -563,8 +570,8 @@ public:
RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
mozIStorageConnection* aConn) override
{
nsresult rv = DBSchema::CacheMatchAll(aConn, mCacheId, mArgs.requestOrVoid(),
mArgs.params(), mSavedResponses);
nsresult rv = DBSchema::CacheMatchAll(aConn, mCacheId, mRequestOrVoid,
mParams, mSavedResponses);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
for (uint32_t i = 0; i < mSavedResponses.Length(); ++i) {
@ -589,8 +596,7 @@ public:
Complete(Listener* aListener, nsresult aRv) override
{
mStreamList->Activate(mCacheId);
aListener->OnOpComplete(aRv, CacheMatchAllResult(), mSavedResponses,
mStreamList);
aListener->OnCacheMatchAll(mRequestId, aRv, mSavedResponses, mStreamList);
mStreamList = nullptr;
}
@ -601,7 +607,8 @@ public:
private:
const CacheId mCacheId;
const CacheMatchAllArgs mArgs;
const PCacheRequestOrVoid mRequestOrVoid;
const PCacheQueryParams mParams;
nsRefPtr<StreamList> mStreamList;
nsTArray<SavedResponse> mSavedResponses;
};
@ -615,13 +622,14 @@ class Manager::CachePutAllAction final : public DBAction
{
public:
CachePutAllAction(Manager* aManager, ListenerId aListenerId,
CacheId aCacheId,
RequestId aRequestId, CacheId aCacheId,
const nsTArray<CacheRequestResponse>& aPutList,
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList)
: DBAction(DBAction::Existing)
, mManager(aManager)
, mListenerId(aListenerId)
, mRequestId(aRequestId)
, mCacheId(aCacheId)
, mList(aPutList.Length())
, mExpectedAsyncCopyCompletions(1)
@ -806,7 +814,7 @@ private:
Listener* listener = mManager->GetListener(mListenerId);
mManager = nullptr;
if (listener) {
listener->OnOpComplete(aRv, CachePutAllResult());
listener->OnCachePutAll(mRequestId, aRv);
}
}
@ -959,6 +967,7 @@ private:
// initiating thread only
nsRefPtr<Manager> mManager;
const ListenerId mListenerId;
const RequestId mRequestId;
// Set on initiating thread, read on target thread. State machine guarantees
// these are not modified while being read by the target thread.
@ -989,10 +998,13 @@ class Manager::CacheDeleteAction final : public Manager::BaseAction
{
public:
CacheDeleteAction(Manager* aManager, ListenerId aListenerId,
CacheId aCacheId, const CacheDeleteArgs& aArgs)
: BaseAction(aManager, aListenerId)
RequestId aRequestId, CacheId aCacheId,
const PCacheRequest& aRequest,
const PCacheQueryParams& aParams)
: BaseAction(aManager, aListenerId, aRequestId)
, mCacheId(aCacheId)
, mArgs(aArgs)
, mRequest(aRequest)
, mParams(aParams)
, mSuccess(false)
{ }
@ -1003,9 +1015,8 @@ public:
mozStorageTransaction trans(aConn, false,
mozIStorageConnection::TRANSACTION_IMMEDIATE);
nsresult rv = DBSchema::CacheDelete(aConn, mCacheId, mArgs.request(),
mArgs.params(), mDeletedBodyIdList,
&mSuccess);
nsresult rv = DBSchema::CacheDelete(aConn, mCacheId, mRequest, mParams,
mDeletedBodyIdList, &mSuccess);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = trans.Commit();
@ -1021,7 +1032,7 @@ public:
Complete(Listener* aListener, nsresult aRv) override
{
mManager->NoteOrphanedBodyIdList(mDeletedBodyIdList);
aListener->OnOpComplete(aRv, CacheDeleteResult(mSuccess));
aListener->OnCacheDelete(mRequestId, aRv, mSuccess);
}
virtual bool MatchesCacheId(CacheId aCacheId) const override
@ -1031,7 +1042,8 @@ public:
private:
const CacheId mCacheId;
const CacheDeleteArgs mArgs;
const PCacheRequest mRequest;
const PCacheQueryParams mParams;
bool mSuccess;
nsTArray<nsID> mDeletedBodyIdList;
};
@ -1042,11 +1054,14 @@ class Manager::CacheKeysAction final : public Manager::BaseAction
{
public:
CacheKeysAction(Manager* aManager, ListenerId aListenerId,
CacheId aCacheId, const CacheKeysArgs& aArgs,
RequestId aRequestId, CacheId aCacheId,
const PCacheRequestOrVoid& aRequestOrVoid,
const PCacheQueryParams& aParams,
StreamList* aStreamList)
: BaseAction(aManager, aListenerId)
: BaseAction(aManager, aListenerId, aRequestId)
, mCacheId(aCacheId)
, mArgs(aArgs)
, mRequestOrVoid(aRequestOrVoid)
, mParams(aParams)
, mStreamList(aStreamList)
{ }
@ -1054,8 +1069,8 @@ public:
RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
mozIStorageConnection* aConn) override
{
nsresult rv = DBSchema::CacheKeys(aConn, mCacheId, mArgs.requestOrVoid(),
mArgs.params(), mSavedRequests);
nsresult rv = DBSchema::CacheKeys(aConn, mCacheId, mRequestOrVoid, mParams,
mSavedRequests);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
for (uint32_t i = 0; i < mSavedRequests.Length(); ++i) {
@ -1080,8 +1095,7 @@ public:
Complete(Listener* aListener, nsresult aRv) override
{
mStreamList->Activate(mCacheId);
aListener->OnOpComplete(aRv, CacheKeysResult(), mSavedRequests,
mStreamList);
aListener->OnCacheKeys(mRequestId, aRv, mSavedRequests, mStreamList);
mStreamList = nullptr;
}
@ -1092,7 +1106,8 @@ public:
private:
const CacheId mCacheId;
const CacheKeysArgs mArgs;
const PCacheRequestOrVoid mRequestOrVoid;
const PCacheQueryParams mParams;
nsRefPtr<StreamList> mStreamList;
nsTArray<SavedRequest> mSavedRequests;
};
@ -1103,12 +1118,14 @@ class Manager::StorageMatchAction final : public Manager::BaseAction
{
public:
StorageMatchAction(Manager* aManager, ListenerId aListenerId,
Namespace aNamespace,
const StorageMatchArgs& aArgs,
RequestId aRequestId, Namespace aNamespace,
const PCacheRequest& aRequest,
const PCacheQueryParams& aParams,
StreamList* aStreamList)
: BaseAction(aManager, aListenerId)
: BaseAction(aManager, aListenerId, aRequestId)
, mNamespace(aNamespace)
, mArgs(aArgs)
, mRequest(aRequest)
, mParams(aParams)
, mStreamList(aStreamList)
, mFoundResponse(false)
{ }
@ -1117,9 +1134,8 @@ public:
RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
mozIStorageConnection* aConn) override
{
nsresult rv = DBSchema::StorageMatch(aConn, mNamespace, mArgs.request(),
mArgs.params(), &mFoundResponse,
&mSavedResponse);
nsresult rv = DBSchema::StorageMatch(aConn, mNamespace, mRequest, mParams,
&mFoundResponse, &mSavedResponse);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
if (!mFoundResponse || !mSavedResponse.mHasBodyId) {
@ -1141,18 +1157,18 @@ public:
Complete(Listener* aListener, nsresult aRv) override
{
if (!mFoundResponse) {
aListener->OnOpComplete(aRv, StorageMatchResult(void_t()));
aListener->OnStorageMatch(mRequestId, aRv, nullptr, nullptr);
} else {
mStreamList->Activate(mSavedResponse.mCacheId);
aListener->OnOpComplete(aRv, StorageMatchResult(void_t()), mSavedResponse,
mStreamList);
aListener->OnStorageMatch(mRequestId, aRv, &mSavedResponse, mStreamList);
}
mStreamList = nullptr;
}
private:
const Namespace mNamespace;
const StorageMatchArgs mArgs;
const PCacheRequest mRequest;
const PCacheQueryParams mParams;
nsRefPtr<StreamList> mStreamList;
bool mFoundResponse;
SavedResponse mSavedResponse;
@ -1164,10 +1180,11 @@ class Manager::StorageHasAction final : public Manager::BaseAction
{
public:
StorageHasAction(Manager* aManager, ListenerId aListenerId,
Namespace aNamespace, const StorageHasArgs& aArgs)
: BaseAction(aManager, aListenerId)
RequestId aRequestId, Namespace aNamespace,
const nsAString& aKey)
: BaseAction(aManager, aListenerId, aRequestId)
, mNamespace(aNamespace)
, mArgs(aArgs)
, mKey(aKey)
, mCacheFound(false)
{ }
@ -1176,19 +1193,19 @@ public:
mozIStorageConnection* aConn) override
{
CacheId cacheId;
return DBSchema::StorageGetCacheId(aConn, mNamespace, mArgs.key(),
return DBSchema::StorageGetCacheId(aConn, mNamespace, mKey,
&mCacheFound, &cacheId);
}
virtual void
Complete(Listener* aListener, nsresult aRv) override
{
aListener->OnOpComplete(aRv, StorageHasResult(mCacheFound));
aListener->OnStorageHas(mRequestId, aRv, mCacheFound);
}
private:
const Namespace mNamespace;
const StorageHasArgs mArgs;
const nsString mKey;
bool mCacheFound;
};
@ -1198,10 +1215,11 @@ class Manager::StorageOpenAction final : public Manager::BaseAction
{
public:
StorageOpenAction(Manager* aManager, ListenerId aListenerId,
Namespace aNamespace, const StorageOpenArgs& aArgs)
: BaseAction(aManager, aListenerId)
RequestId aRequestId, Namespace aNamespace,
const nsAString& aKey)
: BaseAction(aManager, aListenerId, aRequestId)
, mNamespace(aNamespace)
, mArgs(aArgs)
, mKey(aKey)
, mCacheId(INVALID_CACHE_ID)
{ }
@ -1215,7 +1233,7 @@ public:
// Look for existing cache
bool cacheFound;
nsresult rv = DBSchema::StorageGetCacheId(aConn, mNamespace, mArgs.key(),
nsresult rv = DBSchema::StorageGetCacheId(aConn, mNamespace, mKey,
&cacheFound, &mCacheId);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
if (cacheFound) {
@ -1225,7 +1243,7 @@ public:
rv = DBSchema::CreateCache(aConn, &mCacheId);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = DBSchema::StoragePutCache(aConn, mNamespace, mArgs.key(), mCacheId);
rv = DBSchema::StoragePutCache(aConn, mNamespace, mKey, mCacheId);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = trans.Commit();
@ -1237,12 +1255,12 @@ public:
virtual void
Complete(Listener* aListener, nsresult aRv) override
{
aListener->OnOpComplete(aRv, StorageOpenResult(), mCacheId);
aListener->OnStorageOpen(mRequestId, aRv, mCacheId);
}
private:
const Namespace mNamespace;
const StorageOpenArgs mArgs;
const nsString mKey;
CacheId mCacheId;
};
@ -1252,10 +1270,11 @@ class Manager::StorageDeleteAction final : public Manager::BaseAction
{
public:
StorageDeleteAction(Manager* aManager, ListenerId aListenerId,
Namespace aNamespace, const StorageDeleteArgs& aArgs)
: BaseAction(aManager, aListenerId)
RequestId aRequestId, Namespace aNamespace,
const nsAString& aKey)
: BaseAction(aManager, aListenerId, aRequestId)
, mNamespace(aNamespace)
, mArgs(aArgs)
, mKey(aKey)
, mCacheDeleted(false)
, mCacheId(INVALID_CACHE_ID)
{ }
@ -1268,8 +1287,8 @@ public:
mozIStorageConnection::TRANSACTION_IMMEDIATE);
bool exists;
nsresult rv = DBSchema::StorageGetCacheId(aConn, mNamespace, mArgs.key(),
&exists, &mCacheId);
nsresult rv = DBSchema::StorageGetCacheId(aConn, mNamespace, mKey, &exists,
&mCacheId);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
if (!exists) {
@ -1277,7 +1296,7 @@ public:
return NS_OK;
}
rv = DBSchema::StorageForgetCache(aConn, mNamespace, mArgs.key());
rv = DBSchema::StorageForgetCache(aConn, mNamespace, mKey);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = trans.Commit();
@ -1304,12 +1323,12 @@ public:
}
}
aListener->OnOpComplete(aRv, StorageDeleteResult(mCacheDeleted));
aListener->OnStorageDelete(mRequestId, aRv, mCacheDeleted);
}
private:
const Namespace mNamespace;
const StorageDeleteArgs mArgs;
const nsString mKey;
bool mCacheDeleted;
CacheId mCacheId;
};
@ -1320,8 +1339,8 @@ class Manager::StorageKeysAction final : public Manager::BaseAction
{
public:
StorageKeysAction(Manager* aManager, ListenerId aListenerId,
Namespace aNamespace)
: BaseAction(aManager, aListenerId)
RequestId aRequestId, Namespace aNamespace)
: BaseAction(aManager, aListenerId, aRequestId)
, mNamespace(aNamespace)
{ }
@ -1338,7 +1357,7 @@ public:
if (NS_FAILED(aRv)) {
mKeys.Clear();
}
aListener->OnOpComplete(aRv, StorageKeysResult(mKeys));
aListener->OnStorageKeys(mRequestId, aRv, mKeys);
}
private:
@ -1351,50 +1370,6 @@ private:
//static
Manager::ListenerId Manager::sNextListenerId = 0;
void
Manager::Listener::OnOpComplete(nsresult aRv, const CacheOpResult& aResult)
{
OnOpComplete(aRv, aResult, INVALID_CACHE_ID, nsTArray<SavedResponse>(),
nsTArray<SavedRequest>(), nullptr);
}
void
Manager::Listener::OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
CacheId aOpenedCacheId)
{
OnOpComplete(aRv, aResult, aOpenedCacheId, nsTArray<SavedResponse>(),
nsTArray<SavedRequest>(), nullptr);
}
void
Manager::Listener::OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
const SavedResponse& aSavedResponse,
StreamList* aStreamList)
{
nsAutoTArray<SavedResponse, 1> responseList;
responseList.AppendElement(aSavedResponse);
OnOpComplete(aRv, aResult, INVALID_CACHE_ID, responseList,
nsTArray<SavedRequest>(), aStreamList);
}
void
Manager::Listener::OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
const nsTArray<SavedResponse>& aSavedResponseList,
StreamList* aStreamList)
{
OnOpComplete(aRv, aResult, INVALID_CACHE_ID, aSavedResponseList,
nsTArray<SavedRequest>(), aStreamList);
}
void
Manager::Listener::OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
const nsTArray<SavedRequest>& aSavedRequestList,
StreamList* aStreamList)
{
OnOpComplete(aRv, aResult, INVALID_CACHE_ID, nsTArray<SavedResponse>(),
aSavedRequestList, aStreamList);
}
// static
nsresult
Manager::GetOrCreate(ManagerId* aManagerId, Manager** aManagerOut)
@ -1585,115 +1560,195 @@ Manager::RemoveStreamList(StreamList* aStreamList)
}
void
Manager::ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
const CacheOpArgs& aOpArgs)
Manager::CacheMatch(Listener* aListener, RequestId aRequestId, CacheId aCacheId,
const PCacheRequest& aRequest,
const PCacheQueryParams& aParams)
{
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCacheAddAllArgs);
MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCachePutAllArgs);
if (mShuttingDown || !mValid) {
aListener->OnOpComplete(NS_ERROR_FAILURE, void_t());
aListener->OnCacheMatch(aRequestId, NS_ERROR_FAILURE, nullptr, nullptr);
return;
}
nsRefPtr<Context> context = CurrentContext();
nsRefPtr<StreamList> streamList = new StreamList(this, context);
ListenerId listenerId = SaveListener(aListener);
nsRefPtr<Action> action;
switch(aOpArgs.type()) {
case CacheOpArgs::TCacheMatchArgs:
action = new CacheMatchAction(this, listenerId, aCacheId,
aOpArgs.get_CacheMatchArgs(), streamList);
break;
case CacheOpArgs::TCacheMatchAllArgs:
action = new CacheMatchAllAction(this, listenerId, aCacheId,
aOpArgs.get_CacheMatchAllArgs(),
streamList);
break;
case CacheOpArgs::TCacheDeleteArgs:
action = new CacheDeleteAction(this, listenerId, aCacheId,
aOpArgs.get_CacheDeleteArgs());
break;
case CacheOpArgs::TCacheKeysArgs:
action = new CacheKeysAction(this, listenerId, aCacheId,
aOpArgs.get_CacheKeysArgs(), streamList);
break;
default:
MOZ_CRASH("Unknown Cache operation!");
}
nsRefPtr<Action> action = new CacheMatchAction(this, listenerId, aRequestId,
aCacheId, aRequest, aParams,
streamList);
context->Dispatch(mIOThread, action);
}
void
Manager::ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
const CacheOpArgs& aOpArgs)
Manager::CacheMatchAll(Listener* aListener, RequestId aRequestId,
CacheId aCacheId, const PCacheRequestOrVoid& aRequest,
const PCacheQueryParams& aParams)
{
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mShuttingDown || !mValid) {
aListener->OnOpComplete(NS_ERROR_FAILURE, void_t());
aListener->OnCacheMatchAll(aRequestId, NS_ERROR_FAILURE,
nsTArray<SavedResponse>(), nullptr);
return;
}
nsRefPtr<Context> context = CurrentContext();
nsRefPtr<StreamList> streamList = new StreamList(this, context);
ListenerId listenerId = SaveListener(aListener);
nsRefPtr<Action> action;
switch(aOpArgs.type()) {
case CacheOpArgs::TStorageMatchArgs:
action = new StorageMatchAction(this, listenerId, aNamespace,
aOpArgs.get_StorageMatchArgs(),
streamList);
break;
case CacheOpArgs::TStorageHasArgs:
action = new StorageHasAction(this, listenerId, aNamespace,
aOpArgs.get_StorageHasArgs());
break;
case CacheOpArgs::TStorageOpenArgs:
action = new StorageOpenAction(this, listenerId, aNamespace,
aOpArgs.get_StorageOpenArgs());
break;
case CacheOpArgs::TStorageDeleteArgs:
action = new StorageDeleteAction(this, listenerId, aNamespace,
aOpArgs.get_StorageDeleteArgs());
break;
case CacheOpArgs::TStorageKeysArgs:
action = new StorageKeysAction(this, listenerId, aNamespace);
break;
default:
MOZ_CRASH("Unknown CacheStorage operation!");
}
nsRefPtr<Action> action = new CacheMatchAllAction(this, listenerId, aRequestId,
aCacheId, aRequest, aParams,
streamList);
context->Dispatch(mIOThread, action);
}
void
Manager::ExecutePutAll(Listener* aListener, CacheId aCacheId,
const nsTArray<CacheRequestResponse>& aPutList,
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList)
Manager::CachePutAll(Listener* aListener, RequestId aRequestId, CacheId aCacheId,
const nsTArray<CacheRequestResponse>& aPutList,
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList)
{
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mShuttingDown || !mValid) {
aListener->OnOpComplete(NS_ERROR_FAILURE, CachePutAllResult());
aListener->OnCachePutAll(aRequestId, NS_ERROR_FAILURE);
return;
}
nsRefPtr<Context> context = CurrentContext();
ListenerId listenerId = SaveListener(aListener);
nsRefPtr<Action> action = new CachePutAllAction(this, listenerId, aCacheId,
aPutList, aRequestStreamList,
nsRefPtr<Action> action = new CachePutAllAction(this, listenerId, aRequestId,
aCacheId, aPutList,
aRequestStreamList,
aResponseStreamList);
nsRefPtr<Context> context = CurrentContext();
context->Dispatch(mIOThread, action);
}
void
Manager::CacheDelete(Listener* aListener, RequestId aRequestId,
CacheId aCacheId, const PCacheRequest& aRequest,
const PCacheQueryParams& aParams)
{
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mShuttingDown || !mValid) {
aListener->OnCacheDelete(aRequestId, NS_ERROR_FAILURE, false);
return;
}
ListenerId listenerId = SaveListener(aListener);
nsRefPtr<Action> action = new CacheDeleteAction(this, listenerId, aRequestId,
aCacheId, aRequest, aParams);
nsRefPtr<Context> context = CurrentContext();
context->Dispatch(mIOThread, action);
}
void
Manager::CacheKeys(Listener* aListener, RequestId aRequestId,
CacheId aCacheId, const PCacheRequestOrVoid& aRequestOrVoid,
const PCacheQueryParams& aParams)
{
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mShuttingDown || !mValid) {
aListener->OnCacheKeys(aRequestId, NS_ERROR_FAILURE,
nsTArray<SavedRequest>(), nullptr);
return;
}
nsRefPtr<Context> context = CurrentContext();
nsRefPtr<StreamList> streamList = new StreamList(this, context);
ListenerId listenerId = SaveListener(aListener);
nsRefPtr<Action> action = new CacheKeysAction(this, listenerId, aRequestId,
aCacheId, aRequestOrVoid,
aParams, streamList);
context->Dispatch(mIOThread, action);
}
void
Manager::StorageMatch(Listener* aListener, RequestId aRequestId,
Namespace aNamespace, const PCacheRequest& aRequest,
const PCacheQueryParams& aParams)
{
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mShuttingDown || !mValid) {
aListener->OnStorageMatch(aRequestId, NS_ERROR_FAILURE,
nullptr, nullptr);
return;
}
nsRefPtr<Context> context = CurrentContext();
nsRefPtr<StreamList> streamList = new StreamList(this, context);
ListenerId listenerId = SaveListener(aListener);
nsRefPtr<Action> action = new StorageMatchAction(this, listenerId, aRequestId,
aNamespace, aRequest,
aParams, streamList);
context->Dispatch(mIOThread, action);
}
void
Manager::StorageHas(Listener* aListener, RequestId aRequestId,
Namespace aNamespace, const nsAString& aKey)
{
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mShuttingDown || !mValid) {
aListener->OnStorageHas(aRequestId, NS_ERROR_FAILURE,
false);
return;
}
ListenerId listenerId = SaveListener(aListener);
nsRefPtr<Action> action = new StorageHasAction(this, listenerId, aRequestId,
aNamespace, aKey);
nsRefPtr<Context> context = CurrentContext();
context->Dispatch(mIOThread, action);
}
void
Manager::StorageOpen(Listener* aListener, RequestId aRequestId,
Namespace aNamespace, const nsAString& aKey)
{
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mShuttingDown || !mValid) {
aListener->OnStorageOpen(aRequestId, NS_ERROR_FAILURE, 0);
return;
}
ListenerId listenerId = SaveListener(aListener);
nsRefPtr<Action> action = new StorageOpenAction(this, listenerId, aRequestId,
aNamespace, aKey);
nsRefPtr<Context> context = CurrentContext();
context->Dispatch(mIOThread, action);
}
void
Manager::StorageDelete(Listener* aListener, RequestId aRequestId,
Namespace aNamespace, const nsAString& aKey)
{
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mShuttingDown || !mValid) {
aListener->OnStorageDelete(aRequestId, NS_ERROR_FAILURE,
false);
return;
}
ListenerId listenerId = SaveListener(aListener);
nsRefPtr<Action> action = new StorageDeleteAction(this, listenerId, aRequestId,
aNamespace, aKey);
nsRefPtr<Context> context = CurrentContext();
context->Dispatch(mIOThread, action);
}
void
Manager::StorageKeys(Listener* aListener, RequestId aRequestId,
Namespace aNamespace)
{
NS_ASSERT_OWNINGTHREAD(Manager);
MOZ_ASSERT(aListener);
if (mShuttingDown || !mValid) {
aListener->OnStorageKeys(aRequestId, NS_ERROR_FAILURE,
nsTArray<nsString>());
return;
}
ListenerId listenerId = SaveListener(aListener);
nsRefPtr<Action> action = new StorageKeysAction(this, listenerId, aRequestId,
aNamespace);
nsRefPtr<Context> context = CurrentContext();
context->Dispatch(mIOThread, action);
}

91
dom/cache/Manager.h vendored
View File

@ -7,6 +7,7 @@
#ifndef mozilla_dom_cache_Manager_h
#define mozilla_dom_cache_Manager_h
#include "mozilla/dom/cache/CacheInitData.h"
#include "mozilla/dom/cache/PCacheStreamControlParent.h"
#include "mozilla/dom/cache/Types.h"
#include "nsCOMPtr.h"
@ -21,8 +22,6 @@ namespace mozilla {
namespace dom {
namespace cache {
class CacheOpArgs;
class CacheOpResult;
class CacheRequestResponse;
class Context;
class ManagerId;
@ -87,36 +86,30 @@ public:
class Listener
{
public:
// convenience routines
void
OnOpComplete(nsresult aRv, const CacheOpResult& aResult);
virtual void OnCacheMatch(RequestId aRequestId, nsresult aRv,
const SavedResponse* aResponse,
StreamList* aStreamList) { }
virtual void OnCacheMatchAll(RequestId aRequestId, nsresult aRv,
const nsTArray<SavedResponse>& aSavedResponses,
StreamList* aStreamList) { }
virtual void OnCachePutAll(RequestId aRequestId, nsresult aRv) { }
virtual void OnCacheDelete(RequestId aRequestId, nsresult aRv,
bool aSuccess) { }
virtual void OnCacheKeys(RequestId aRequestId, nsresult aRv,
const nsTArray<SavedRequest>& aSavedRequests,
StreamList* aStreamList) { }
void
OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
CacheId aOpenedCacheId);
void
OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
const SavedResponse& aSavedResponse,
StreamList* aStreamList);
void
OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
const nsTArray<SavedResponse>& aSavedResponseList,
StreamList* aStreamList);
void
OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
const nsTArray<SavedRequest>& aSavedRequestList,
StreamList* aStreamList);
// interface to be implemented
virtual void
OnOpComplete(nsresult aRv, const CacheOpResult& aResult,
CacheId aOpenedCacheId,
const nsTArray<SavedResponse>& aSavedResponseList,
const nsTArray<SavedRequest>& aSavedRequestList,
StreamList* aStreamList) { }
virtual void OnStorageMatch(RequestId aRequestId, nsresult aRv,
const SavedResponse* aResponse,
StreamList* aStreamList) { }
virtual void OnStorageHas(RequestId aRequestId, nsresult aRv,
bool aCacheFound) { }
virtual void OnStorageOpen(RequestId aRequestId, nsresult aRv,
CacheId aCacheId) { }
virtual void OnStorageDelete(RequestId aRequestId, nsresult aRv,
bool aCacheDeleted) { }
virtual void OnStorageKeys(RequestId aRequestId, nsresult aRv,
const nsTArray<nsString>& aKeys) { }
protected:
~Listener() { }
@ -157,15 +150,35 @@ public:
void AddStreamList(StreamList* aStreamList);
void RemoveStreamList(StreamList* aStreamList);
void ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
const CacheOpArgs& aOpArgs);
void ExecutePutAll(Listener* aListener, CacheId aCacheId,
const nsTArray<CacheRequestResponse>& aPutList,
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList);
// TODO: consider moving CacheId up in the argument lists below (bug 1110485)
void CacheMatch(Listener* aListener, RequestId aRequestId, CacheId aCacheId,
const PCacheRequest& aRequest,
const PCacheQueryParams& aParams);
void CacheMatchAll(Listener* aListener, RequestId aRequestId,
CacheId aCacheId, const PCacheRequestOrVoid& aRequestOrVoid,
const PCacheQueryParams& aParams);
void CachePutAll(Listener* aListener, RequestId aRequestId, CacheId aCacheId,
const nsTArray<CacheRequestResponse>& aPutList,
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList);
void CacheDelete(Listener* aListener, RequestId aRequestId,
CacheId aCacheId, const PCacheRequest& aRequest,
const PCacheQueryParams& aParams);
void CacheKeys(Listener* aListener, RequestId aRequestId,
CacheId aCacheId, const PCacheRequestOrVoid& aRequestOrVoid,
const PCacheQueryParams& aParams);
void ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
const CacheOpArgs& aOpArgs);
void StorageMatch(Listener* aListener, RequestId aRequestId,
Namespace aNamespace, const PCacheRequest& aRequest,
const PCacheQueryParams& aParams);
void StorageHas(Listener* aListener, RequestId aRequestId,
Namespace aNamespace, const nsAString& aKey);
void StorageOpen(Listener* aListener, RequestId aRequestId,
Namespace aNamespace, const nsAString& aKey);
void StorageDelete(Listener* aListener, RequestId aRequestId,
Namespace aNamespace, const nsAString& aKey);
void StorageKeys(Listener* aListener, RequestId aRequestId,
Namespace aNamespace);
private:
class Factory;

20
dom/cache/PCache.ipdl vendored
View File

@ -3,7 +3,6 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PBackground;
include protocol PCacheOp;
include protocol PCachePushStream;
include PCacheTypes;
include protocol PFileDescriptorSet;
@ -11,6 +10,9 @@ include protocol PFileDescriptorSet;
include protocol PBlob; // FIXME: bug 792908
include protocol PCacheStreamControl;
using mozilla::dom::cache::RequestId from "mozilla/dom/cache/Types.h";
include "mozilla/dom/cache/IPCUtils.h";
namespace mozilla {
namespace dom {
namespace cache {
@ -18,15 +20,27 @@ namespace cache {
protocol PCache
{
manager PBackground;
manages PCacheOp;
manages PCachePushStream;
parent:
PCacheOp(CacheOpArgs aOpArgs);
PCachePushStream();
Teardown();
Match(RequestId requestId, PCacheRequest request, PCacheQueryParams params);
MatchAll(RequestId requestId, PCacheRequestOrVoid request, PCacheQueryParams params);
AddAll(RequestId requestId, PCacheRequest[] requests);
Put(RequestId requestId, CacheRequestResponse aPut);
Delete(RequestId requestId, PCacheRequest request, PCacheQueryParams params);
Keys(RequestId requestId, PCacheRequestOrVoid request, PCacheQueryParams params);
child:
MatchResponse(RequestId requestId, nsresult aRv, PCacheResponseOrVoid aResponse);
MatchAllResponse(RequestId requestId, nsresult aRv, PCacheResponse[] responses);
AddAllResponse(RequestId requestId, nsresult aRv);
PutResponse(RequestId requestId, nsresult aRv);
DeleteResponse(RequestId requestId, nsresult aRv, bool success);
KeysResponse(RequestId requestId, nsresult aRv, PCacheRequest[] requests);
both:
__delete__();
};

View File

@ -1,29 +0,0 @@
/* 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 PCache;
include protocol PCacheStorage;
// these are needed indirectly through CacheOpResult
include protocol PCachePushStream;
include protocol PCacheStreamControl;
include protocol PFileDescriptorSet;
include PCacheTypes;
namespace mozilla {
namespace dom {
namespace cache {
protocol PCacheOp
{
manager PCache or PCacheStorage;
child:
__delete__(nsresult aStatus, CacheOpResult aResult);
};
} // namespace cache
} // namespace dom
} // namespace mozilla

View File

@ -4,13 +4,14 @@
include protocol PBackground;
include protocol PCache;
include protocol PCacheOp;
include PCacheTypes;
include protocol PFileDescriptorSet;
include protocol PBlob; // FIXME: bug 792908
include protocol PCacheStreamControl;
using mozilla::dom::cache::RequestId from "mozilla/dom/cache/IPCUtils.h";
namespace mozilla {
namespace dom {
namespace cache {
@ -18,13 +19,23 @@ namespace cache {
protocol PCacheStorage
{
manager PBackground;
manages PCacheOp;
parent:
PCacheOp(CacheOpArgs aOpArgs);
Teardown();
Match(RequestId aRequestId, PCacheRequest aRequest,
PCacheQueryParams aParams);
Has(RequestId aRequestId, nsString aKey);
Open(RequestId aRequestId, nsString aKey);
Delete(RequestId aRequestId, nsString aKey);
Keys(RequestId aRequestId);
child:
MatchResponse(RequestId aRequestId, nsresult aRv,
PCacheResponseOrVoid aResponseOrVoid);
HasResponse(RequestId aRequestId, nsresult aRv, bool aSuccess);
OpenResponse(RequestId aRequestId, nsresult aRv, nullable PCache aActor);
DeleteResponse(RequestId aRequestId, nsresult aRv, bool aSuccess);
KeysResponse(RequestId aRequestId, nsresult aRv, nsString[] aKeys);
__delete__();
};

View File

@ -2,7 +2,6 @@
* 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 PCache;
include protocol PCachePushStream;
include protocol PCacheStreamControl;
include PHeaders;
@ -91,149 +90,6 @@ struct CacheRequestResponse
PCacheResponse response;
};
struct CacheMatchArgs
{
PCacheRequest request;
PCacheQueryParams params;
};
struct CacheMatchAllArgs
{
PCacheRequestOrVoid requestOrVoid;
PCacheQueryParams params;
};
struct CacheAddAllArgs
{
PCacheRequest[] requestList;
};
struct CachePutAllArgs
{
CacheRequestResponse[] requestResponseList;
};
struct CacheDeleteArgs
{
PCacheRequest request;
PCacheQueryParams params;
};
struct CacheKeysArgs
{
PCacheRequestOrVoid requestOrVoid;
PCacheQueryParams params;
};
struct StorageMatchArgs
{
PCacheRequest request;
PCacheQueryParams params;
};
struct StorageHasArgs
{
nsString key;
};
struct StorageOpenArgs
{
nsString key;
};
struct StorageDeleteArgs
{
nsString key;
};
struct StorageKeysArgs
{
};
union CacheOpArgs
{
CacheMatchArgs;
CacheMatchAllArgs;
CacheAddAllArgs;
CachePutAllArgs;
CacheDeleteArgs;
CacheKeysArgs;
StorageMatchArgs;
StorageHasArgs;
StorageOpenArgs;
StorageDeleteArgs;
StorageKeysArgs;
};
struct CacheMatchResult
{
PCacheResponseOrVoid responseOrVoid;
};
struct CacheMatchAllResult
{
PCacheResponse[] responseList;
};
struct CacheAddAllResult
{
};
struct CachePutAllResult
{
};
struct CacheDeleteResult
{
bool success;
};
struct CacheKeysResult
{
PCacheRequest[] requestList;
};
struct StorageMatchResult
{
PCacheResponseOrVoid responseOrVoid;
};
struct StorageHasResult
{
bool success;
};
struct StorageOpenResult
{
nullable PCache actor;
};
struct StorageDeleteResult
{
bool success;
};
struct StorageKeysResult
{
nsString[] keyList;
};
union CacheOpResult
{
void_t;
CacheMatchResult;
CacheMatchAllResult;
CacheAddAllResult;
CachePutAllResult;
CacheDeleteResult;
CacheKeysResult;
StorageMatchResult;
StorageHasResult;
StorageOpenResult;
StorageDeleteResult;
StorageKeysResult;
};
} // namespace cache
} // namespace dom
} // namespace mozilla

View File

@ -46,35 +46,25 @@ PrincipalVerifier::CreateAndDispatch(Listener* aListener,
}
void
PrincipalVerifier::AddListener(Listener* aListener)
PrincipalVerifier::ClearListener()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aListener);
MOZ_ASSERT(!mListenerList.Contains(aListener));
mListenerList.AppendElement(aListener);
}
void
PrincipalVerifier::RemoveListener(Listener* aListener)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aListener);
MOZ_ALWAYS_TRUE(mListenerList.RemoveElement(aListener));
MOZ_ASSERT(mListener);
mListener = nullptr;
}
PrincipalVerifier::PrincipalVerifier(Listener* aListener,
PBackgroundParent* aActor,
const PrincipalInfo& aPrincipalInfo)
: mActor(BackgroundParent::GetContentParent(aActor))
: mListener(aListener)
, mActor(BackgroundParent::GetContentParent(aActor))
, mPrincipalInfo(aPrincipalInfo)
, mInitiatingThread(NS_GetCurrentThread())
, mResult(NS_OK)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mListener);
MOZ_ASSERT(mInitiatingThread);
MOZ_ASSERT(aListener);
mListenerList.AppendElement(aListener);
}
PrincipalVerifier::~PrincipalVerifier()
@ -83,7 +73,7 @@ PrincipalVerifier::~PrincipalVerifier()
// threads, its a race to see which thread de-refs us last. Therefore
// we cannot guarantee which thread we destruct on.
MOZ_ASSERT(mListenerList.IsEmpty());
MOZ_ASSERT(!mListener);
// We should always be able to explicitly release the actor on the main
// thread.
@ -182,13 +172,17 @@ void
PrincipalVerifier::CompleteOnInitiatingThread()
{
AssertIsOnBackgroundThread();
ListenerList::ForwardIterator iter(mListenerList);
while (iter.HasMore()) {
iter.GetNext()->OnPrincipalVerified(mResult, mManagerId);
// This can happen if the listener is destroyed before we finish. For
// example, if the child process OOMs and the actor is destroyed.
if (!mListener) {
return;
}
// The listener must clear its reference in OnPrincipalVerified()
MOZ_ASSERT(mListenerList.IsEmpty());
mListener->OnPrincipalVerified(mResult, mManagerId);
// The listener must clear their reference in OnPrincipalVerified()
MOZ_ASSERT(!mListener);
}
void

View File

@ -9,7 +9,6 @@
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "nsThreadUtils.h"
#include "nsTObserverArray.h"
namespace mozilla {
@ -27,7 +26,7 @@ class PrincipalVerifier final : public nsRunnable
public:
// An interface to be implemented by code wishing to use the
// PrincipalVerifier. Note, the Listener implementation is responsible
// for calling RemoveListener() on the PrincipalVerifier to clear the
// for calling ClearListener() on the PrincipalVerifier to clear the
// weak reference.
class Listener
{
@ -39,11 +38,9 @@ public:
CreateAndDispatch(Listener* aListener, mozilla::ipc::PBackgroundParent* aActor,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
void AddListener(Listener* aListener);
// The Listener must call RemoveListener() when OnPrincipalVerified() is
// The Listener must call ClearListener() when OnPrincipalVerified() is
// called or when the Listener is destroyed.
void RemoveListener(Listener* aListener);
void ClearListener();
private:
PrincipalVerifier(Listener* aListener, mozilla::ipc::PBackgroundParent* aActor,
@ -55,9 +52,8 @@ private:
void DispatchToInitiatingThread(nsresult aRv);
// Weak reference cleared by RemoveListener()
typedef nsTObserverArray<Listener*> ListenerList;
ListenerList mListenerList;
// Weak reference cleared by ClearListener()
Listener* mListener;
// set in originating thread at construction, but must be accessed and
// released on main thread

4
dom/cache/Types.h vendored
View File

@ -22,7 +22,9 @@ enum Namespace
CHROME_ONLY_NAMESPACE,
NUMBER_OF_NAMESPACES
};
static const Namespace INVALID_NAMESPACE = NUMBER_OF_NAMESPACES;
typedef uintptr_t RequestId;
static const RequestId INVALID_REQUEST_ID = 0;
typedef int64_t CacheId;
static const CacheId INVALID_CACHE_ID = -1;

6
dom/cache/moz.build vendored
View File

@ -11,8 +11,6 @@ EXPORTS.mozilla.dom.cache += [
'AutoUtils.h',
'Cache.h',
'CacheChild.h',
'CacheOpChild.h',
'CacheOpParent.h',
'CacheParent.h',
'CachePushStreamChild.h',
'CachePushStreamParent.h',
@ -48,8 +46,6 @@ UNIFIED_SOURCES += [
'AutoUtils.cpp',
'Cache.cpp',
'CacheChild.cpp',
'CacheOpChild.cpp',
'CacheOpParent.cpp',
'CacheParent.cpp',
'CachePushStreamChild.cpp',
'CachePushStreamParent.cpp',
@ -77,8 +73,8 @@ UNIFIED_SOURCES += [
]
IPDL_SOURCES += [
'CacheInitData.ipdlh',
'PCache.ipdl',
'PCacheOp.ipdl',
'PCachePushStream.ipdl',
'PCacheStorage.ipdl',
'PCacheStreamControl.ipdl',