fune/netwerk/protocol/http/AltDataOutputStreamChild.cpp
Valentin Gosu b830ea1f6d Bug 1363653 - Make AltDataOutputStreamParent not send any messages after object destruction r=mayhemer
This patch prevents the following error:
AltDataOutputStreamChild::Close -> SendClose()
AltDataOutputStreamChild::Release -> Send__delete__()
AltDataOutputStreamParent::RecvClose() -> SendError()
AltDataOutputStreamParent::ActorDestroy -> mIPCOpen = false
AltDataOutputStreamChild::RecvError -> === Crash - object was deleted ===

We introduce the DeleteSelf message.
AltDataOutputStreamChild::Release -> SendDeleteSelf()
AltDataOutputStreamParent::RecvDeleteSelf -> mIPCOpen = false; SendDeleteSelf()
AltDataOutputStreamChild::RecvDeleteSelf -> Send__delete__()

The parent will not send any more messages after receiving the DeleteSelf message.

MozReview-Commit-ID: I9RQ5I7eSt9

--HG--
extra : rebase_source : 8f918d24595248149ebd3857e05e38dc5237059b
2017-05-11 21:35:37 +02:00

158 lines
3.4 KiB
C++

#include "mozilla/net/AltDataOutputStreamChild.h"
#include "mozilla/Unused.h"
#include "nsIInputStream.h"
namespace mozilla {
namespace net {
NS_IMPL_ADDREF(AltDataOutputStreamChild)
NS_IMETHODIMP_(MozExternalRefCountType) AltDataOutputStreamChild::Release()
{
NS_PRECONDITION(0 != mRefCnt, "dup release");
MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
--mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "AltDataOutputStreamChild");
if (mRefCnt == 1 && mIPCOpen) {
// The only reference left is the IPDL one. After the parent replies back
// with a DeleteSelf message, the child will call Send__delete__(this),
// decrementing the ref count and triggering the destructor.
SendDeleteSelf();
return 1;
}
if (mRefCnt == 0) {
mRefCnt = 1; /* stabilize */
delete this;
return 0;
}
return mRefCnt;
}
NS_INTERFACE_MAP_BEGIN(AltDataOutputStreamChild)
NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
AltDataOutputStreamChild::AltDataOutputStreamChild()
: mIPCOpen(false)
, mError(NS_OK)
{
MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
}
AltDataOutputStreamChild::~AltDataOutputStreamChild()
{
}
void
AltDataOutputStreamChild::AddIPDLReference()
{
MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
mIPCOpen = true;
AddRef();
}
void
AltDataOutputStreamChild::ReleaseIPDLReference()
{
MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference");
mIPCOpen = false;
Release();
}
bool
AltDataOutputStreamChild::WriteDataInChunks(const nsCString& data)
{
const uint32_t kChunkSize = 128*1024;
uint32_t next = std::min(data.Length(), kChunkSize);
for (uint32_t i = 0; i < data.Length();
i = next, next = std::min(data.Length(), next + kChunkSize)) {
nsCString chunk(Substring(data, i, kChunkSize));
if (mIPCOpen && !SendWriteData(chunk)) {
mIPCOpen = false;
return false;
}
}
return true;
}
NS_IMETHODIMP
AltDataOutputStreamChild::Close()
{
if (!mIPCOpen) {
return NS_ERROR_NOT_AVAILABLE;
}
if (NS_FAILED(mError)) {
return mError;
}
Unused << SendClose();
return NS_OK;
}
NS_IMETHODIMP
AltDataOutputStreamChild::Flush()
{
if (!mIPCOpen) {
return NS_ERROR_NOT_AVAILABLE;
}
if (NS_FAILED(mError)) {
return mError;
}
// This is a no-op
return NS_OK;
}
NS_IMETHODIMP
AltDataOutputStreamChild::Write(const char * aBuf, uint32_t aCount, uint32_t *_retval)
{
if (!mIPCOpen) {
return NS_ERROR_NOT_AVAILABLE;
}
if (NS_FAILED(mError)) {
return mError;
}
if (WriteDataInChunks(nsCString(aBuf, aCount))) {
*_retval = aCount;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
AltDataOutputStreamChild::WriteFrom(nsIInputStream *aFromStream, uint32_t aCount, uint32_t *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
AltDataOutputStreamChild::WriteSegments(nsReadSegmentFun aReader, void *aClosure, uint32_t aCount, uint32_t *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
AltDataOutputStreamChild::IsNonBlocking(bool *_retval)
{
*_retval = false;
return NS_OK;
}
mozilla::ipc::IPCResult
AltDataOutputStreamChild::RecvError(const nsresult& err)
{
mError = err;
return IPC_OK();
}
mozilla::ipc::IPCResult
AltDataOutputStreamChild::RecvDeleteSelf()
{
PAltDataOutputStreamChild::Send__delete__(this);
return IPC_OK();
}
} // namespace net
} // namespace mozilla